chromium/ios/chrome/browser/ui/settings/search_engine_table_view_controller_unittest.mm

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

#import "ios/chrome/browser/ui/settings/search_engine_table_view_controller_unittest.h"

#import "base/apple/foundation_util.h"
#import "base/strings/sys_string_conversions.h"
#import "base/test/ios/wait_util.h"
#import "ios/chrome/browser/favicon/model/favicon_service_factory.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_favicon_loader_factory.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_large_icon_service_factory.h"
#import "ios/chrome/browser/history/model/history_service_factory.h"
#import "ios/chrome/browser/search_engines/model/template_url_service_factory.h"
#import "ios/chrome/browser/ui/settings/cells/settings_search_engine_item.h"
#import "ios/chrome/browser/ui/settings/search_engine_table_view_controller.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"

SearchEngineTableViewControllerTest::SearchEngineTableViewControllerTest()
    : prepopulated_search_engine_({
          {"google.com", GURL("https://p1.com?q={searchTerms}")},
          {"bing.com", GURL("https://p2.com?q={searchTerms}")},
          {"duckduckgo.com", GURL("https://p3.com?q={searchTerms}")},
      }),
      custom_search_engine_({
          {"custom-1", GURL("https://c1.com?q={searchTerms}")},
          {"custom-2", GURL("https://c2.com?q={searchTerms}")},
          {"custom-3", GURL("https://c3.com?q={searchTerms}")},
          {"custom-4", GURL("https://c4.com?q={searchTerms}")},
      }) {}

SearchEngineTableViewControllerTest::~SearchEngineTableViewControllerTest() {}

void SearchEngineTableViewControllerTest::SetUp() {
  LegacyChromeTableViewControllerTest::SetUp();

  TestChromeBrowserState::Builder test_cbs_builder;

  test_cbs_builder.AddTestingFactory(
      ios::TemplateURLServiceFactory::GetInstance(),
      ios::TemplateURLServiceFactory::GetDefaultFactory());
  test_cbs_builder.AddTestingFactory(
      ios::FaviconServiceFactory::GetInstance(),
      ios::FaviconServiceFactory::GetDefaultFactory());
  test_cbs_builder.AddTestingFactory(
      IOSChromeLargeIconServiceFactory::GetInstance(),
      IOSChromeLargeIconServiceFactory::GetDefaultFactory());
  test_cbs_builder.AddTestingFactory(
      IOSChromeFaviconLoaderFactory::GetInstance(),
      IOSChromeFaviconLoaderFactory::GetDefaultFactory());
  test_cbs_builder.AddTestingFactory(
      ios::HistoryServiceFactory::GetInstance(),
      ios::HistoryServiceFactory::GetDefaultFactory());
  chrome_browser_state_ = std::move(test_cbs_builder).Build();
  // Override the country checks to simulate being in Belgium.
  pref_service_ = chrome_browser_state_->GetTestingPrefService();
  DefaultSearchManager::SetFallbackSearchEnginesDisabledForTesting(true);
  template_url_service_ = ios::TemplateURLServiceFactory::GetForBrowserState(
      chrome_browser_state_.get());
  template_url_service_->Load();
}

void SearchEngineTableViewControllerTest::TearDown() {
  DefaultSearchManager::SetFallbackSearchEnginesDisabledForTesting(false);
  [base::apple::ObjCCastStrict<SearchEngineTableViewController>(controller())
      settingsWillBeDismissed];
}

LegacyChromeTableViewController*
SearchEngineTableViewControllerTest::InstantiateController() {
  return [[SearchEngineTableViewController alloc]
      initWithBrowserState:chrome_browser_state_.get()];
}

// Adds a prepopulated search engine to TemplateURLService.
// `prepopulate_id` should be big enough (>1000) to avoid collision with real
// prepopulated search engines. The collision happens when
// TemplateURLService::SetUserSelectedDefaultSearchProvider is called, in the
// callback of PrefService the DefaultSearchManager will update the searchable
// URL of default search engine from prepopulated search engines list.
TemplateURL* SearchEngineTableViewControllerTest::AddPriorSearchEngine(
    const SearchEngineTest& search_engine,
    int prepopulate_id,
    bool set_default) {
  TemplateURLData data;
  data.SetShortName(base::ASCIIToUTF16(search_engine.short_name));
  data.SetKeyword(base::ASCIIToUTF16(search_engine.short_name));
  data.SetURL(search_engine.searchable_url.possibly_invalid_spec());
  data.favicon_url =
      TemplateURL::GenerateFaviconURL(search_engine.searchable_url);
  data.prepopulate_id = prepopulate_id;
  TemplateURL* url =
      template_url_service_->Add(std::make_unique<TemplateURL>(data));
  if (set_default) {
    template_url_service_->SetUserSelectedDefaultSearchProvider(url);
  }
  return url;
}

