普通文本  |  1198行  |  46.13 KB

// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/search_engines/search_host_to_urls_map.h"
#include "chrome/browser/search_engines/search_terms_data.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_model_test_util.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
#include "chrome/test/testing_profile.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_details.h"
#include "content/common/notification_source.h"
#include "testing/gtest/include/gtest/gtest.h"

using base::Time;
using base::TimeDelta;

#if defined(OS_LINUX)
// Timed out on Chromium Linux.  http://crbug.com/53607
#define MAYBE_Load DISABLED_Load
#else
#define MAYBE_Load Load
#endif

// Test the GenerateSearchURL on a thread or the main thread.
class TestGenerateSearchURL
    : public base::RefCountedThreadSafe<TestGenerateSearchURL> {
 public:
  explicit TestGenerateSearchURL(SearchTermsData* search_terms_data)
      : search_terms_data_(search_terms_data),
        passed_(false) {
  }

  // Run the test cases for GenerateSearchURL.
  void RunTest();

  // Did the test pass?
  bool passed() const { return passed_; }

 private:
  friend class base::RefCountedThreadSafe<TestGenerateSearchURL>;
  ~TestGenerateSearchURL() {}

  SearchTermsData* search_terms_data_;
  bool passed_;

  DISALLOW_COPY_AND_ASSIGN(TestGenerateSearchURL);
};

// Simple implementation of SearchTermsData.
class TestSearchTermsData : public SearchTermsData {
 public:
  explicit TestSearchTermsData(const char* google_base_url)
      : google_base_url_(google_base_url)  {
  }

  virtual std::string GoogleBaseURLValue() const {
    return google_base_url_;
  }

  virtual std::string GetApplicationLocale() const {
    return "yy";
  }

#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
  // Returns the value for the Chrome Omnibox rlz.
  virtual string16 GetRlzParameterValue() const {
    return string16();
  }
#endif

 private:
  std::string google_base_url_;

  DISALLOW_COPY_AND_ASSIGN(TestSearchTermsData);
};

// Create an URL that appears to have been prepopulated, but won't be in the
// current data. The caller owns the returned TemplateURL*.
static TemplateURL* CreatePreloadedTemplateURL() {
  TemplateURL* t_url = new TemplateURL();
  t_url->SetURL("http://www.unittest.com/", 0, 0);
  t_url->set_keyword(ASCIIToUTF16("unittest"));
  t_url->set_short_name(ASCIIToUTF16("unittest"));
  t_url->set_safe_for_autoreplace(true);
  GURL favicon_url("http://favicon.url");
  t_url->SetFaviconURL(favicon_url);
  t_url->set_date_created(Time::FromTimeT(100));
  t_url->set_prepopulate_id(999999);
  return t_url;
}

class TemplateURLModelTest : public testing::Test {
 public:
  TemplateURLModelTest() {}

  virtual void SetUp() {
    test_util_.SetUp();
  }

  virtual void TearDown() {
    test_util_.TearDown();
  }

  TemplateURL* AddKeywordWithDate(const std::string& keyword,
                                  bool autogenerate_keyword,
                                  const std::string& url,
                                  const std::string& suggest_url,
                                  const std::string& favicon_url,
                                  const std::string& encodings,
                                  const std::string& short_name,
                                  bool safe_for_autoreplace,
                                  Time created_date) {
    TemplateURL* template_url = new TemplateURL();
    template_url->SetURL(url, 0, 0);
    template_url->SetSuggestionsURL(suggest_url, 0, 0);
    template_url->SetFaviconURL(GURL(favicon_url));
    template_url->set_keyword(UTF8ToUTF16(keyword));
    template_url->set_autogenerate_keyword(autogenerate_keyword);
    template_url->set_short_name(UTF8ToUTF16(short_name));
    std::vector<std::string> encodings_vector;
    base::SplitString(encodings, ';', &encodings_vector);
    template_url->set_input_encodings(encodings_vector);
    template_url->set_date_created(created_date);
    template_url->set_safe_for_autoreplace(safe_for_autoreplace);
    model()->Add(template_url);
    EXPECT_NE(0, template_url->id());
    return template_url;
  }

  // Simulate firing by the prefs service specifying that the managed
  // preferences have changed.
  void NotifyManagedPrefsHaveChanged() {
    model()->Observe(
        NotificationType::PREF_CHANGED,
        Source<PrefService>(profile()->GetTestingPrefService()),
        Details<std::string>(NULL));
  }

  // Verifies the two TemplateURLs are equal.
  void AssertEquals(const TemplateURL& expected, const TemplateURL& actual) {
    ASSERT_TRUE(TemplateURLRef::SameUrlRefs(expected.url(), actual.url()));
    ASSERT_TRUE(TemplateURLRef::SameUrlRefs(expected.suggestions_url(),
                                            actual.suggestions_url()));
    ASSERT_EQ(expected.keyword(), actual.keyword());
    ASSERT_EQ(expected.short_name(), actual.short_name());
    ASSERT_EQ(JoinString(expected.input_encodings(), ';'),
              JoinString(actual.input_encodings(), ';'));
    ASSERT_TRUE(expected.GetFaviconURL() == actual.GetFaviconURL());
    ASSERT_EQ(expected.id(), actual.id());
    ASSERT_EQ(expected.safe_for_autoreplace(), actual.safe_for_autoreplace());
    ASSERT_EQ(expected.show_in_default_list(), actual.show_in_default_list());
    ASSERT_TRUE(expected.date_created() == actual.date_created());
  }

