chromium/chrome/browser/search_engines/template_url_service_unittest.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "components/search_engines/template_url_service.h"

#include <stddef.h>

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/simple_test_clock.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/search_engines/template_url_service_test_util.h"
#include "chrome/test/base/testing_profile.h"
#include "components/history/core/browser/history_service.h"
#include "components/omnibox/common/omnibox_features.h"
#include "components/search_engines/keyword_web_data_service.h"
#include "components/search_engines/search_engine_type.h"
#include "components/search_engines/search_engines_pref_names.h"
#include "components/search_engines/search_engines_switches.h"
#include "components/search_engines/search_engines_test_util.h"
#include "components/search_engines/search_host_to_urls_map.h"
#include "components/search_engines/search_terms_data.h"
#include "components/search_engines/template_url.h"
#include "components/search_engines/template_url_data.h"
#include "components/search_engines/template_url_prepopulate_data.h"
#include "components/search_engines/template_url_starter_pack_data.h"
#include "components/search_engines/util.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

ASCIIToUTF16;
Time;
SiteSearchPolicyConflictType;
NotNull;

namespace {

// A prepopulated ID to set for engines we want to show in the default list.
// This must simply be greater than 0.
static constexpr int kPrepopulatedId =;

std::unique_ptr<TemplateURL> CreateKeywordWithDate(
    TemplateURLService* model,
    const std::string& short_name,
    const std::string& keyword,
    const std::string& url,
    const std::string& suggest_url,
    const std::string& alternate_url,
    const std::string& favicon_url,
    bool safe_for_autoreplace,
    int prepopulate_id,
    const std::string& encodings = "UTF-8",
    Time date_created = Time(),
    Time last_modified = Time(),
    Time last_visited = Time(),
    TemplateURL::Type type = TemplateURL::NORMAL) {}

TemplateURL* AddKeywordWithDate(TemplateURLService* model,
                                const std::string& short_name,
                                const std::string& keyword,
                                const std::string& url,
                                const std::string& suggest_url,
                                const std::string& alternate_url,
                                const std::string& favicon_url,
                                bool safe_for_autoreplace,
                                const std::string& encodings,
                                Time date_created,
                                Time last_modified,
                                Time last_visited) {}

// Checks that the two TemplateURLs are similar. It does not check the id or
// any time-related fields. Neither pointer should be NULL.
void ExpectSimilar(const TemplateURL* expected, const TemplateURL* actual) {}

std::unique_ptr<TemplateURLData> CreateTestSearchEngine() {}

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
    BUILDFLAG(IS_CHROMEOS)
// Creates a `TemplateURLData` corresponding to a site search engine set by
// policy, with some fake data generated from `keyword` and the
// `featured_by_policy` field set according to the corresponding parameter.
std::unique_ptr<TemplateURLData> CreateTestSiteSearchEntry(
    const std::string& keyword,
    bool featured_by_policy) {}

// Creates a `TemplateURLData` corresponding to a site search engine set by
// policy, with some fake data generated from `keyword` and
// `featured_by_policy` set as false.
std::unique_ptr<TemplateURLData> CreateTestSiteSearchEntry(
    const std::string& keyword) {}

// Creates a `TemplateURLData` with some fake data generated from `keyword`
// and with the `safe_for_autoreplace` field set according to the
// corresponding parameter.
TemplateURLData CreateTestSearchEngineWithSafeForAutoreplace(
    const std::string& keyword,
    bool safe_for_autoreplace) {}

void VerifySiteSearchPolicyConflictHistograms(
    const base::HistogramTester& histogram_tester,
    const base::flat_map<SiteSearchPolicyConflictType, int>& expected_counts) {}
#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
        // BUILDFLAG(IS_CHROMEOS)

std::string ParamToTestSuffix(const ::testing::TestParamInfo<bool>& info) {}

}  // namespace


// TemplateURLServiceTest -----------------------------------------------------

class TemplateURLServiceTestBase : public testing::Test {};

class TemplateURLServiceTest : public TemplateURLServiceTestBase,
                               public testing::WithParamInterface<bool> {};

class TemplateURLServiceWithoutFallbackTest : public TemplateURLServiceTest {};

