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