  // Checks that the two TemplateURLs are similar. It does not check the id
  // and the date_created.  Neither pointer should be NULL.
  void ExpectSimilar(const TemplateURL* expected, const TemplateURL* actual) {
    ASSERT_TRUE(expected != NULL);
    ASSERT_TRUE(actual != NULL);
    EXPECT_TRUE(TemplateURLRef::SameUrlRefs(expected->url(), actual->url()));
    EXPECT_TRUE(TemplateURLRef::SameUrlRefs(expected->suggestions_url(),
                                            actual->suggestions_url()));
    EXPECT_EQ(expected->keyword(), actual->keyword());
    EXPECT_EQ(expected->short_name(), actual->short_name());
    EXPECT_EQ(JoinString(expected->input_encodings(), ';'),
              JoinString(actual->input_encodings(), ';'));
    EXPECT_TRUE(expected->GetFaviconURL() == actual->GetFaviconURL());
    EXPECT_EQ(expected->safe_for_autoreplace(), actual->safe_for_autoreplace());
    EXPECT_EQ(expected->show_in_default_list(), actual->show_in_default_list());
  }

  // Set the managed preferences for the default search provider and trigger
  // notification.
  void SetManagedDefaultSearchPreferences(bool enabled,
                                          const char* name,
                                          const char* search_url,
                                          const char* suggest_url,
                                          const char* icon_url,
                                          const char* encodings,
                                          const char* keyword) {
    TestingPrefService* service = profile()->GetTestingPrefService();
    service->SetManagedPref(
        prefs::kDefaultSearchProviderEnabled,
        Value::CreateBooleanValue(enabled));
    service->SetManagedPref(
        prefs::kDefaultSearchProviderName,
        Value::CreateStringValue(name));
    service->SetManagedPref(
        prefs::kDefaultSearchProviderSearchURL,
        Value::CreateStringValue(search_url));
    service->SetManagedPref(
        prefs::kDefaultSearchProviderSuggestURL,
        Value::CreateStringValue(suggest_url));
    service->SetManagedPref(
        prefs::kDefaultSearchProviderIconURL,
        Value::CreateStringValue(icon_url));
    service->SetManagedPref(
        prefs::kDefaultSearchProviderEncodings,
        Value::CreateStringValue(encodings));
    service->SetManagedPref(
        prefs::kDefaultSearchProviderKeyword,
        Value::CreateStringValue(keyword));
  }

  // Remove all the managed preferences for the default search provider and
  // trigger notification.
  void RemoveManagedDefaultSearchPreferences() {
    TestingPrefService* service = profile()->GetTestingPrefService();
    service->RemoveManagedPref(
        prefs::kDefaultSearchProviderSearchURL);
    service->RemoveManagedPref(
        prefs::kDefaultSearchProviderEnabled);
    service->RemoveManagedPref(
        prefs::kDefaultSearchProviderName);
    service->RemoveManagedPref(
        prefs::kDefaultSearchProviderSuggestURL);
    service->RemoveManagedPref(
        prefs::kDefaultSearchProviderIconURL);
    service->RemoveManagedPref(
        prefs::kDefaultSearchProviderEncodings);
    service->RemoveManagedPref(
        prefs::kDefaultSearchProviderKeyword);
    service->RemoveManagedPref(
        prefs::kDefaultSearchProviderID);
    service->RemoveManagedPref(
        prefs::kDefaultSearchProviderPrepopulateID);
  }

  // Creates a TemplateURL with the same prepopulated id as a real prepopulated
  // item. The input number determines which prepopulated item. The caller is
  // responsible for owning the returned TemplateURL*.
  TemplateURL* CreateReplaceablePreloadedTemplateURL(
      size_t index_offset_from_default,
      string16* prepopulated_display_url);

  // Verifies the behavior of when a preloaded url later gets changed.
  // Since the input is the offset from the default, when one passes in
  // 0, it tests the default. Passing in a number > 0 will verify what
  // happens when a preloaded url that is not the default gets updated.
  void TestLoadUpdatingPreloadedURL(size_t index_offset_from_default);

  // Helper methods to make calling TemplateURLModelTestUtil methods less
  // visually noisy in the test code.
  void VerifyObserverCount(int expected_changed_count) {
    EXPECT_EQ(expected_changed_count, test_util_.GetObserverCount());
    test_util_.ResetObserverCount();
  }
  void VerifyObserverFired() {
    EXPECT_LE(1, test_util_.GetObserverCount());
    test_util_.ResetObserverCount();
  }
  void BlockTillServiceProcessesRequests() {
    TemplateURLModelTestUtil::BlockTillServiceProcessesRequests();
  }
  void VerifyLoad() { test_util_.VerifyLoad(); }
  void ChangeModelToLoadState() { test_util_.ChangeModelToLoadState(); }
  void ResetModel(bool verify_load) { test_util_.ResetModel(verify_load); }
  string16 GetAndClearSearchTerm() {
    return test_util_.GetAndClearSearchTerm();
  }
  void SetGoogleBaseURL(const std::string& base_url) const {
    test_util_.SetGoogleBaseURL(base_url);
  }
  WebDataService* GetWebDataService() { return test_util_.GetWebDataService(); }
  TemplateURLModel* model() { return test_util_.model(); }
  TestingProfile* profile() { return test_util_.profile(); }

 protected:
  TemplateURLModelTestUtil test_util_;

  DISALLOW_COPY_AND_ASSIGN(TemplateURLModelTest);
};

void TestGenerateSearchURL::RunTest() {
  struct GenerateSearchURLCase {
    const char* test_name;
    const char* url;
    const char* expected;
  } generate_url_cases[] = {
    { "empty TemplateURLRef", NULL, "" },
    { "invalid URL", "foo{searchTerms}", "" },
    { "URL with no replacements", "http://foo/", "http://foo/" },
    { "basic functionality", "http://foo/{searchTerms}",
      "http://foo/blah.blah.blah.blah.blah" }
  };

  // Don't use ASSERT/EXPECT since this is run on a thread in one test
  // and those macros aren't meant for threads at this time according to
  // gtest documentation.
  bool everything_passed = true;
  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(generate_url_cases); ++i) {
    TemplateURL t_url;
    if (generate_url_cases[i].url)
      t_url.SetURL(generate_url_cases[i].url, 0, 0);

    std::string result = search_terms_data_ ?
        TemplateURLModel::GenerateSearchURLUsingTermsData(
            &t_url, *search_terms_data_).spec() :
        TemplateURLModel::GenerateSearchURL(&t_url).spec();
    if (strcmp(generate_url_cases[i].expected, result.c_str())) {
      LOG(ERROR) << generate_url_cases[i].test_name << " failed. Expected " <<
          generate_url_cases[i].expected << " Actual " << result;

      everything_passed = false;
    }
  }
  passed_ = everything_passed;
}

