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