// Adds a custom search engine to TemplateURLService.
TemplateURL* SearchEngineTableViewControllerTest::AddCustomSearchEngine(
    const SearchEngineTest& search_engine,
    base::Time last_visited_time,
    bool set_default) {
  TemplateURLData data;
  data.SetShortName(base::ASCIIToUTF16(search_engine.short_name));
  data.SetKeyword(base::ASCIIToUTF16(search_engine.short_name));
  data.SetURL(search_engine.searchable_url.possibly_invalid_spec());
  data.favicon_url =
      TemplateURL::GenerateFaviconURL(search_engine.searchable_url);
  data.last_visited = last_visited_time;
  TemplateURL* url =
      template_url_service_->Add(std::make_unique<TemplateURL>(data));
  if (set_default) {
    template_url_service_->SetUserSelectedDefaultSearchProvider(url);
  }
  return url;
}

void SearchEngineTableViewControllerTest::CheckItem(
    NSString* expected_text,
    NSString* expected_detail_text,
    bool expected_checked,
    int section,
    int row,
    bool enabled) {
  SettingsSearchEngineItem* item =
      base::apple::ObjCCastStrict<SettingsSearchEngineItem>(
          GetTableViewItem(section, row));
  EXPECT_NSEQ(expected_text, item.text);
  EXPECT_NSEQ(expected_detail_text, item.detailText);
  EXPECT_EQ(expected_checked ? UITableViewCellAccessoryCheckmark
                             : UITableViewCellAccessoryNone,
            item.accessoryType);
  EXPECT_EQ(enabled, item.enabled);
}

// Checks a LegacySettingsSearchEngineItem with data from a fabricated
// TemplateURL. The LegacySettingsSearchEngineItem in the `row` of `section`
// should contain a title and a subtitle that are equal to `expected_text` and
// an URL which can be generated by filling empty query word into
// `expected_searchable_url`. If `expected_checked` is true, the
// LegacySettingsSearchEngineItem should have a
// UITableViewCellAccessoryCheckmark.
void SearchEngineTableViewControllerTest::CheckPrepopulatedItem(
    const SearchEngineTest& search_engine,
    bool expected_checked,
    int section,
    int row,
    bool enabled) {
  TemplateURLData data;
  data.SetURL(search_engine.searchable_url.possibly_invalid_spec());
  const std::string expected_url =
      TemplateURL(data).url_ref().ReplaceSearchTerms(
          TemplateURLRef::SearchTermsArgs(std::u16string()),
          template_url_service_->search_terms_data());
  CheckItem(base::SysUTF8ToNSString(search_engine.short_name),
            base::SysUTF8ToNSString(search_engine.short_name), expected_checked,
            section, row, enabled);
}

// Checks a LegacySettingsSearchEngineItem with data from a fabricated
// TemplateURL. The LegacySettingsSearchEngineItem in the `row` of `section`
// should contain a title and a subtitle that are equal to `expected_text` and
// an URL which can be generated from `expected_searchable_url` by
// TemplateURL::GenerateFaviconURL. If `expected_checked` is true, the
// LegacySettingsSearchEngineItem should have a
// UITableViewCellAccessoryCheckmark.
void SearchEngineTableViewControllerTest::CheckCustomItem(
    const SearchEngineTest& search_engine,
    bool expected_checked,
    int section,
    int row,
    bool enabled) {
  CheckItem(base::SysUTF8ToNSString(search_engine.short_name),
            base::SysUTF8ToNSString(search_engine.short_name), expected_checked,
            section, row, enabled);
}

// Checks a LegacySettingsSearchEngineItem with data from a real prepopulated
// TemplateURL. The LegacySettingsSearchEngineItem in the `row` of `section`
// should contain a title equal to `expected_text`, a subtitle equal to
// `expected_detail_text`, and an URL equal to `expected_favicon_url`. If
// `expected_checked` is true, the LegacySettingsSearchEngineItem should have
// a UITableViewCellAccessoryCheckmark.
void SearchEngineTableViewControllerTest::CheckRealItem(const TemplateURL* turl,
                                                        bool expected_checked,
                                                        int section,
                                                        int row,
                                                        bool enabled) {
  CheckItem(base::SysUTF16ToNSString(turl->short_name()),
            base::SysUTF16ToNSString(turl->keyword()), expected_checked,
            section, row, enabled);
}

// Deletes items at `indexes` and wait util condition returns true or timeout.
[[nodiscard]] bool SearchEngineTableViewControllerTest::DeleteItemsAndWait(
    NSArray<NSIndexPath*>* indexes,
    ConditionBlock condition) {
  SearchEngineTableViewController* searchEngineController =
      static_cast<SearchEngineTableViewController*>(controller());
  [searchEngineController deleteItems:indexes];
  return base::test::ios::WaitUntilConditionOrTimeout(
      base::test::ios::kWaitForUIElementTimeout, condition);
}