TemplateURL* TemplateURLModelTest::CreateReplaceablePreloadedTemplateURL(
    size_t index_offset_from_default,
    string16* prepopulated_display_url) {
  TemplateURL* t_url = CreatePreloadedTemplateURL();
  ScopedVector<TemplateURL> prepopulated_urls;
  size_t default_search_provider_index = 0;
  TemplateURLPrepopulateData::GetPrepopulatedEngines(
      profile()->GetPrefs(),
      &prepopulated_urls.get(),
      &default_search_provider_index);
  EXPECT_LT(index_offset_from_default, prepopulated_urls.size());
  size_t prepopulated_index =
      (default_search_provider_index + index_offset_from_default) %
      prepopulated_urls.size();
  t_url->set_prepopulate_id(
      prepopulated_urls[prepopulated_index]->prepopulate_id());
  *prepopulated_display_url =
      prepopulated_urls[prepopulated_index]->url()->DisplayURL();
  return t_url;
}

void TemplateURLModelTest::TestLoadUpdatingPreloadedURL(
    size_t index_offset_from_default) {
  string16 prepopulated_url;
  TemplateURL* t_url = CreateReplaceablePreloadedTemplateURL(
      index_offset_from_default, &prepopulated_url);
  t_url->set_safe_for_autoreplace(false);

  string16 original_url = t_url->url()->DisplayURL();
  ASSERT_NE(prepopulated_url, original_url);

  // Then add it to the model and save it all.
  ChangeModelToLoadState();
  model()->Add(t_url);
  const TemplateURL* keyword_url =
      model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
  ASSERT_EQ(t_url, keyword_url);
  ASSERT_EQ(original_url, keyword_url->url()->DisplayURL());
  BlockTillServiceProcessesRequests();

  // Now reload the model and verify that the merge updates the url.
  ResetModel(true);
  keyword_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
  ASSERT_TRUE(keyword_url != NULL);
  ASSERT_EQ(prepopulated_url, keyword_url->url()->DisplayURL());

  // Wait for any saves to finish.
  BlockTillServiceProcessesRequests();

  // Reload the model to verify that change was saved correctly.
  ResetModel(true);
  keyword_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
  ASSERT_TRUE(keyword_url != NULL);
  ASSERT_EQ(prepopulated_url, keyword_url->url()->DisplayURL());
}

TEST_F(TemplateURLModelTest, MAYBE_Load) {
  VerifyLoad();
}

TEST_F(TemplateURLModelTest, AddUpdateRemove) {
  // Add a new TemplateURL.
  VerifyLoad();
  const size_t initial_count = model()->GetTemplateURLs().size();

  TemplateURL* t_url = new TemplateURL();
  t_url->SetURL("http://www.google.com/foo/bar", 0, 0);
  t_url->set_keyword(ASCIIToUTF16("keyword"));
  t_url->set_short_name(ASCIIToUTF16("google"));
  GURL favicon_url("http://favicon.url");
  t_url->SetFaviconURL(favicon_url);
  t_url->set_date_created(Time::FromTimeT(100));
  t_url->set_safe_for_autoreplace(true);
  model()->Add(t_url);
  ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"),
                                         GURL(), NULL));
  VerifyObserverCount(1);
  BlockTillServiceProcessesRequests();
  // We need to clone as model takes ownership of TemplateURL and will
  // delete it.
  TemplateURL cloned_url(*t_url);
  ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
  ASSERT_TRUE(model()->GetTemplateURLForKeyword(t_url->keyword()) == t_url);
  ASSERT_TRUE(t_url->date_created() == cloned_url.date_created());

  // Reload the model to verify it was actually saved to the database.
  ResetModel(true);
  ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
  const TemplateURL* loaded_url =
      model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
  ASSERT_TRUE(loaded_url != NULL);
  AssertEquals(cloned_url, *loaded_url);
  ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"),
                                         GURL(), NULL));

  // Mutate an element and verify it succeeded.
  model()->ResetTemplateURL(loaded_url, ASCIIToUTF16("a"),
                            ASCIIToUTF16("b"), "c");
  ASSERT_EQ(ASCIIToUTF16("a"), loaded_url->short_name());
  ASSERT_EQ(ASCIIToUTF16("b"), loaded_url->keyword());
  ASSERT_EQ("c", loaded_url->url()->url());
  ASSERT_FALSE(loaded_url->safe_for_autoreplace());
  ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"),
                                         GURL(), NULL));
  ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("b"), GURL(), NULL));
  cloned_url = *loaded_url;
  BlockTillServiceProcessesRequests();
  ResetModel(true);
  ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
  loaded_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("b"));
  ASSERT_TRUE(loaded_url != NULL);
  AssertEquals(cloned_url, *loaded_url);

  // Remove an element and verify it succeeded.
  model()->Remove(loaded_url);
  VerifyObserverCount(1);
  ResetModel(true);
  ASSERT_EQ(initial_count, model()->GetTemplateURLs().size());
  EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("b")) == NULL);
}