#if BUILDFLAG(IS_ANDROID)
class TemplateURLServicePlayApiTest : public TemplateURLServiceTestBase,
                                      public testing::WithParamInterface<bool> {
 public:
  static std::string ParamToTestSuffix(
      const ::testing::TestParamInfo<bool>& info) {
    std::string suffix =
        info.param ? "SearchEngineChoiceEnabled" : "SearchEngineChoiceDisabled";

    return suffix;
  }

  TemplateURLServicePlayApiTest() : TemplateURLServiceTestBase(GetParam()) {
    EXPECT_EQ(
        IsSearchEngineChoiceEnabled(),
        base::FeatureList::IsEnabled(switches::kSearchEngineChoiceTrigger));
  }

 private:
  base::test::ScopedFeatureList feature_list_;
};
#endif  // BUILDFLAG(IS_ANDROID)

TemplateURLServiceTestBase::TemplateURLServiceTestBase(
    bool is_search_engine_choice_enabled)
    :{}

void TemplateURLServiceTestBase::SetUp() {}

void TemplateURLServiceTestBase::TearDown() {}

TemplateURL* TemplateURLServiceTestBase::AddKeywordWithDate(
    const std::string& short_name,
    const std::string& keyword,
    const std::string& url,
    const std::string& suggest_url,
    const std::string& alternate_url,
    const std::string& favicon_url,
    bool safe_for_autoreplace,
    const std::string& encodings,
    Time date_created,
    Time last_modified,
    Time last_visited) {}

TemplateURL* TemplateURLServiceTestBase::AddExtensionSearchEngine(
    const std::string& keyword,
    const std::string& extension_name,
    bool wants_to_be_default_engine,
    const Time& install_time) {}

void TemplateURLServiceTestBase::AssertEquals(const TemplateURL& expected,
                                              const TemplateURL& actual) {}

void TemplateURLServiceTestBase::AssertEquals(const TemplateURL* expected,
                                              const TemplateURL* actual) {}

void TemplateURLServiceTestBase::AssertTimesEqual(const Time& expected,
                                                  const Time& actual) {}

std::unique_ptr<TemplateURL>
TemplateURLServiceTestBase::CreatePreloadedTemplateURL(
    bool safe_for_autoreplace,
    int prepopulate_id) {}

void TemplateURLServiceTestBase::SetOverriddenEngines() {}

void TemplateURLServiceTestBase::VerifyObserverCount(
    int expected_changed_count) {}

void TemplateURLServiceTestBase::VerifyObserverFired() {}

// Actual tests ---------------------------------------------------------------

TEST_P(TemplateURLServiceTest, Load) {}

TEST_P(TemplateURLServiceTest, AddUpdateRemove) {}

TEST_P(TemplateURLServiceTest, AddSameKeyword) {}

TEST_P(TemplateURLServiceTest, AddOmniboxExtensionKeyword) {}

TEST_P(TemplateURLServiceTest, AddSameKeywordWithOmniboxExtensionPresent) {}

TEST_P(TemplateURLServiceTest, NotPersistOmniboxExtensionKeyword) {}

TEST_P(TemplateURLServiceTest, ClearBrowsingData_Keywords) {}

TEST_P(TemplateURLServiceTest, ClearBrowsingData_KeywordsForUrls) {}

TEST_P(TemplateURLServiceTest, Reset) {}

#if BUILDFLAG(IS_ANDROID)
TEST_P(TemplateURLServicePlayApiTest, CreateFromPlayAPI) {
  test_util()->VerifyLoad();
  const size_t initial_count = model()->GetTemplateURLs().size();

  const std::u16string short_name = u"google";
  const std::u16string keyword = u"keyword";
  const std::string search_url = "http://www.google.com/foo/bar";
  const std::string suggest_url = "http://www.google.com/suggest";
  const std::string favicon_url = "http://favicon.url";
  const std::string new_tab_url = "https://site.com/newtab";
  const std::string image_url = "https://site.com/img";
  const std::string image_url_post_params = "param";
  const std::string image_translate_url = "https://site.com/transl";
  const std::string image_translate_source_language_param_key = "s";
  const std::string image_translate_target_language_param_key = "t";
  TemplateURL* t_url = model()->Add(std::make_unique<TemplateURL>(
      TemplateURLService::CreatePlayAPITemplateURLData(
          keyword, short_name, search_url, suggest_url, favicon_url,
          new_tab_url, image_url, image_url_post_params, image_translate_url,
          image_translate_source_language_param_key,
          image_translate_target_language_param_key)));
  ASSERT_TRUE(t_url);
  ASSERT_EQ(short_name, t_url->short_name());
  ASSERT_EQ(keyword, t_url->keyword());
  ASSERT_EQ(search_url, t_url->url());
  ASSERT_EQ(suggest_url, t_url->suggestions_url());
  ASSERT_EQ(GURL(favicon_url), t_url->favicon_url());
  ASSERT_EQ(new_tab_url, t_url->new_tab_url());
  ASSERT_EQ(image_url, t_url->image_url());
  ASSERT_EQ(image_url_post_params, t_url->image_url_post_params());
  ASSERT_EQ(image_translate_url, t_url->image_translate_url());
  ASSERT_EQ(image_translate_source_language_param_key,
            t_url->image_translate_source_language_param_key());
  ASSERT_EQ(image_translate_target_language_param_key,
            t_url->image_translate_target_language_param_key());

  ASSERT_TRUE(t_url->created_from_play_api());
  ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(keyword));

  auto cloned_url = std::make_unique<TemplateURL>(t_url->data());

  // Reload the model from the database and make sure the change took.
  test_util()->ResetModel(true);
  EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
  const TemplateURL* read_url = model()->GetTemplateURLForKeyword(keyword);
  ASSERT_TRUE(read_url);
  AssertEquals(*cloned_url, *read_url);
}

