5338d9762f1098e1ad8807e396e5b828a93f6cb2
[platform/framework/web/crosswalk.git] / src / chrome / browser / search_engines / template_url_service_unittest.cc
1 // Copyright (c) 2012 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/bind.h"
6 #include "base/bind_helpers.h"
7 #include "base/callback.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/test/mock_time_provider.h"
15 #include "base/threading/thread.h"
16 #include "base/time/time.h"
17 #include "chrome/browser/extensions/extension_service_unittest.h"
18 #include "chrome/browser/history/history_notifications.h"
19 #include "chrome/browser/history/history_service.h"
20 #include "chrome/browser/history/history_service_factory.h"
21 #include "chrome/browser/search_engines/search_host_to_urls_map.h"
22 #include "chrome/browser/search_engines/search_terms_data.h"
23 #include "chrome/browser/search_engines/template_url.h"
24 #include "chrome/browser/search_engines/template_url_prepopulate_data.h"
25 #include "chrome/browser/search_engines/template_url_service.h"
26 #include "chrome/browser/search_engines/template_url_service_test_util.h"
27 #include "chrome/browser/webdata/web_data_service_factory.h"
28 #include "chrome/common/url_constants.h"
29 #include "chrome/test/base/testing_profile.h"
30 #include "components/webdata/common/web_database.h"
31 #include "content/public/test/test_browser_thread.h"
32 #include "extensions/common/constants.h"
33 #include "extensions/common/extension.h"
34 #include "extensions/common/manifest_constants.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36
37 using base::ASCIIToUTF16;
38 using base::Time;
39 using base::TimeDelta;
40 using content::BrowserThread;
41 using ::testing::Return;
42 using ::testing::StrictMock;
43
44 namespace {
45
46 // TestSearchTermsData --------------------------------------------------------
47
48 // Simple implementation of SearchTermsData.
49 class TestSearchTermsData : public SearchTermsData {
50  public:
51   explicit TestSearchTermsData(const char* google_base_url);
52
53   virtual std::string GoogleBaseURLValue() const OVERRIDE;
54
55  private:
56   std::string google_base_url_;
57
58   DISALLOW_COPY_AND_ASSIGN(TestSearchTermsData);
59 };
60
61 TestSearchTermsData::TestSearchTermsData(const char* google_base_url)
62     : google_base_url_(google_base_url)  {
63 }
64
65 std::string TestSearchTermsData::GoogleBaseURLValue() const {
66   return google_base_url_;
67 }
68
69
70 // QueryHistoryCallbackImpl ---------------------------------------------------
71
72 struct QueryHistoryCallbackImpl {
73   QueryHistoryCallbackImpl() : success(false) {}
74
75   void Callback(HistoryService::Handle handle,
76                 bool success,
77                 const history::URLRow* row,
78                 history::VisitVector* visits) {
79     this->success = success;
80     if (row)
81       this->row = *row;
82     if (visits)
83       this->visits = *visits;
84   }
85
86   bool success;
87   history::URLRow row;
88   history::VisitVector visits;
89 };
90
91 TemplateURL* CreateKeywordWithDate(
92     TemplateURLService* model,
93     const std::string& short_name,
94     const std::string& keyword,
95     const std::string& url,
96     const std::string& suggest_url,
97     const std::string& alternate_url,
98     const std::string& favicon_url,
99     bool safe_for_autoreplace,
100     const std::string& encodings,
101     Time date_created,
102     Time last_modified) {
103   TemplateURLData data;
104   data.short_name = base::UTF8ToUTF16(short_name);
105   data.SetKeyword(base::UTF8ToUTF16(keyword));
106   data.SetURL(url);
107   data.suggestions_url = suggest_url;
108   if (!alternate_url.empty())
109     data.alternate_urls.push_back(alternate_url);
110   data.favicon_url = GURL(favicon_url);
111   data.safe_for_autoreplace = safe_for_autoreplace;
112   base::SplitString(encodings, ';', &data.input_encodings);
113   data.date_created = date_created;
114   data.last_modified = last_modified;
115   return new TemplateURL(model->profile(), data);
116 }
117
118 TemplateURL* AddKeywordWithDate(
119     TemplateURLService* model,
120     const std::string& short_name,
121     const std::string& keyword,
122     const std::string& url,
123     const std::string& suggest_url,
124     const std::string& alternate_url,
125     const std::string& favicon_url,
126     bool safe_for_autoreplace,
127     const std::string& encodings,
128     Time date_created,
129     Time last_modified) {
130   TemplateURL* t_url = CreateKeywordWithDate(
131       model, short_name, keyword, url, suggest_url, alternate_url,favicon_url,
132       safe_for_autoreplace, encodings, date_created, last_modified);
133   model->Add(t_url);
134   EXPECT_NE(0, t_url->id());
135   return t_url;
136 }
137
138 // Checks that the two TemplateURLs are similar. It does not check the id, the
139 // date_created or the last_modified time.  Neither pointer should be NULL.
140 void ExpectSimilar(const TemplateURL* expected, const TemplateURL* actual) {
141   ASSERT_TRUE(expected != NULL);
142   ASSERT_TRUE(actual != NULL);
143   EXPECT_EQ(expected->short_name(), actual->short_name());
144   EXPECT_EQ(expected->keyword(), actual->keyword());
145   EXPECT_EQ(expected->url(), actual->url());
146   EXPECT_EQ(expected->suggestions_url(), actual->suggestions_url());
147   EXPECT_EQ(expected->favicon_url(), actual->favicon_url());
148   EXPECT_EQ(expected->alternate_urls(), actual->alternate_urls());
149   EXPECT_EQ(expected->show_in_default_list(), actual->show_in_default_list());
150   EXPECT_EQ(expected->safe_for_autoreplace(), actual->safe_for_autoreplace());
151   EXPECT_EQ(expected->input_encodings(), actual->input_encodings());
152   EXPECT_EQ(expected->search_terms_replacement_key(),
153             actual->search_terms_replacement_key());
154 }
155
156 }  // namespace
157
158
159 // TemplateURLServiceTest -----------------------------------------------------
160
161 class TemplateURLServiceTest : public testing::Test {
162  public:
163   TemplateURLServiceTest();
164
165   // testing::Test
166   virtual void SetUp();
167   virtual void TearDown();
168
169   TemplateURL* AddKeywordWithDate(const std::string& short_name,
170                                   const std::string& keyword,
171                                   const std::string& url,
172                                   const std::string& suggest_url,
173                                   const std::string& alternate_url,
174                                   const std::string& favicon_url,
175                                   bool safe_for_autoreplace,
176                                   const std::string& encodings,
177                                   Time date_created,
178                                   Time last_modified);
179
180   // Verifies the two TemplateURLs are equal.
181   void AssertEquals(const TemplateURL& expected, const TemplateURL& actual);
182
183   // Create an URL that appears to have been prepopulated, but won't be in the
184   // current data. The caller owns the returned TemplateURL*.
185   TemplateURL* CreatePreloadedTemplateURL(bool safe_for_autoreplace,
186                                           int prepopulate_id);
187
188   // Creates a TemplateURL with the same prepopulated id as a real prepopulated
189   // item. The input number determines which prepopulated item. The caller is
190   // responsible for owning the returned TemplateURL*.
191   TemplateURL* CreateReplaceablePreloadedTemplateURL(
192       bool safe_for_autoreplace,
193       size_t index_offset_from_default,
194       base::string16* prepopulated_display_url);
195
196   // Verifies the behavior of when a preloaded url later gets changed.
197   // Since the input is the offset from the default, when one passes in
198   // 0, it tests the default. Passing in a number > 0 will verify what
199   // happens when a preloaded url that is not the default gets updated.
200   void TestLoadUpdatingPreloadedURL(size_t index_offset_from_default);
201
202   // Helper methods to make calling TemplateURLServiceTestUtil methods less
203   // visually noisy in the test code.
204   void VerifyObserverCount(int expected_changed_count);
205   void VerifyObserverFired();
206   TemplateURLService* model() { return test_util_.model(); }
207
208  protected:
209   TemplateURLServiceTestUtil test_util_;
210
211   void TestGenerateSearchURL(SearchTermsData* search_terms_data) {
212     struct GenerateSearchURLCase {
213       const char* test_name;
214       const char* url;
215       const char* expected;
216     } generate_url_cases[] = {
217       { "invalid URL", "foo{searchTerms}", "" },
218       { "URL with no replacements", "http://foo/", "http://foo/" },
219       { "basic functionality", "http://foo/{searchTerms}",
220         "http://foo/blah.blah.blah.blah.blah" }
221     };
222
223     for (size_t i = 0; i < ARRAYSIZE_UNSAFE(generate_url_cases); ++i) {
224       TemplateURLData data;
225       data.SetURL(generate_url_cases[i].url);
226       TemplateURL t_url(NULL, data);
227       std::string result;
228       if (search_terms_data) {
229           result = TemplateURLService::GenerateSearchURLUsingTermsData(
230               &t_url, *search_terms_data).spec();
231       } else {
232           result = TemplateURLService::GenerateSearchURL(&t_url).spec();
233       }
234       EXPECT_EQ(result,  generate_url_cases[i].expected)
235           << generate_url_cases[i].test_name << " failed. Expected "
236           << generate_url_cases[i].expected << " Actual " << result;
237     }
238   }
239
240
241   DISALLOW_COPY_AND_ASSIGN(TemplateURLServiceTest);
242 };
243
244 TemplateURLServiceTest::TemplateURLServiceTest() {
245 }
246
247 void TemplateURLServiceTest::SetUp() {
248   test_util_.SetUp();
249 }
250
251 void TemplateURLServiceTest::TearDown() {
252   test_util_.TearDown();
253 }
254
255 TemplateURL* TemplateURLServiceTest::AddKeywordWithDate(
256     const std::string& short_name,
257     const std::string& keyword,
258     const std::string& url,
259     const std::string& suggest_url,
260     const std::string& alternate_url,
261     const std::string& favicon_url,
262     bool safe_for_autoreplace,
263     const std::string& encodings,
264     Time date_created,
265     Time last_modified) {
266   return ::AddKeywordWithDate(model(), short_name, keyword, url, suggest_url,
267                               alternate_url, favicon_url, safe_for_autoreplace,
268                               encodings, date_created, last_modified);
269 }
270
271 void TemplateURLServiceTest::AssertEquals(const TemplateURL& expected,
272                                           const TemplateURL& actual) {
273   ASSERT_EQ(expected.short_name(), actual.short_name());
274   ASSERT_EQ(expected.keyword(), actual.keyword());
275   ASSERT_EQ(expected.url(), actual.url());
276   ASSERT_EQ(expected.suggestions_url(), actual.suggestions_url());
277   ASSERT_EQ(expected.favicon_url(), actual.favicon_url());
278   ASSERT_EQ(expected.alternate_urls(), actual.alternate_urls());
279   ASSERT_EQ(expected.show_in_default_list(), actual.show_in_default_list());
280   ASSERT_EQ(expected.safe_for_autoreplace(), actual.safe_for_autoreplace());
281   ASSERT_EQ(expected.input_encodings(), actual.input_encodings());
282   ASSERT_EQ(expected.id(), actual.id());
283   ASSERT_EQ(expected.date_created(), actual.date_created());
284   ASSERT_EQ(expected.last_modified(), actual.last_modified());
285   ASSERT_EQ(expected.sync_guid(), actual.sync_guid());
286   ASSERT_EQ(expected.search_terms_replacement_key(),
287             actual.search_terms_replacement_key());
288 }
289
290 TemplateURL* TemplateURLServiceTest::CreatePreloadedTemplateURL(
291     bool safe_for_autoreplace,
292     int prepopulate_id) {
293   TemplateURLData data;
294   data.short_name = ASCIIToUTF16("unittest");
295   data.SetKeyword(ASCIIToUTF16("unittest"));
296   data.SetURL("http://www.unittest.com/{searchTerms}");
297   data.favicon_url = GURL("http://favicon.url");
298   data.show_in_default_list = true;
299   data.safe_for_autoreplace = safe_for_autoreplace;
300   data.input_encodings.push_back("UTF-8");
301   data.date_created = Time::FromTimeT(100);
302   data.last_modified = Time::FromTimeT(100);
303   data.prepopulate_id = prepopulate_id;
304   return new TemplateURL(test_util_.profile(), data);
305 }
306
307 TemplateURL* TemplateURLServiceTest::CreateReplaceablePreloadedTemplateURL(
308     bool safe_for_autoreplace,
309     size_t index_offset_from_default,
310     base::string16* prepopulated_display_url) {
311   size_t default_search_provider_index = 0;
312   ScopedVector<TemplateURL> prepopulated_urls =
313       TemplateURLPrepopulateData::GetPrepopulatedEngines(
314           test_util_.profile(), &default_search_provider_index);
315   EXPECT_LT(index_offset_from_default, prepopulated_urls.size());
316   size_t prepopulated_index = (default_search_provider_index +
317       index_offset_from_default) % prepopulated_urls.size();
318   TemplateURL* t_url = CreatePreloadedTemplateURL(safe_for_autoreplace,
319       prepopulated_urls[prepopulated_index]->prepopulate_id());
320   *prepopulated_display_url =
321       prepopulated_urls[prepopulated_index]->url_ref().DisplayURL();
322   return t_url;
323 }
324
325 void TemplateURLServiceTest::TestLoadUpdatingPreloadedURL(
326     size_t index_offset_from_default) {
327   base::string16 prepopulated_url;
328   TemplateURL* t_url = CreateReplaceablePreloadedTemplateURL(false,
329       index_offset_from_default, &prepopulated_url);
330
331   base::string16 original_url = t_url->url_ref().DisplayURL();
332   std::string original_guid = t_url->sync_guid();
333   EXPECT_NE(prepopulated_url, original_url);
334
335   // Then add it to the model and save it all.
336   test_util_.ChangeModelToLoadState();
337   model()->Add(t_url);
338   const TemplateURL* keyword_url =
339       model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
340   ASSERT_TRUE(keyword_url != NULL);
341   EXPECT_EQ(t_url, keyword_url);
342   EXPECT_EQ(original_url, keyword_url->url_ref().DisplayURL());
343   base::RunLoop().RunUntilIdle();
344
345   // Now reload the model and verify that the merge updates the url, and
346   // preserves the sync GUID.
347   test_util_.ResetModel(true);
348   keyword_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
349   ASSERT_TRUE(keyword_url != NULL);
350   EXPECT_EQ(prepopulated_url, keyword_url->url_ref().DisplayURL());
351   EXPECT_EQ(original_guid, keyword_url->sync_guid());
352
353   // Wait for any saves to finish.
354   base::RunLoop().RunUntilIdle();
355
356   // Reload the model to verify that change was saved correctly.
357   test_util_.ResetModel(true);
358   keyword_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
359   ASSERT_TRUE(keyword_url != NULL);
360   EXPECT_EQ(prepopulated_url, keyword_url->url_ref().DisplayURL());
361   EXPECT_EQ(original_guid, keyword_url->sync_guid());
362 }
363
364 void TemplateURLServiceTest::VerifyObserverCount(int expected_changed_count) {
365   EXPECT_EQ(expected_changed_count, test_util_.GetObserverCount());
366   test_util_.ResetObserverCount();
367 }
368
369 void TemplateURLServiceTest::VerifyObserverFired() {
370   EXPECT_LE(1, test_util_.GetObserverCount());
371   test_util_.ResetObserverCount();
372 }
373
374
375 // Actual tests ---------------------------------------------------------------
376
377 TEST_F(TemplateURLServiceTest, Load) {
378   test_util_.VerifyLoad();
379 }
380
381 TEST_F(TemplateURLServiceTest, AddUpdateRemove) {
382   // Add a new TemplateURL.
383   test_util_.VerifyLoad();
384   const size_t initial_count = model()->GetTemplateURLs().size();
385
386   TemplateURLData data;
387   data.short_name = ASCIIToUTF16("google");
388   data.SetKeyword(ASCIIToUTF16("keyword"));
389   data.SetURL("http://www.google.com/foo/bar");
390   data.favicon_url = GURL("http://favicon.url");
391   data.safe_for_autoreplace = true;
392   data.date_created = Time::FromTimeT(100);
393   data.last_modified = Time::FromTimeT(100);
394   data.sync_guid = "00000000-0000-0000-0000-000000000001";
395   TemplateURL* t_url = new TemplateURL(test_util_.profile(), data);
396   model()->Add(t_url);
397   ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"), GURL(),
398                                          NULL));
399   VerifyObserverCount(1);
400   base::RunLoop().RunUntilIdle();
401   ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
402   ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(t_url->keyword()));
403   // We need to make a second copy as the model takes ownership of |t_url| and
404   // will delete it.  We have to do this after calling Add() since that gives
405   // |t_url| its ID.
406   scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->profile(),
407                                                      t_url->data()));
408
409   // Reload the model to verify it was actually saved to the database.
410   test_util_.ResetModel(true);
411   ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
412   TemplateURL* loaded_url =
413       model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
414   ASSERT_TRUE(loaded_url != NULL);
415   AssertEquals(*cloned_url, *loaded_url);
416   ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"), GURL(),
417                                          NULL));
418
419   // We expect the last_modified time to be updated to the present time on an
420   // explicit reset. We have to set up the expectation here because ResetModel
421   // resets the TimeProvider in the TemplateURLService.
422   StrictMock<base::MockTimeProvider> mock_time;
423   model()->set_time_provider(&base::MockTimeProvider::StaticNow);
424   EXPECT_CALL(mock_time, Now()).WillOnce(Return(base::Time::FromDoubleT(1337)));
425
426   // Mutate an element and verify it succeeded.
427   model()->ResetTemplateURL(loaded_url, ASCIIToUTF16("a"), ASCIIToUTF16("b"),
428                             "c");
429   ASSERT_EQ(ASCIIToUTF16("a"), loaded_url->short_name());
430   ASSERT_EQ(ASCIIToUTF16("b"), loaded_url->keyword());
431   ASSERT_EQ("c", loaded_url->url());
432   ASSERT_FALSE(loaded_url->safe_for_autoreplace());
433   ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"), GURL(),
434                                          NULL));
435   ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("b"), GURL(), NULL));
436   cloned_url.reset(new TemplateURL(loaded_url->profile(), loaded_url->data()));
437   base::RunLoop().RunUntilIdle();
438   test_util_.ResetModel(true);
439   ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
440   loaded_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("b"));
441   ASSERT_TRUE(loaded_url != NULL);
442   AssertEquals(*cloned_url, *loaded_url);
443   // We changed a TemplateURL in the service, so ensure that the time was
444   // updated.
445   ASSERT_EQ(base::Time::FromDoubleT(1337), loaded_url->last_modified());
446
447   // Remove an element and verify it succeeded.
448   model()->Remove(loaded_url);
449   VerifyObserverCount(1);
450   test_util_.ResetModel(true);
451   ASSERT_EQ(initial_count, model()->GetTemplateURLs().size());
452   EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("b")) == NULL);
453 }
454
455 TEST_F(TemplateURLServiceTest, AddSameKeyword) {
456   test_util_.VerifyLoad();
457
458   AddKeywordWithDate(
459       "first", "keyword", "http://test1", std::string(), std::string(),
460       std::string(), true, "UTF-8", Time(), Time());
461   VerifyObserverCount(1);
462
463   // Test what happens when we try to add a TemplateURL with the same keyword as
464   // one in the model.
465   TemplateURLData data;
466   data.short_name = ASCIIToUTF16("second");
467   data.SetKeyword(ASCIIToUTF16("keyword"));
468   data.SetURL("http://test2");
469   data.safe_for_autoreplace = false;
470   TemplateURL* t_url = new TemplateURL(test_util_.profile(), data);
471   model()->Add(t_url);
472
473   // Because the old TemplateURL was replaceable and the new one wasn't, the new
474   // one should have replaced the old.
475   VerifyObserverCount(1);
476   EXPECT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
477   EXPECT_EQ(ASCIIToUTF16("second"), t_url->short_name());
478   EXPECT_EQ(ASCIIToUTF16("keyword"), t_url->keyword());
479   EXPECT_FALSE(t_url->safe_for_autoreplace());
480
481   // Now try adding a replaceable TemplateURL.  This should just delete the
482   // passed-in URL.
483   data.short_name = ASCIIToUTF16("third");
484   data.SetURL("http://test3");
485   data.safe_for_autoreplace = true;
486   model()->Add(new TemplateURL(test_util_.profile(), data));
487   VerifyObserverCount(0);
488   EXPECT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
489   EXPECT_EQ(ASCIIToUTF16("second"), t_url->short_name());
490   EXPECT_EQ(ASCIIToUTF16("keyword"), t_url->keyword());
491   EXPECT_FALSE(t_url->safe_for_autoreplace());
492
493   // Now try adding a non-replaceable TemplateURL again.  This should uniquify
494   // the existing entry's keyword.
495   data.short_name = ASCIIToUTF16("fourth");
496   data.SetURL("http://test4");
497   data.safe_for_autoreplace = false;
498   TemplateURL* t_url2 = new TemplateURL(test_util_.profile(), data);
499   model()->Add(t_url2);
500   VerifyObserverCount(2);
501   EXPECT_EQ(t_url2, model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
502   EXPECT_EQ(ASCIIToUTF16("fourth"), t_url2->short_name());
503   EXPECT_EQ(ASCIIToUTF16("keyword"), t_url2->keyword());
504   EXPECT_EQ(ASCIIToUTF16("second"), t_url->short_name());
505   EXPECT_EQ(ASCIIToUTF16("test2"), t_url->keyword());
506 }
507
508 TEST_F(TemplateURLServiceTest, AddExtensionKeyword) {
509   test_util_.VerifyLoad();
510
511   TemplateURL* original1 = AddKeywordWithDate(
512       "replaceable", "keyword1", "http://test1", std::string(), std::string(),
513       std::string(), true, "UTF-8", Time(), Time());
514   TemplateURL* original2 = AddKeywordWithDate(
515       "nonreplaceable", "keyword2", "http://test2", std::string(),
516       std::string(), std::string(), false, "UTF-8", Time(), Time());
517   TemplateURL* original3 = AddKeywordWithDate(
518       "extension", "keyword3",
519       std::string(extensions::kExtensionScheme) + "://test3", std::string(),
520       std::string(), std::string(), false, "UTF-8", Time(), Time());
521
522   // Add an extension keyword that conflicts with each of the above three
523   // keywords.
524   TemplateURLData data;
525   data.short_name = ASCIIToUTF16("test");
526   data.SetKeyword(ASCIIToUTF16("keyword1"));
527   data.SetURL(std::string(extensions::kExtensionScheme) + "://test4");
528   data.safe_for_autoreplace = false;
529
530   // Both replaceable and non-replaceable keywords should be uniquified.
531   TemplateURL* extension1 = new TemplateURL(test_util_.profile(), data);
532   model()->Add(extension1);
533   ASSERT_EQ(extension1,
534             model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword1")));
535   EXPECT_EQ(original1,
536             model()->GetTemplateURLForKeyword(ASCIIToUTF16("test1")));
537   data.SetKeyword(ASCIIToUTF16("keyword2"));
538   TemplateURL* extension2 = new TemplateURL(test_util_.profile(), data);
539   model()->Add(extension2);
540   ASSERT_EQ(extension2,
541             model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword2")));
542   EXPECT_EQ(original2,
543             model()->GetTemplateURLForKeyword(ASCIIToUTF16("test2")));
544
545   // They should override extension keywords added earlier.
546   data.SetKeyword(ASCIIToUTF16("keyword3"));
547   TemplateURL* extension3 = new TemplateURL(test_util_.profile(), data);
548   model()->Add(extension3);
549   ASSERT_EQ(extension3,
550             model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword3")));
551   EXPECT_EQ(original3,
552             model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword3_")));
553 }
554
555 TEST_F(TemplateURLServiceTest, AddSameKeywordWithExtensionPresent) {
556   test_util_.VerifyLoad();
557
558   // Similar to the AddSameKeyword test, but with an extension keyword masking a
559   // replaceable TemplateURL.  We should still do correct conflict resolution
560   // between the non-template URLs.
561   TemplateURL* extension = AddKeywordWithDate(
562       "extension", "keyword",
563       std::string(extensions::kExtensionScheme) + "://test2", std::string(),
564       std::string(), std::string(), false, "UTF-8", Time(), Time());
565   // Adding a keyword that matches the extension should cause the extension
566   // to uniquify.
567   AddKeywordWithDate(
568       "replaceable", "keyword", "http://test1", std::string(),  std::string(),
569       std::string(), true, "UTF-8", Time(), Time());
570
571   // Adding another replaceable keyword should remove the existing one, but
572   // leave the extension as is.
573   TemplateURLData data;
574   data.short_name = ASCIIToUTF16("name1");
575   data.SetKeyword(ASCIIToUTF16("keyword"));
576   data.SetURL("http://test3");
577   data.safe_for_autoreplace = true;
578   TemplateURL* t_url = new TemplateURL(test_util_.profile(), data);
579   model()->Add(t_url);
580   EXPECT_EQ(extension,
581             model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword_")));
582   EXPECT_TRUE(model()->GetTemplateURLForHost("test1") == NULL);
583   EXPECT_EQ(t_url, model()->GetTemplateURLForHost("test3"));
584
585   // Adding a nonreplaceable keyword should remove the existing replaceable
586   // keyword.
587   data.short_name = ASCIIToUTF16("name2");
588   data.SetURL("http://test4");
589   data.safe_for_autoreplace = false;
590   TemplateURL* t_url2 = new TemplateURL(test_util_.profile(), data);
591   model()->Add(t_url2);
592   EXPECT_EQ(t_url2,
593             model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
594   EXPECT_TRUE(model()->GetTemplateURLForHost("test3") == NULL);
595   EXPECT_EQ(extension,
596             model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword_")));
597 }
598
599 TEST_F(TemplateURLServiceTest, GenerateKeyword) {
600   ASSERT_EQ(ASCIIToUTF16("foo"),
601             TemplateURLService::GenerateKeyword(GURL("http://foo")));
602   // www. should be stripped.
603   ASSERT_EQ(ASCIIToUTF16("foo"),
604             TemplateURLService::GenerateKeyword(GURL("http://www.foo")));
605   // Make sure we don't get a trailing '/'.
606   ASSERT_EQ(ASCIIToUTF16("blah"),
607             TemplateURLService::GenerateKeyword(GURL("http://blah/")));
608   // Don't generate the empty string.
609   ASSERT_EQ(ASCIIToUTF16("www"),
610             TemplateURLService::GenerateKeyword(GURL("http://www.")));
611 }
612
613 TEST_F(TemplateURLServiceTest, GenerateSearchURL) {
614   TestGenerateSearchURL(NULL);
615 }
616
617 TEST_F(TemplateURLServiceTest, GenerateSearchURLUsingTermsData) {
618   // Run the test for GenerateSearchURLUsingTermsData on the "IO" thread and
619   // wait for it to finish.
620   TestSearchTermsData search_terms_data("http://google.com/");
621   TestGenerateSearchURL(&search_terms_data);
622 }
623
624 TEST_F(TemplateURLServiceTest, ClearBrowsingData_Keywords) {
625   Time now = Time::Now();
626   TimeDelta one_day = TimeDelta::FromDays(1);
627   Time month_ago = now - TimeDelta::FromDays(30);
628
629   // Nothing has been added.
630   EXPECT_EQ(0U, model()->GetTemplateURLs().size());
631
632   // Create one with a 0 time.
633   AddKeywordWithDate("name1", "key1", "http://foo1", "http://suggest1",
634                      std::string(), "http://icon1", true, "UTF-8;UTF-16",
635                      Time(), Time());
636   // Create one for now and +/- 1 day.
637   AddKeywordWithDate("name2", "key2", "http://foo2", "http://suggest2",
638                      std::string(),  "http://icon2", true, "UTF-8;UTF-16",
639                      now - one_day, Time());
640   AddKeywordWithDate("name3", "key3", "http://foo3", std::string(),
641                      std::string(), std::string(), true, std::string(), now,
642                      Time());
643   AddKeywordWithDate("name4", "key4", "http://foo4", std::string(),
644                      std::string(), std::string(), true, std::string(),
645                      now + one_day, Time());
646   // Try the other three states.
647   AddKeywordWithDate("name5", "key5", "http://foo5", "http://suggest5",
648                      std::string(), "http://icon5", false, "UTF-8;UTF-16", now,
649                      Time());
650   AddKeywordWithDate("name6", "key6", "http://foo6", "http://suggest6",
651                      std::string(), "http://icon6", false, "UTF-8;UTF-16",
652                      month_ago, Time());
653
654   // We just added a few items, validate them.
655   EXPECT_EQ(6U, model()->GetTemplateURLs().size());
656
657   // Try removing from current timestamp. This should delete the one in the
658   // future and one very recent one.
659   model()->RemoveAutoGeneratedSince(now);
660   EXPECT_EQ(4U, model()->GetTemplateURLs().size());
661
662   // Try removing from two months ago. This should only delete items that are
663   // auto-generated.
664   model()->RemoveAutoGeneratedBetween(now - TimeDelta::FromDays(60), now);
665   EXPECT_EQ(3U, model()->GetTemplateURLs().size());
666
667   // Make sure the right values remain.
668   EXPECT_EQ(ASCIIToUTF16("key1"), model()->GetTemplateURLs()[0]->keyword());
669   EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
670   EXPECT_EQ(0U,
671             model()->GetTemplateURLs()[0]->date_created().ToInternalValue());
672
673   EXPECT_EQ(ASCIIToUTF16("key5"), model()->GetTemplateURLs()[1]->keyword());
674   EXPECT_FALSE(model()->GetTemplateURLs()[1]->safe_for_autoreplace());
675   EXPECT_EQ(now.ToInternalValue(),
676             model()->GetTemplateURLs()[1]->date_created().ToInternalValue());
677
678   EXPECT_EQ(ASCIIToUTF16("key6"), model()->GetTemplateURLs()[2]->keyword());
679   EXPECT_FALSE(model()->GetTemplateURLs()[2]->safe_for_autoreplace());
680   EXPECT_EQ(month_ago.ToInternalValue(),
681             model()->GetTemplateURLs()[2]->date_created().ToInternalValue());
682
683   // Try removing from Time=0. This should delete one more.
684   model()->RemoveAutoGeneratedSince(Time());
685   EXPECT_EQ(2U, model()->GetTemplateURLs().size());
686 }
687
688 TEST_F(TemplateURLServiceTest, ClearBrowsingData_KeywordsForOrigin) {
689   Time now = Time::Now();
690   TimeDelta one_day = TimeDelta::FromDays(1);
691   Time month_ago = now - TimeDelta::FromDays(30);
692
693   // Nothing has been added.
694   EXPECT_EQ(0U, model()->GetTemplateURLs().size());
695
696   // Create one for now and +/- 1 day.
697   AddKeywordWithDate("name1", "key1", "http://foo1", "http://suggest1",
698                      std::string(), "http://icon2", true, "UTF-8;UTF-16",
699                      now - one_day, Time());
700   AddKeywordWithDate("name2", "key2", "http://foo2", std::string(),
701                      std::string(), std::string(), true, std::string(), now,
702                      Time());
703   AddKeywordWithDate("name3", "key3", "http://foo3", std::string(),
704                      std::string(), std::string(), true, std::string(),
705                      now + one_day, Time());
706
707   // We just added a few items, validate them.
708   EXPECT_EQ(3U, model()->GetTemplateURLs().size());
709
710   // Try removing foo2. This should delete foo2, but leave foo1 and 3 untouched.
711   model()->RemoveAutoGeneratedForOriginBetween(GURL("http://foo2"), month_ago,
712       now + one_day);
713   EXPECT_EQ(2U, model()->GetTemplateURLs().size());
714   EXPECT_EQ(ASCIIToUTF16("key1"), model()->GetTemplateURLs()[0]->keyword());
715   EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
716   EXPECT_EQ(ASCIIToUTF16("key3"), model()->GetTemplateURLs()[1]->keyword());
717   EXPECT_TRUE(model()->GetTemplateURLs()[1]->safe_for_autoreplace());
718
719   // Try removing foo1, but outside the range in which it was modified. It
720   // should remain untouched.
721   model()->RemoveAutoGeneratedForOriginBetween(GURL("http://foo1"), now,
722       now + one_day);
723   EXPECT_EQ(2U, model()->GetTemplateURLs().size());
724   EXPECT_EQ(ASCIIToUTF16("key1"), model()->GetTemplateURLs()[0]->keyword());
725   EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
726   EXPECT_EQ(ASCIIToUTF16("key3"), model()->GetTemplateURLs()[1]->keyword());
727   EXPECT_TRUE(model()->GetTemplateURLs()[1]->safe_for_autoreplace());
728
729
730   // Try removing foo3. This should delete foo3, but leave foo1 untouched.
731   model()->RemoveAutoGeneratedForOriginBetween(GURL("http://foo3"), month_ago,
732       now + one_day + one_day);
733   EXPECT_EQ(1U, model()->GetTemplateURLs().size());
734   EXPECT_EQ(ASCIIToUTF16("key1"), model()->GetTemplateURLs()[0]->keyword());
735   EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
736 }
737
738 TEST_F(TemplateURLServiceTest, Reset) {
739   // Add a new TemplateURL.
740   test_util_.VerifyLoad();
741   const size_t initial_count = model()->GetTemplateURLs().size();
742   TemplateURLData data;
743   data.short_name = ASCIIToUTF16("google");
744   data.SetKeyword(ASCIIToUTF16("keyword"));
745   data.SetURL("http://www.google.com/foo/bar");
746   data.favicon_url = GURL("http://favicon.url");
747   data.date_created = Time::FromTimeT(100);
748   data.last_modified = Time::FromTimeT(100);
749   TemplateURL* t_url = new TemplateURL(test_util_.profile(), data);
750   model()->Add(t_url);
751
752   VerifyObserverCount(1);
753   base::RunLoop().RunUntilIdle();
754
755   StrictMock<base::MockTimeProvider> mock_time;
756   model()->set_time_provider(&base::MockTimeProvider::StaticNow);
757   EXPECT_CALL(mock_time, Now()).WillOnce(Return(base::Time::FromDoubleT(1337)));
758
759   // Reset the short name, keyword, url and make sure it takes.
760   const base::string16 new_short_name(ASCIIToUTF16("a"));
761   const base::string16 new_keyword(ASCIIToUTF16("b"));
762   const std::string new_url("c");
763   model()->ResetTemplateURL(t_url, new_short_name, new_keyword, new_url);
764   ASSERT_EQ(new_short_name, t_url->short_name());
765   ASSERT_EQ(new_keyword, t_url->keyword());
766   ASSERT_EQ(new_url, t_url->url());
767
768   // Make sure the mappings in the model were updated.
769   ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(new_keyword));
770   ASSERT_TRUE(
771       model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")) == NULL);
772
773   scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->profile(),
774                                                      t_url->data()));
775
776   // Reload the model from the database and make sure the change took.
777   test_util_.ResetModel(true);
778   EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
779   const TemplateURL* read_url = model()->GetTemplateURLForKeyword(new_keyword);
780   ASSERT_TRUE(read_url);
781   AssertEquals(*cloned_url, *read_url);
782   ASSERT_EQ(base::Time::FromDoubleT(1337), read_url->last_modified());
783 }
784
785 TEST_F(TemplateURLServiceTest, DefaultSearchProvider) {
786   // Add a new TemplateURL.
787   test_util_.VerifyLoad();
788   const size_t initial_count = model()->GetTemplateURLs().size();
789   TemplateURL* t_url = AddKeywordWithDate(
790       "name1", "key1", "http://foo1/{searchTerms}", "http://sugg1",
791       std::string(), "http://icon1", true, "UTF-8;UTF-16", Time(), Time());
792   test_util_.ResetObserverCount();
793
794   model()->SetDefaultSearchProvider(t_url);
795   ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());
796   ASSERT_TRUE(t_url->safe_for_autoreplace());
797   ASSERT_TRUE(t_url->show_in_default_list());
798
799   // Setting the default search provider should have caused notification.
800   VerifyObserverCount(1);
801   base::RunLoop().RunUntilIdle();
802
803   scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->profile(),
804                                                      t_url->data()));
805
806   // Make sure when we reload we get a default search provider.
807   test_util_.ResetModel(true);
808   EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
809   ASSERT_TRUE(model()->GetDefaultSearchProvider());
810   AssertEquals(*cloned_url, *model()->GetDefaultSearchProvider());
811 }
812
813 TEST_F(TemplateURLServiceTest, CantReplaceWithSameKeyword) {
814   test_util_.ChangeModelToLoadState();
815   ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"), GURL(), NULL));
816   TemplateURL* t_url = AddKeywordWithDate(
817       "name1", "foo", "http://foo1", "http://sugg1", std::string(),
818       "http://icon1", true, "UTF-8;UTF-16", Time(), Time());
819
820   // Can still replace, newly added template url is marked safe to replace.
821   ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
822                                          GURL("http://foo2"), NULL));
823
824   // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
825   // no longer be replaceable.
826   model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
827                             t_url->url());
828
829   ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
830                                           GURL("http://foo2"), NULL));
831 }
832
833 TEST_F(TemplateURLServiceTest, CantReplaceWithSameHosts) {
834   test_util_.ChangeModelToLoadState();
835   ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
836                                          GURL("http://foo.com"), NULL));
837   TemplateURL* t_url = AddKeywordWithDate(
838       "name1", "foo", "http://foo.com", "http://sugg1", std::string(),
839       "http://icon1", true, "UTF-8;UTF-16", Time(), Time());
840
841   // Can still replace, newly added template url is marked safe to replace.
842   ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("bar"),
843                                          GURL("http://foo.com"), NULL));
844
845   // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
846   // no longer be replaceable.
847   model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
848                             t_url->url());
849
850   ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("bar"),
851                                           GURL("http://foo.com"), NULL));
852 }
853
854 TEST_F(TemplateURLServiceTest, HasDefaultSearchProvider) {
855   // We should have a default search provider even if we haven't loaded.
856   ASSERT_TRUE(model()->GetDefaultSearchProvider());
857
858   // Now force the model to load and make sure we still have a default.
859   test_util_.VerifyLoad();
860
861   ASSERT_TRUE(model()->GetDefaultSearchProvider());
862 }
863
864 TEST_F(TemplateURLServiceTest, DefaultSearchProviderLoadedFromPrefs) {
865   test_util_.VerifyLoad();
866
867   TemplateURLData data;
868   data.short_name = ASCIIToUTF16("a");
869   data.safe_for_autoreplace = true;
870   data.SetURL("http://url/{searchTerms}");
871   data.suggestions_url = "http://url2";
872   data.instant_url = "http://instant";
873   data.date_created = Time::FromTimeT(100);
874   data.last_modified = Time::FromTimeT(100);
875   TemplateURL* t_url = new TemplateURL(test_util_.profile(), data);
876   model()->Add(t_url);
877   const TemplateURLID id = t_url->id();
878
879   model()->SetDefaultSearchProvider(t_url);
880   base::RunLoop().RunUntilIdle();
881   scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->profile(),
882                                                      t_url->data()));
883
884   // Reset the model and don't load it. The template url we set as the default
885   // should be pulled from prefs now.
886   test_util_.ResetModel(false);
887
888   // NOTE: This doesn't use AssertEquals as only a subset of the TemplateURLs
889   // value are persisted to prefs.
890   const TemplateURL* default_turl = model()->GetDefaultSearchProvider();
891   ASSERT_TRUE(default_turl);
892   EXPECT_EQ(ASCIIToUTF16("a"), default_turl->short_name());
893   EXPECT_EQ("http://url/{searchTerms}", default_turl->url());
894   EXPECT_EQ("http://url2", default_turl->suggestions_url());
895   EXPECT_EQ("http://instant", default_turl->instant_url());
896   EXPECT_EQ(id, default_turl->id());
897
898   // Now do a load and make sure the default search provider really takes.
899   test_util_.VerifyLoad();
900
901   ASSERT_TRUE(model()->GetDefaultSearchProvider());
902   AssertEquals(*cloned_url, *model()->GetDefaultSearchProvider());
903 }
904
905 TEST_F(TemplateURLServiceTest, RepairPrepopulatedSearchEngines) {
906   test_util_.VerifyLoad();
907
908   // Edit Google search engine.
909   TemplateURL* google = model()->GetTemplateURLForKeyword(
910       ASCIIToUTF16("google.com"));
911   ASSERT_TRUE(google);
912   model()->ResetTemplateURL(google, ASCIIToUTF16("trash"), ASCIIToUTF16("xxx"),
913                             "http://www.foo.com/s?q={searchTerms}");
914   EXPECT_EQ(ASCIIToUTF16("trash"), google->short_name());
915   EXPECT_EQ(ASCIIToUTF16("xxx"), google->keyword());
916
917   // Add third-party default search engine.
918   TemplateURL* user_dse = AddKeywordWithDate(
919       "malware", "google.com", "http://www.goo.com/s?q={searchTerms}",
920       std::string(), std::string(), std::string(),
921       true, "UTF-8", Time(), Time());
922   model()->SetDefaultSearchProvider(user_dse);
923   EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider());
924
925   // Remove bing.
926   TemplateURL* bing = model()->GetTemplateURLForKeyword(
927       ASCIIToUTF16("bing.com"));
928   ASSERT_TRUE(bing);
929   model()->Remove(bing);
930   EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("bing.com")));
931
932   // Register an extension with bing keyword.
933   model()->RegisterOmniboxKeyword("abcdefg", "extension_name", "bing.com");
934   EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("bing.com")));
935
936   model()->RepairPrepopulatedSearchEngines();
937
938   // Google is default.
939   ASSERT_EQ(google, model()->GetDefaultSearchProvider());
940   // The keyword wasn't reverted.
941   EXPECT_EQ(ASCIIToUTF16("trash"), google->short_name());
942   EXPECT_EQ("www.google.com",
943             TemplateURLService::GenerateSearchURL(google).host());
944
945   // Bing was repaired.
946   bing = model()->GetTemplateURLForKeyword(ASCIIToUTF16("bing.com"));
947   ASSERT_TRUE(bing);
948   EXPECT_EQ(TemplateURL::NORMAL, bing->GetType());
949
950   // User search engine is preserved.
951   EXPECT_EQ(user_dse, model()->GetTemplateURLForHost("www.goo.com"));
952   EXPECT_EQ(ASCIIToUTF16("google.com"), user_dse->keyword());
953 }
954
955 TEST_F(TemplateURLServiceTest, RepairSearchEnginesWithManagedDefault) {
956   // Set a managed preference that establishes a default search provider.
957   const char kName[] = "test1";
958   const char kKeyword[] = "test.com";
959   const char kSearchURL[] = "http://test.com/search?t={searchTerms}";
960   const char kIconURL[] = "http://test.com/icon.jpg";
961   const char kEncodings[] = "UTF-16;UTF-32";
962   const char kAlternateURL[] = "http://test.com/search#t={searchTerms}";
963   const char kSearchTermsReplacementKey[] = "espv";
964   test_util_.SetManagedDefaultSearchPreferences(true, kName, kKeyword,
965                                                 kSearchURL, std::string(),
966                                                 kIconURL, kEncodings,
967                                                 kAlternateURL,
968                                                 kSearchTermsReplacementKey);
969   test_util_.VerifyLoad();
970   // Verify that the default manager we are getting is the managed one.
971   TemplateURLData data;
972   data.short_name = ASCIIToUTF16(kName);
973   data.SetKeyword(ASCIIToUTF16(kKeyword));
974   data.SetURL(kSearchURL);
975   data.favicon_url = GURL(kIconURL);
976   data.show_in_default_list = true;
977   base::SplitString(kEncodings, ';', &data.input_encodings);
978   data.alternate_urls.push_back(kAlternateURL);
979   data.search_terms_replacement_key = kSearchTermsReplacementKey;
980   scoped_ptr<TemplateURL> expected_managed_default(new TemplateURL(
981       test_util_.profile(), data));
982   EXPECT_TRUE(model()->is_default_search_managed());
983   const TemplateURL* actual_managed_default =
984       model()->GetDefaultSearchProvider();
985   ExpectSimilar(expected_managed_default.get(), actual_managed_default);
986
987   // The following call has no effect on the managed search engine.
988   model()->RepairPrepopulatedSearchEngines();
989
990   EXPECT_TRUE(model()->is_default_search_managed());
991   actual_managed_default = model()->GetDefaultSearchProvider();
992   ExpectSimilar(expected_managed_default.get(), actual_managed_default);
993 }
994
995 TEST_F(TemplateURLServiceTest, UpdateKeywordSearchTermsForURL) {
996   struct TestData {
997     const std::string url;
998     const base::string16 term;
999   } data[] = {
1000     { "http://foo/", base::string16() },
1001     { "http://foo/foo?q=xx", base::string16() },
1002     { "http://x/bar?q=xx", base::string16() },
1003     { "http://x/foo?y=xx", base::string16() },
1004     { "http://x/foo?q=xx", ASCIIToUTF16("xx") },
1005     { "http://x/foo?a=b&q=xx", ASCIIToUTF16("xx") },
1006     { "http://x/foo?q=b&q=xx", base::string16() },
1007     { "http://x/foo#query=xx", ASCIIToUTF16("xx") },
1008     { "http://x/foo?q=b#query=xx", ASCIIToUTF16("xx") },
1009     { "http://x/foo?q=b#q=xx", ASCIIToUTF16("b") },
1010     { "http://x/foo?query=b#q=xx", base::string16() },
1011   };
1012
1013   test_util_.ChangeModelToLoadState();
1014   AddKeywordWithDate("name", "x", "http://x/foo?q={searchTerms}",
1015                      "http://sugg1", "http://x/foo#query={searchTerms}",
1016                      "http://icon1", false, "UTF-8;UTF-16", Time(), Time());
1017
1018   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
1019     history::URLVisitedDetails details;
1020     details.row = history::URLRow(GURL(data[i].url));
1021     details.transition = content::PageTransitionFromInt(0);
1022     model()->UpdateKeywordSearchTermsForURL(details);
1023     EXPECT_EQ(data[i].term, test_util_.GetAndClearSearchTerm());
1024   }
1025 }
1026
1027 TEST_F(TemplateURLServiceTest, DontUpdateKeywordSearchForNonReplaceable) {
1028   struct TestData {
1029     const std::string url;
1030   } data[] = {
1031     { "http://foo/" },
1032     { "http://x/bar?q=xx" },
1033     { "http://x/foo?y=xx" },
1034   };
1035
1036   test_util_.ChangeModelToLoadState();
1037   AddKeywordWithDate("name", "x", "http://x/foo", "http://sugg1", std::string(),
1038                      "http://icon1", false, "UTF-8;UTF-16", Time(), Time());
1039
1040   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
1041     history::URLVisitedDetails details;
1042     details.row = history::URLRow(GURL(data[i].url));
1043     details.transition = content::PageTransitionFromInt(0);
1044     model()->UpdateKeywordSearchTermsForURL(details);
1045     ASSERT_EQ(base::string16(), test_util_.GetAndClearSearchTerm());
1046   }
1047 }
1048
1049 TEST_F(TemplateURLServiceTest, ChangeGoogleBaseValue) {
1050   // NOTE: Do not do a VerifyLoad() here as it will load the prepopulate data,
1051   // which also has a {google:baseURL} keyword in it, which will confuse this
1052   // test.
1053   test_util_.ChangeModelToLoadState();
1054   test_util_.SetGoogleBaseURL(GURL("http://google.com/"));
1055   const TemplateURL* t_url = AddKeywordWithDate(
1056       "name", "google.com", "{google:baseURL}?q={searchTerms}", "http://sugg1",
1057       std::string(), "http://icon1", false, "UTF-8;UTF-16", Time(), Time());
1058   ASSERT_EQ(t_url, model()->GetTemplateURLForHost("google.com"));
1059   EXPECT_EQ("google.com", t_url->url_ref().GetHost());
1060   EXPECT_EQ(ASCIIToUTF16("google.com"), t_url->keyword());
1061
1062   // Change the Google base url.
1063   test_util_.ResetObserverCount();
1064   test_util_.SetGoogleBaseURL(GURL("http://google.co.uk/"));
1065   VerifyObserverCount(1);
1066
1067   // Make sure the host->TemplateURL map was updated appropriately.
1068   ASSERT_EQ(t_url, model()->GetTemplateURLForHost("google.co.uk"));
1069   EXPECT_TRUE(model()->GetTemplateURLForHost("google.com") == NULL);
1070   EXPECT_EQ("google.co.uk", t_url->url_ref().GetHost());
1071   EXPECT_EQ(ASCIIToUTF16("google.co.uk"), t_url->keyword());
1072   EXPECT_EQ("http://google.co.uk/?q=x", t_url->url_ref().ReplaceSearchTerms(
1073       TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("x"))));
1074
1075   // Now add a manual entry and then change the Google base URL such that the
1076   // autogenerated Google search keyword would conflict.
1077   TemplateURL* manual = AddKeywordWithDate(
1078     "manual", "google.de", "http://google.de/search?q={searchTerms}",
1079     std::string(), std::string(), std::string(), false, "UTF-8", Time(),
1080     Time());
1081   test_util_.SetGoogleBaseURL(GURL("http://google.de"));
1082
1083   // Verify that the manual entry is untouched, and the autogenerated keyword
1084   // has not changed.
1085   ASSERT_EQ(manual,
1086             model()->GetTemplateURLForKeyword(ASCIIToUTF16("google.de")));
1087   EXPECT_EQ("google.de", manual->url_ref().GetHost());
1088   ASSERT_EQ(t_url,
1089             model()->GetTemplateURLForKeyword(ASCIIToUTF16("google.co.uk")));
1090   EXPECT_EQ("google.de", t_url->url_ref().GetHost());
1091   EXPECT_EQ(ASCIIToUTF16("google.co.uk"), t_url->keyword());
1092
1093   // Change the base URL again and verify that the autogenerated keyword follows
1094   // even though it didn't match the base URL, while the manual entry is still
1095   // untouched.
1096   test_util_.SetGoogleBaseURL(GURL("http://google.fr/"));
1097   ASSERT_EQ(manual, model()->GetTemplateURLForHost("google.de"));
1098   EXPECT_EQ("google.de", manual->url_ref().GetHost());
1099   EXPECT_EQ(ASCIIToUTF16("google.de"), manual->keyword());
1100   ASSERT_EQ(t_url, model()->GetTemplateURLForHost("google.fr"));
1101   EXPECT_TRUE(model()->GetTemplateURLForHost("google.co.uk") == NULL);
1102   EXPECT_EQ("google.fr", t_url->url_ref().GetHost());
1103   EXPECT_EQ(ASCIIToUTF16("google.fr"), t_url->keyword());
1104 }
1105
1106 // Make sure TemplateURLService generates a KEYWORD_GENERATED visit for
1107 // KEYWORD visits.
1108 TEST_F(TemplateURLServiceTest, GenerateVisitOnKeyword) {
1109   test_util_.VerifyLoad();
1110   ASSERT_TRUE(test_util_.profile()->CreateHistoryService(true, false));
1111
1112   // Create a keyword.
1113   TemplateURL* t_url = AddKeywordWithDate(
1114       "keyword", "keyword", "http://foo.com/foo?query={searchTerms}",
1115       "http://sugg1", std::string(), "http://icon1", true, "UTF-8;UTF-16",
1116       base::Time::Now(), base::Time::Now());
1117
1118   // Add a visit that matches the url of the keyword.
1119   HistoryService* history =
1120       HistoryServiceFactory::GetForProfile(test_util_.profile(),
1121                                            Profile::EXPLICIT_ACCESS);
1122   history->AddPage(
1123       GURL(t_url->url_ref().ReplaceSearchTerms(
1124           TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("blah")))),
1125       base::Time::Now(), NULL, 0, GURL(), history::RedirectList(),
1126       content::PAGE_TRANSITION_KEYWORD, history::SOURCE_BROWSED, false);
1127
1128   // Wait for history to finish processing the request.
1129   test_util_.profile()->BlockUntilHistoryProcessesPendingRequests();
1130
1131   // Query history for the generated url.
1132   CancelableRequestConsumer consumer;
1133   QueryHistoryCallbackImpl callback;
1134   history->QueryURL(GURL("http://keyword"), true, &consumer,
1135       base::Bind(&QueryHistoryCallbackImpl::Callback,
1136                  base::Unretained(&callback)));
1137
1138   // Wait for the request to be processed.
1139   test_util_.profile()->BlockUntilHistoryProcessesPendingRequests();
1140
1141   // And make sure the url and visit were added.
1142   EXPECT_TRUE(callback.success);
1143   EXPECT_NE(0, callback.row.id());
1144   ASSERT_EQ(1U, callback.visits.size());
1145   EXPECT_EQ(content::PAGE_TRANSITION_KEYWORD_GENERATED,
1146       content::PageTransitionStripQualifier(callback.visits[0].transition));
1147 }
1148
1149 // Make sure that the load routine deletes prepopulated engines that no longer
1150 // exist in the prepopulate data.
1151 TEST_F(TemplateURLServiceTest, LoadDeletesUnusedProvider) {
1152   // Create a preloaded template url. Add it to a loaded model and wait for the
1153   // saves to finish.
1154   TemplateURL* t_url = CreatePreloadedTemplateURL(true, 999999);
1155   test_util_.ChangeModelToLoadState();
1156   model()->Add(t_url);
1157   ASSERT_TRUE(
1158       model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) != NULL);
1159   base::RunLoop().RunUntilIdle();
1160
1161   // Ensure that merging clears this engine.
1162   test_util_.ResetModel(true);
1163   ASSERT_TRUE(
1164       model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) == NULL);
1165
1166   // Wait for any saves to finish.
1167   base::RunLoop().RunUntilIdle();
1168
1169   // Reload the model to verify that the database was updated as a result of the
1170   // merge.
1171   test_util_.ResetModel(true);
1172   ASSERT_TRUE(
1173       model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) == NULL);
1174 }
1175
1176 // Make sure that load routine doesn't delete prepopulated engines that no
1177 // longer exist in the prepopulate data if it has been modified by the user.
1178 TEST_F(TemplateURLServiceTest, LoadRetainsModifiedProvider) {
1179   // Create a preloaded template url and add it to a loaded model.
1180   TemplateURL* t_url = CreatePreloadedTemplateURL(false, 999999);
1181   test_util_.ChangeModelToLoadState();
1182   model()->Add(t_url);
1183
1184   // Do the copy after t_url is added so that the id is set.
1185   scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->profile(),
1186                                                      t_url->data()));
1187   ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")));
1188
1189   // Wait for any saves to finish.
1190   base::RunLoop().RunUntilIdle();
1191
1192   // Ensure that merging won't clear it if the user has edited it.
1193   test_util_.ResetModel(true);
1194   const TemplateURL* url_for_unittest =
1195       model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
1196   ASSERT_TRUE(url_for_unittest != NULL);
1197   AssertEquals(*cloned_url, *url_for_unittest);
1198
1199   // Wait for any saves to finish.
1200   base::RunLoop().RunUntilIdle();
1201
1202   // Reload the model to verify that save/reload retains the item.
1203   test_util_.ResetModel(true);
1204   ASSERT_TRUE(
1205       model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) != NULL);
1206 }
1207
1208 // Make sure that load routine doesn't delete
1209 // prepopulated engines that no longer exist in the prepopulate data if
1210 // it has been modified by the user.
1211 TEST_F(TemplateURLServiceTest, LoadSavesPrepopulatedDefaultSearchProvider) {
1212   test_util_.VerifyLoad();
1213   // Verify that the default search provider is set to something.
1214   TemplateURL* default_search = model()->GetDefaultSearchProvider();
1215   ASSERT_TRUE(default_search != NULL);
1216   scoped_ptr<TemplateURL> cloned_url(new TemplateURL(default_search->profile(),
1217                                                      default_search->data()));
1218
1219   // Wait for any saves to finish.
1220   base::RunLoop().RunUntilIdle();
1221
1222   // Reload the model and check that the default search provider
1223   // was properly saved.
1224   test_util_.ResetModel(true);
1225   default_search = model()->GetDefaultSearchProvider();
1226   ASSERT_TRUE(default_search != NULL);
1227   AssertEquals(*cloned_url, *default_search);
1228 }
1229
1230 TEST_F(TemplateURLServiceTest, FindNewDefaultSearchProvider) {
1231   // Ensure that if our service is initially empty, we don't initial have a
1232   // valid new DSP.
1233   EXPECT_FALSE(model()->FindNewDefaultSearchProvider());
1234
1235   // Add a few entries with searchTerms, but ensure only the last one is in the
1236   // default list.
1237   AddKeywordWithDate("name1", "key1", "http://foo1/{searchTerms}",
1238                      "http://sugg1", std::string(), "http://icon1", true,
1239                      "UTF-8;UTF-16", Time(), Time());
1240   AddKeywordWithDate("name2", "key2", "http://foo2/{searchTerms}",
1241                      "http://sugg2", std::string(), "http://icon1", true,
1242                      "UTF-8;UTF-16", Time(), Time());
1243   AddKeywordWithDate("name3", "key3", "http://foo1/{searchTerms}",
1244                      "http://sugg3", std::string(), "http://icon3", true,
1245                      "UTF-8;UTF-16", Time(), Time());
1246   TemplateURLData data;
1247   data.short_name = ASCIIToUTF16("valid");
1248   data.SetKeyword(ASCIIToUTF16("validkeyword"));
1249   data.SetURL("http://valid/{searchTerms}");
1250   data.favicon_url = GURL("http://validicon");
1251   data.show_in_default_list = true;
1252   TemplateURL* valid_turl(new TemplateURL(test_util_.profile(), data));
1253   model()->Add(valid_turl);
1254   EXPECT_EQ(4U, model()->GetTemplateURLs().size());
1255
1256   // Request a new DSP from the service and only expect the valid one.
1257   TemplateURL* new_default = model()->FindNewDefaultSearchProvider();
1258   ASSERT_TRUE(new_default);
1259   EXPECT_EQ(valid_turl, new_default);
1260
1261   // Remove the default we received and ensure that the service returns NULL.
1262   model()->Remove(new_default);
1263   EXPECT_FALSE(model()->FindNewDefaultSearchProvider());
1264 }
1265
1266 // Make sure that the load routine doesn't delete
1267 // prepopulated engines that no longer exist in the prepopulate data if
1268 // it is the default search provider.
1269 TEST_F(TemplateURLServiceTest, LoadRetainsDefaultProvider) {
1270   // Set the default search provider to a preloaded template url which
1271   // is not in the current set of preloaded template urls and save
1272   // the result.
1273   TemplateURL* t_url = CreatePreloadedTemplateURL(true, 999999);
1274   test_util_.ChangeModelToLoadState();
1275   model()->Add(t_url);
1276   model()->SetDefaultSearchProvider(t_url);
1277   // Do the copy after t_url is added and set as default so that its
1278   // internal state is correct.
1279   scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->profile(),
1280                                                      t_url->data()));
1281
1282   ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")));
1283   ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());
1284   base::RunLoop().RunUntilIdle();
1285
1286   // Ensure that merging won't clear the prepopulated template url
1287   // which is no longer present if it's the default engine.
1288   test_util_.ResetModel(true);
1289   {
1290     const TemplateURL* keyword_url =
1291         model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
1292     ASSERT_TRUE(keyword_url != NULL);
1293     AssertEquals(*cloned_url, *keyword_url);
1294     ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
1295   }
1296
1297   // Wait for any saves to finish.
1298   base::RunLoop().RunUntilIdle();
1299
1300   // Reload the model to verify that the update was saved.
1301   test_util_.ResetModel(true);
1302   {
1303     const TemplateURL* keyword_url =
1304         model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
1305     ASSERT_TRUE(keyword_url != NULL);
1306     AssertEquals(*cloned_url, *keyword_url);
1307     ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
1308   }
1309 }
1310
1311 // Make sure that the load routine updates the url of a preexisting
1312 // default search engine provider and that the result is saved correctly.
1313 TEST_F(TemplateURLServiceTest, LoadUpdatesDefaultSearchURL) {
1314   TestLoadUpdatingPreloadedURL(0);
1315 }
1316
1317 // Make sure that the load routine updates the url of a preexisting
1318 // non-default search engine provider and that the result is saved correctly.
1319 TEST_F(TemplateURLServiceTest, LoadUpdatesSearchURL) {
1320   TestLoadUpdatingPreloadedURL(1);
1321 }
1322
1323 // Make sure that the load routine sets a default search provider if it was
1324 // missing and not managed.
1325 TEST_F(TemplateURLServiceTest, LoadEnsuresDefaultSearchProviderExists) {
1326   // Force the model to load and make sure we have a default search provider.
1327   test_util_.VerifyLoad();
1328   TemplateURL* old_default = model()->GetDefaultSearchProvider();
1329   EXPECT_TRUE(old_default);
1330
1331   // Now remove it.
1332   model()->SetDefaultSearchProvider(NULL);
1333   model()->Remove(old_default);
1334   base::RunLoop().RunUntilIdle();
1335
1336   EXPECT_FALSE(model()->GetDefaultSearchProvider());
1337
1338   // Reset the model and load it. There should be a default search provider.
1339   test_util_.ResetModel(true);
1340
1341   ASSERT_TRUE(model()->GetDefaultSearchProvider());
1342   EXPECT_TRUE(model()->GetDefaultSearchProvider()->SupportsReplacement());
1343
1344   // Make default search provider unusable (no search terms).
1345   model()->ResetTemplateURL(model()->GetDefaultSearchProvider(),
1346                             ASCIIToUTF16("test"), ASCIIToUTF16("test"),
1347                             "http://example.com/");
1348   base::RunLoop().RunUntilIdle();
1349
1350   // Reset the model and load it. There should be a usable default search
1351   // provider.
1352   test_util_.ResetModel(true);
1353
1354   ASSERT_TRUE(model()->GetDefaultSearchProvider());
1355   EXPECT_TRUE(model()->GetDefaultSearchProvider()->SupportsReplacement());
1356 }
1357
1358 // Simulates failing to load the webdb and makes sure the default search
1359 // provider is valid.
1360 TEST_F(TemplateURLServiceTest, FailedInit) {
1361   test_util_.VerifyLoad();
1362
1363   test_util_.ClearModel();
1364   scoped_refptr<WebDataService> web_service =
1365       WebDataService::FromBrowserContext(test_util_.profile());
1366   web_service->ShutdownDatabase();
1367
1368   test_util_.ResetModel(false);
1369   model()->Load();
1370   base::RunLoop().RunUntilIdle();
1371
1372   ASSERT_TRUE(model()->GetDefaultSearchProvider());
1373 }
1374
1375 // Verifies that if the default search URL preference is managed, we report
1376 // the default search as managed.  Also check that we are getting the right
1377 // values.
1378 TEST_F(TemplateURLServiceTest, TestManagedDefaultSearch) {
1379   test_util_.VerifyLoad();
1380   const size_t initial_count = model()->GetTemplateURLs().size();
1381   test_util_.ResetObserverCount();
1382
1383   // Set a regular default search provider.
1384   TemplateURL* regular_default = AddKeywordWithDate(
1385       "name1", "key1", "http://foo1/{searchTerms}", "http://sugg1",
1386       std::string(), "http://icon1", true, "UTF-8;UTF-16", Time(), Time());
1387   VerifyObserverCount(1);
1388   model()->SetDefaultSearchProvider(regular_default);
1389   // Adding the URL and setting the default search provider should have caused
1390   // notifications.
1391   VerifyObserverCount(1);
1392   EXPECT_FALSE(model()->is_default_search_managed());
1393   EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1394
1395   // Set a managed preference that establishes a default search provider.
1396   const char kName[] = "test1";
1397   const char kKeyword[] = "test.com";
1398   const char kSearchURL[] = "http://test.com/search?t={searchTerms}";
1399   const char kIconURL[] = "http://test.com/icon.jpg";
1400   const char kEncodings[] = "UTF-16;UTF-32";
1401   const char kAlternateURL[] = "http://test.com/search#t={searchTerms}";
1402   const char kSearchTermsReplacementKey[] = "espv";
1403   test_util_.SetManagedDefaultSearchPreferences(true, kName, kKeyword,
1404       kSearchURL, std::string(), kIconURL, kEncodings, kAlternateURL,
1405       kSearchTermsReplacementKey);
1406   VerifyObserverFired();
1407   EXPECT_TRUE(model()->is_default_search_managed());
1408   EXPECT_EQ(initial_count + 2, model()->GetTemplateURLs().size());
1409
1410   // Verify that the default manager we are getting is the managed one.
1411   TemplateURLData data;
1412   data.short_name = ASCIIToUTF16(kName);
1413   data.SetKeyword(ASCIIToUTF16(kKeyword));
1414   data.SetURL(kSearchURL);
1415   data.favicon_url = GURL(kIconURL);
1416   data.show_in_default_list = true;
1417   base::SplitString(kEncodings, ';', &data.input_encodings);
1418   data.alternate_urls.push_back(kAlternateURL);
1419   data.search_terms_replacement_key = kSearchTermsReplacementKey;
1420   Profile* profile = test_util_.profile();
1421   scoped_ptr<TemplateURL> expected_managed_default1(new TemplateURL(profile,
1422                                                                     data));
1423   const TemplateURL* actual_managed_default =
1424       model()->GetDefaultSearchProvider();
1425   ExpectSimilar(expected_managed_default1.get(), actual_managed_default);
1426   EXPECT_TRUE(actual_managed_default->show_in_default_list());
1427
1428   // Update the managed preference and check that the model has changed.
1429   const char kNewName[] = "test2";
1430   const char kNewKeyword[] = "other.com";
1431   const char kNewSearchURL[] = "http://other.com/search?t={searchTerms}";
1432   const char kNewSuggestURL[] = "http://other.com/suggest?t={searchTerms}";
1433   test_util_.SetManagedDefaultSearchPreferences(true, kNewName, kNewKeyword,
1434       kNewSearchURL, kNewSuggestURL, std::string(), std::string(),
1435       std::string(), std::string());
1436   VerifyObserverFired();
1437   EXPECT_TRUE(model()->is_default_search_managed());
1438   EXPECT_EQ(initial_count + 2, model()->GetTemplateURLs().size());
1439
1440   // Verify that the default manager we are now getting is the correct one.
1441   TemplateURLData data2;
1442   data2.short_name = ASCIIToUTF16(kNewName);
1443   data2.SetKeyword(ASCIIToUTF16(kNewKeyword));
1444   data2.SetURL(kNewSearchURL);
1445   data2.suggestions_url = kNewSuggestURL;
1446   data2.show_in_default_list = true;
1447   scoped_ptr<TemplateURL> expected_managed_default2(new TemplateURL(profile,
1448                                                                     data2));
1449   actual_managed_default = model()->GetDefaultSearchProvider();
1450   ExpectSimilar(expected_managed_default2.get(), actual_managed_default);
1451   EXPECT_EQ(actual_managed_default->show_in_default_list(), true);
1452
1453   // Remove all the managed prefs and check that we are no longer managed.
1454   test_util_.RemoveManagedDefaultSearchPreferences();
1455   VerifyObserverFired();
1456   EXPECT_FALSE(model()->is_default_search_managed());
1457   EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1458
1459   // The default should now be the first URL added
1460   const TemplateURL* actual_final_managed_default =
1461       model()->GetDefaultSearchProvider();
1462   ExpectSimilar(model()->GetTemplateURLs()[0], actual_final_managed_default);
1463   EXPECT_EQ(actual_final_managed_default->show_in_default_list(), true);
1464
1465   // Disable the default search provider through policy.
1466   test_util_.SetManagedDefaultSearchPreferences(false, std::string(),
1467       std::string(), std::string(), std::string(), std::string(),
1468       std::string(), std::string(), std::string());
1469   VerifyObserverFired();
1470   EXPECT_TRUE(model()->is_default_search_managed());
1471   EXPECT_TRUE(NULL == model()->GetDefaultSearchProvider());
1472   EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1473
1474   // Re-enable it.
1475   test_util_.SetManagedDefaultSearchPreferences(true, kName, kKeyword,
1476       kSearchURL, std::string(), kIconURL, kEncodings, kAlternateURL,
1477       kSearchTermsReplacementKey);
1478   VerifyObserverFired();
1479   EXPECT_TRUE(model()->is_default_search_managed());
1480   EXPECT_EQ(initial_count + 2, model()->GetTemplateURLs().size());
1481
1482   // Verify that the default manager we are getting is the managed one.
1483   actual_managed_default = model()->GetDefaultSearchProvider();
1484   ExpectSimilar(expected_managed_default1.get(), actual_managed_default);
1485   EXPECT_EQ(actual_managed_default->show_in_default_list(), true);
1486
1487   // Clear the model and disable the default search provider through policy.
1488   // Verify that there is no default search provider after loading the model.
1489   // This checks against regressions of http://crbug.com/67180
1490
1491   // First, remove the preferences, reset the model, and set a default.
1492   test_util_.RemoveManagedDefaultSearchPreferences();
1493   test_util_.ResetModel(true);
1494   TemplateURL* new_default =
1495       model()->GetTemplateURLForKeyword(ASCIIToUTF16("key1"));
1496   ASSERT_FALSE(new_default == NULL);
1497   model()->SetDefaultSearchProvider(new_default);
1498   EXPECT_EQ(new_default, model()->GetDefaultSearchProvider());
1499
1500   // Now reset the model again but load it after setting the preferences.
1501   test_util_.ResetModel(false);
1502   test_util_.SetManagedDefaultSearchPreferences(false, std::string(),
1503       std::string(), std::string(), std::string(), std::string(),
1504       std::string(), std::string(), std::string());
1505   test_util_.VerifyLoad();
1506   EXPECT_TRUE(model()->is_default_search_managed());
1507   EXPECT_TRUE(model()->GetDefaultSearchProvider() == NULL);
1508 }
1509
1510 // Test that if we load a TemplateURL with an empty GUID, the load process
1511 // assigns it a newly generated GUID.
1512 TEST_F(TemplateURLServiceTest, PatchEmptySyncGUID) {
1513   // Add a new TemplateURL.
1514   test_util_.VerifyLoad();
1515   const size_t initial_count = model()->GetTemplateURLs().size();
1516
1517   TemplateURLData data;
1518   data.short_name = ASCIIToUTF16("google");
1519   data.SetKeyword(ASCIIToUTF16("keyword"));
1520   data.SetURL("http://www.google.com/foo/bar");
1521   data.sync_guid.clear();
1522   TemplateURL* t_url = new TemplateURL(test_util_.profile(), data);
1523   model()->Add(t_url);
1524
1525   VerifyObserverCount(1);
1526   base::RunLoop().RunUntilIdle();
1527   ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1528
1529   // Reload the model to verify it was actually saved to the database and
1530   // assigned a new GUID when brought back.
1531   test_util_.ResetModel(true);
1532   ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1533   const TemplateURL* loaded_url =
1534       model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
1535   ASSERT_FALSE(loaded_url == NULL);
1536   ASSERT_FALSE(loaded_url->sync_guid().empty());
1537 }
1538
1539 // Test that if we load a TemplateURL with duplicate input encodings, the load
1540 // process de-dupes them.
1541 TEST_F(TemplateURLServiceTest, DuplicateInputEncodings) {
1542   // Add a new TemplateURL.
1543   test_util_.VerifyLoad();
1544   const size_t initial_count = model()->GetTemplateURLs().size();
1545
1546   TemplateURLData data;
1547   data.short_name = ASCIIToUTF16("google");
1548   data.SetKeyword(ASCIIToUTF16("keyword"));
1549   data.SetURL("http://www.google.com/foo/bar");
1550   std::vector<std::string> encodings;
1551   data.input_encodings.push_back("UTF-8");
1552   data.input_encodings.push_back("UTF-8");
1553   data.input_encodings.push_back("UTF-16");
1554   data.input_encodings.push_back("UTF-8");
1555   data.input_encodings.push_back("Big5");
1556   data.input_encodings.push_back("UTF-16");
1557   data.input_encodings.push_back("Big5");
1558   data.input_encodings.push_back("Windows-1252");
1559   TemplateURL* t_url = new TemplateURL(test_util_.profile(), data);
1560   model()->Add(t_url);
1561
1562   VerifyObserverCount(1);
1563   base::RunLoop().RunUntilIdle();
1564   ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1565   const TemplateURL* loaded_url =
1566       model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
1567   ASSERT_TRUE(loaded_url != NULL);
1568   EXPECT_EQ(8U, loaded_url->input_encodings().size());
1569
1570   // Reload the model to verify it was actually saved to the database and the
1571   // duplicate encodings were removed.
1572   test_util_.ResetModel(true);
1573   ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1574   loaded_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
1575   ASSERT_FALSE(loaded_url == NULL);
1576   EXPECT_EQ(4U, loaded_url->input_encodings().size());
1577 }
1578
1579 TEST_F(TemplateURLServiceTest, DefaultExtensionEngine) {
1580   test_util_.VerifyLoad();
1581   // Add third-party default search engine.
1582   TemplateURL* user_dse = AddKeywordWithDate(
1583       "user", "user", "http://www.goo.com/s?q={searchTerms}",
1584       std::string(), std::string(), std::string(),
1585       true, "UTF-8", Time(), Time());
1586   model()->SetDefaultSearchProvider(user_dse);
1587   EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider());
1588
1589   TemplateURL* ext_dse = CreateKeywordWithDate(
1590       model(), "ext", "ext", "http://www.search.com/s?q={searchTerms}",
1591       std::string(), std::string(), std::string(),
1592       true, "UTF-8", Time(), Time());
1593   scoped_ptr<AssociatedExtensionInfo> extension_info(
1594       new AssociatedExtensionInfo);
1595   extension_info->wants_to_be_default_engine = true;
1596   extension_info->extension_id = "ext";
1597   model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
1598   EXPECT_EQ(ext_dse, model()->GetDefaultSearchProvider());
1599
1600   model()->RemoveExtensionControlledTURL("ext");
1601   ExpectSimilar(user_dse, model()->GetDefaultSearchProvider());
1602 }
1603
1604 TEST_F(TemplateURLServiceTest, ExtensionEnginesNotPersist) {
1605   test_util_.VerifyLoad();
1606   // Add third-party default search engine.
1607   TemplateURL* user_dse = AddKeywordWithDate(
1608       "user", "user", "http://www.goo.com/s?q={searchTerms}",
1609       std::string(), std::string(), std::string(),
1610       true, "UTF-8", Time(), Time());
1611   model()->SetDefaultSearchProvider(user_dse);
1612   EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider());
1613
1614   TemplateURL* ext_dse = CreateKeywordWithDate(
1615       model(), "ext1", "ext1", "http://www.ext1.com/s?q={searchTerms}",
1616       std::string(), std::string(), std::string(),
1617       true, "UTF-8", Time(), Time());
1618   scoped_ptr<AssociatedExtensionInfo> extension_info(
1619       new AssociatedExtensionInfo);
1620   extension_info->wants_to_be_default_engine = false;
1621   extension_info->extension_id = "ext1";
1622   model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
1623   EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider());
1624
1625   ext_dse = CreateKeywordWithDate(
1626       model(), "ext2", "ext2", "http://www.ext2.com/s?q={searchTerms}",
1627       std::string(), std::string(), std::string(),
1628       true, "UTF-8", Time(), Time());
1629   extension_info.reset(new AssociatedExtensionInfo);
1630   extension_info->wants_to_be_default_engine = true;
1631   extension_info->extension_id = "ext2";
1632   model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
1633   EXPECT_EQ(ext_dse, model()->GetDefaultSearchProvider());
1634
1635   test_util_.ResetModel(true);
1636   user_dse = model()->GetTemplateURLForKeyword(ASCIIToUTF16("user"));
1637   ExpectSimilar(user_dse, model()->GetDefaultSearchProvider());
1638   EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext1")));
1639   EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext2")));
1640 }
1641
1642 TEST_F(TemplateURLServiceTest, ExtensionEngineVsPolicy) {
1643   // Set a managed preference that establishes a default search provider.
1644   const char kName[] = "test";
1645   const char kKeyword[] = "test.com";
1646   const char kSearchURL[] = "http://test.com/search?t={searchTerms}";
1647   const char kIconURL[] = "http://test.com/icon.jpg";
1648   const char kEncodings[] = "UTF-16;UTF-32";
1649   const char kAlternateURL[] = "http://test.com/search#t={searchTerms}";
1650   const char kSearchTermsReplacementKey[] = "espv";
1651   test_util_.SetManagedDefaultSearchPreferences(
1652       true, kName, kKeyword, kSearchURL, std::string(), kIconURL, kEncodings,
1653       kAlternateURL, kSearchTermsReplacementKey);
1654   test_util_.VerifyLoad();
1655   // Verify that the default manager we are getting is the managed one.
1656   TemplateURLData data;
1657   data.short_name = ASCIIToUTF16(kName);
1658   data.SetKeyword(ASCIIToUTF16(kKeyword));
1659   data.SetURL(kSearchURL);
1660   data.favicon_url = GURL(kIconURL);
1661   data.show_in_default_list = true;
1662   base::SplitString(kEncodings, ';', &data.input_encodings);
1663   data.alternate_urls.push_back(kAlternateURL);
1664   data.search_terms_replacement_key = kSearchTermsReplacementKey;
1665   scoped_ptr<TemplateURL> expected_managed_default(new TemplateURL(
1666       test_util_.profile(), data));
1667   EXPECT_TRUE(model()->is_default_search_managed());
1668   const TemplateURL* actual_managed_default =
1669       model()->GetDefaultSearchProvider();
1670   ExpectSimilar(expected_managed_default.get(), actual_managed_default);
1671
1672   TemplateURL* ext_dse = CreateKeywordWithDate(
1673       model(), "ext1", "ext1", "http://www.ext1.com/s?q={searchTerms}",
1674       std::string(), std::string(), std::string(),
1675       true, "UTF-8", Time(), Time());
1676   scoped_ptr<AssociatedExtensionInfo> extension_info(
1677       new AssociatedExtensionInfo);
1678   extension_info->wants_to_be_default_engine = true;
1679   extension_info->extension_id = "ext1";
1680   model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
1681   EXPECT_EQ(ext_dse, model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext1")));
1682   EXPECT_TRUE(model()->is_default_search_managed());
1683   actual_managed_default = model()->GetDefaultSearchProvider();
1684   ExpectSimilar(expected_managed_default.get(), actual_managed_default);
1685 }