TEST_F(TemplateURLModelTest, GenerateKeyword) {
  ASSERT_EQ(string16(), TemplateURLModel::GenerateKeyword(GURL(), true));
  // Shouldn't generate keywords for https.
  ASSERT_EQ(string16(),
            TemplateURLModel::GenerateKeyword(GURL("https://blah"), true));
  ASSERT_EQ(ASCIIToUTF16("foo"),
            TemplateURLModel::GenerateKeyword(GURL("http://foo"), true));
  // www. should be stripped.
  ASSERT_EQ(ASCIIToUTF16("foo"),
            TemplateURLModel::GenerateKeyword(GURL("http://www.foo"), true));
  // Shouldn't generate keywords with paths, if autodetected.
  ASSERT_EQ(string16(),
            TemplateURLModel::GenerateKeyword(GURL("http://blah/foo"), true));
  ASSERT_EQ(ASCIIToUTF16("blah"),
            TemplateURLModel::GenerateKeyword(GURL("http://blah/foo"), false));
  // FTP shouldn't generate a keyword.
  ASSERT_EQ(string16(),
            TemplateURLModel::GenerateKeyword(GURL("ftp://blah/"), true));
  // Make sure we don't get a trailing /
  ASSERT_EQ(ASCIIToUTF16("blah"),
            TemplateURLModel::GenerateKeyword(GURL("http://blah/"), true));
}

TEST_F(TemplateURLModelTest, GenerateSearchURL) {
  scoped_refptr<TestGenerateSearchURL> test_generate_search_url(
      new TestGenerateSearchURL(NULL));
  test_generate_search_url->RunTest();
  EXPECT_TRUE(test_generate_search_url->passed());
}

TEST_F(TemplateURLModelTest, GenerateSearchURLUsingTermsData) {
  // Run the test for GenerateSearchURLUsingTermsData on the "IO" thread and
  // wait for it to finish.
  TestSearchTermsData search_terms_data("http://google.com/");
  scoped_refptr<TestGenerateSearchURL> test_generate_search_url(
      new TestGenerateSearchURL(&search_terms_data));

  test_util_.StartIOThread();
  BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)->PostTask(
          FROM_HERE,
          NewRunnableMethod(test_generate_search_url.get(),
                            &TestGenerateSearchURL::RunTest));
  TemplateURLModelTestUtil::BlockTillIOThreadProcessesRequests();
  EXPECT_TRUE(test_generate_search_url->passed());
}

TEST_F(TemplateURLModelTest, ClearBrowsingData_Keywords) {
  Time now = Time::Now();
  TimeDelta one_day = TimeDelta::FromDays(1);
  Time month_ago = now - TimeDelta::FromDays(30);

  // Nothing has been added.
  EXPECT_EQ(0U, model()->GetTemplateURLs().size());

  // Create one with a 0 time.
  AddKeywordWithDate("key1", false, "http://foo1", "http://suggest1",
                     "http://icon1", "UTF-8;UTF-16", "name1", true, Time());
  // Create one for now and +/- 1 day.
  AddKeywordWithDate("key2", false, "http://foo2", "http://suggest2",
                     "http://icon2", "UTF-8;UTF-16", "name2", true,
                     now - one_day);
  AddKeywordWithDate("key3", false, "http://foo3", "", "", "", "name3",
                     true, now);
  AddKeywordWithDate("key4", false, "http://foo4", "", "", "", "name4",
                     true, now + one_day);
  // Try the other three states.
  AddKeywordWithDate("key5", false, "http://foo5", "http://suggest5",
                     "http://icon5", "UTF-8;UTF-16", "name5", false, now);
  AddKeywordWithDate("key6", false, "http://foo6", "http://suggest6",
                     "http://icon6", "UTF-8;UTF-16", "name6", false,
                     month_ago);

  // We just added a few items, validate them.
  EXPECT_EQ(6U, model()->GetTemplateURLs().size());

  // Try removing from current timestamp. This should delete the one in the
  // future and one very recent one.
  model()->RemoveAutoGeneratedSince(now);
  EXPECT_EQ(4U, model()->GetTemplateURLs().size());

  // Try removing from two months ago. This should only delete items that are
  // auto-generated.
  model()->RemoveAutoGeneratedSince(now - TimeDelta::FromDays(60));
  EXPECT_EQ(3U, model()->GetTemplateURLs().size());

  // Make sure the right values remain.
  EXPECT_EQ(ASCIIToUTF16("key1"), model()->GetTemplateURLs()[0]->keyword());
  EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
  EXPECT_EQ(0U,
            model()->GetTemplateURLs()[0]->date_created().ToInternalValue());

  EXPECT_EQ(ASCIIToUTF16("key5"), model()->GetTemplateURLs()[1]->keyword());
  EXPECT_FALSE(model()->GetTemplateURLs()[1]->safe_for_autoreplace());
  EXPECT_EQ(now.ToInternalValue(),
            model()->GetTemplateURLs()[1]->date_created().ToInternalValue());

  EXPECT_EQ(ASCIIToUTF16("key6"), model()->GetTemplateURLs()[2]->keyword());
  EXPECT_FALSE(model()->GetTemplateURLs()[2]->safe_for_autoreplace());
  EXPECT_EQ(month_ago.ToInternalValue(),
            model()->GetTemplateURLs()[2]->date_created().ToInternalValue());

  // Try removing from Time=0. This should delete one more.
  model()->RemoveAutoGeneratedSince(Time());
  EXPECT_EQ(2U, model()->GetTemplateURLs().size());
}