TEST_P(TemplateURLServicePlayApiTest, UpdateFromPlayAPI) {
  std::u16string keyword = u"keyword";

  // Add a new TemplateURL.
  test_util()->VerifyLoad();
  const size_t initial_count = model()->GetTemplateURLs().size();
  TemplateURLData data;
  data.SetShortName(u"google");
  data.SetKeyword(keyword);
  data.SetURL("http://www.google.com/foo/bar");
  data.favicon_url = GURL("http://favicon.url");
  data.date_created = Time::FromTimeT(100);
  data.last_modified = Time::FromTimeT(100);
  data.last_visited = Time::FromTimeT(100);
  // Play API only replaces safe_for_autoreplace engines.
  data.safe_for_autoreplace = true;
  TemplateURL* t_url = model()->Add(std::make_unique<TemplateURL>(data));

  VerifyObserverCount(1);
  base::RunLoop().RunUntilIdle();

  auto clock = std::make_unique<base::SimpleTestClock>();
  clock->SetNow(base::Time::FromTimeT(200));
  model()->set_clock(std::move(clock));

  // Reset the short name and url and make sure it takes.
  const std::u16string new_short_name = u"new_name";
  const std::string new_search_url = "new_url";
  const std::string new_suggest_url = "new_suggest_url";
  const std::string new_favicon_url = "new_favicon_url";
  const std::string new_other_data = "other_data";

  // The update creates a new Play API engine and deletes the old replaceable
  // one.
  t_url = model()->Add(std::make_unique<TemplateURL>(
      TemplateURLService::CreatePlayAPITemplateURLData(
          keyword, new_short_name, new_search_url, new_suggest_url,
          new_favicon_url, new_other_data, new_other_data, new_other_data,
          new_other_data, new_other_data, new_other_data)));
  ASSERT_TRUE(t_url);
  ASSERT_EQ(new_short_name, t_url->short_name());
  ASSERT_EQ(keyword, t_url->keyword());
  ASSERT_EQ(new_search_url, t_url->url());
  ASSERT_EQ(new_suggest_url, t_url->suggestions_url());
  ASSERT_EQ(GURL(new_favicon_url), t_url->favicon_url());
  ASSERT_EQ(new_other_data, t_url->new_tab_url());
  ASSERT_EQ(new_other_data, t_url->image_url());
  ASSERT_EQ(new_other_data, t_url->image_url_post_params());
  ASSERT_EQ(new_other_data, t_url->image_translate_url());
  ASSERT_EQ(new_other_data, t_url->image_translate_source_language_param_key());
  ASSERT_EQ(new_other_data, t_url->image_translate_target_language_param_key());
  ASSERT_TRUE(t_url->created_from_play_api());

  // Make sure the mappings in the model were updated.
  ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(keyword));

  auto cloned_url = std::make_unique<TemplateURL>(t_url->data());

  // Reload the model from the database and make sure the change took.
  test_util()->ResetModel(true);
  EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
  const TemplateURL* read_url = model()->GetTemplateURLForKeyword(keyword);
  ASSERT_TRUE(read_url);
  AssertEquals(*cloned_url, *read_url);
}

INSTANTIATE_TEST_SUITE_P(,
                         TemplateURLServicePlayApiTest,
                         testing::Values(true, false),
                         &TemplateURLServicePlayApiTest::ParamToTestSuffix);

#endif  // BUILDFLAG(IS_ANDROID)

