template_url_model_unittest.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/callback.h"
6#include "base/scoped_vector.h"
7#include "base/string_split.h"
8#include "base/string_util.h"
9#include "base/ref_counted.h"
10#include "base/threading/thread.h"
11#include "chrome/browser/browser_thread.h"
12#include "chrome/browser/history/history.h"
13#include "chrome/browser/history/history_notifications.h"
14#include "chrome/browser/search_engines/search_host_to_urls_map.h"
15#include "chrome/browser/search_engines/search_terms_data.h"
16#include "chrome/browser/search_engines/template_url.h"
17#include "chrome/browser/search_engines/template_url_model.h"
18#include "chrome/browser/search_engines/template_url_model_test_util.h"
19#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
20#include "chrome/browser/webdata/web_database.h"
21#include "chrome/common/notification_details.h"
22#include "chrome/common/notification_source.h"
23#include "chrome/common/pref_names.h"
24#include "chrome/test/testing_pref_service.h"
25#include "chrome/test/testing_profile.h"
26#include "testing/gtest/include/gtest/gtest.h"
27
28using base::Time;
29using base::TimeDelta;
30
31#if defined(OS_LINUX)
32// Timed out on Chromium Linux.  http://crbug.com/53607
33#define MAYBE_Load DISABLED_Load
34#else
35#define MAYBE_Load Load
36#endif
37
38// Test the GenerateSearchURL on a thread or the main thread.
39class TestGenerateSearchURL
40    : public base::RefCountedThreadSafe<TestGenerateSearchURL> {
41 public:
42  explicit TestGenerateSearchURL(SearchTermsData* search_terms_data)
43      : search_terms_data_(search_terms_data),
44        passed_(false) {
45  }
46
47  // Run the test cases for GenerateSearchURL.
48  void RunTest();
49
50  // Did the test pass?
51  bool passed() const { return passed_; }
52
53 private:
54  friend class base::RefCountedThreadSafe<TestGenerateSearchURL>;
55  ~TestGenerateSearchURL() {}
56
57  SearchTermsData* search_terms_data_;
58  bool passed_;
59
60  DISALLOW_COPY_AND_ASSIGN(TestGenerateSearchURL);
61};
62
63// Simple implementation of SearchTermsData.
64class TestSearchTermsData : public SearchTermsData {
65 public:
66  explicit TestSearchTermsData(const char* google_base_url)
67      : google_base_url_(google_base_url)  {
68  }
69
70  virtual std::string GoogleBaseURLValue() const {
71    return google_base_url_;
72  }
73
74  virtual std::string GetApplicationLocale() const {
75    return "yy";
76  }
77
78#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
79  // Returns the value for the Chrome Omnibox rlz.
80  virtual std::wstring GetRlzParameterValue() const {
81    return std::wstring();
82  }
83#endif
84
85 private:
86  std::string google_base_url_;
87
88  DISALLOW_COPY_AND_ASSIGN(TestSearchTermsData);
89};
90
91// Create an URL that appears to have been prepopulated, but won't be in the
92// current data. The caller owns the returned TemplateURL*.
93static TemplateURL* CreatePreloadedTemplateURL() {
94  TemplateURL* t_url = new TemplateURL();
95  t_url->SetURL("http://www.unittest.com/", 0, 0);
96  t_url->set_keyword(L"unittest");
97  t_url->set_short_name(L"unittest");
98  t_url->set_safe_for_autoreplace(true);
99  GURL favicon_url("http://favicon.url");
100  t_url->SetFavIconURL(favicon_url);
101  t_url->set_date_created(Time::FromTimeT(100));
102  t_url->set_prepopulate_id(999999);
103  return t_url;
104}
105
106class TemplateURLModelTest : public testing::Test {
107 public:
108  TemplateURLModelTest() {}
109
110  virtual void SetUp() {
111    test_util_.SetUp();
112  }
113
114  virtual void TearDown() {
115    test_util_.TearDown();
116  }
117
118  TemplateURL* AddKeywordWithDate(const std::wstring& keyword,
119                                  bool autogenerate_keyword,
120                                  const std::string& url,
121                                  const std::string& suggest_url,
122                                  const std::string& fav_icon_url,
123                                  const std::string& encodings,
124                                  const std::wstring& short_name,
125                                  bool safe_for_autoreplace,
126                                  Time created_date) {
127    TemplateURL* template_url = new TemplateURL();
128    template_url->SetURL(url, 0, 0);
129    template_url->SetSuggestionsURL(suggest_url, 0, 0);
130    template_url->SetFavIconURL(GURL(fav_icon_url));
131    template_url->set_keyword(keyword);
132    template_url->set_autogenerate_keyword(autogenerate_keyword);
133    template_url->set_short_name(short_name);
134    std::vector<std::string> encodings_vector;
135    base::SplitString(encodings, ';', &encodings_vector);
136    template_url->set_input_encodings(encodings_vector);
137    template_url->set_date_created(created_date);
138    template_url->set_safe_for_autoreplace(safe_for_autoreplace);
139    model()->Add(template_url);
140    EXPECT_NE(0, template_url->id());
141    return template_url;
142  }
143
144  // Simulate firing by the prefs service specifying that the managed
145  // preferences have changed.
146  void NotifyManagedPrefsHaveChanged() {
147    model()->Observe(
148        NotificationType::PREF_CHANGED,
149        Source<PrefService>(profile()->GetTestingPrefService()),
150        Details<std::string>(NULL));
151  }
152
153  // Verifies the two TemplateURLs are equal.
154  void AssertEquals(const TemplateURL& expected, const TemplateURL& actual) {
155    ASSERT_TRUE(TemplateURLRef::SameUrlRefs(expected.url(), actual.url()));
156    ASSERT_TRUE(TemplateURLRef::SameUrlRefs(expected.suggestions_url(),
157                                            actual.suggestions_url()));
158    ASSERT_EQ(expected.keyword(), actual.keyword());
159    ASSERT_EQ(expected.short_name(), actual.short_name());
160    ASSERT_EQ(JoinString(expected.input_encodings(), ';'),
161              JoinString(actual.input_encodings(), ';'));
162    ASSERT_TRUE(expected.GetFavIconURL() == actual.GetFavIconURL());
163    ASSERT_EQ(expected.id(), actual.id());
164    ASSERT_EQ(expected.safe_for_autoreplace(), actual.safe_for_autoreplace());
165    ASSERT_EQ(expected.show_in_default_list(), actual.show_in_default_list());
166    ASSERT_TRUE(expected.date_created() == actual.date_created());
167  }
168
169  // Checks that the two TemplateURLs are similar. It does not check the id
170  // and the date_created.  Neither pointer should be NULL.
171  void ExpectSimilar(const TemplateURL* expected, const TemplateURL* actual) {
172    ASSERT_TRUE(expected != NULL);
173    ASSERT_TRUE(actual != NULL);
174    EXPECT_TRUE(TemplateURLRef::SameUrlRefs(expected->url(), actual->url()));
175    EXPECT_TRUE(TemplateURLRef::SameUrlRefs(expected->suggestions_url(),
176                                            actual->suggestions_url()));
177    EXPECT_EQ(expected->keyword(), actual->keyword());
178    EXPECT_EQ(expected->short_name(), actual->short_name());
179    EXPECT_EQ(JoinString(expected->input_encodings(), ';'),
180              JoinString(actual->input_encodings(), ';'));
181    EXPECT_TRUE(expected->GetFavIconURL() == actual->GetFavIconURL());
182    EXPECT_EQ(expected->safe_for_autoreplace(), actual->safe_for_autoreplace());
183    EXPECT_EQ(expected->show_in_default_list(), actual->show_in_default_list());
184  }
185
186  // Set the managed preferences for the default search provider and trigger
187  // notification.
188  void SetManagedDefaultSearchPreferences(bool enabled,
189                                          const char* name,
190                                          const char* search_url,
191                                          const char* suggest_url,
192                                          const char* icon_url,
193                                          const char* encodings,
194                                          const char* keyword) {
195    TestingPrefService* service = profile()->GetTestingPrefService();
196    service->SetManagedPref(
197        prefs::kDefaultSearchProviderEnabled,
198        Value::CreateBooleanValue(enabled));
199    service->SetManagedPref(
200        prefs::kDefaultSearchProviderName,
201        Value::CreateStringValue(name));
202    service->SetManagedPref(
203        prefs::kDefaultSearchProviderSearchURL,
204        Value::CreateStringValue(search_url));
205    service->SetManagedPref(
206        prefs::kDefaultSearchProviderSuggestURL,
207        Value::CreateStringValue(suggest_url));
208    service->SetManagedPref(
209        prefs::kDefaultSearchProviderIconURL,
210        Value::CreateStringValue(icon_url));
211    service->SetManagedPref(
212        prefs::kDefaultSearchProviderEncodings,
213        Value::CreateStringValue(encodings));
214    service->SetManagedPref(
215        prefs::kDefaultSearchProviderKeyword,
216        Value::CreateStringValue(keyword));
217  }
218
219  // Remove all the managed preferences for the default search provider and
220  // trigger notification.
221  void RemoveManagedDefaultSearchPreferences() {
222    TestingPrefService* service = profile()->GetTestingPrefService();
223    service->RemoveManagedPref(
224        prefs::kDefaultSearchProviderSearchURL);
225    service->RemoveManagedPref(
226        prefs::kDefaultSearchProviderEnabled);
227    service->RemoveManagedPref(
228        prefs::kDefaultSearchProviderName);
229    service->RemoveManagedPref(
230        prefs::kDefaultSearchProviderSuggestURL);
231    service->RemoveManagedPref(
232        prefs::kDefaultSearchProviderIconURL);
233    service->RemoveManagedPref(
234        prefs::kDefaultSearchProviderEncodings);
235    service->RemoveManagedPref(
236        prefs::kDefaultSearchProviderKeyword);
237    service->RemoveManagedPref(
238        prefs::kDefaultSearchProviderID);
239    service->RemoveManagedPref(
240        prefs::kDefaultSearchProviderPrepopulateID);
241  }
242
243  // Creates a TemplateURL with the same prepopluated id as a real prepopulated
244  // item. The input number determines which prepopulated item. The caller is
245  // responsible for owning the returned TemplateURL*.
246  TemplateURL* CreateReplaceablePreloadedTemplateURL(
247      size_t index_offset_from_default,
248      std::wstring* prepopulated_display_url);
249
250  // Verifies the behavior of when a preloaded url later gets changed.
251  // Since the input is the offset from the default, when one passes in
252  // 0, it tests the default. Passing in a number > 0 will verify what
253  // happens when a preloaded url that is not the default gets updated.
254  void TestLoadUpdatingPreloadedURL(size_t index_offset_from_default);
255
256  // Helper methods to make calling TemplateURLModelTestUtil methods less
257  // visually noisy in the test code.
258  void VerifyObserverCount(int expected_changed_count) {
259    EXPECT_EQ(expected_changed_count, test_util_.GetObserverCount());
260    test_util_.ResetObserverCount();
261  }
262  void VerifyObserverFired() {
263    EXPECT_LE(1, test_util_.GetObserverCount());
264    test_util_.ResetObserverCount();
265  }
266  void BlockTillServiceProcessesRequests() {
267    TemplateURLModelTestUtil::BlockTillServiceProcessesRequests();
268  }
269  void VerifyLoad() { test_util_.VerifyLoad(); }
270  void ChangeModelToLoadState() { test_util_.ChangeModelToLoadState(); }
271  void ResetModel(bool verify_load) { test_util_.ResetModel(verify_load); }
272  std::wstring GetAndClearSearchTerm() {
273    return test_util_.GetAndClearSearchTerm();
274  }
275  void SetGoogleBaseURL(const std::string& base_url) const {
276    test_util_.SetGoogleBaseURL(base_url);
277  }
278  WebDataService* GetWebDataService() { return test_util_.GetWebDataService(); }
279  TemplateURLModel* model() { return test_util_.model(); }
280  TestingProfile* profile() { return test_util_.profile(); }
281
282 protected:
283  TemplateURLModelTestUtil test_util_;
284
285  DISALLOW_COPY_AND_ASSIGN(TemplateURLModelTest);
286};
287
288void TestGenerateSearchURL::RunTest() {
289  struct GenerateSearchURLCase {
290    const char* test_name;
291    const char* url;
292    const char* expected;
293  } generate_url_cases[] = {
294    { "empty TemplateURLRef", NULL, "" },
295    { "invalid URL", "foo{searchTerms}", "" },
296    { "URL with no replacements", "http://foo/", "http://foo/" },
297    { "basic functionality", "http://foo/{searchTerms}",
298      "http://foo/blah.blah.blah.blah.blah" }
299  };
300
301  // Don't use ASSERT/EXPECT since this is run on a thread in one test
302  // and those macros aren't meant for threads at this time according to
303  // gtest documentation.
304  bool everything_passed = true;
305  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(generate_url_cases); ++i) {
306    TemplateURL t_url;
307    if (generate_url_cases[i].url)
308      t_url.SetURL(generate_url_cases[i].url, 0, 0);
309
310    std::string result = search_terms_data_ ?
311        TemplateURLModel::GenerateSearchURLUsingTermsData(
312            &t_url, *search_terms_data_).spec() :
313        TemplateURLModel::GenerateSearchURL(&t_url).spec();
314    if (strcmp(generate_url_cases[i].expected, result.c_str())) {
315      LOG(ERROR) << generate_url_cases[i].test_name << " failed. Expected " <<
316          generate_url_cases[i].expected << " Actual " << result;
317
318      everything_passed = false;
319    }
320  }
321  passed_ = everything_passed;
322}
323
324TemplateURL* TemplateURLModelTest::CreateReplaceablePreloadedTemplateURL(
325    size_t index_offset_from_default,
326    std::wstring* prepopulated_display_url) {
327  TemplateURL* t_url = CreatePreloadedTemplateURL();
328  ScopedVector<TemplateURL> prepopulated_urls;
329  size_t default_search_provider_index = 0;
330  TemplateURLPrepopulateData::GetPrepopulatedEngines(
331      profile()->GetPrefs(),
332      &prepopulated_urls.get(),
333      &default_search_provider_index);
334  EXPECT_LT(index_offset_from_default, prepopulated_urls.size());
335  size_t prepopulated_index =
336      (default_search_provider_index + index_offset_from_default) %
337      prepopulated_urls.size();
338  t_url->set_prepopulate_id(
339      prepopulated_urls[prepopulated_index]->prepopulate_id());
340  *prepopulated_display_url =
341      prepopulated_urls[prepopulated_index]->url()->DisplayURL();
342  return t_url;
343}
344
345void TemplateURLModelTest::TestLoadUpdatingPreloadedURL(
346    size_t index_offset_from_default) {
347  std::wstring prepopulated_url;
348  TemplateURL* t_url = CreateReplaceablePreloadedTemplateURL(
349      index_offset_from_default, &prepopulated_url);
350  t_url->set_safe_for_autoreplace(false);
351
352  std::wstring original_url = t_url->url()->DisplayURL();
353  ASSERT_STRNE(prepopulated_url.c_str(), original_url.c_str());
354
355  // Then add it to the model and save it all.
356  ChangeModelToLoadState();
357  model()->Add(t_url);
358  const TemplateURL* keyword_url =
359      model()->GetTemplateURLForKeyword(L"unittest");
360  ASSERT_EQ(t_url, keyword_url);
361  ASSERT_STREQ(original_url.c_str(), keyword_url->url()->DisplayURL().c_str());
362  BlockTillServiceProcessesRequests();
363
364  // Now reload the model and verify that the merge updates the url.
365  ResetModel(true);
366  keyword_url = model()->GetTemplateURLForKeyword(L"unittest");
367  ASSERT_TRUE(keyword_url != NULL);
368  ASSERT_STREQ(prepopulated_url.c_str(),
369               keyword_url->url()->DisplayURL().c_str());
370
371  // Wait for any saves to finish.
372  BlockTillServiceProcessesRequests();
373
374  // Reload the model to verify that change was saved correctly.
375  ResetModel(true);
376  keyword_url = model()->GetTemplateURLForKeyword(L"unittest");
377  ASSERT_TRUE(keyword_url != NULL);
378  ASSERT_STREQ(prepopulated_url.c_str(),
379               keyword_url->url()->DisplayURL().c_str());
380}
381
382TEST_F(TemplateURLModelTest, MAYBE_Load) {
383  VerifyLoad();
384}
385
386TEST_F(TemplateURLModelTest, AddUpdateRemove) {
387  // Add a new TemplateURL.
388  VerifyLoad();
389  const size_t initial_count = model()->GetTemplateURLs().size();
390
391  TemplateURL* t_url = new TemplateURL();
392  t_url->SetURL("http://www.google.com/foo/bar", 0, 0);
393  t_url->set_keyword(L"keyword");
394  t_url->set_short_name(L"google");
395  GURL favicon_url("http://favicon.url");
396  t_url->SetFavIconURL(favicon_url);
397  t_url->set_date_created(Time::FromTimeT(100));
398  t_url->set_safe_for_autoreplace(true);
399  model()->Add(t_url);
400  ASSERT_TRUE(model()->CanReplaceKeyword(L"keyword", GURL(), NULL));
401  VerifyObserverCount(1);
402  BlockTillServiceProcessesRequests();
403  // We need to clone as model takes ownership of TemplateURL and will
404  // delete it.
405  TemplateURL cloned_url(*t_url);
406  ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
407  ASSERT_TRUE(model()->GetTemplateURLForKeyword(t_url->keyword()) == t_url);
408  ASSERT_TRUE(t_url->date_created() == cloned_url.date_created());
409
410  // Reload the model to verify it was actually saved to the database.
411  ResetModel(true);
412  ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
413  const TemplateURL* loaded_url = model()->GetTemplateURLForKeyword(L"keyword");
414  ASSERT_TRUE(loaded_url != NULL);
415  AssertEquals(cloned_url, *loaded_url);
416  ASSERT_TRUE(model()->CanReplaceKeyword(L"keyword", GURL(), NULL));
417
418  // Mutate an element and verify it succeeded.
419  model()->ResetTemplateURL(loaded_url, L"a", L"b", "c");
420  ASSERT_EQ(L"a", loaded_url->short_name());
421  ASSERT_EQ(L"b", loaded_url->keyword());
422  ASSERT_EQ("c", loaded_url->url()->url());
423  ASSERT_FALSE(loaded_url->safe_for_autoreplace());
424  ASSERT_TRUE(model()->CanReplaceKeyword(L"keyword", GURL(), NULL));
425  ASSERT_FALSE(model()->CanReplaceKeyword(L"b", GURL(), NULL));
426  cloned_url = *loaded_url;
427  BlockTillServiceProcessesRequests();
428  ResetModel(true);
429  ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
430  loaded_url = model()->GetTemplateURLForKeyword(L"b");
431  ASSERT_TRUE(loaded_url != NULL);
432  AssertEquals(cloned_url, *loaded_url);
433
434  // Remove an element and verify it succeeded.
435  model()->Remove(loaded_url);
436  VerifyObserverCount(1);
437  ResetModel(true);
438  ASSERT_EQ(initial_count, model()->GetTemplateURLs().size());
439  EXPECT_TRUE(model()->GetTemplateURLForKeyword(L"b") == NULL);
440}
441
442TEST_F(TemplateURLModelTest, GenerateKeyword) {
443  ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL(), true));
444  // Shouldn't generate keywords for https.
445  ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL("https://blah"), true));
446  ASSERT_EQ(L"foo", TemplateURLModel::GenerateKeyword(GURL("http://foo"),
447                                                      true));
448  // www. should be stripped.
449  ASSERT_EQ(L"foo", TemplateURLModel::GenerateKeyword(GURL("http://www.foo"),
450                                                      true));
451  // Shouldn't generate keywords with paths, if autodetected.
452  ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL("http://blah/foo"),
453                                                   true));
454  ASSERT_EQ(L"blah", TemplateURLModel::GenerateKeyword(GURL("http://blah/foo"),
455                                                       false));
456  // FTP shouldn't generate a keyword.
457  ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL("ftp://blah/"), true));
458  // Make sure we don't get a trailing /
459  ASSERT_EQ(L"blah", TemplateURLModel::GenerateKeyword(GURL("http://blah/"),
460                                                       true));
461}
462
463TEST_F(TemplateURLModelTest, GenerateSearchURL) {
464  scoped_refptr<TestGenerateSearchURL> test_generate_search_url(
465      new TestGenerateSearchURL(NULL));
466  test_generate_search_url->RunTest();
467  EXPECT_TRUE(test_generate_search_url->passed());
468}
469
470TEST_F(TemplateURLModelTest, GenerateSearchURLUsingTermsData) {
471  // Run the test for GenerateSearchURLUsingTermsData on the "IO" thread and
472  // wait for it to finish.
473  TestSearchTermsData search_terms_data("http://google.com/");
474  scoped_refptr<TestGenerateSearchURL> test_generate_search_url(
475      new TestGenerateSearchURL(&search_terms_data));
476
477  test_util_.StartIOThread();
478  BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)->PostTask(
479          FROM_HERE,
480          NewRunnableMethod(test_generate_search_url.get(),
481                            &TestGenerateSearchURL::RunTest));
482  TemplateURLModelTestUtil::BlockTillIOThreadProcessesRequests();
483  EXPECT_TRUE(test_generate_search_url->passed());
484}
485
486TEST_F(TemplateURLModelTest, ClearBrowsingData_Keywords) {
487  Time now = Time::Now();
488  TimeDelta one_day = TimeDelta::FromDays(1);
489  Time month_ago = now - TimeDelta::FromDays(30);
490
491  // Nothing has been added.
492  EXPECT_EQ(0U, model()->GetTemplateURLs().size());
493
494  // Create one with a 0 time.
495  AddKeywordWithDate(L"key1", false, "http://foo1", "http://suggest1",
496                     "http://icon1", "UTF-8;UTF-16", L"name1", true, Time());
497  // Create one for now and +/- 1 day.
498  AddKeywordWithDate(L"key2", false, "http://foo2", "http://suggest2",
499                     "http://icon2", "UTF-8;UTF-16", L"name2", true,
500                     now - one_day);
501  AddKeywordWithDate(L"key3", false, "http://foo3", "", "", "", L"name3",
502                     true, now);
503  AddKeywordWithDate(L"key4", false, "http://foo4", "", "", "", L"name4",
504                     true, now + one_day);
505  // Try the other three states.
506  AddKeywordWithDate(L"key5", false, "http://foo5", "http://suggest5",
507                     "http://icon5", "UTF-8;UTF-16", L"name5", false, now);
508  AddKeywordWithDate(L"key6", false, "http://foo6", "http://suggest6",
509                     "http://icon6", "UTF-8;UTF-16", L"name6", false,
510                     month_ago);
511
512  // We just added a few items, validate them.
513  EXPECT_EQ(6U, model()->GetTemplateURLs().size());
514
515  // Try removing from current timestamp. This should delete the one in the
516  // future and one very recent one.
517  model()->RemoveAutoGeneratedSince(now);
518  EXPECT_EQ(4U, model()->GetTemplateURLs().size());
519
520  // Try removing from two months ago. This should only delete items that are
521  // auto-generated.
522  model()->RemoveAutoGeneratedSince(now - TimeDelta::FromDays(60));
523  EXPECT_EQ(3U, model()->GetTemplateURLs().size());
524
525  // Make sure the right values remain.
526  EXPECT_EQ(L"key1", model()->GetTemplateURLs()[0]->keyword());
527  EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
528  EXPECT_EQ(0U,
529            model()->GetTemplateURLs()[0]->date_created().ToInternalValue());
530
531  EXPECT_EQ(L"key5", model()->GetTemplateURLs()[1]->keyword());
532  EXPECT_FALSE(model()->GetTemplateURLs()[1]->safe_for_autoreplace());
533  EXPECT_EQ(now.ToInternalValue(),
534            model()->GetTemplateURLs()[1]->date_created().ToInternalValue());
535
536  EXPECT_EQ(L"key6", model()->GetTemplateURLs()[2]->keyword());
537  EXPECT_FALSE(model()->GetTemplateURLs()[2]->safe_for_autoreplace());
538  EXPECT_EQ(month_ago.ToInternalValue(),
539            model()->GetTemplateURLs()[2]->date_created().ToInternalValue());
540
541  // Try removing from Time=0. This should delete one more.
542  model()->RemoveAutoGeneratedSince(Time());
543  EXPECT_EQ(2U, model()->GetTemplateURLs().size());
544}
545
546TEST_F(TemplateURLModelTest, Reset) {
547  // Add a new TemplateURL.
548  VerifyLoad();
549  const size_t initial_count = model()->GetTemplateURLs().size();
550  TemplateURL* t_url = new TemplateURL();
551  t_url->SetURL("http://www.google.com/foo/bar", 0, 0);
552  t_url->set_keyword(L"keyword");
553  t_url->set_short_name(L"google");
554  GURL favicon_url("http://favicon.url");
555  t_url->SetFavIconURL(favicon_url);
556  t_url->set_date_created(Time::FromTimeT(100));
557  model()->Add(t_url);
558
559  VerifyObserverCount(1);
560  BlockTillServiceProcessesRequests();
561
562  // Reset the short name, keyword, url and make sure it takes.
563  const std::wstring new_short_name(L"a");
564  const std::wstring new_keyword(L"b");
565  const std::string new_url("c");
566  model()->ResetTemplateURL(t_url, new_short_name, new_keyword, new_url);
567  ASSERT_EQ(new_short_name, t_url->short_name());
568  ASSERT_EQ(new_keyword, t_url->keyword());
569  ASSERT_EQ(new_url, t_url->url()->url());
570
571  // Make sure the mappings in the model were updated.
572  ASSERT_TRUE(model()->GetTemplateURLForKeyword(new_keyword) == t_url);
573  ASSERT_TRUE(model()->GetTemplateURLForKeyword(L"keyword") == NULL);
574
575  TemplateURL last_url = *t_url;
576
577  // Reload the model from the database and make sure the change took.
578  ResetModel(true);
579  t_url = NULL;
580  EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
581  const TemplateURL* read_url = model()->GetTemplateURLForKeyword(new_keyword);
582  ASSERT_TRUE(read_url);
583  AssertEquals(last_url, *read_url);
584}
585
586TEST_F(TemplateURLModelTest, DefaultSearchProvider) {
587  // Add a new TemplateURL.
588  VerifyLoad();
589  const size_t initial_count = model()->GetTemplateURLs().size();
590  TemplateURL* t_url = AddKeywordWithDate(L"key1", false, "http://foo1",
591      "http://sugg1", "http://icon1", "UTF-8;UTF-16", L"name1", true, Time());
592
593  test_util_.ResetObserverCount();
594  model()->SetDefaultSearchProvider(t_url);
595
596  ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());
597
598  ASSERT_TRUE(t_url->safe_for_autoreplace());
599  ASSERT_TRUE(t_url->show_in_default_list());
600
601  // Setting the default search provider should have caused notification.
602  VerifyObserverCount(1);
603
604  BlockTillServiceProcessesRequests();
605
606  TemplateURL cloned_url = *t_url;
607
608  ResetModel(true);
609  t_url = NULL;
610
611  // Make sure when we reload we get a default search provider.
612  EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
613  ASSERT_TRUE(model()->GetDefaultSearchProvider());
614  AssertEquals(cloned_url, *model()->GetDefaultSearchProvider());
615}
616
617TEST_F(TemplateURLModelTest, TemplateURLWithNoKeyword) {
618  VerifyLoad();
619
620  const size_t initial_count = model()->GetTemplateURLs().size();
621
622  AddKeywordWithDate(std::wstring(), false, "http://foo1", "http://sugg1",
623      "http://icon1", "UTF-8;UTF-16", L"name1", true, Time());
624
625  // We just added a few items, validate them.
626  ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
627
628  // Reload the model from the database and make sure we get the url back.
629  ResetModel(true);
630
631  ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
632
633  bool found_keyword = false;
634  for (size_t i = 0; i < initial_count + 1; ++i) {
635    if (model()->GetTemplateURLs()[i]->keyword().empty()) {
636      found_keyword = true;
637      break;
638    }
639  }
640  ASSERT_TRUE(found_keyword);
641}
642
643TEST_F(TemplateURLModelTest, CantReplaceWithSameKeyword) {
644  ChangeModelToLoadState();
645  ASSERT_TRUE(model()->CanReplaceKeyword(L"foo", GURL(), NULL));
646  TemplateURL* t_url = AddKeywordWithDate(L"foo", false, "http://foo1",
647      "http://sugg1", "http://icon1", "UTF-8;UTF-16",  L"name1", true, Time());
648
649  // Can still replace, newly added template url is marked safe to replace.
650  ASSERT_TRUE(model()->CanReplaceKeyword(L"foo", GURL("http://foo2"), NULL));
651
652  // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
653  // no longer be replaceable.
654  model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
655                           t_url->url()->url());
656
657  ASSERT_FALSE(model()->CanReplaceKeyword(L"foo", GURL("http://foo2"), NULL));
658}
659
660TEST_F(TemplateURLModelTest, CantReplaceWithSameHosts) {
661  ChangeModelToLoadState();
662  ASSERT_TRUE(model()->CanReplaceKeyword(L"foo", GURL("http://foo.com"), NULL));
663  TemplateURL* t_url = AddKeywordWithDate(L"foo", false, "http://foo.com",
664      "http://sugg1", "http://icon1", "UTF-8;UTF-16",  L"name1", true, Time());
665
666  // Can still replace, newly added template url is marked safe to replace.
667  ASSERT_TRUE(model()->CanReplaceKeyword(L"bar", GURL("http://foo.com"), NULL));
668
669  // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
670  // no longer be replaceable.
671  model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
672                           t_url->url()->url());
673
674  ASSERT_FALSE(model()->CanReplaceKeyword(L"bar",
675                                          GURL("http://foo.com"), NULL));
676}
677
678TEST_F(TemplateURLModelTest, HasDefaultSearchProvider) {
679  // We should have a default search provider even if we haven't loaded.
680  ASSERT_TRUE(model()->GetDefaultSearchProvider());
681
682  // Now force the model to load and make sure we still have a default.
683  VerifyLoad();
684
685  ASSERT_TRUE(model()->GetDefaultSearchProvider());
686}
687
688TEST_F(TemplateURLModelTest, DefaultSearchProviderLoadedFromPrefs) {
689  VerifyLoad();
690
691  TemplateURL* template_url = new TemplateURL();
692  template_url->SetURL("http://url", 0, 0);
693  template_url->SetSuggestionsURL("http://url2", 0, 0);
694  template_url->SetInstantURL("http://instant", 0, 0);
695  template_url->set_short_name(L"a");
696  template_url->set_safe_for_autoreplace(true);
697  template_url->set_date_created(Time::FromTimeT(100));
698
699  model()->Add(template_url);
700
701  const TemplateURLID id = template_url->id();
702
703  model()->SetDefaultSearchProvider(template_url);
704
705  BlockTillServiceProcessesRequests();
706
707  TemplateURL first_default_search_provider = *template_url;
708
709  template_url = NULL;
710
711  // Reset the model and don't load it. The template url we set as the default
712  // should be pulled from prefs now.
713  ResetModel(false);
714
715  // NOTE: This doesn't use AssertEquals as only a subset of the TemplateURLs
716  // value are persisted to prefs.
717  const TemplateURL* default_turl = model()->GetDefaultSearchProvider();
718  ASSERT_TRUE(default_turl);
719  ASSERT_TRUE(default_turl->url());
720  ASSERT_EQ("http://url", default_turl->url()->url());
721  ASSERT_TRUE(default_turl->suggestions_url());
722  ASSERT_EQ("http://url2", default_turl->suggestions_url()->url());
723  ASSERT_TRUE(default_turl->instant_url());
724  EXPECT_EQ("http://instant", default_turl->instant_url()->url());
725  ASSERT_EQ(L"a", default_turl->short_name());
726  ASSERT_EQ(id, default_turl->id());
727
728  // Now do a load and make sure the default search provider really takes.
729  VerifyLoad();
730
731  ASSERT_TRUE(model()->GetDefaultSearchProvider());
732  AssertEquals(first_default_search_provider,
733               *model()->GetDefaultSearchProvider());
734}
735
736TEST_F(TemplateURLModelTest, BuildQueryTerms) {
737  struct TestData {
738    const std::string url;
739    const bool result;
740    // Keys and values are a semicolon separated list of expected values in the
741    // map.
742    const std::string keys;
743    const std::string values;
744  } data[] = {
745    // No query should return false.
746    { "http://blah/", false, "", "" },
747
748    // Query with empty key should return false.
749    { "http://blah/foo?=y", false, "", "" },
750
751    // Query with key occurring multiple times should return false.
752    { "http://blah/foo?x=y&x=z", false, "", "" },
753
754    { "http://blah/foo?x=y", true, "x", "y" },
755    { "http://blah/foo?x=y&y=z", true, "x;y", "y;z" },
756
757    // Key occurring multiple times should get an empty string.
758    { "http://blah/foo?x=y&x=z&y=z", true, "x;y", ";z" },
759  };
760
761  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
762    TemplateURLModel::QueryTerms terms;
763    ASSERT_EQ(data[i].result,
764              TemplateURLModel::BuildQueryTerms(GURL(data[i].url), &terms));
765    if (data[i].result) {
766      std::vector<std::string> keys;
767      std::vector<std::string> values;
768      base::SplitString(data[i].keys, ';', &keys);
769      base::SplitString(data[i].values, ';', &values);
770      ASSERT_TRUE(keys.size() == values.size());
771      ASSERT_EQ(keys.size(), terms.size());
772      for (size_t j = 0; j < keys.size(); ++j) {
773        TemplateURLModel::QueryTerms::iterator term_iterator =
774            terms.find(keys[j]);
775        ASSERT_TRUE(term_iterator != terms.end());
776        ASSERT_EQ(values[j], term_iterator->second);
777      }
778    }
779  }
780}
781
782TEST_F(TemplateURLModelTest, UpdateKeywordSearchTermsForURL) {
783  struct TestData {
784    const std::string url;
785    const std::wstring term;
786  } data[] = {
787    { "http://foo/", L"" },
788    { "http://foo/foo?q=xx", L"" },
789    { "http://x/bar?q=xx", L"" },
790    { "http://x/foo?y=xx", L"" },
791    { "http://x/foo?q=xx", L"xx" },
792    { "http://x/foo?a=b&q=xx", L"xx" },
793    { "http://x/foo?q=b&q=xx", L"" },
794  };
795
796  ChangeModelToLoadState();
797  AddKeywordWithDate(L"x", false, "http://x/foo?q={searchTerms}",
798      "http://sugg1", "http://icon1", "UTF-8;UTF-16", L"name", false, Time());
799
800  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
801    history::URLVisitedDetails details;
802    details.row = history::URLRow(GURL(data[i].url));
803    details.transition = 0;
804    model()->UpdateKeywordSearchTermsForURL(details);
805    EXPECT_EQ(data[i].term, GetAndClearSearchTerm());
806  }
807}
808
809TEST_F(TemplateURLModelTest, DontUpdateKeywordSearchForNonReplaceable) {
810  struct TestData {
811    const std::string url;
812  } data[] = {
813    { "http://foo/" },
814    { "http://x/bar?q=xx" },
815    { "http://x/foo?y=xx" },
816  };
817
818  ChangeModelToLoadState();
819  AddKeywordWithDate(L"x", false, "http://x/foo", "http://sugg1",
820      "http://icon1", "UTF-8;UTF-16", L"name", false, Time());
821
822  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
823    history::URLVisitedDetails details;
824    details.row = history::URLRow(GURL(data[i].url));
825    details.transition = 0;
826    model()->UpdateKeywordSearchTermsForURL(details);
827    ASSERT_EQ(std::wstring(), GetAndClearSearchTerm());
828  }
829}
830
831TEST_F(TemplateURLModelTest, ChangeGoogleBaseValue) {
832  // NOTE: Do not do a VerifyLoad() here as it will load the prepopulate data,
833  // which also has a {google:baseURL} keyword in it, which will confuse this
834  // test.
835  ChangeModelToLoadState();
836  SetGoogleBaseURL("http://google.com/");
837  const TemplateURL* t_url = AddKeywordWithDate(std::wstring(), true,
838      "{google:baseURL}?q={searchTerms}", "http://sugg1", "http://icon1",
839      "UTF-8;UTF-16", L"name", false, Time());
840  ASSERT_EQ(t_url, model()->GetTemplateURLForHost("google.com"));
841  EXPECT_EQ("google.com", t_url->url()->GetHost());
842  EXPECT_EQ(L"google.com", t_url->keyword());
843
844  // Change the Google base url.
845  test_util_.ResetObserverCount();
846  SetGoogleBaseURL("http://foo.com/");
847  VerifyObserverCount(1);
848
849  // Make sure the host->TemplateURL map was updated appropriately.
850  ASSERT_EQ(t_url, model()->GetTemplateURLForHost("foo.com"));
851  EXPECT_TRUE(model()->GetTemplateURLForHost("google.com") == NULL);
852  EXPECT_EQ("foo.com", t_url->url()->GetHost());
853  EXPECT_EQ(L"foo.com", t_url->keyword());
854  EXPECT_EQ("http://foo.com/?q=x", t_url->url()->ReplaceSearchTerms(*t_url,
855      L"x", TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()));
856}
857
858struct QueryHistoryCallbackImpl {
859  QueryHistoryCallbackImpl() : success(false) {}
860
861  void Callback(HistoryService::Handle handle,
862                bool success, const history::URLRow* row,
863                history::VisitVector* visits) {
864    this->success = success;
865    if (row)
866      this->row = *row;
867    if (visits)
868      this->visits = *visits;
869  }
870
871  bool success;
872  history::URLRow row;
873  history::VisitVector visits;
874};
875
876// Make sure TemplateURLModel generates a KEYWORD_GENERATED visit for
877// KEYWORD visits.
878TEST_F(TemplateURLModelTest, GenerateVisitOnKeyword) {
879  VerifyLoad();
880  profile()->CreateHistoryService(true, false);
881
882  // Create a keyword.
883  TemplateURL* t_url = AddKeywordWithDate(
884      L"keyword", false, "http://foo.com/foo?query={searchTerms}",
885      "http://sugg1", "http://icon1", "UTF-8;UTF-16", L"keyword", true,
886      base::Time::Now());
887
888  // Add a visit that matches the url of the keyword.
889  HistoryService* history =
890      profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
891  history->AddPage(
892      GURL(t_url->url()->ReplaceSearchTerms(*t_url, L"blah", 0,
893                                            std::wstring())),
894      NULL, 0, GURL(), PageTransition::KEYWORD, history::RedirectList(),
895      history::SOURCE_BROWSED, false);
896
897  // Wait for history to finish processing the request.
898  profile()->BlockUntilHistoryProcessesPendingRequests();
899
900  // Query history for the generated url.
901  CancelableRequestConsumer consumer;
902  QueryHistoryCallbackImpl callback;
903  history->QueryURL(GURL("http://keyword"), true, &consumer,
904      NewCallback(&callback, &QueryHistoryCallbackImpl::Callback));
905
906  // Wait for the request to be processed.
907  profile()->BlockUntilHistoryProcessesPendingRequests();
908
909  // And make sure the url and visit were added.
910  EXPECT_TRUE(callback.success);
911  EXPECT_NE(0, callback.row.id());
912  ASSERT_EQ(1U, callback.visits.size());
913  EXPECT_EQ(PageTransition::KEYWORD_GENERATED,
914            PageTransition::StripQualifier(callback.visits[0].transition));
915}
916
917// Make sure that the load routine deletes prepopulated engines that no longer
918// exist in the prepopulate data.
919TEST_F(TemplateURLModelTest, LoadDeletesUnusedProvider) {
920  // Create a preloaded template url. Add it to a loaded model and wait for the
921  // saves to finish.
922  TemplateURL* t_url = CreatePreloadedTemplateURL();
923  ChangeModelToLoadState();
924  model()->Add(t_url);
925  ASSERT_TRUE(model()->GetTemplateURLForKeyword(L"unittest") != NULL);
926  BlockTillServiceProcessesRequests();
927
928  // Ensure that merging clears this engine.
929  ResetModel(true);
930  ASSERT_TRUE(model()->GetTemplateURLForKeyword(L"unittest") == NULL);
931
932  // Wait for any saves to finish.
933  BlockTillServiceProcessesRequests();
934
935  // Reload the model to verify that the database was updated as a result of the
936  // merge.
937  ResetModel(true);
938  ASSERT_TRUE(model()->GetTemplateURLForKeyword(L"unittest") == NULL);
939}
940
941// Make sure that load routine doesn't delete prepopulated engines that no
942// longer exist in the prepopulate data if it has been modified by the user.
943TEST_F(TemplateURLModelTest, LoadRetainsModifiedProvider) {
944  // Create a preloaded template url and add it to a loaded model.
945  TemplateURL* t_url = CreatePreloadedTemplateURL();
946  t_url->set_safe_for_autoreplace(false);
947  ChangeModelToLoadState();
948  model()->Add(t_url);
949
950  // Do the copy after t_url is added so that the id is set.
951  TemplateURL copy_t_url = *t_url;
952  ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(L"unittest"));
953
954  // Wait for any saves to finish.
955  BlockTillServiceProcessesRequests();
956
957  // Ensure that merging won't clear it if the user has edited it.
958  ResetModel(true);
959  const TemplateURL* url_for_unittest =
960      model()->GetTemplateURLForKeyword(L"unittest");
961  ASSERT_TRUE(url_for_unittest != NULL);
962  AssertEquals(copy_t_url, *url_for_unittest);
963
964  // Wait for any saves to finish.
965  BlockTillServiceProcessesRequests();
966
967  // Reload the model to verify that save/reload retains the item.
968  ResetModel(true);
969  ASSERT_TRUE(model()->GetTemplateURLForKeyword(L"unittest") != NULL);
970}
971
972// Make sure that load routine doesn't delete
973// prepopulated engines that no longer exist in the prepopulate data if
974// it has been modified by the user.
975TEST_F(TemplateURLModelTest, LoadSavesPrepopulatedDefaultSearchProvider) {
976  VerifyLoad();
977  // Verify that the default search provider is set to something.
978  ASSERT_TRUE(model()->GetDefaultSearchProvider() != NULL);
979  TemplateURL default_url = *model()->GetDefaultSearchProvider();
980
981  // Wait for any saves to finish.
982  BlockTillServiceProcessesRequests();
983
984  // Reload the model and check that the default search provider
985  // was properly saved.
986  ResetModel(true);
987  ASSERT_TRUE(model()->GetDefaultSearchProvider() != NULL);
988  AssertEquals(default_url, *model()->GetDefaultSearchProvider());
989}
990
991// Make sure that the load routine doesn't delete
992// prepopulated engines that no longer exist in the prepopulate data if
993// it is the default search provider.
994TEST_F(TemplateURLModelTest, LoadRetainsDefaultProvider) {
995  // Set the default search provider to a preloaded template url which
996  // is not in the current set of preloaded template urls and save
997  // the result.
998  TemplateURL* t_url = CreatePreloadedTemplateURL();
999  ChangeModelToLoadState();
1000  model()->Add(t_url);
1001  model()->SetDefaultSearchProvider(t_url);
1002  // Do the copy after t_url is added and set as default so that its
1003  // internal state is correct.
1004  TemplateURL copy_t_url = *t_url;
1005
1006  ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(L"unittest"));
1007  ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());
1008  BlockTillServiceProcessesRequests();
1009
1010  // Ensure that merging won't clear the prepopulated template url
1011  // which is no longer present if it's the default engine.
1012  ResetModel(true);
1013  {
1014    const TemplateURL* keyword_url =
1015        model()->GetTemplateURLForKeyword(L"unittest");
1016    ASSERT_TRUE(keyword_url != NULL);
1017    AssertEquals(copy_t_url, *keyword_url);
1018    ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
1019  }
1020
1021  // Wait for any saves to finish.
1022  BlockTillServiceProcessesRequests();
1023
1024  // Reload the model to verify that the update was saved.
1025  ResetModel(true);
1026  {
1027    const TemplateURL* keyword_url =
1028        model()->GetTemplateURLForKeyword(L"unittest");
1029    ASSERT_TRUE(keyword_url != NULL);
1030    AssertEquals(copy_t_url, *keyword_url);
1031    ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
1032  }
1033}
1034
1035// Make sure that the load routine updates the url of a preexisting
1036// default search engine provider and that the result is saved correctly.
1037TEST_F(TemplateURLModelTest, LoadUpdatesDefaultSearchURL) {
1038  TestLoadUpdatingPreloadedURL(0);
1039}
1040
1041// Make sure that the load routine updates the url of a preexisting
1042// non-default search engine provider and that the result is saved correctly.
1043TEST_F(TemplateURLModelTest, LoadUpdatesSearchURL) {
1044  TestLoadUpdatingPreloadedURL(1);
1045}
1046
1047// Make sure that the load does update of auto-keywords correctly.
1048// This test basically verifies that no asserts or crashes occur
1049// during this operation.
1050TEST_F(TemplateURLModelTest, LoadDoesAutoKeywordUpdate) {
1051  std::wstring prepopulated_url;
1052  TemplateURL* t_url = CreateReplaceablePreloadedTemplateURL(
1053      0, &prepopulated_url);
1054  t_url->set_safe_for_autoreplace(false);
1055  t_url->SetURL("{google:baseURL}?q={searchTerms}", 0, 0);
1056  t_url->set_autogenerate_keyword(true);
1057
1058  // Then add it to the model and save it all.
1059  ChangeModelToLoadState();
1060  model()->Add(t_url);
1061  BlockTillServiceProcessesRequests();
1062
1063  // Now reload the model and verify that the merge updates the url.
1064  ResetModel(true);
1065
1066  // Wait for any saves to finish.
1067  BlockTillServiceProcessesRequests();
1068}
1069
1070// Simulates failing to load the webdb and makes sure the default search
1071// provider is valid.
1072TEST_F(TemplateURLModelTest, FailedInit) {
1073  VerifyLoad();
1074
1075  test_util_.ClearModel();
1076  test_util_.GetWebDataService()->UnloadDatabase();
1077  test_util_.GetWebDataService()->set_failed_init(true);
1078
1079  ResetModel(false);
1080  model()->Load();
1081  BlockTillServiceProcessesRequests();
1082
1083  ASSERT_TRUE(model()->GetDefaultSearchProvider());
1084}
1085
1086// Verifies that if the default search URL preference is managed, we report
1087// the default search as managed.  Also check that we are getting the right
1088// values.
1089TEST_F(TemplateURLModelTest, TestManagedDefaultSearch) {
1090  VerifyLoad();
1091  const size_t initial_count = model()->GetTemplateURLs().size();
1092  test_util_.ResetObserverCount();
1093
1094  // Set a regular default search provider.
1095  TemplateURL* regular_default = AddKeywordWithDate(L"key1", false,
1096      "http://foo1", "http://sugg1", "http://icon1", "UTF-8;UTF-16", L"name1",
1097      true, Time());
1098  VerifyObserverCount(1);
1099  model()->SetDefaultSearchProvider(regular_default);
1100  // Adding the URL and setting the default search provider should have caused
1101  // notifications.
1102  VerifyObserverCount(1);
1103  EXPECT_FALSE(model()->is_default_search_managed());
1104  EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
1105
1106  // Set a managed preference that establishes a default search provider.
1107  const char kName[] = "test1";
1108  const char kSearchURL[] = "http://test.com/search?t={searchTerms}";
1109  const char kIconURL[] = "http://test.com/icon.jpg";
1110  const char kEncodings[] = "UTF-16;UTF-32";
1111  SetManagedDefaultSearchPreferences(true, kName, kSearchURL, "", kIconURL,
1112                                     kEncodings, "");
1113  VerifyObserverFired();
1114  EXPECT_TRUE(model()->is_default_search_managed());
1115  EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());
1116
1117  // Verify that the default manager we are getting is the managed one.
1118  scoped_ptr<TemplateURL> expected_managed_default1(new TemplateURL());
1119  expected_managed_default1->SetURL(kSearchURL, 0, 0);
1120  expected_managed_default1->SetFavIconURL(GURL(kIconURL));
1121  expected_managed_default1->set_short_name(L"test1");
1122  std::vector<std::string> encodings_vector;
1123  base::SplitString(kEncodings, ';', &encodings_vector);
1124  expected_managed_default1->set_input_encodings(encodings_vector);
1125  expected_managed_default1->set_show_in_default_list(true);
1126  const TemplateURL* actual_managed_default =
1127      model()->GetDefaultSearchProvider();
1128  ExpectSimilar(actual_managed_default, expected_managed_default1.get());
1129  EXPECT_EQ(actual_managed_default->show_in_default_list(), true);
1130
1131  // Update the managed preference and check that the model has changed.
1132  const char kNewName[] = "test2";
1133  const char kNewSearchURL[] = "http://other.com/search?t={searchTerms}";
1134  const char kNewSuggestURL[] = "http://other.com/suggest?t={searchTerms}";
1135  SetManagedDefaultSearchPreferences(true, kNewName, kNewSearchURL,
1136                                     kNewSuggestURL, "", "", "");
1137  VerifyObserverFired();
1138  EXPECT_TRUE(model()->is_default_search_managed());
1139  EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());
1140
1141  // Verify that the default manager we are now getting is the correct one.
1142  scoped_ptr<TemplateURL> expected_managed_default2(new TemplateURL());
1143  expected_managed_default2->SetURL(kNewSearchURL, 0, 0);
1144  expected_managed_default2->SetSuggestionsURL(kNewSuggestURL, 0, 0);
1145  expected_managed_default2->set_short_name(L"test2");
1146  expected_managed_default2->set_show_in_default_list(true);
1147  actual_managed_default = model()->GetDefaultSearchProvider();
1148  ExpectSimilar(actual_managed_default, expected_managed_default2.get());
1149  EXPECT_EQ(actual_managed_default->show_in_default_list(), true);
1150
1151  // Remove all the managed prefs and check that we are no longer managed.
1152  RemoveManagedDefaultSearchPreferences();
1153  VerifyObserverFired();
1154  EXPECT_FALSE(model()->is_default_search_managed());
1155  EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
1156
1157  // The default should now be the first URL added
1158  const TemplateURL* actual_final_managed_default =
1159      model()->GetDefaultSearchProvider();
1160  ExpectSimilar(actual_final_managed_default,
1161      model()->GetTemplateURLs()[0]);
1162  EXPECT_EQ(actual_final_managed_default->show_in_default_list(), true);
1163
1164  // Disable the default search provider through policy.
1165  SetManagedDefaultSearchPreferences(false, "", "", "", "", "", "");
1166  VerifyObserverFired();
1167  EXPECT_TRUE(model()->is_default_search_managed());
1168  EXPECT_TRUE(NULL == model()->GetDefaultSearchProvider());
1169  EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
1170
1171  // Re-enable it.
1172  SetManagedDefaultSearchPreferences(true, kName, kSearchURL, "", kIconURL,
1173                                     kEncodings, "");
1174  VerifyObserverFired();
1175  EXPECT_TRUE(model()->is_default_search_managed());
1176  EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());
1177
1178  // Verify that the default manager we are getting is the managed one.
1179  actual_managed_default = model()->GetDefaultSearchProvider();
1180  ExpectSimilar(actual_managed_default, expected_managed_default1.get());
1181  EXPECT_EQ(actual_managed_default->show_in_default_list(), true);
1182}
1183