TEST_F(TemplateURLModelTest, Reset) {
  // Add a new TemplateURL.
  VerifyLoad();
  const size_t initial_count = model()->GetTemplateURLs().size();
  TemplateURL* t_url = new TemplateURL();
  t_url->SetURL("http://www.google.com/foo/bar", 0, 0);
  t_url->set_keyword(ASCIIToUTF16("keyword"));
  t_url->set_short_name(ASCIIToUTF16("google"));
  GURL favicon_url("http://favicon.url");
  t_url->SetFaviconURL(favicon_url);
  t_url->set_date_created(Time::FromTimeT(100));
  model()->Add(t_url);

  VerifyObserverCount(1);
  BlockTillServiceProcessesRequests();

  // Reset the short name, keyword, url and make sure it takes.
  const string16 new_short_name(ASCIIToUTF16("a"));
  const string16 new_keyword(ASCIIToUTF16("b"));
  const std::string new_url("c");
  model()->ResetTemplateURL(t_url, new_short_name, new_keyword, new_url);
  ASSERT_EQ(new_short_name, t_url->short_name());
  ASSERT_EQ(new_keyword, t_url->keyword());
  ASSERT_EQ(new_url, t_url->url()->url());

  // Make sure the mappings in the model were updated.
  ASSERT_TRUE(model()->GetTemplateURLForKeyword(new_keyword) == t_url);
  ASSERT_TRUE(
      model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")) == NULL);

  TemplateURL last_url = *t_url;

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

TEST_F(TemplateURLModelTest, DefaultSearchProvider) {
  // Add a new TemplateURL.
  VerifyLoad();
  const size_t initial_count = model()->GetTemplateURLs().size();
  TemplateURL* t_url = AddKeywordWithDate("key1", false, "http://foo1",
      "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time());

  test_util_.ResetObserverCount();
  model()->SetDefaultSearchProvider(t_url);

  ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());

  ASSERT_TRUE(t_url->safe_for_autoreplace());
  ASSERT_TRUE(t_url->show_in_default_list());

  // Setting the default search provider should have caused notification.
  VerifyObserverCount(1);

  BlockTillServiceProcessesRequests();

  TemplateURL cloned_url = *t_url;

  ResetModel(true);
  t_url = NULL;

  // Make sure when we reload we get a default search provider.
  EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
  ASSERT_TRUE(model()->GetDefaultSearchProvider());
  AssertEquals(cloned_url, *model()->GetDefaultSearchProvider());
}

TEST_F(TemplateURLModelTest, TemplateURLWithNoKeyword) {
  VerifyLoad();

  const size_t initial_count = model()->GetTemplateURLs().size();

  AddKeywordWithDate("", false, "http://foo1", "http://sugg1",
      "http://icon1", "UTF-8;UTF-16", "name1", true, Time());

  // We just added a few items, validate them.
  ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());

  // Reload the model from the database and make sure we get the url back.
  ResetModel(true);

  ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());

  bool found_keyword = false;
  for (size_t i = 0; i < initial_count + 1; ++i) {
    if (model()->GetTemplateURLs()[i]->keyword().empty()) {
      found_keyword = true;
      break;
    }
  }
  ASSERT_TRUE(found_keyword);
}

TEST_F(TemplateURLModelTest, CantReplaceWithSameKeyword) {
  ChangeModelToLoadState();
  ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"), GURL(), NULL));
  TemplateURL* t_url = AddKeywordWithDate("foo", false, "http://foo1",
      "http://sugg1", "http://icon1", "UTF-8;UTF-16",  "name1", true, Time());

  // Can still replace, newly added template url is marked safe to replace.
  ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
                                         GURL("http://foo2"), NULL));

  // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
  // no longer be replaceable.
  model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
                           t_url->url()->url());

  ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
                                          GURL("http://foo2"), NULL));
}

TEST_F(TemplateURLModelTest, CantReplaceWithSameHosts) {
  ChangeModelToLoadState();
  ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
                                         GURL("http://foo.com"), NULL));
  TemplateURL* t_url = AddKeywordWithDate("foo", false, "http://foo.com",
      "http://sugg1", "http://icon1", "UTF-8;UTF-16",  "name1", true, Time());

  // Can still replace, newly added template url is marked safe to replace.
  ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("bar"),
                                         GURL("http://foo.com"), NULL));

  // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
  // no longer be replaceable.
  model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
                           t_url->url()->url());

  ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("bar"),
                                          GURL("http://foo.com"), NULL));
}

TEST_F(TemplateURLModelTest, HasDefaultSearchProvider) {
  // We should have a default search provider even if we haven't loaded.
  ASSERT_TRUE(model()->GetDefaultSearchProvider());

  // Now force the model to load and make sure we still have a default.
  VerifyLoad();

  ASSERT_TRUE(model()->GetDefaultSearchProvider());
}

TEST_F(TemplateURLModelTest, DefaultSearchProviderLoadedFromPrefs) {
  VerifyLoad();

  TemplateURL* template_url = new TemplateURL();
  template_url->SetURL("http://url", 0, 0);
  template_url->SetSuggestionsURL("http://url2", 0, 0);
  template_url->SetInstantURL("http://instant", 0, 0);
  template_url->set_short_name(ASCIIToUTF16("a"));
  template_url->set_safe_for_autoreplace(true);
  template_url->set_date_created(Time::FromTimeT(100));

  model()->Add(template_url);

  const TemplateURLID id = template_url->id();

  model()->SetDefaultSearchProvider(template_url);

  BlockTillServiceProcessesRequests();

  TemplateURL first_default_search_provider = *template_url;

  template_url = NULL;

  // Reset the model and don't load it. The template url we set as the default
  // should be pulled from prefs now.
  ResetModel(false);

  // NOTE: This doesn't use AssertEquals as only a subset of the TemplateURLs
  // value are persisted to prefs.
  const TemplateURL* default_turl = model()->GetDefaultSearchProvider();
  ASSERT_TRUE(default_turl);
  ASSERT_TRUE(default_turl->url());
  ASSERT_EQ("http://url", default_turl->url()->url());
  ASSERT_TRUE(default_turl->suggestions_url());
  ASSERT_EQ("http://url2", default_turl->suggestions_url()->url());
  ASSERT_TRUE(default_turl->instant_url());
  EXPECT_EQ("http://instant", default_turl->instant_url()->url());
  ASSERT_EQ(ASCIIToUTF16("a"), default_turl->short_name());
  ASSERT_EQ(id, default_turl->id());

  // Now do a load and make sure the default search provider really takes.
  VerifyLoad();

  ASSERT_TRUE(model()->GetDefaultSearchProvider());
  AssertEquals(first_default_search_provider,
               *model()->GetDefaultSearchProvider());
}

