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