TEST_P(TemplateURLServiceTest, DefaultSearchProvider) {}

TEST_P(TemplateURLServiceTest, CantReplaceWithSameKeyword) {}

TEST_P(TemplateURLServiceTest, CantReplaceWithSameHosts) {}

TEST_P(TemplateURLServiceTest, HasDefaultSearchProvider) {}

TEST_P(TemplateURLServiceTest, DefaultSearchProviderLoadedFromPrefs) {}

TEST_P(TemplateURLServiceTest,
       DefaultSearchProviderShouldBeProtectedFromKeywordConflictDuringLoad) {}

TEST_P(TemplateURLServiceTest, RepairPrepopulatedSearchEngines) {}

TEST_P(TemplateURLServiceTest, RepairSearchEnginesWithManagedDefault) {}

// Checks that RepairPrepopulatedEngines correctly updates sync guid for default
// search. Repair is considered a user action and new DSE must be synced to
// other devices as well. Otherwise previous user selected engine will arrive on
// next sync attempt.
TEST_P(TemplateURLServiceTest, RepairPrepopulatedEnginesUpdatesSyncGuid) {}

// Checks that RepairPrepopulatedEngines correctly updates sync guid for default
// search when search engines are overridden using pref.
TEST_P(TemplateURLServiceTest,
       RepairPrepopulatedEnginesWithOverridesUpdatesSyncGuid) {}

// Checks that RepairPrepopulatedEngines correctly updates sync guid for default
// search when search engines is overridden by extension.
TEST_P(TemplateURLServiceTest,
       RepairPrepopulatedEnginesWithExtensionUpdatesSyncGuid) {}

TEST_P(TemplateURLServiceTest, RepairStarterPackEngines) {}

TEST_P(TemplateURLServiceTest, SetDefaultSearchProviderPref) {}

TEST_P(TemplateURLServiceTest, GetDefaultSearchProviderPref) {}

TEST_P(TemplateURLServiceTest, UpdateKeywordSearchTermsForURL) {}

TEST_P(TemplateURLServiceTest, DontUpdateKeywordSearchForNonReplaceable) {}

// Historically, {google:baseURL} keywords would change to different
// country-specific Google URLs dynamically. That logic was removed, but test
// that country-specific Google URLs can still be added manually.
TEST_P(TemplateURLServiceWithoutFallbackTest, ManualCountrySpecificGoogleURL) {}

INSTANTIATE_TEST_SUITE_P();

// Make sure TemplateURLService generates a KEYWORD_GENERATED visit for
// KEYWORD visits.
TEST_P(TemplateURLServiceTest, GenerateVisitOnKeyword) {}

// Make sure that the load routine deletes prepopulated engines that no longer
// exist in the prepopulate data.
TEST_P(TemplateURLServiceTest, LoadDeletesUnusedProvider) {}

// Make sure that load routine doesn't delete prepopulated engines that no
// longer exist in the prepopulate data if it has been modified by the user.
TEST_P(TemplateURLServiceTest, LoadRetainsModifiedProvider) {}

// Make sure that load routine doesn't delete
// prepopulated engines that no longer exist in the prepopulate data if
// it has been modified by the user.
TEST_P(TemplateURLServiceTest, LoadSavesPrepopulatedDefaultSearchProvider) {}

// Make sure that the load routine doesn't delete
// prepopulated engines that no longer exist in the prepopulate data if
// it is the default search provider.
TEST_P(TemplateURLServiceTest, LoadRetainsDefaultProvider) {}

// Make sure that the load routine sets a default search provider if it was
// missing and not managed.
TEST_P(TemplateURLServiceTest, LoadEnsuresDefaultSearchProviderExists) {}

// Make sure that the load routine does not update user modified starter pack
// engines unless the current version is incompatible.
TEST_P(TemplateURLServiceTest,
       LoadUpdatesStarterPackOnlyIfIncompatibleVersion) {}

// Simulates failing to load the webdb and makes sure the default search
// provider is valid.
TEST_P(TemplateURLServiceTest, FailedInit) {}

// Verifies that if the default search URL preference is managed, we report
// the default search as managed.  Also check that we are getting the right
// values.
TEST_P(TemplateURLServiceTest, TestManagedDefaultSearch) {}

// Test that if we load a TemplateURL with an empty GUID, the load process
// assigns it a newly generated GUID.
TEST_P(TemplateURLServiceTest, PatchEmptySyncGUID) {}

// Test that if we load a TemplateURL with duplicate input encodings, the load
// process de-dupes them.
TEST_P(TemplateURLServiceTest, DuplicateInputEncodings) {}