TEST_F(TemplateURLModelTest, BuildQueryTerms) {
  struct TestData {
    const std::string url;
    const bool result;
    // Keys and values are a semicolon separated list of expected values in the
    // map.
    const std::string keys;
    const std::string values;
  } data[] = {
    // No query should return false.
    { "http://blah/", false, "", "" },

    // Query with empty key should return false.
    { "http://blah/foo?=y", false, "", "" },

    // Query with key occurring multiple times should return false.
    { "http://blah/foo?x=y&x=z", false, "", "" },

    { "http://blah/foo?x=y", true, "x", "y" },
    { "http://blah/foo?x=y&y=z", true, "x;y", "y;z" },

    // Key occurring multiple times should get an empty string.
    { "http://blah/foo?x=y&x=z&y=z", true, "x;y", ";z" },
  };

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
    TemplateURLModel::QueryTerms terms;
    ASSERT_EQ(data[i].result,
              TemplateURLModel::BuildQueryTerms(GURL(data[i].url), &terms));
    if (data[i].result) {
      std::vector<std::string> keys;
      std::vector<std::string> values;
      base::SplitString(data[i].keys, ';', &keys);
      base::SplitString(data[i].values, ';', &values);
      ASSERT_TRUE(keys.size() == values.size());
      ASSERT_EQ(keys.size(), terms.size());
      for (size_t j = 0; j < keys.size(); ++j) {
        TemplateURLModel::QueryTerms::iterator term_iterator =
            terms.find(keys[j]);
        ASSERT_TRUE(term_iterator != terms.end());
        ASSERT_EQ(values[j], term_iterator->second);
      }
    }
  }
}

TEST_F(TemplateURLModelTest, UpdateKeywordSearchTermsForURL) {
  struct TestData {
    const std::string url;
    const string16 term;
  } data[] = {
    { "http://foo/", string16() },
    { "http://foo/foo?q=xx", string16() },
    { "http://x/bar?q=xx", string16() },
    { "http://x/foo?y=xx", string16() },
    { "http://x/foo?q=xx", ASCIIToUTF16("xx") },
    { "http://x/foo?a=b&q=xx", ASCIIToUTF16("xx") },
    { "http://x/foo?q=b&q=xx", string16() },
  };

  ChangeModelToLoadState();
  AddKeywordWithDate("x", false, "http://x/foo?q={searchTerms}",
      "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name", false, Time());

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
    history::URLVisitedDetails details;
    details.row = history::URLRow(GURL(data[i].url));
    details.transition = 0;
    model()->UpdateKeywordSearchTermsForURL(details);
    EXPECT_EQ(data[i].term, GetAndClearSearchTerm());
  }
}

TEST_F(TemplateURLModelTest, DontUpdateKeywordSearchForNonReplaceable) {
  struct TestData {
    const std::string url;
  } data[] = {
    { "http://foo/" },
    { "http://x/bar?q=xx" },
    { "http://x/foo?y=xx" },
  };

  ChangeModelToLoadState();
  AddKeywordWithDate("x", false, "http://x/foo", "http://sugg1",
      "http://icon1", "UTF-8;UTF-16", "name", false, Time());

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
    history::URLVisitedDetails details;
    details.row = history::URLRow(GURL(data[i].url));
    details.transition = 0;
    model()->UpdateKeywordSearchTermsForURL(details);
    ASSERT_EQ(string16(), GetAndClearSearchTerm());
  }
}

