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.
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/task/cancelable_task_tracker.h"
15 #include "base/test/mock_time_provider.h"
16 #include "base/threading/thread.h"
17 #include "base/time/time.h"
18 #include "chrome/browser/history/history_service.h"
19 #include "chrome/browser/history/history_service_factory.h"
20 #include "chrome/browser/search_engines/template_url_service_test_util.h"
21 #include "chrome/test/base/testing_profile.h"
22 #include "components/search_engines/keyword_web_data_service.h"
23 #include "components/search_engines/search_host_to_urls_map.h"
24 #include "components/search_engines/search_terms_data.h"
25 #include "components/search_engines/template_url.h"
26 #include "components/search_engines/template_url_prepopulate_data.h"
27 #include "components/search_engines/template_url_service.h"
28 #include "content/public/test/test_browser_thread_bundle.h"
29 #include "testing/gtest/include/gtest/gtest.h"
31 using base::ASCIIToUTF16;
33 using base::TimeDelta;
34 using ::testing::Return;
35 using ::testing::StrictMock;
39 // QueryHistoryCallbackImpl ---------------------------------------------------
41 struct QueryHistoryCallbackImpl {
42 QueryHistoryCallbackImpl() : success(false) {}
44 void Callback(bool success,
45 const history::URLRow& row,
46 const history::VisitVector& visits) {
47 this->success = success;
50 this->visits = visits;
56 history::VisitVector visits;
59 TemplateURL* CreateKeywordWithDate(
60 TemplateURLService* model,
61 const std::string& short_name,
62 const std::string& keyword,
63 const std::string& url,
64 const std::string& suggest_url,
65 const std::string& alternate_url,
66 const std::string& favicon_url,
67 bool safe_for_autoreplace,
68 bool show_in_default_list,
69 const std::string& encodings,
73 data.short_name = base::UTF8ToUTF16(short_name);
74 data.SetKeyword(base::UTF8ToUTF16(keyword));
76 data.suggestions_url = suggest_url;
77 if (!alternate_url.empty())
78 data.alternate_urls.push_back(alternate_url);
79 data.favicon_url = GURL(favicon_url);
80 data.safe_for_autoreplace = safe_for_autoreplace;
81 data.show_in_default_list = show_in_default_list;
82 base::SplitString(encodings, ';', &data.input_encodings);
83 data.date_created = date_created;
84 data.last_modified = last_modified;
85 return new TemplateURL(data);
88 TemplateURL* AddKeywordWithDate(
89 TemplateURLService* model,
90 const std::string& short_name,
91 const std::string& keyword,
92 const std::string& url,
93 const std::string& suggest_url,
94 const std::string& alternate_url,
95 const std::string& favicon_url,
96 bool safe_for_autoreplace,
97 const std::string& encodings,
100 TemplateURL* t_url = CreateKeywordWithDate(
101 model, short_name, keyword, url, suggest_url, alternate_url,favicon_url,
102 safe_for_autoreplace, false, encodings, date_created, last_modified);
104 EXPECT_NE(0, t_url->id());
108 // Checks that the two TemplateURLs are similar. It does not check the id, the
109 // date_created or the last_modified time. Neither pointer should be NULL.
110 void ExpectSimilar(const TemplateURL* expected, const TemplateURL* actual) {
111 ASSERT_TRUE(expected != NULL);
112 ASSERT_TRUE(actual != NULL);
113 EXPECT_EQ(expected->short_name(), actual->short_name());
114 EXPECT_EQ(expected->keyword(), actual->keyword());
115 EXPECT_EQ(expected->url(), actual->url());
116 EXPECT_EQ(expected->suggestions_url(), actual->suggestions_url());
117 EXPECT_EQ(expected->favicon_url(), actual->favicon_url());
118 EXPECT_EQ(expected->alternate_urls(), actual->alternate_urls());
119 EXPECT_EQ(expected->show_in_default_list(), actual->show_in_default_list());
120 EXPECT_EQ(expected->safe_for_autoreplace(), actual->safe_for_autoreplace());
121 EXPECT_EQ(expected->input_encodings(), actual->input_encodings());
122 EXPECT_EQ(expected->search_terms_replacement_key(),
123 actual->search_terms_replacement_key());
129 // TemplateURLServiceTest -----------------------------------------------------
131 class TemplateURLServiceTest : public testing::Test {
133 TemplateURLServiceTest();
136 virtual void SetUp() OVERRIDE;
137 virtual void TearDown() OVERRIDE;
139 TemplateURL* AddKeywordWithDate(const std::string& short_name,
140 const std::string& keyword,
141 const std::string& url,
142 const std::string& suggest_url,
143 const std::string& alternate_url,
144 const std::string& favicon_url,
145 bool safe_for_autoreplace,
146 const std::string& encodings,
150 // Verifies the two TemplateURLs are equal.
151 void AssertEquals(const TemplateURL& expected, const TemplateURL& actual);
153 // Create an URL that appears to have been prepopulated, but won't be in the
154 // current data. The caller owns the returned TemplateURL*.
155 TemplateURL* CreatePreloadedTemplateURL(bool safe_for_autoreplace,
158 // Helper methods to make calling TemplateURLServiceTestUtil methods less
159 // visually noisy in the test code.
160 void VerifyObserverCount(int expected_changed_count);
161 void VerifyObserverFired();
162 TemplateURLServiceTestUtil* test_util() { return test_util_.get(); }
163 TemplateURLService* model() { return test_util_->model(); }
164 const SearchTermsData& search_terms_data() {
165 return model()->search_terms_data();
169 content::TestBrowserThreadBundle thread_bundle_; // To set up BrowserThreads.
170 scoped_ptr<TemplateURLServiceTestUtil> test_util_;
172 DISALLOW_COPY_AND_ASSIGN(TemplateURLServiceTest);
175 class TemplateURLServiceWithoutFallbackTest : public TemplateURLServiceTest {
177 TemplateURLServiceWithoutFallbackTest() : TemplateURLServiceTest() {}
179 virtual void SetUp() OVERRIDE {
180 DefaultSearchManager::SetFallbackSearchEnginesDisabledForTesting(true);
181 TemplateURLServiceTest::SetUp();
184 virtual void TearDown() OVERRIDE {
185 TemplateURLServiceTest::TearDown();
186 DefaultSearchManager::SetFallbackSearchEnginesDisabledForTesting(false);
190 TemplateURLServiceTest::TemplateURLServiceTest() {
193 void TemplateURLServiceTest::SetUp() {
194 test_util_.reset(new TemplateURLServiceTestUtil);
197 void TemplateURLServiceTest::TearDown() {
201 TemplateURL* TemplateURLServiceTest::AddKeywordWithDate(
202 const std::string& short_name,
203 const std::string& keyword,
204 const std::string& url,
205 const std::string& suggest_url,
206 const std::string& alternate_url,
207 const std::string& favicon_url,
208 bool safe_for_autoreplace,
209 const std::string& encodings,
211 Time last_modified) {
212 return ::AddKeywordWithDate(model(), short_name, keyword, url, suggest_url,
213 alternate_url, favicon_url, safe_for_autoreplace,
214 encodings, date_created, last_modified);
217 void TemplateURLServiceTest::AssertEquals(const TemplateURL& expected,
218 const TemplateURL& actual) {
219 ASSERT_EQ(expected.short_name(), actual.short_name());
220 ASSERT_EQ(expected.keyword(), actual.keyword());
221 ASSERT_EQ(expected.url(), actual.url());
222 ASSERT_EQ(expected.suggestions_url(), actual.suggestions_url());
223 ASSERT_EQ(expected.favicon_url(), actual.favicon_url());
224 ASSERT_EQ(expected.alternate_urls(), actual.alternate_urls());
225 ASSERT_EQ(expected.show_in_default_list(), actual.show_in_default_list());
226 ASSERT_EQ(expected.safe_for_autoreplace(), actual.safe_for_autoreplace());
227 ASSERT_EQ(expected.input_encodings(), actual.input_encodings());
228 ASSERT_EQ(expected.id(), actual.id());
229 ASSERT_EQ(expected.date_created(), actual.date_created());
230 ASSERT_EQ(expected.last_modified(), actual.last_modified());
231 ASSERT_EQ(expected.sync_guid(), actual.sync_guid());
232 ASSERT_EQ(expected.search_terms_replacement_key(),
233 actual.search_terms_replacement_key());
236 TemplateURL* TemplateURLServiceTest::CreatePreloadedTemplateURL(
237 bool safe_for_autoreplace,
238 int prepopulate_id) {
239 TemplateURLData data;
240 data.short_name = ASCIIToUTF16("unittest");
241 data.SetKeyword(ASCIIToUTF16("unittest"));
242 data.SetURL("http://www.unittest.com/{searchTerms}");
243 data.favicon_url = GURL("http://favicon.url");
244 data.show_in_default_list = true;
245 data.safe_for_autoreplace = safe_for_autoreplace;
246 data.input_encodings.push_back("UTF-8");
247 data.date_created = Time::FromTimeT(100);
248 data.last_modified = Time::FromTimeT(100);
249 data.prepopulate_id = prepopulate_id;
250 return new TemplateURL(data);
253 void TemplateURLServiceTest::VerifyObserverCount(int expected_changed_count) {
254 EXPECT_EQ(expected_changed_count, test_util_->GetObserverCount());
255 test_util_->ResetObserverCount();
258 void TemplateURLServiceTest::VerifyObserverFired() {
259 EXPECT_LE(1, test_util_->GetObserverCount());
260 test_util_->ResetObserverCount();
264 // Actual tests ---------------------------------------------------------------
266 TEST_F(TemplateURLServiceTest, Load) {
267 test_util()->VerifyLoad();
270 TEST_F(TemplateURLServiceTest, AddUpdateRemove) {
271 // Add a new TemplateURL.
272 test_util()->VerifyLoad();
273 const size_t initial_count = model()->GetTemplateURLs().size();
275 TemplateURLData data;
276 data.short_name = ASCIIToUTF16("google");
277 data.SetKeyword(ASCIIToUTF16("keyword"));
278 data.SetURL("http://www.google.com/foo/bar");
279 data.favicon_url = GURL("http://favicon.url");
280 data.safe_for_autoreplace = true;
281 data.date_created = Time::FromTimeT(100);
282 data.last_modified = Time::FromTimeT(100);
283 data.sync_guid = "00000000-0000-0000-0000-000000000001";
284 TemplateURL* t_url = new TemplateURL(data);
286 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"), GURL(),
288 VerifyObserverCount(1);
289 base::RunLoop().RunUntilIdle();
290 ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
291 ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(t_url->keyword()));
292 // We need to make a second copy as the model takes ownership of |t_url| and
293 // will delete it. We have to do this after calling Add() since that gives
295 scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->data()));
297 // Reload the model to verify it was actually saved to the database.
298 test_util()->ResetModel(true);
299 ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
300 TemplateURL* loaded_url =
301 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
302 ASSERT_TRUE(loaded_url != NULL);
303 AssertEquals(*cloned_url, *loaded_url);
304 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"), GURL(),
307 // We expect the last_modified time to be updated to the present time on an
308 // explicit reset. We have to set up the expectation here because ResetModel
309 // resets the TimeProvider in the TemplateURLService.
310 StrictMock<base::MockTimeProvider> mock_time;
311 model()->set_time_provider(&base::MockTimeProvider::StaticNow);
312 EXPECT_CALL(mock_time, Now()).WillOnce(Return(base::Time::FromDoubleT(1337)));
314 // Mutate an element and verify it succeeded.
315 model()->ResetTemplateURL(loaded_url, ASCIIToUTF16("a"), ASCIIToUTF16("b"),
317 ASSERT_EQ(ASCIIToUTF16("a"), loaded_url->short_name());
318 ASSERT_EQ(ASCIIToUTF16("b"), loaded_url->keyword());
319 ASSERT_EQ("c", loaded_url->url());
320 ASSERT_FALSE(loaded_url->safe_for_autoreplace());
321 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"), GURL(),
323 ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("b"), GURL(), NULL));
324 cloned_url.reset(new TemplateURL(loaded_url->data()));
325 base::RunLoop().RunUntilIdle();
326 test_util()->ResetModel(true);
327 ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
328 loaded_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("b"));
329 ASSERT_TRUE(loaded_url != NULL);
330 AssertEquals(*cloned_url, *loaded_url);
331 // We changed a TemplateURL in the service, so ensure that the time was
333 ASSERT_EQ(base::Time::FromDoubleT(1337), loaded_url->last_modified());
335 // Remove an element and verify it succeeded.
336 model()->Remove(loaded_url);
337 VerifyObserverCount(1);
338 test_util()->ResetModel(true);
339 ASSERT_EQ(initial_count, model()->GetTemplateURLs().size());
340 EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("b")) == NULL);
343 TEST_F(TemplateURLServiceTest, AddSameKeyword) {
344 test_util()->VerifyLoad();
347 "first", "keyword", "http://test1", std::string(), std::string(),
348 std::string(), true, "UTF-8", Time(), Time());
349 VerifyObserverCount(1);
351 // Test what happens when we try to add a TemplateURL with the same keyword as
353 TemplateURLData data;
354 data.short_name = ASCIIToUTF16("second");
355 data.SetKeyword(ASCIIToUTF16("keyword"));
356 data.SetURL("http://test2");
357 data.safe_for_autoreplace = false;
358 TemplateURL* t_url = new TemplateURL(data);
361 // Because the old TemplateURL was replaceable and the new one wasn't, the new
362 // one should have replaced the old.
363 VerifyObserverCount(1);
364 EXPECT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
365 EXPECT_EQ(ASCIIToUTF16("second"), t_url->short_name());
366 EXPECT_EQ(ASCIIToUTF16("keyword"), t_url->keyword());
367 EXPECT_FALSE(t_url->safe_for_autoreplace());
369 // Now try adding a replaceable TemplateURL. This should just delete the
371 data.short_name = ASCIIToUTF16("third");
372 data.SetURL("http://test3");
373 data.safe_for_autoreplace = true;
374 model()->Add(new TemplateURL(data));
375 VerifyObserverCount(0);
376 EXPECT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
377 EXPECT_EQ(ASCIIToUTF16("second"), t_url->short_name());
378 EXPECT_EQ(ASCIIToUTF16("keyword"), t_url->keyword());
379 EXPECT_FALSE(t_url->safe_for_autoreplace());
381 // Now try adding a non-replaceable TemplateURL again. This should uniquify
382 // the existing entry's keyword.
383 data.short_name = ASCIIToUTF16("fourth");
384 data.SetURL("http://test4");
385 data.safe_for_autoreplace = false;
386 TemplateURL* t_url2 = new TemplateURL(data);
387 model()->Add(t_url2);
388 VerifyObserverCount(1);
389 EXPECT_EQ(t_url2, model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
390 EXPECT_EQ(ASCIIToUTF16("fourth"), t_url2->short_name());
391 EXPECT_EQ(ASCIIToUTF16("keyword"), t_url2->keyword());
392 EXPECT_EQ(ASCIIToUTF16("second"), t_url->short_name());
393 EXPECT_EQ(ASCIIToUTF16("test2"), t_url->keyword());
396 TEST_F(TemplateURLServiceTest, AddExtensionKeyword) {
397 test_util()->VerifyLoad();
399 TemplateURL* original1 = AddKeywordWithDate(
400 "replaceable", "keyword1", "http://test1", std::string(), std::string(),
401 std::string(), true, "UTF-8", Time(), Time());
402 TemplateURL* original2 = AddKeywordWithDate(
403 "nonreplaceable", "keyword2", "http://test2", std::string(),
404 std::string(), std::string(), false, "UTF-8", Time(), Time());
405 model()->RegisterOmniboxKeyword("test3", "extension", "keyword3",
407 TemplateURL* original3 =
408 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword3"));
409 ASSERT_TRUE(original3);
411 // Add an extension keyword that conflicts with each of the above three
413 // Both replaceable and non-replaceable keywords should be uniquified.
414 model()->RegisterOmniboxKeyword("test4", "test", "keyword1", "http://test4");
415 TemplateURL* extension1 =
416 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword1"));
417 ASSERT_TRUE(extension1);
419 model()->GetTemplateURLForKeyword(ASCIIToUTF16("test1")));
421 model()->RegisterOmniboxKeyword("test5", "test", "keyword2", "http://test5");
422 TemplateURL* extension2 =
423 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword2"));
424 ASSERT_TRUE(extension2);
426 model()->GetTemplateURLForKeyword(ASCIIToUTF16("test2")));
428 // They should override extension keywords added earlier.
429 model()->RegisterOmniboxKeyword("test6", "test", "keyword3", "http://test6");
430 TemplateURL* extension3 =
431 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword3"));
432 ASSERT_TRUE(extension3);
434 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword3_")));
437 TEST_F(TemplateURLServiceTest, AddSameKeywordWithExtensionPresent) {
438 test_util()->VerifyLoad();
440 // Similar to the AddSameKeyword test, but with an extension keyword masking a
441 // replaceable TemplateURL. We should still do correct conflict resolution
442 // between the non-template URLs.
443 model()->RegisterOmniboxKeyword("test2", "extension", "keyword",
445 TemplateURL* extension =
446 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
447 ASSERT_TRUE(extension);
448 // Adding a keyword that matches the extension should cause the extension
451 "replaceable", "keyword", "http://test1", std::string(), std::string(),
452 std::string(), true, "UTF-8", Time(), Time());
454 // Adding another replaceable keyword should remove the existing one, but
455 // leave the extension as is.
456 TemplateURLData data;
457 data.short_name = ASCIIToUTF16("name1");
458 data.SetKeyword(ASCIIToUTF16("keyword"));
459 data.SetURL("http://test3");
460 data.safe_for_autoreplace = true;
461 TemplateURL* t_url = new TemplateURL(data);
464 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword_")));
465 EXPECT_TRUE(model()->GetTemplateURLForHost("test1") == NULL);
466 EXPECT_EQ(t_url, model()->GetTemplateURLForHost("test3"));
468 // Adding a nonreplaceable keyword should remove the existing replaceable
470 data.short_name = ASCIIToUTF16("name2");
471 data.SetURL("http://test4");
472 data.safe_for_autoreplace = false;
473 TemplateURL* t_url2 = new TemplateURL(data);
474 model()->Add(t_url2);
476 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
477 EXPECT_TRUE(model()->GetTemplateURLForHost("test3") == NULL);
479 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword_")));
482 TEST_F(TemplateURLServiceTest, RestoreOmniboxExtensionKeyword) {
483 test_util()->VerifyLoad();
485 // Register an omnibox keyword.
486 model()->RegisterOmniboxKeyword("test", "extension", "keyword",
487 "chrome-extension://test");
488 ASSERT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
491 test_util()->ResetModel(true);
493 // Ensure the omnibox keyword is restored correctly.
495 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
497 ASSERT_EQ(TemplateURL::OMNIBOX_API_EXTENSION, t_url->GetType());
498 EXPECT_EQ("test", t_url->GetExtensionId());
501 TEST_F(TemplateURLServiceTest, ClearBrowsingData_Keywords) {
502 Time now = Time::Now();
503 TimeDelta one_day = TimeDelta::FromDays(1);
504 Time month_ago = now - TimeDelta::FromDays(30);
506 // Nothing has been added.
507 EXPECT_EQ(0U, model()->GetTemplateURLs().size());
509 // Create one with a 0 time.
510 AddKeywordWithDate("name1", "key1", "http://foo1", "http://suggest1",
511 std::string(), "http://icon1", true, "UTF-8;UTF-16",
513 // Create one for now and +/- 1 day.
514 AddKeywordWithDate("name2", "key2", "http://foo2", "http://suggest2",
515 std::string(), "http://icon2", true, "UTF-8;UTF-16",
516 now - one_day, Time());
517 AddKeywordWithDate("name3", "key3", "http://foo3", std::string(),
518 std::string(), std::string(), true, std::string(), now,
520 AddKeywordWithDate("name4", "key4", "http://foo4", std::string(),
521 std::string(), std::string(), true, std::string(),
522 now + one_day, Time());
523 // Try the other three states.
524 AddKeywordWithDate("name5", "key5", "http://foo5", "http://suggest5",
525 std::string(), "http://icon5", false, "UTF-8;UTF-16", now,
527 AddKeywordWithDate("name6", "key6", "http://foo6", "http://suggest6",
528 std::string(), "http://icon6", false, "UTF-8;UTF-16",
531 // We just added a few items, validate them.
532 EXPECT_EQ(6U, model()->GetTemplateURLs().size());
534 // Try removing from current timestamp. This should delete the one in the
535 // future and one very recent one.
536 model()->RemoveAutoGeneratedSince(now);
537 EXPECT_EQ(4U, model()->GetTemplateURLs().size());
539 // Try removing from two months ago. This should only delete items that are
541 model()->RemoveAutoGeneratedBetween(now - TimeDelta::FromDays(60), now);
542 EXPECT_EQ(3U, model()->GetTemplateURLs().size());
544 // Make sure the right values remain.
545 EXPECT_EQ(ASCIIToUTF16("key1"), model()->GetTemplateURLs()[0]->keyword());
546 EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
548 model()->GetTemplateURLs()[0]->date_created().ToInternalValue());
550 EXPECT_EQ(ASCIIToUTF16("key5"), model()->GetTemplateURLs()[1]->keyword());
551 EXPECT_FALSE(model()->GetTemplateURLs()[1]->safe_for_autoreplace());
552 EXPECT_EQ(now.ToInternalValue(),
553 model()->GetTemplateURLs()[1]->date_created().ToInternalValue());
555 EXPECT_EQ(ASCIIToUTF16("key6"), model()->GetTemplateURLs()[2]->keyword());
556 EXPECT_FALSE(model()->GetTemplateURLs()[2]->safe_for_autoreplace());
557 EXPECT_EQ(month_ago.ToInternalValue(),
558 model()->GetTemplateURLs()[2]->date_created().ToInternalValue());
560 // Try removing from Time=0. This should delete one more.
561 model()->RemoveAutoGeneratedSince(Time());
562 EXPECT_EQ(2U, model()->GetTemplateURLs().size());
565 TEST_F(TemplateURLServiceTest, ClearBrowsingData_KeywordsForOrigin) {
566 Time now = Time::Now();
567 TimeDelta one_day = TimeDelta::FromDays(1);
568 Time month_ago = now - TimeDelta::FromDays(30);
570 // Nothing has been added.
571 EXPECT_EQ(0U, model()->GetTemplateURLs().size());
573 // Create one for now and +/- 1 day.
574 AddKeywordWithDate("name1", "key1", "http://foo1", "http://suggest1",
575 std::string(), "http://icon2", true, "UTF-8;UTF-16",
576 now - one_day, Time());
577 AddKeywordWithDate("name2", "key2", "http://foo2", std::string(),
578 std::string(), std::string(), true, std::string(), now,
580 AddKeywordWithDate("name3", "key3", "http://foo3", std::string(),
581 std::string(), std::string(), true, std::string(),
582 now + one_day, Time());
584 // We just added a few items, validate them.
585 EXPECT_EQ(3U, model()->GetTemplateURLs().size());
587 // Try removing foo2. This should delete foo2, but leave foo1 and 3 untouched.
588 model()->RemoveAutoGeneratedForOriginBetween(GURL("http://foo2"), month_ago,
590 EXPECT_EQ(2U, model()->GetTemplateURLs().size());
591 EXPECT_EQ(ASCIIToUTF16("key1"), model()->GetTemplateURLs()[0]->keyword());
592 EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
593 EXPECT_EQ(ASCIIToUTF16("key3"), model()->GetTemplateURLs()[1]->keyword());
594 EXPECT_TRUE(model()->GetTemplateURLs()[1]->safe_for_autoreplace());
596 // Try removing foo1, but outside the range in which it was modified. It
597 // should remain untouched.
598 model()->RemoveAutoGeneratedForOriginBetween(GURL("http://foo1"), now,
600 EXPECT_EQ(2U, model()->GetTemplateURLs().size());
601 EXPECT_EQ(ASCIIToUTF16("key1"), model()->GetTemplateURLs()[0]->keyword());
602 EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
603 EXPECT_EQ(ASCIIToUTF16("key3"), model()->GetTemplateURLs()[1]->keyword());
604 EXPECT_TRUE(model()->GetTemplateURLs()[1]->safe_for_autoreplace());
607 // Try removing foo3. This should delete foo3, but leave foo1 untouched.
608 model()->RemoveAutoGeneratedForOriginBetween(GURL("http://foo3"), month_ago,
609 now + one_day + one_day);
610 EXPECT_EQ(1U, model()->GetTemplateURLs().size());
611 EXPECT_EQ(ASCIIToUTF16("key1"), model()->GetTemplateURLs()[0]->keyword());
612 EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
615 TEST_F(TemplateURLServiceTest, Reset) {
616 // Add a new TemplateURL.
617 test_util()->VerifyLoad();
618 const size_t initial_count = model()->GetTemplateURLs().size();
619 TemplateURLData data;
620 data.short_name = ASCIIToUTF16("google");
621 data.SetKeyword(ASCIIToUTF16("keyword"));
622 data.SetURL("http://www.google.com/foo/bar");
623 data.favicon_url = GURL("http://favicon.url");
624 data.date_created = Time::FromTimeT(100);
625 data.last_modified = Time::FromTimeT(100);
626 TemplateURL* t_url = new TemplateURL(data);
629 VerifyObserverCount(1);
630 base::RunLoop().RunUntilIdle();
632 StrictMock<base::MockTimeProvider> mock_time;
633 model()->set_time_provider(&base::MockTimeProvider::StaticNow);
634 EXPECT_CALL(mock_time, Now()).WillOnce(Return(base::Time::FromDoubleT(1337)));
636 // Reset the short name, keyword, url and make sure it takes.
637 const base::string16 new_short_name(ASCIIToUTF16("a"));
638 const base::string16 new_keyword(ASCIIToUTF16("b"));
639 const std::string new_url("c");
640 model()->ResetTemplateURL(t_url, new_short_name, new_keyword, new_url);
641 ASSERT_EQ(new_short_name, t_url->short_name());
642 ASSERT_EQ(new_keyword, t_url->keyword());
643 ASSERT_EQ(new_url, t_url->url());
645 // Make sure the mappings in the model were updated.
646 ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(new_keyword));
648 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")) == NULL);
650 scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->data()));
652 // Reload the model from the database and make sure the change took.
653 test_util()->ResetModel(true);
654 EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
655 const TemplateURL* read_url = model()->GetTemplateURLForKeyword(new_keyword);
656 ASSERT_TRUE(read_url);
657 AssertEquals(*cloned_url, *read_url);
658 ASSERT_EQ(base::Time::FromDoubleT(1337), read_url->last_modified());
661 TEST_F(TemplateURLServiceTest, DefaultSearchProvider) {
662 // Add a new TemplateURL.
663 test_util()->VerifyLoad();
664 const size_t initial_count = model()->GetTemplateURLs().size();
665 TemplateURL* t_url = AddKeywordWithDate(
666 "name1", "key1", "http://foo1/{searchTerms}", "http://sugg1",
667 std::string(), "http://icon1", true, "UTF-8;UTF-16", Time(), Time());
668 test_util()->ResetObserverCount();
670 model()->SetUserSelectedDefaultSearchProvider(t_url);
671 ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());
672 ASSERT_TRUE(t_url->safe_for_autoreplace());
673 ASSERT_TRUE(t_url->show_in_default_list());
675 // Setting the default search provider should have caused notification.
676 VerifyObserverCount(1);
677 base::RunLoop().RunUntilIdle();
679 scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->data()));
681 // Make sure when we reload we get a default search provider.
682 test_util()->ResetModel(true);
683 EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
684 ASSERT_TRUE(model()->GetDefaultSearchProvider());
685 AssertEquals(*cloned_url, *model()->GetDefaultSearchProvider());
688 TEST_F(TemplateURLServiceTest, CantReplaceWithSameKeyword) {
689 test_util()->ChangeModelToLoadState();
690 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"), GURL(), NULL));
691 TemplateURL* t_url = AddKeywordWithDate(
692 "name1", "foo", "http://foo1", "http://sugg1", std::string(),
693 "http://icon1", true, "UTF-8;UTF-16", Time(), Time());
695 // Can still replace, newly added template url is marked safe to replace.
696 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
697 GURL("http://foo2"), NULL));
699 // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
700 // no longer be replaceable.
701 model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
704 ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
705 GURL("http://foo2"), NULL));
708 TEST_F(TemplateURLServiceTest, CantReplaceWithSameHosts) {
709 test_util()->ChangeModelToLoadState();
710 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
711 GURL("http://foo.com"), NULL));
712 TemplateURL* t_url = AddKeywordWithDate(
713 "name1", "foo", "http://foo.com", "http://sugg1", std::string(),
714 "http://icon1", true, "UTF-8;UTF-16", Time(), Time());
716 // Can still replace, newly added template url is marked safe to replace.
717 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("bar"),
718 GURL("http://foo.com"), NULL));
720 // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
721 // no longer be replaceable.
722 model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
725 ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("bar"),
726 GURL("http://foo.com"), NULL));
729 TEST_F(TemplateURLServiceTest, HasDefaultSearchProvider) {
730 // We should have a default search provider even if we haven't loaded.
731 ASSERT_TRUE(model()->GetDefaultSearchProvider());
733 // Now force the model to load and make sure we still have a default.
734 test_util()->VerifyLoad();
736 ASSERT_TRUE(model()->GetDefaultSearchProvider());
739 TEST_F(TemplateURLServiceTest, DefaultSearchProviderLoadedFromPrefs) {
740 test_util()->VerifyLoad();
742 TemplateURLData data;
743 data.short_name = ASCIIToUTF16("a");
744 data.safe_for_autoreplace = true;
745 data.SetURL("http://url/{searchTerms}");
746 data.suggestions_url = "http://url2";
747 data.instant_url = "http://instant";
748 data.date_created = Time::FromTimeT(100);
749 data.last_modified = Time::FromTimeT(100);
750 TemplateURL* t_url = new TemplateURL(data);
752 const TemplateURLID id = t_url->id();
754 model()->SetUserSelectedDefaultSearchProvider(t_url);
755 base::RunLoop().RunUntilIdle();
756 scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->data()));
758 // Reset the model and don't load it. The template url we set as the default
759 // should be pulled from prefs now.
760 test_util()->ResetModel(false);
762 // NOTE: This doesn't use AssertEquals as only a subset of the TemplateURLs
763 // value are persisted to prefs.
764 const TemplateURL* default_turl = model()->GetDefaultSearchProvider();
765 ASSERT_TRUE(default_turl);
766 EXPECT_EQ(ASCIIToUTF16("a"), default_turl->short_name());
767 EXPECT_EQ("http://url/{searchTerms}", default_turl->url());
768 EXPECT_EQ("http://url2", default_turl->suggestions_url());
769 EXPECT_EQ("http://instant", default_turl->instant_url());
770 EXPECT_EQ(id, default_turl->id());
772 // Now do a load and make sure the default search provider really takes.
773 test_util()->VerifyLoad();
775 ASSERT_TRUE(model()->GetDefaultSearchProvider());
776 AssertEquals(*cloned_url, *model()->GetDefaultSearchProvider());
779 TEST_F(TemplateURLServiceTest, RepairPrepopulatedSearchEngines) {
780 test_util()->VerifyLoad();
782 // Edit Google search engine.
783 TemplateURL* google = model()->GetTemplateURLForKeyword(
784 ASCIIToUTF16("google.com"));
786 model()->ResetTemplateURL(google, ASCIIToUTF16("trash"), ASCIIToUTF16("xxx"),
787 "http://www.foo.com/s?q={searchTerms}");
788 EXPECT_EQ(ASCIIToUTF16("trash"), google->short_name());
789 EXPECT_EQ(ASCIIToUTF16("xxx"), google->keyword());
791 // Add third-party default search engine.
792 TemplateURL* user_dse = AddKeywordWithDate(
793 "malware", "google.com", "http://www.goo.com/s?q={searchTerms}",
794 std::string(), std::string(), std::string(),
795 true, "UTF-8", Time(), Time());
796 model()->SetUserSelectedDefaultSearchProvider(user_dse);
797 EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider());
800 TemplateURL* bing = model()->GetTemplateURLForKeyword(
801 ASCIIToUTF16("bing.com"));
803 model()->Remove(bing);
804 EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("bing.com")));
806 // Register an extension with bing keyword.
807 model()->RegisterOmniboxKeyword("abcdefg", "extension_name", "bing.com",
809 EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("bing.com")));
811 model()->RepairPrepopulatedSearchEngines();
813 // Google is default.
814 ASSERT_EQ(google, model()->GetDefaultSearchProvider());
815 // The keyword wasn't reverted.
816 EXPECT_EQ(ASCIIToUTF16("trash"), google->short_name());
817 EXPECT_EQ("www.google.com",
818 google->GenerateSearchURL(model()->search_terms_data()).host());
820 // Bing was repaired.
821 bing = model()->GetTemplateURLForKeyword(ASCIIToUTF16("bing.com"));
823 EXPECT_EQ(TemplateURL::NORMAL, bing->GetType());
825 // User search engine is preserved.
826 EXPECT_EQ(user_dse, model()->GetTemplateURLForHost("www.goo.com"));
827 EXPECT_EQ(ASCIIToUTF16("google.com"), user_dse->keyword());
830 TEST_F(TemplateURLServiceTest, RepairSearchEnginesWithManagedDefault) {
831 // Set a managed preference that establishes a default search provider.
832 const char kName[] = "test1";
833 const char kKeyword[] = "test.com";
834 const char kSearchURL[] = "http://test.com/search?t={searchTerms}";
835 const char kIconURL[] = "http://test.com/icon.jpg";
836 const char kEncodings[] = "UTF-16;UTF-32";
837 const char kAlternateURL[] = "http://test.com/search#t={searchTerms}";
838 const char kSearchTermsReplacementKey[] = "espv";
839 test_util()->SetManagedDefaultSearchPreferences(true, kName, kKeyword,
840 kSearchURL, std::string(),
841 kIconURL, kEncodings,
843 kSearchTermsReplacementKey);
844 test_util()->VerifyLoad();
845 // Verify that the default manager we are getting is the managed one.
846 TemplateURLData data;
847 data.short_name = ASCIIToUTF16(kName);
848 data.SetKeyword(ASCIIToUTF16(kKeyword));
849 data.SetURL(kSearchURL);
850 data.favicon_url = GURL(kIconURL);
851 data.show_in_default_list = true;
852 base::SplitString(kEncodings, ';', &data.input_encodings);
853 data.alternate_urls.push_back(kAlternateURL);
854 data.search_terms_replacement_key = kSearchTermsReplacementKey;
855 scoped_ptr<TemplateURL> expected_managed_default(new TemplateURL(data));
856 EXPECT_TRUE(model()->is_default_search_managed());
857 const TemplateURL* actual_managed_default =
858 model()->GetDefaultSearchProvider();
859 ExpectSimilar(expected_managed_default.get(), actual_managed_default);
861 // The following call has no effect on the managed search engine.
862 model()->RepairPrepopulatedSearchEngines();
864 EXPECT_TRUE(model()->is_default_search_managed());
865 actual_managed_default = model()->GetDefaultSearchProvider();
866 ExpectSimilar(expected_managed_default.get(), actual_managed_default);
869 TEST_F(TemplateURLServiceTest, UpdateKeywordSearchTermsForURL) {
871 const std::string url;
872 const base::string16 term;
874 { "http://foo/", base::string16() },
875 { "http://foo/foo?q=xx", base::string16() },
876 { "http://x/bar?q=xx", base::string16() },
877 { "http://x/foo?y=xx", base::string16() },
878 { "http://x/foo?q=xx", ASCIIToUTF16("xx") },
879 { "http://x/foo?a=b&q=xx", ASCIIToUTF16("xx") },
880 { "http://x/foo?q=b&q=xx", base::string16() },
881 { "http://x/foo#query=xx", ASCIIToUTF16("xx") },
882 { "http://x/foo?q=b#query=xx", ASCIIToUTF16("xx") },
883 { "http://x/foo?q=b#q=xx", ASCIIToUTF16("b") },
884 { "http://x/foo?query=b#q=xx", base::string16() },
887 test_util()->ChangeModelToLoadState();
888 AddKeywordWithDate("name", "x", "http://x/foo?q={searchTerms}",
889 "http://sugg1", "http://x/foo#query={searchTerms}",
890 "http://icon1", false, "UTF-8;UTF-16", Time(), Time());
892 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
893 TemplateURLService::URLVisitedDetails details = {
894 GURL(data[i].url), false
896 model()->UpdateKeywordSearchTermsForURL(details);
897 EXPECT_EQ(data[i].term, test_util()->GetAndClearSearchTerm());
901 TEST_F(TemplateURLServiceTest, DontUpdateKeywordSearchForNonReplaceable) {
903 const std::string url;
906 { "http://x/bar?q=xx" },
907 { "http://x/foo?y=xx" },
910 test_util()->ChangeModelToLoadState();
911 AddKeywordWithDate("name", "x", "http://x/foo", "http://sugg1", std::string(),
912 "http://icon1", false, "UTF-8;UTF-16", Time(), Time());
914 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
915 TemplateURLService::URLVisitedDetails details = {
916 GURL(data[i].url), false
918 model()->UpdateKeywordSearchTermsForURL(details);
919 ASSERT_EQ(base::string16(), test_util()->GetAndClearSearchTerm());
923 TEST_F(TemplateURLServiceWithoutFallbackTest, ChangeGoogleBaseValue) {
924 // NOTE: Do not load the prepopulate data, which also has a {google:baseURL}
925 // keyword in it and would confuse this test.
926 test_util()->ChangeModelToLoadState();
928 test_util()->SetGoogleBaseURL(GURL("http://google.com/"));
929 const TemplateURL* t_url = AddKeywordWithDate(
930 "name", "google.com", "{google:baseURL}?q={searchTerms}", "http://sugg1",
931 std::string(), "http://icon1", false, "UTF-8;UTF-16", Time(), Time());
932 ASSERT_EQ(t_url, model()->GetTemplateURLForHost("google.com"));
933 EXPECT_EQ("google.com", t_url->url_ref().GetHost(search_terms_data()));
934 EXPECT_EQ(ASCIIToUTF16("google.com"), t_url->keyword());
936 // Change the Google base url.
937 test_util()->ResetObserverCount();
938 test_util()->SetGoogleBaseURL(GURL("http://google.co.uk/"));
939 VerifyObserverCount(1);
941 // Make sure the host->TemplateURL map was updated appropriately.
942 ASSERT_EQ(t_url, model()->GetTemplateURLForHost("google.co.uk"));
943 EXPECT_TRUE(model()->GetTemplateURLForHost("google.com") == NULL);
944 EXPECT_EQ("google.co.uk", t_url->url_ref().GetHost(search_terms_data()));
945 EXPECT_EQ(ASCIIToUTF16("google.co.uk"), t_url->keyword());
946 EXPECT_EQ("http://google.co.uk/?q=x", t_url->url_ref().ReplaceSearchTerms(
947 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("x")), search_terms_data()));
949 // Now add a manual entry and then change the Google base URL such that the
950 // autogenerated Google search keyword would conflict.
951 TemplateURL* manual = AddKeywordWithDate(
952 "manual", "google.de", "http://google.de/search?q={searchTerms}",
953 std::string(), std::string(), std::string(), false, "UTF-8", Time(),
955 test_util()->SetGoogleBaseURL(GURL("http://google.de"));
957 // Verify that the manual entry is untouched, and the autogenerated keyword
960 model()->GetTemplateURLForKeyword(ASCIIToUTF16("google.de")));
961 EXPECT_EQ("google.de", manual->url_ref().GetHost(search_terms_data()));
963 model()->GetTemplateURLForKeyword(ASCIIToUTF16("google.co.uk")));
964 EXPECT_EQ("google.de", t_url->url_ref().GetHost(search_terms_data()));
965 EXPECT_EQ(ASCIIToUTF16("google.co.uk"), t_url->keyword());
967 // Change the base URL again and verify that the autogenerated keyword follows
968 // even though it didn't match the base URL, while the manual entry is still
970 test_util()->SetGoogleBaseURL(GURL("http://google.fr/"));
971 ASSERT_EQ(manual, model()->GetTemplateURLForHost("google.de"));
972 EXPECT_EQ("google.de", manual->url_ref().GetHost(search_terms_data()));
973 EXPECT_EQ(ASCIIToUTF16("google.de"), manual->keyword());
974 ASSERT_EQ(t_url, model()->GetTemplateURLForHost("google.fr"));
975 EXPECT_TRUE(model()->GetTemplateURLForHost("google.co.uk") == NULL);
976 EXPECT_EQ("google.fr", t_url->url_ref().GetHost(search_terms_data()));
977 EXPECT_EQ(ASCIIToUTF16("google.fr"), t_url->keyword());
980 // Make sure TemplateURLService generates a KEYWORD_GENERATED visit for
982 TEST_F(TemplateURLServiceTest, GenerateVisitOnKeyword) {
983 test_util()->VerifyLoad();
984 ASSERT_TRUE(test_util()->profile()->CreateHistoryService(true, false));
987 TemplateURL* t_url = AddKeywordWithDate(
988 "keyword", "keyword", "http://foo.com/foo?query={searchTerms}",
989 "http://sugg1", std::string(), "http://icon1", true, "UTF-8;UTF-16",
990 base::Time::Now(), base::Time::Now());
992 // Add a visit that matches the url of the keyword.
993 HistoryService* history =
994 HistoryServiceFactory::GetForProfile(test_util()->profile(),
995 Profile::EXPLICIT_ACCESS);
997 GURL(t_url->url_ref().ReplaceSearchTerms(
998 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("blah")),
999 search_terms_data())),
1000 base::Time::Now(), NULL, 0, GURL(), history::RedirectList(),
1001 ui::PAGE_TRANSITION_KEYWORD, history::SOURCE_BROWSED, false);
1003 // Wait for history to finish processing the request.
1004 test_util()->profile()->BlockUntilHistoryProcessesPendingRequests();
1006 // Query history for the generated url.
1007 base::CancelableTaskTracker tracker;
1008 QueryHistoryCallbackImpl callback;
1009 history->QueryURL(GURL("http://keyword"),
1011 base::Bind(&QueryHistoryCallbackImpl::Callback,
1012 base::Unretained(&callback)),
1015 // Wait for the request to be processed.
1016 test_util()->profile()->BlockUntilHistoryProcessesPendingRequests();
1018 // And make sure the url and visit were added.
1019 EXPECT_TRUE(callback.success);
1020 EXPECT_NE(0, callback.row.id());
1021 ASSERT_EQ(1U, callback.visits.size());
1022 EXPECT_EQ(ui::PAGE_TRANSITION_KEYWORD_GENERATED,
1023 ui::PageTransitionStripQualifier(callback.visits[0].transition));
1026 // Make sure that the load routine deletes prepopulated engines that no longer
1027 // exist in the prepopulate data.
1028 TEST_F(TemplateURLServiceTest, LoadDeletesUnusedProvider) {
1029 // Create a preloaded template url. Add it to a loaded model and wait for the
1031 TemplateURL* t_url = CreatePreloadedTemplateURL(true, 999999);
1032 test_util()->ChangeModelToLoadState();
1033 model()->Add(t_url);
1035 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) != NULL);
1036 base::RunLoop().RunUntilIdle();
1038 // Ensure that merging clears this engine.
1039 test_util()->ResetModel(true);
1041 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) == NULL);
1043 // Wait for any saves to finish.
1044 base::RunLoop().RunUntilIdle();
1046 // Reload the model to verify that the database was updated as a result of the
1048 test_util()->ResetModel(true);
1050 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) == NULL);
1053 // Make sure that load routine doesn't delete prepopulated engines that no
1054 // longer exist in the prepopulate data if it has been modified by the user.
1055 TEST_F(TemplateURLServiceTest, LoadRetainsModifiedProvider) {
1056 // Create a preloaded template url and add it to a loaded model.
1057 TemplateURL* t_url = CreatePreloadedTemplateURL(false, 999999);
1058 test_util()->ChangeModelToLoadState();
1059 model()->Add(t_url);
1061 // Do the copy after t_url is added so that the id is set.
1062 scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->data()));
1063 ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")));
1065 // Wait for any saves to finish.
1066 base::RunLoop().RunUntilIdle();
1068 // Ensure that merging won't clear it if the user has edited it.
1069 test_util()->ResetModel(true);
1070 const TemplateURL* url_for_unittest =
1071 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
1072 ASSERT_TRUE(url_for_unittest != NULL);
1073 AssertEquals(*cloned_url, *url_for_unittest);
1075 // Wait for any saves to finish.
1076 base::RunLoop().RunUntilIdle();
1078 // Reload the model to verify that save/reload retains the item.
1079 test_util()->ResetModel(true);
1081 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) != NULL);
1084 // Make sure that load routine doesn't delete
1085 // prepopulated engines that no longer exist in the prepopulate data if
1086 // it has been modified by the user.
1087 TEST_F(TemplateURLServiceTest, LoadSavesPrepopulatedDefaultSearchProvider) {
1088 test_util()->VerifyLoad();
1089 // Verify that the default search provider is set to something.
1090 TemplateURL* default_search = model()->GetDefaultSearchProvider();
1091 ASSERT_TRUE(default_search != NULL);
1092 scoped_ptr<TemplateURL> cloned_url(new TemplateURL(default_search->data()));
1094 // Wait for any saves to finish.
1095 base::RunLoop().RunUntilIdle();
1097 // Reload the model and check that the default search provider
1098 // was properly saved.
1099 test_util()->ResetModel(true);
1100 default_search = model()->GetDefaultSearchProvider();
1101 ASSERT_TRUE(default_search != NULL);
1102 AssertEquals(*cloned_url, *default_search);
1105 // Make sure that the load routine doesn't delete
1106 // prepopulated engines that no longer exist in the prepopulate data if
1107 // it is the default search provider.
1108 TEST_F(TemplateURLServiceTest, LoadRetainsDefaultProvider) {
1109 // Set the default search provider to a preloaded template url which
1110 // is not in the current set of preloaded template urls and save
1112 TemplateURL* t_url = CreatePreloadedTemplateURL(true, 999999);
1113 test_util()->ChangeModelToLoadState();
1114 model()->Add(t_url);
1115 model()->SetUserSelectedDefaultSearchProvider(t_url);
1116 // Do the copy after t_url is added and set as default so that its
1117 // internal state is correct.
1118 scoped_ptr<TemplateURL> cloned_url(new TemplateURL(t_url->data()));
1120 ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")));
1121 ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());
1122 base::RunLoop().RunUntilIdle();
1124 // Ensure that merging won't clear the prepopulated template url
1125 // which is no longer present if it's the default engine.
1126 test_util()->ResetModel(true);
1128 const TemplateURL* keyword_url =
1129 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
1130 ASSERT_TRUE(keyword_url != NULL);
1131 AssertEquals(*cloned_url, *keyword_url);
1132 ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
1135 // Wait for any saves to finish.
1136 base::RunLoop().RunUntilIdle();
1138 // Reload the model to verify that the update was saved.
1139 test_util()->ResetModel(true);
1141 const TemplateURL* keyword_url =
1142 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
1143 ASSERT_TRUE(keyword_url != NULL);
1144 AssertEquals(*cloned_url, *keyword_url);
1145 ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
1149 // Make sure that the load routine sets a default search provider if it was
1150 // missing and not managed.
1151 TEST_F(TemplateURLServiceTest, LoadEnsuresDefaultSearchProviderExists) {
1152 // Force the model to load and make sure we have a default search provider.
1153 test_util()->VerifyLoad();
1154 EXPECT_TRUE(model()->GetDefaultSearchProvider());
1156 EXPECT_TRUE(model()->GetDefaultSearchProvider()->SupportsReplacement(
1157 search_terms_data()));
1159 // Make default search provider unusable (no search terms).
1160 model()->ResetTemplateURL(model()->GetDefaultSearchProvider(),
1161 ASCIIToUTF16("test"), ASCIIToUTF16("test"),
1162 "http://example.com/");
1163 base::RunLoop().RunUntilIdle();
1165 // Reset the model and load it. There should be a usable default search
1167 test_util()->ResetModel(true);
1169 ASSERT_TRUE(model()->GetDefaultSearchProvider());
1170 EXPECT_TRUE(model()->GetDefaultSearchProvider()->SupportsReplacement(
1171 search_terms_data()));
1174 // Simulates failing to load the webdb and makes sure the default search
1175 // provider is valid.
1176 TEST_F(TemplateURLServiceTest, FailedInit) {
1177 test_util()->VerifyLoad();
1179 test_util()->ClearModel();
1180 test_util()->web_data_service()->ShutdownDatabase();
1182 test_util()->ResetModel(false);
1184 base::RunLoop().RunUntilIdle();
1186 ASSERT_TRUE(model()->GetDefaultSearchProvider());
1189 // Verifies that if the default search URL preference is managed, we report
1190 // the default search as managed. Also check that we are getting the right
1192 TEST_F(TemplateURLServiceTest, TestManagedDefaultSearch) {
1193 test_util()->VerifyLoad();
1194 const size_t initial_count = model()->GetTemplateURLs().size();
1195 test_util()->ResetObserverCount();
1197 // Set a regular default search provider.
1198 TemplateURL* regular_default = AddKeywordWithDate(
1199 "name1", "key1", "http://foo1/{searchTerms}", "http://sugg1",
1200 std::string(), "http://icon1", true, "UTF-8;UTF-16", Time(), Time());
1201 VerifyObserverCount(1);
1202 model()->SetUserSelectedDefaultSearchProvider(regular_default);
1203 // Adding the URL and setting the default search provider should have caused
1205 VerifyObserverCount(1);
1206 EXPECT_FALSE(model()->is_default_search_managed());
1207 EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1209 // Set a managed preference that establishes a default search provider.
1210 const char kName[] = "test1";
1211 const char kKeyword[] = "test.com";
1212 const char kSearchURL[] = "http://test.com/search?t={searchTerms}";
1213 const char kIconURL[] = "http://test.com/icon.jpg";
1214 const char kEncodings[] = "UTF-16;UTF-32";
1215 const char kAlternateURL[] = "http://test.com/search#t={searchTerms}";
1216 const char kSearchTermsReplacementKey[] = "espv";
1217 test_util()->SetManagedDefaultSearchPreferences(true, kName, kKeyword,
1218 kSearchURL, std::string(), kIconURL, kEncodings, kAlternateURL,
1219 kSearchTermsReplacementKey);
1220 VerifyObserverFired();
1221 EXPECT_TRUE(model()->is_default_search_managed());
1222 EXPECT_EQ(initial_count + 2, model()->GetTemplateURLs().size());
1224 // Verify that the default manager we are getting is the managed one.
1225 TemplateURLData data;
1226 data.short_name = ASCIIToUTF16(kName);
1227 data.SetKeyword(ASCIIToUTF16(kKeyword));
1228 data.SetURL(kSearchURL);
1229 data.favicon_url = GURL(kIconURL);
1230 data.show_in_default_list = true;
1231 base::SplitString(kEncodings, ';', &data.input_encodings);
1232 data.alternate_urls.push_back(kAlternateURL);
1233 data.search_terms_replacement_key = kSearchTermsReplacementKey;
1234 scoped_ptr<TemplateURL> expected_managed_default1(new TemplateURL(data));
1235 const TemplateURL* actual_managed_default =
1236 model()->GetDefaultSearchProvider();
1237 ExpectSimilar(expected_managed_default1.get(), actual_managed_default);
1238 EXPECT_TRUE(actual_managed_default->show_in_default_list());
1240 // Update the managed preference and check that the model has changed.
1241 const char kNewName[] = "test2";
1242 const char kNewKeyword[] = "other.com";
1243 const char kNewSearchURL[] = "http://other.com/search?t={searchTerms}";
1244 const char kNewSuggestURL[] = "http://other.com/suggest?t={searchTerms}";
1245 test_util()->SetManagedDefaultSearchPreferences(true, kNewName, kNewKeyword,
1246 kNewSearchURL, kNewSuggestURL, std::string(), std::string(),
1247 std::string(), std::string());
1248 VerifyObserverFired();
1249 EXPECT_TRUE(model()->is_default_search_managed());
1250 EXPECT_EQ(initial_count + 2, model()->GetTemplateURLs().size());
1252 // Verify that the default manager we are now getting is the correct one.
1253 TemplateURLData data2;
1254 data2.short_name = ASCIIToUTF16(kNewName);
1255 data2.SetKeyword(ASCIIToUTF16(kNewKeyword));
1256 data2.SetURL(kNewSearchURL);
1257 data2.suggestions_url = kNewSuggestURL;
1258 data2.show_in_default_list = true;
1259 scoped_ptr<TemplateURL> expected_managed_default2(new TemplateURL(data2));
1260 actual_managed_default = model()->GetDefaultSearchProvider();
1261 ExpectSimilar(expected_managed_default2.get(), actual_managed_default);
1262 EXPECT_EQ(actual_managed_default->show_in_default_list(), true);
1264 // Remove all the managed prefs and check that we are no longer managed.
1265 test_util()->RemoveManagedDefaultSearchPreferences();
1266 VerifyObserverFired();
1267 EXPECT_FALSE(model()->is_default_search_managed());
1268 EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1270 // The default should now be the user preference.
1271 const TemplateURL* actual_final_managed_default =
1272 model()->GetDefaultSearchProvider();
1273 ExpectSimilar(regular_default, actual_final_managed_default);
1274 EXPECT_EQ(actual_final_managed_default->show_in_default_list(), true);
1276 // Disable the default search provider through policy.
1277 test_util()->SetManagedDefaultSearchPreferences(false, std::string(),
1278 std::string(), std::string(), std::string(), std::string(),
1279 std::string(), std::string(), std::string());
1280 VerifyObserverFired();
1281 EXPECT_TRUE(model()->is_default_search_managed());
1282 EXPECT_TRUE(NULL == model()->GetDefaultSearchProvider());
1283 EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1286 test_util()->SetManagedDefaultSearchPreferences(true, kName, kKeyword,
1287 kSearchURL, std::string(), kIconURL, kEncodings, kAlternateURL,
1288 kSearchTermsReplacementKey);
1289 VerifyObserverFired();
1290 EXPECT_TRUE(model()->is_default_search_managed());
1291 EXPECT_EQ(initial_count + 2, model()->GetTemplateURLs().size());
1293 // Verify that the default manager we are getting is the managed one.
1294 actual_managed_default = model()->GetDefaultSearchProvider();
1295 ExpectSimilar(expected_managed_default1.get(), actual_managed_default);
1296 EXPECT_EQ(actual_managed_default->show_in_default_list(), true);
1298 // Clear the model and disable the default search provider through policy.
1299 // Verify that there is no default search provider after loading the model.
1300 // This checks against regressions of http://crbug.com/67180
1302 // First, remove the preferences, reset the model, and set a default.
1303 test_util()->RemoveManagedDefaultSearchPreferences();
1304 test_util()->ResetModel(true);
1305 TemplateURL* new_default =
1306 model()->GetTemplateURLForKeyword(ASCIIToUTF16("key1"));
1307 ASSERT_FALSE(new_default == NULL);
1308 model()->SetUserSelectedDefaultSearchProvider(new_default);
1309 EXPECT_EQ(new_default, model()->GetDefaultSearchProvider());
1311 // Now reset the model again but load it after setting the preferences.
1312 test_util()->ResetModel(false);
1313 test_util()->SetManagedDefaultSearchPreferences(false, std::string(),
1314 std::string(), std::string(), std::string(), std::string(),
1315 std::string(), std::string(), std::string());
1316 test_util()->VerifyLoad();
1317 EXPECT_TRUE(model()->is_default_search_managed());
1318 EXPECT_TRUE(model()->GetDefaultSearchProvider() == NULL);
1321 // Test that if we load a TemplateURL with an empty GUID, the load process
1322 // assigns it a newly generated GUID.
1323 TEST_F(TemplateURLServiceTest, PatchEmptySyncGUID) {
1324 // Add a new TemplateURL.
1325 test_util()->VerifyLoad();
1326 const size_t initial_count = model()->GetTemplateURLs().size();
1328 TemplateURLData data;
1329 data.short_name = ASCIIToUTF16("google");
1330 data.SetKeyword(ASCIIToUTF16("keyword"));
1331 data.SetURL("http://www.google.com/foo/bar");
1332 data.sync_guid.clear();
1333 TemplateURL* t_url = new TemplateURL(data);
1334 model()->Add(t_url);
1336 VerifyObserverCount(1);
1337 base::RunLoop().RunUntilIdle();
1338 ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1340 // Reload the model to verify it was actually saved to the database and
1341 // assigned a new GUID when brought back.
1342 test_util()->ResetModel(true);
1343 ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1344 const TemplateURL* loaded_url =
1345 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
1346 ASSERT_FALSE(loaded_url == NULL);
1347 ASSERT_FALSE(loaded_url->sync_guid().empty());
1350 // Test that if we load a TemplateURL with duplicate input encodings, the load
1351 // process de-dupes them.
1352 TEST_F(TemplateURLServiceTest, DuplicateInputEncodings) {
1353 // Add a new TemplateURL.
1354 test_util()->VerifyLoad();
1355 const size_t initial_count = model()->GetTemplateURLs().size();
1357 TemplateURLData data;
1358 data.short_name = ASCIIToUTF16("google");
1359 data.SetKeyword(ASCIIToUTF16("keyword"));
1360 data.SetURL("http://www.google.com/foo/bar");
1361 std::vector<std::string> encodings;
1362 data.input_encodings.push_back("UTF-8");
1363 data.input_encodings.push_back("UTF-8");
1364 data.input_encodings.push_back("UTF-16");
1365 data.input_encodings.push_back("UTF-8");
1366 data.input_encodings.push_back("Big5");
1367 data.input_encodings.push_back("UTF-16");
1368 data.input_encodings.push_back("Big5");
1369 data.input_encodings.push_back("Windows-1252");
1370 TemplateURL* t_url = new TemplateURL(data);
1371 model()->Add(t_url);
1373 VerifyObserverCount(1);
1374 base::RunLoop().RunUntilIdle();
1375 ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1376 const TemplateURL* loaded_url =
1377 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
1378 ASSERT_TRUE(loaded_url != NULL);
1379 EXPECT_EQ(8U, loaded_url->input_encodings().size());
1381 // Reload the model to verify it was actually saved to the database and the
1382 // duplicate encodings were removed.
1383 test_util()->ResetModel(true);
1384 ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
1385 loaded_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
1386 ASSERT_FALSE(loaded_url == NULL);
1387 EXPECT_EQ(4U, loaded_url->input_encodings().size());
1390 TEST_F(TemplateURLServiceTest, DefaultExtensionEngine) {
1391 test_util()->VerifyLoad();
1392 // Add third-party default search engine.
1393 TemplateURL* user_dse = AddKeywordWithDate(
1394 "user", "user", "http://www.goo.com/s?q={searchTerms}",
1395 std::string(), std::string(), std::string(),
1396 true, "UTF-8", Time(), Time());
1397 model()->SetUserSelectedDefaultSearchProvider(user_dse);
1398 EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider());
1400 TemplateURL* ext_dse = CreateKeywordWithDate(
1401 model(), "ext", "ext", "http://www.search.com/s?q={searchTerms}",
1402 std::string(), std::string(), std::string(),
1403 true, true, "UTF-8", Time(), Time());
1404 scoped_ptr<TemplateURL::AssociatedExtensionInfo> extension_info(
1405 new TemplateURL::AssociatedExtensionInfo(
1406 TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION, "ext"));
1407 extension_info->wants_to_be_default_engine = true;
1408 model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
1409 EXPECT_EQ(ext_dse, model()->GetDefaultSearchProvider());
1411 model()->RemoveExtensionControlledTURL(
1412 "ext", TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION);
1413 ExpectSimilar(user_dse, model()->GetDefaultSearchProvider());
1416 TEST_F(TemplateURLServiceTest, ExtensionEnginesNotPersist) {
1417 test_util()->VerifyLoad();
1418 // Add third-party default search engine.
1419 TemplateURL* user_dse = AddKeywordWithDate(
1420 "user", "user", "http://www.goo.com/s?q={searchTerms}",
1421 std::string(), std::string(), std::string(),
1422 true, "UTF-8", Time(), Time());
1423 model()->SetUserSelectedDefaultSearchProvider(user_dse);
1424 EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider());
1426 TemplateURL* ext_dse = CreateKeywordWithDate(
1427 model(), "ext1", "ext1", "http://www.ext1.com/s?q={searchTerms}",
1428 std::string(), std::string(), std::string(),
1429 true, false, "UTF-8", Time(), Time());
1430 scoped_ptr<TemplateURL::AssociatedExtensionInfo> extension_info(
1431 new TemplateURL::AssociatedExtensionInfo(
1432 TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION, "ext1"));
1433 extension_info->wants_to_be_default_engine = false;
1434 model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
1435 EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider());
1437 ext_dse = CreateKeywordWithDate(
1438 model(), "ext2", "ext2", "http://www.ext2.com/s?q={searchTerms}",
1439 std::string(), std::string(), std::string(),
1440 true, true, "UTF-8", Time(), Time());
1441 extension_info.reset(new TemplateURL::AssociatedExtensionInfo(
1442 TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION, "ext2"));
1443 extension_info->wants_to_be_default_engine = true;
1444 model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
1445 EXPECT_EQ(ext_dse, model()->GetDefaultSearchProvider());
1447 test_util()->ResetModel(true);
1448 user_dse = model()->GetTemplateURLForKeyword(ASCIIToUTF16("user"));
1449 ExpectSimilar(user_dse, model()->GetDefaultSearchProvider());
1450 EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext1")));
1451 EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext2")));
1454 TEST_F(TemplateURLServiceTest, ExtensionEngineVsPolicy) {
1455 // Set a managed preference that establishes a default search provider.
1456 const char kName[] = "test";
1457 const char kKeyword[] = "test.com";
1458 const char kSearchURL[] = "http://test.com/search?t={searchTerms}";
1459 const char kIconURL[] = "http://test.com/icon.jpg";
1460 const char kEncodings[] = "UTF-16;UTF-32";
1461 const char kAlternateURL[] = "http://test.com/search#t={searchTerms}";
1462 const char kSearchTermsReplacementKey[] = "espv";
1463 test_util()->SetManagedDefaultSearchPreferences(
1464 true, kName, kKeyword, kSearchURL, std::string(), kIconURL, kEncodings,
1465 kAlternateURL, kSearchTermsReplacementKey);
1466 test_util()->VerifyLoad();
1467 // Verify that the default manager we are getting is the managed one.
1468 TemplateURLData data;
1469 data.short_name = ASCIIToUTF16(kName);
1470 data.SetKeyword(ASCIIToUTF16(kKeyword));
1471 data.SetURL(kSearchURL);
1472 data.favicon_url = GURL(kIconURL);
1473 data.show_in_default_list = true;
1474 base::SplitString(kEncodings, ';', &data.input_encodings);
1475 data.alternate_urls.push_back(kAlternateURL);
1476 data.search_terms_replacement_key = kSearchTermsReplacementKey;
1477 scoped_ptr<TemplateURL> expected_managed_default(new TemplateURL(data));
1478 EXPECT_TRUE(model()->is_default_search_managed());
1479 const TemplateURL* actual_managed_default =
1480 model()->GetDefaultSearchProvider();
1481 ExpectSimilar(expected_managed_default.get(), actual_managed_default);
1483 TemplateURL* ext_dse = CreateKeywordWithDate(
1484 model(), "ext1", "ext1", "http://www.ext1.com/s?q={searchTerms}",
1485 std::string(), std::string(), std::string(),
1486 true, true, "UTF-8", Time(), Time());
1487 scoped_ptr<TemplateURL::AssociatedExtensionInfo> extension_info(
1488 new TemplateURL::AssociatedExtensionInfo(
1489 TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION, "ext1"));
1490 extension_info->wants_to_be_default_engine = true;
1491 model()->AddExtensionControlledTURL(ext_dse, extension_info.Pass());
1492 EXPECT_EQ(ext_dse, model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext1")));
1493 EXPECT_TRUE(model()->is_default_search_managed());
1494 actual_managed_default = model()->GetDefaultSearchProvider();
1495 ExpectSimilar(expected_managed_default.get(), actual_managed_default);