TEST_P(TemplateURLServiceTest, DefaultExtensionEngine) {}

TEST_P(TemplateURLServiceTest, SetDefaultExtensionEngineAndRemoveUserDSE) {}

TEST_P(TemplateURLServiceTest, DefaultExtensionEnginePersist) {}

TEST_P(TemplateURLServiceTest, DefaultExtensionEnginePersistsBeforeLoad) {}

// Checks that correct priority is applied when resolving conflicts between the
// omnibox extension, search engine extension and user search engines with same
// keyword.
TEST_P(TemplateURLServiceTest, KeywordConflictNonReplaceableEngines) {}

// Verifies that we don't have reentrant behavior when resolving default search
// provider keyword conflicts. crbug.com/1031506
TEST_P(TemplateURLServiceTest, DefaultSearchProviderKeywordConflictReentrancy) {}

TEST_P(TemplateURLServiceTest, ReplaceableEngineUpdateHandlesKeywordConflicts) {}

// Verifies that we favor prepopulated engines over other safe_for_autoreplace()
// engines, even if they are newer. Also verifies that we never remove the
// prepopulated engine, even if outranked. https://crbug.com/1164024
TEST_P(TemplateURLServiceTest, KeywordConflictFavorsPrepopulatedEngines) {}

TEST_P(TemplateURLServiceTest, CheckNonreplaceableEnginesKeywordsConflicts) {}

TEST_P(TemplateURLServiceTest, CheckReplaceableEnginesKeywordsConflicts) {}

// Check that two extensions with the same engine are handled correctly.
TEST_P(TemplateURLServiceTest, ExtensionsWithSameKeywords) {}

TEST_P(TemplateURLServiceTest, ExtensionEngineVsPolicy) {}

TEST_P(TemplateURLServiceTest, LastVisitedTimeUpdate) {}

TEST_P(TemplateURLServiceTest, LastModifiedTimeUpdate) {}

TEST_P(TemplateURLServiceTest, GetDefaultSearchProviderIgnoringExtensions) {}

TEST_P(TemplateURLServiceTest,
       EngineReturnedByGetDefaultSearchProviderIgnoringExtensionsTakesOver) {}

TEST_P(
    TemplateURLServiceTest,
    GetDefaultSearchProviderIgnoringExtensionsWhenDefaultSearchDisabledByPolicy) {}

// Tests that a TemplateURL's `is_active` field is correctly set and
// Omnibox.KeywordModeUsageByEngineType histogram is correctly emitted when a
// TemplateURL is activated and/or deactivated.
TEST_P(TemplateURLServiceTest, SetIsActiveTemplateURL) {}

// Tests that the `Omnibox.KeywordModeUsageByEngineType.ActiveOnStartup` and
// `InactiveOnStartup` are emitted correctly when the model is loaded.
TEST_P(TemplateURLServiceTest, EmitTemplateURLActiveOnStartupHistogram) {}

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
    BUILDFLAG(IS_CHROMEOS)
TEST_P(TemplateURLServiceTest, SiteSearchPolicyBeforeLoading) {}

TEST_P(TemplateURLServiceTest, SiteSearchPolicyAfterLoading) {}

TEST_P(TemplateURLServiceTest, SiteSearchPolicyUpdates) {}

TEST_P(TemplateURLServiceTest,
       NonFeaturedSiteSearchPolicyConflictWithExistingEngines) {}

TEST_P(TemplateURLServiceTest,
       FeaturedSiteSearchPolicyConflictWithExistingEngines) {}

TEST_P(TemplateURLServiceTest, NonFeaturedSiteSearchPolicyConflictWithDSP) {}

TEST_P(TemplateURLServiceTest,
       NonFeaturedSiteSearchPolicyConflictWithUserDefinedDSP) {}

TEST_P(TemplateURLServiceTest,
       NonFeaturedSiteSearchPolicyConflictWithDSPSetByExtension) {}

TEST_P(TemplateURLServiceTest,
       FeaturedSiteSearchPolicyConflictWithUserDefinedDSP) {}

TEST_P(TemplateURLServiceTest,
       FeaturedSiteSearchPolicyConflictWithDSPSetByExtension) {}

TEST_P(TemplateURLServiceTest,
       FeaturedSiteSearchPolicyConflictWithStarterPack) {}

#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
        // BUILDFLAG(IS_CHROMEOS)

INSTANTIATE_TEST_SUITE_P();