TEST_F(TemplateURLModelTest, ChangeGoogleBaseValue) {
  // NOTE: Do not do a VerifyLoad() here as it will load the prepopulate data,
  // which also has a {google:baseURL} keyword in it, which will confuse this
  // test.
  ChangeModelToLoadState();
  SetGoogleBaseURL("http://google.com/");
  const TemplateURL* t_url = AddKeywordWithDate("", true,
      "{google:baseURL}?q={searchTerms}", "http://sugg1", "http://icon1",
      "UTF-8;UTF-16", "name", false, Time());
  ASSERT_EQ(t_url, model()->GetTemplateURLForHost("google.com"));
  EXPECT_EQ("google.com", t_url->url()->GetHost());
  EXPECT_EQ(ASCIIToUTF16("google.com"), t_url->keyword());

  // Change the Google base url.
  test_util_.ResetObserverCount();
  SetGoogleBaseURL("http://foo.com/");
  VerifyObserverCount(1);

  // Make sure the host->TemplateURL map was updated appropriately.
  ASSERT_EQ(t_url, model()->GetTemplateURLForHost("foo.com"));
  EXPECT_TRUE(model()->GetTemplateURLForHost("google.com") == NULL);
  EXPECT_EQ("foo.com", t_url->url()->GetHost());
  EXPECT_EQ(ASCIIToUTF16("foo.com"), t_url->keyword());
  EXPECT_EQ("http://foo.com/?q=x", t_url->url()->ReplaceSearchTerms(*t_url,
      ASCIIToUTF16("x"), TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
}

struct QueryHistoryCallbackImpl {
  QueryHistoryCallbackImpl() : success(false) {}

  void Callback(HistoryService::Handle handle,
                bool success, const history::URLRow* row,
                history::VisitVector* visits) {
    this->success = success;
    if (row)
      this->row = *row;
    if (visits)
      this->visits = *visits;
  }

  bool success;
  history::URLRow row;
  history::VisitVector visits;
};

// Make sure TemplateURLModel generates a KEYWORD_GENERATED visit for
// KEYWORD visits.
TEST_F(TemplateURLModelTest, GenerateVisitOnKeyword) {
  VerifyLoad();
  profile()->CreateHistoryService(true, false);

  // Create a keyword.
  TemplateURL* t_url = AddKeywordWithDate(
      "keyword", false, "http://foo.com/foo?query={searchTerms}",
      "http://sugg1", "http://icon1", "UTF-8;UTF-16", "keyword",
      true, base::Time::Now());

  // Add a visit that matches the url of the keyword.
  HistoryService* history =
      profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
  history->AddPage(
      GURL(t_url->url()->ReplaceSearchTerms(*t_url, ASCIIToUTF16("blah"), 0,
                                            string16())),
      NULL, 0, GURL(), PageTransition::KEYWORD, history::RedirectList(),
      history::SOURCE_BROWSED, false);

  // Wait for history to finish processing the request.
  profile()->BlockUntilHistoryProcessesPendingRequests();

  // Query history for the generated url.
  CancelableRequestConsumer consumer;
  QueryHistoryCallbackImpl callback;
  history->QueryURL(GURL("http://keyword"), true, &consumer,
      NewCallback(&callback, &QueryHistoryCallbackImpl::Callback));

  // Wait for the request to be processed.
  profile()->BlockUntilHistoryProcessesPendingRequests();

  // And make sure the url and visit were added.
  EXPECT_TRUE(callback.success);
  EXPECT_NE(0, callback.row.id());
  ASSERT_EQ(1U, callback.visits.size());
  EXPECT_EQ(PageTransition::KEYWORD_GENERATED,
            PageTransition::StripQualifier(callback.visits[0].transition));
}

// Make sure that the load routine deletes prepopulated engines that no longer
// exist in the prepopulate data.
TEST_F(TemplateURLModelTest, LoadDeletesUnusedProvider) {
  // Create a preloaded template url. Add it to a loaded model and wait for the
  // saves to finish.
  TemplateURL* t_url = CreatePreloadedTemplateURL();
  ChangeModelToLoadState();
  model()->Add(t_url);
  ASSERT_TRUE(
      model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) != NULL);
  BlockTillServiceProcessesRequests();

  // Ensure that merging clears this engine.
  ResetModel(true);
  ASSERT_TRUE(
      model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) == NULL);

  // Wait for any saves to finish.
  BlockTillServiceProcessesRequests();

  // Reload the model to verify that the database was updated as a result of the
  // merge.
  ResetModel(true);
  ASSERT_TRUE(
      model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) == NULL);
}

// 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_F(TemplateURLModelTest, LoadRetainsModifiedProvider) {
  // Create a preloaded template url and add it to a loaded model.
  TemplateURL* t_url = CreatePreloadedTemplateURL();
  t_url->set_safe_for_autoreplace(false);
  ChangeModelToLoadState();
  model()->Add(t_url);

  // Do the copy after t_url is added so that the id is set.
  TemplateURL copy_t_url = *t_url;
  ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")));

  // Wait for any saves to finish.
  BlockTillServiceProcessesRequests();

  // Ensure that merging won't clear it if the user has edited it.
  ResetModel(true);
  const TemplateURL* url_for_unittest =
      model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
  ASSERT_TRUE(url_for_unittest != NULL);
  AssertEquals(copy_t_url, *url_for_unittest);

  // Wait for any saves to finish.
  BlockTillServiceProcessesRequests();

  // Reload the model to verify that save/reload retains the item.
  ResetModel(true);
  ASSERT_TRUE(
      model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) != NULL);
}

// 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_F(TemplateURLModelTest, LoadSavesPrepopulatedDefaultSearchProvider) {
  VerifyLoad();
  // Verify that the default search provider is set to something.
  ASSERT_TRUE(model()->GetDefaultSearchProvider() != NULL);
  TemplateURL default_url = *model()->GetDefaultSearchProvider();

  // Wait for any saves to finish.
  BlockTillServiceProcessesRequests();

  // Reload the model and check that the default search provider
  // was properly saved.
  ResetModel(true);
  ASSERT_TRUE(model()->GetDefaultSearchProvider() != NULL);
  AssertEquals(default_url, *model()->GetDefaultSearchProvider());
}

// 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_F(TemplateURLModelTest, LoadRetainsDefaultProvider) {
  // Set the default search provider to a preloaded template url which
  // is not in the current set of preloaded template urls and save
  // the result.
  TemplateURL* t_url = CreatePreloadedTemplateURL();
  ChangeModelToLoadState();
  model()->Add(t_url);
  model()->SetDefaultSearchProvider(t_url);
  // Do the copy after t_url is added and set as default so that its
  // internal state is correct.
  TemplateURL copy_t_url = *t_url;

  ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")));
  ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());
  BlockTillServiceProcessesRequests();

  // Ensure that merging won't clear the prepopulated template url
  // which is no longer present if it's the default engine.
  ResetModel(true);
  {
    const TemplateURL* keyword_url =
        model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
    ASSERT_TRUE(keyword_url != NULL);
    AssertEquals(copy_t_url, *keyword_url);
    ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
  }

  // Wait for any saves to finish.
  BlockTillServiceProcessesRequests();

  // Reload the model to verify that the update was saved.
  ResetModel(true);
  {
    const TemplateURL* keyword_url =
        model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
    ASSERT_TRUE(keyword_url != NULL);
    AssertEquals(copy_t_url, *keyword_url);
    ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
  }
}

// Make sure that the load routine updates the url of a preexisting
// default search engine provider and that the result is saved correctly.
TEST_F(TemplateURLModelTest, LoadUpdatesDefaultSearchURL) {
  TestLoadUpdatingPreloadedURL(0);
}

// Make sure that the load routine updates the url of a preexisting
// non-default search engine provider and that the result is saved correctly.
TEST_F(TemplateURLModelTest, LoadUpdatesSearchURL) {
  TestLoadUpdatingPreloadedURL(1);
}

