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