// Make sure that the load does update of auto-keywords correctly.
// This test basically verifies that no asserts or crashes occur
// during this operation.
TEST_F(TemplateURLModelTest, LoadDoesAutoKeywordUpdate) {
  string16 prepopulated_url;
  TemplateURL* t_url = CreateReplaceablePreloadedTemplateURL(
      0, &prepopulated_url);
  t_url->set_safe_for_autoreplace(false);
  t_url->SetURL("{google:baseURL}?q={searchTerms}", 0, 0);
  t_url->set_autogenerate_keyword(true);

  // Then add it to the model and save it all.
  ChangeModelToLoadState();
  model()->Add(t_url);
  BlockTillServiceProcessesRequests();

  // Now reload the model and verify that the merge updates the url.
  ResetModel(true);

  // Wait for any saves to finish.
  BlockTillServiceProcessesRequests();
}

// Simulates failing to load the webdb and makes sure the default search
// provider is valid.
TEST_F(TemplateURLModelTest, FailedInit) {
  VerifyLoad();

  test_util_.ClearModel();
  test_util_.GetWebDataService()->UnloadDatabase();
  test_util_.GetWebDataService()->set_failed_init(true);

  ResetModel(false);
  model()->Load();
  BlockTillServiceProcessesRequests();

  ASSERT_TRUE(model()->GetDefaultSearchProvider());
}

// 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_F(TemplateURLModelTest, TestManagedDefaultSearch) {
  VerifyLoad();
  const size_t initial_count = model()->GetTemplateURLs().size();
  test_util_.ResetObserverCount();

  // Set a regular default search provider.
  TemplateURL* regular_default = AddKeywordWithDate("key1", false,
      "http://foo1", "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1",
      true, Time());
  VerifyObserverCount(1);
  model()->SetDefaultSearchProvider(regular_default);
  // Adding the URL and setting the default search provider should have caused
  // notifications.
  VerifyObserverCount(1);
  EXPECT_FALSE(model()->is_default_search_managed());
  EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());

  // Set a managed preference that establishes a default search provider.
  const char kName[] = "test1";
  const char kSearchURL[] = "http://test.com/search?t={searchTerms}";
  const char kIconURL[] = "http://test.com/icon.jpg";
  const char kEncodings[] = "UTF-16;UTF-32";
  SetManagedDefaultSearchPreferences(true, kName, kSearchURL, "", kIconURL,
                                     kEncodings, "");
  VerifyObserverFired();
  EXPECT_TRUE(model()->is_default_search_managed());
  EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());

  // Verify that the default manager we are getting is the managed one.
  scoped_ptr<TemplateURL> expected_managed_default1(new TemplateURL());
  expected_managed_default1->SetURL(kSearchURL, 0, 0);
  expected_managed_default1->SetFaviconURL(GURL(kIconURL));
  expected_managed_default1->set_short_name(ASCIIToUTF16("test1"));
  std::vector<std::string> encodings_vector;
  base::SplitString(kEncodings, ';', &encodings_vector);
  expected_managed_default1->set_input_encodings(encodings_vector);
  expected_managed_default1->set_show_in_default_list(true);
  const TemplateURL* actual_managed_default =
      model()->GetDefaultSearchProvider();
  ExpectSimilar(actual_managed_default, expected_managed_default1.get());
  EXPECT_EQ(actual_managed_default->show_in_default_list(), true);

  // Update the managed preference and check that the model has changed.
  const char kNewName[] = "test2";
  const char kNewSearchURL[] = "http://other.com/search?t={searchTerms}";
  const char kNewSuggestURL[] = "http://other.com/suggest?t={searchTerms}";
  SetManagedDefaultSearchPreferences(true, kNewName, kNewSearchURL,
                                     kNewSuggestURL, "", "", "");
  VerifyObserverFired();
  EXPECT_TRUE(model()->is_default_search_managed());
  EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());

  // Verify that the default manager we are now getting is the correct one.
  scoped_ptr<TemplateURL> expected_managed_default2(new TemplateURL());
  expected_managed_default2->SetURL(kNewSearchURL, 0, 0);
  expected_managed_default2->SetSuggestionsURL(kNewSuggestURL, 0, 0);
  expected_managed_default2->set_short_name(ASCIIToUTF16("test2"));
  expected_managed_default2->set_show_in_default_list(true);
  actual_managed_default = model()->GetDefaultSearchProvider();
  ExpectSimilar(actual_managed_default, expected_managed_default2.get());
  EXPECT_EQ(actual_managed_default->show_in_default_list(), true);

  // Remove all the managed prefs and check that we are no longer managed.
  RemoveManagedDefaultSearchPreferences();
  VerifyObserverFired();
  EXPECT_FALSE(model()->is_default_search_managed());
  EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());

  // The default should now be the first URL added
  const TemplateURL* actual_final_managed_default =
      model()->GetDefaultSearchProvider();
  ExpectSimilar(actual_final_managed_default,
      model()->GetTemplateURLs()[0]);
  EXPECT_EQ(actual_final_managed_default->show_in_default_list(), true);

  // Disable the default search provider through policy.
  SetManagedDefaultSearchPreferences(false, "", "", "", "", "", "");
  VerifyObserverFired();
  EXPECT_TRUE(model()->is_default_search_managed());
  EXPECT_TRUE(NULL == model()->GetDefaultSearchProvider());
  EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());

  // Re-enable it.
  SetManagedDefaultSearchPreferences(true, kName, kSearchURL, "", kIconURL,
                                     kEncodings, "");
  VerifyObserverFired();
  EXPECT_TRUE(model()->is_default_search_managed());
  EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());

  // Verify that the default manager we are getting is the managed one.
  actual_managed_default = model()->GetDefaultSearchProvider();
  ExpectSimilar(actual_managed_default, expected_managed_default1.get());
  EXPECT_EQ(actual_managed_default->show_in_default_list(), true);
}