1 // Copyright (c) 2011 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/callback.h"
6 #include "base/memory/ref_counted.h"
7 #include "base/memory/scoped_vector.h"
8 #include "base/string_split.h"
9 #include "base/string_util.h"
10 #include "base/threading/thread.h"
11 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/history/history.h"
13 #include "chrome/browser/history/history_notifications.h"
14 #include "chrome/browser/search_engines/search_host_to_urls_map.h"
15 #include "chrome/browser/search_engines/search_terms_data.h"
16 #include "chrome/browser/search_engines/template_url.h"
17 #include "chrome/browser/search_engines/template_url_model.h"
18 #include "chrome/browser/search_engines/template_url_model_test_util.h"
19 #include "chrome/browser/search_engines/template_url_prepopulate_data.h"
20 #include "chrome/browser/webdata/web_database.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/test/testing_pref_service.h"
23 #include "chrome/test/testing_profile.h"
24 #include "content/browser/browser_thread.h"
25 #include "content/common/notification_details.h"
26 #include "content/common/notification_source.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 using base::Time;
30 using base::TimeDelta;
31
32 #if defined(OS_LINUX)
33 // Timed out on Chromium Linux. http://crbug.com/53607
34 #define MAYBE_Load DISABLED_Load
35 #else
36 #define MAYBE_Load Load
37 #endif
38
39 // Test the GenerateSearchURL on a thread or the main thread.
40 class TestGenerateSearchURL
41 : public base::RefCountedThreadSafe<TestGenerateSearchURL> {
42 public:
TestGenerateSearchURL(SearchTermsData * search_terms_data)43 explicit TestGenerateSearchURL(SearchTermsData* search_terms_data)
44 : search_terms_data_(search_terms_data),
45 passed_(false) {
46 }
47
48 // Run the test cases for GenerateSearchURL.
49 void RunTest();
50
51 // Did the test pass?
passed() const52 bool passed() const { return passed_; }
53
54 private:
55 friend class base::RefCountedThreadSafe<TestGenerateSearchURL>;
~TestGenerateSearchURL()56 ~TestGenerateSearchURL() {}
57
58 SearchTermsData* search_terms_data_;
59 bool passed_;
60
61 DISALLOW_COPY_AND_ASSIGN(TestGenerateSearchURL);
62 };
63
64 // Simple implementation of SearchTermsData.
65 class TestSearchTermsData : public SearchTermsData {
66 public:
TestSearchTermsData(const char * google_base_url)67 explicit TestSearchTermsData(const char* google_base_url)
68 : google_base_url_(google_base_url) {
69 }
70
GoogleBaseURLValue() const71 virtual std::string GoogleBaseURLValue() const {
72 return google_base_url_;
73 }
74
GetApplicationLocale() const75 virtual std::string GetApplicationLocale() const {
76 return "yy";
77 }
78
79 #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
80 // Returns the value for the Chrome Omnibox rlz.
GetRlzParameterValue() const81 virtual string16 GetRlzParameterValue() const {
82 return string16();
83 }
84 #endif
85
86 private:
87 std::string google_base_url_;
88
89 DISALLOW_COPY_AND_ASSIGN(TestSearchTermsData);
90 };
91
92 // Create an URL that appears to have been prepopulated, but won't be in the
93 // current data. The caller owns the returned TemplateURL*.
CreatePreloadedTemplateURL()94 static TemplateURL* CreatePreloadedTemplateURL() {
95 TemplateURL* t_url = new TemplateURL();
96 t_url->SetURL("http://www.unittest.com/", 0, 0);
97 t_url->set_keyword(ASCIIToUTF16("unittest"));
98 t_url->set_short_name(ASCIIToUTF16("unittest"));
99 t_url->set_safe_for_autoreplace(true);
100 GURL favicon_url("http://favicon.url");
101 t_url->SetFaviconURL(favicon_url);
102 t_url->set_date_created(Time::FromTimeT(100));
103 t_url->set_prepopulate_id(999999);
104 return t_url;
105 }
106
107 class TemplateURLModelTest : public testing::Test {
108 public:
TemplateURLModelTest()109 TemplateURLModelTest() {}
110
SetUp()111 virtual void SetUp() {
112 test_util_.SetUp();
113 }
114
TearDown()115 virtual void TearDown() {
116 test_util_.TearDown();
117 }
118
AddKeywordWithDate(const std::string & keyword,bool autogenerate_keyword,const std::string & url,const std::string & suggest_url,const std::string & favicon_url,const std::string & encodings,const std::string & short_name,bool safe_for_autoreplace,Time created_date)119 TemplateURL* AddKeywordWithDate(const std::string& keyword,
120 bool autogenerate_keyword,
121 const std::string& url,
122 const std::string& suggest_url,
123 const std::string& favicon_url,
124 const std::string& encodings,
125 const std::string& short_name,
126 bool safe_for_autoreplace,
127 Time created_date) {
128 TemplateURL* template_url = new TemplateURL();
129 template_url->SetURL(url, 0, 0);
130 template_url->SetSuggestionsURL(suggest_url, 0, 0);
131 template_url->SetFaviconURL(GURL(favicon_url));
132 template_url->set_keyword(UTF8ToUTF16(keyword));
133 template_url->set_autogenerate_keyword(autogenerate_keyword);
134 template_url->set_short_name(UTF8ToUTF16(short_name));
135 std::vector<std::string> encodings_vector;
136 base::SplitString(encodings, ';', &encodings_vector);
137 template_url->set_input_encodings(encodings_vector);
138 template_url->set_date_created(created_date);
139 template_url->set_safe_for_autoreplace(safe_for_autoreplace);
140 model()->Add(template_url);
141 EXPECT_NE(0, template_url->id());
142 return template_url;
143 }
144
145 // Simulate firing by the prefs service specifying that the managed
146 // preferences have changed.
NotifyManagedPrefsHaveChanged()147 void NotifyManagedPrefsHaveChanged() {
148 model()->Observe(
149 NotificationType::PREF_CHANGED,
150 Source<PrefService>(profile()->GetTestingPrefService()),
151 Details<std::string>(NULL));
152 }
153
154 // Verifies the two TemplateURLs are equal.
AssertEquals(const TemplateURL & expected,const TemplateURL & actual)155 void AssertEquals(const TemplateURL& expected, const TemplateURL& actual) {
156 ASSERT_TRUE(TemplateURLRef::SameUrlRefs(expected.url(), actual.url()));
157 ASSERT_TRUE(TemplateURLRef::SameUrlRefs(expected.suggestions_url(),
158 actual.suggestions_url()));
159 ASSERT_EQ(expected.keyword(), actual.keyword());
160 ASSERT_EQ(expected.short_name(), actual.short_name());
161 ASSERT_EQ(JoinString(expected.input_encodings(), ';'),
162 JoinString(actual.input_encodings(), ';'));
163 ASSERT_TRUE(expected.GetFaviconURL() == actual.GetFaviconURL());
164 ASSERT_EQ(expected.id(), actual.id());
165 ASSERT_EQ(expected.safe_for_autoreplace(), actual.safe_for_autoreplace());
166 ASSERT_EQ(expected.show_in_default_list(), actual.show_in_default_list());
167 ASSERT_TRUE(expected.date_created() == actual.date_created());
168 }
169
170 // Checks that the two TemplateURLs are similar. It does not check the id
171 // and the date_created. Neither pointer should be NULL.
ExpectSimilar(const TemplateURL * expected,const TemplateURL * actual)172 void ExpectSimilar(const TemplateURL* expected, const TemplateURL* actual) {
173 ASSERT_TRUE(expected != NULL);
174 ASSERT_TRUE(actual != NULL);
175 EXPECT_TRUE(TemplateURLRef::SameUrlRefs(expected->url(), actual->url()));
176 EXPECT_TRUE(TemplateURLRef::SameUrlRefs(expected->suggestions_url(),
177 actual->suggestions_url()));
178 EXPECT_EQ(expected->keyword(), actual->keyword());
179 EXPECT_EQ(expected->short_name(), actual->short_name());
180 EXPECT_EQ(JoinString(expected->input_encodings(), ';'),
181 JoinString(actual->input_encodings(), ';'));
182 EXPECT_TRUE(expected->GetFaviconURL() == actual->GetFaviconURL());
183 EXPECT_EQ(expected->safe_for_autoreplace(), actual->safe_for_autoreplace());
184 EXPECT_EQ(expected->show_in_default_list(), actual->show_in_default_list());
185 }
186
187 // Set the managed preferences for the default search provider and trigger
188 // notification.
SetManagedDefaultSearchPreferences(bool enabled,const char * name,const char * search_url,const char * suggest_url,const char * icon_url,const char * encodings,const char * keyword)189 void SetManagedDefaultSearchPreferences(bool enabled,
190 const char* name,
191 const char* search_url,
192 const char* suggest_url,
193 const char* icon_url,
194 const char* encodings,
195 const char* keyword) {
196 TestingPrefService* service = profile()->GetTestingPrefService();
197 service->SetManagedPref(
198 prefs::kDefaultSearchProviderEnabled,
199 Value::CreateBooleanValue(enabled));
200 service->SetManagedPref(
201 prefs::kDefaultSearchProviderName,
202 Value::CreateStringValue(name));
203 service->SetManagedPref(
204 prefs::kDefaultSearchProviderSearchURL,
205 Value::CreateStringValue(search_url));
206 service->SetManagedPref(
207 prefs::kDefaultSearchProviderSuggestURL,
208 Value::CreateStringValue(suggest_url));
209 service->SetManagedPref(
210 prefs::kDefaultSearchProviderIconURL,
211 Value::CreateStringValue(icon_url));
212 service->SetManagedPref(
213 prefs::kDefaultSearchProviderEncodings,
214 Value::CreateStringValue(encodings));
215 service->SetManagedPref(
216 prefs::kDefaultSearchProviderKeyword,
217 Value::CreateStringValue(keyword));
218 }
219
220 // Remove all the managed preferences for the default search provider and
221 // trigger notification.
RemoveManagedDefaultSearchPreferences()222 void RemoveManagedDefaultSearchPreferences() {
223 TestingPrefService* service = profile()->GetTestingPrefService();
224 service->RemoveManagedPref(
225 prefs::kDefaultSearchProviderSearchURL);
226 service->RemoveManagedPref(
227 prefs::kDefaultSearchProviderEnabled);
228 service->RemoveManagedPref(
229 prefs::kDefaultSearchProviderName);
230 service->RemoveManagedPref(
231 prefs::kDefaultSearchProviderSuggestURL);
232 service->RemoveManagedPref(
233 prefs::kDefaultSearchProviderIconURL);
234 service->RemoveManagedPref(
235 prefs::kDefaultSearchProviderEncodings);
236 service->RemoveManagedPref(
237 prefs::kDefaultSearchProviderKeyword);
238 service->RemoveManagedPref(
239 prefs::kDefaultSearchProviderID);
240 service->RemoveManagedPref(
241 prefs::kDefaultSearchProviderPrepopulateID);
242 }
243
244 // Creates a TemplateURL with the same prepopulated id as a real prepopulated
245 // item. The input number determines which prepopulated item. The caller is
246 // responsible for owning the returned TemplateURL*.
247 TemplateURL* CreateReplaceablePreloadedTemplateURL(
248 size_t index_offset_from_default,
249 string16* prepopulated_display_url);
250
251 // Verifies the behavior of when a preloaded url later gets changed.
252 // Since the input is the offset from the default, when one passes in
253 // 0, it tests the default. Passing in a number > 0 will verify what
254 // happens when a preloaded url that is not the default gets updated.
255 void TestLoadUpdatingPreloadedURL(size_t index_offset_from_default);
256
257 // Helper methods to make calling TemplateURLModelTestUtil methods less
258 // visually noisy in the test code.
VerifyObserverCount(int expected_changed_count)259 void VerifyObserverCount(int expected_changed_count) {
260 EXPECT_EQ(expected_changed_count, test_util_.GetObserverCount());
261 test_util_.ResetObserverCount();
262 }
VerifyObserverFired()263 void VerifyObserverFired() {
264 EXPECT_LE(1, test_util_.GetObserverCount());
265 test_util_.ResetObserverCount();
266 }
BlockTillServiceProcessesRequests()267 void BlockTillServiceProcessesRequests() {
268 TemplateURLModelTestUtil::BlockTillServiceProcessesRequests();
269 }
VerifyLoad()270 void VerifyLoad() { test_util_.VerifyLoad(); }
ChangeModelToLoadState()271 void ChangeModelToLoadState() { test_util_.ChangeModelToLoadState(); }
ResetModel(bool verify_load)272 void ResetModel(bool verify_load) { test_util_.ResetModel(verify_load); }
GetAndClearSearchTerm()273 string16 GetAndClearSearchTerm() {
274 return test_util_.GetAndClearSearchTerm();
275 }
SetGoogleBaseURL(const std::string & base_url) const276 void SetGoogleBaseURL(const std::string& base_url) const {
277 test_util_.SetGoogleBaseURL(base_url);
278 }
GetWebDataService()279 WebDataService* GetWebDataService() { return test_util_.GetWebDataService(); }
model()280 TemplateURLModel* model() { return test_util_.model(); }
profile()281 TestingProfile* profile() { return test_util_.profile(); }
282
283 protected:
284 TemplateURLModelTestUtil test_util_;
285
286 DISALLOW_COPY_AND_ASSIGN(TemplateURLModelTest);
287 };
288
RunTest()289 void TestGenerateSearchURL::RunTest() {
290 struct GenerateSearchURLCase {
291 const char* test_name;
292 const char* url;
293 const char* expected;
294 } generate_url_cases[] = {
295 { "empty TemplateURLRef", NULL, "" },
296 { "invalid URL", "foo{searchTerms}", "" },
297 { "URL with no replacements", "http://foo/", "http://foo/" },
298 { "basic functionality", "http://foo/{searchTerms}",
299 "http://foo/blah.blah.blah.blah.blah" }
300 };
301
302 // Don't use ASSERT/EXPECT since this is run on a thread in one test
303 // and those macros aren't meant for threads at this time according to
304 // gtest documentation.
305 bool everything_passed = true;
306 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(generate_url_cases); ++i) {
307 TemplateURL t_url;
308 if (generate_url_cases[i].url)
309 t_url.SetURL(generate_url_cases[i].url, 0, 0);
310
311 std::string result = search_terms_data_ ?
312 TemplateURLModel::GenerateSearchURLUsingTermsData(
313 &t_url, *search_terms_data_).spec() :
314 TemplateURLModel::GenerateSearchURL(&t_url).spec();
315 if (strcmp(generate_url_cases[i].expected, result.c_str())) {
316 LOG(ERROR) << generate_url_cases[i].test_name << " failed. Expected " <<
317 generate_url_cases[i].expected << " Actual " << result;
318
319 everything_passed = false;
320 }
321 }
322 passed_ = everything_passed;
323 }
324
CreateReplaceablePreloadedTemplateURL(size_t index_offset_from_default,string16 * prepopulated_display_url)325 TemplateURL* TemplateURLModelTest::CreateReplaceablePreloadedTemplateURL(
326 size_t index_offset_from_default,
327 string16* prepopulated_display_url) {
328 TemplateURL* t_url = CreatePreloadedTemplateURL();
329 ScopedVector<TemplateURL> prepopulated_urls;
330 size_t default_search_provider_index = 0;
331 TemplateURLPrepopulateData::GetPrepopulatedEngines(
332 profile()->GetPrefs(),
333 &prepopulated_urls.get(),
334 &default_search_provider_index);
335 EXPECT_LT(index_offset_from_default, prepopulated_urls.size());
336 size_t prepopulated_index =
337 (default_search_provider_index + index_offset_from_default) %
338 prepopulated_urls.size();
339 t_url->set_prepopulate_id(
340 prepopulated_urls[prepopulated_index]->prepopulate_id());
341 *prepopulated_display_url =
342 prepopulated_urls[prepopulated_index]->url()->DisplayURL();
343 return t_url;
344 }
345
TestLoadUpdatingPreloadedURL(size_t index_offset_from_default)346 void TemplateURLModelTest::TestLoadUpdatingPreloadedURL(
347 size_t index_offset_from_default) {
348 string16 prepopulated_url;
349 TemplateURL* t_url = CreateReplaceablePreloadedTemplateURL(
350 index_offset_from_default, &prepopulated_url);
351 t_url->set_safe_for_autoreplace(false);
352
353 string16 original_url = t_url->url()->DisplayURL();
354 ASSERT_NE(prepopulated_url, original_url);
355
356 // Then add it to the model and save it all.
357 ChangeModelToLoadState();
358 model()->Add(t_url);
359 const TemplateURL* keyword_url =
360 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
361 ASSERT_EQ(t_url, keyword_url);
362 ASSERT_EQ(original_url, keyword_url->url()->DisplayURL());
363 BlockTillServiceProcessesRequests();
364
365 // Now reload the model and verify that the merge updates the url.
366 ResetModel(true);
367 keyword_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
368 ASSERT_TRUE(keyword_url != NULL);
369 ASSERT_EQ(prepopulated_url, keyword_url->url()->DisplayURL());
370
371 // Wait for any saves to finish.
372 BlockTillServiceProcessesRequests();
373
374 // Reload the model to verify that change was saved correctly.
375 ResetModel(true);
376 keyword_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
377 ASSERT_TRUE(keyword_url != NULL);
378 ASSERT_EQ(prepopulated_url, keyword_url->url()->DisplayURL());
379 }
380
TEST_F(TemplateURLModelTest,MAYBE_Load)381 TEST_F(TemplateURLModelTest, MAYBE_Load) {
382 VerifyLoad();
383 }
384
TEST_F(TemplateURLModelTest,AddUpdateRemove)385 TEST_F(TemplateURLModelTest, AddUpdateRemove) {
386 // Add a new TemplateURL.
387 VerifyLoad();
388 const size_t initial_count = model()->GetTemplateURLs().size();
389
390 TemplateURL* t_url = new TemplateURL();
391 t_url->SetURL("http://www.google.com/foo/bar", 0, 0);
392 t_url->set_keyword(ASCIIToUTF16("keyword"));
393 t_url->set_short_name(ASCIIToUTF16("google"));
394 GURL favicon_url("http://favicon.url");
395 t_url->SetFaviconURL(favicon_url);
396 t_url->set_date_created(Time::FromTimeT(100));
397 t_url->set_safe_for_autoreplace(true);
398 model()->Add(t_url);
399 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"),
400 GURL(), NULL));
401 VerifyObserverCount(1);
402 BlockTillServiceProcessesRequests();
403 // We need to clone as model takes ownership of TemplateURL and will
404 // delete it.
405 TemplateURL cloned_url(*t_url);
406 ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
407 ASSERT_TRUE(model()->GetTemplateURLForKeyword(t_url->keyword()) == t_url);
408 ASSERT_TRUE(t_url->date_created() == cloned_url.date_created());
409
410 // Reload the model to verify it was actually saved to the database.
411 ResetModel(true);
412 ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
413 const TemplateURL* loaded_url =
414 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
415 ASSERT_TRUE(loaded_url != NULL);
416 AssertEquals(cloned_url, *loaded_url);
417 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"),
418 GURL(), NULL));
419
420 // Mutate an element and verify it succeeded.
421 model()->ResetTemplateURL(loaded_url, ASCIIToUTF16("a"),
422 ASCIIToUTF16("b"), "c");
423 ASSERT_EQ(ASCIIToUTF16("a"), loaded_url->short_name());
424 ASSERT_EQ(ASCIIToUTF16("b"), loaded_url->keyword());
425 ASSERT_EQ("c", loaded_url->url()->url());
426 ASSERT_FALSE(loaded_url->safe_for_autoreplace());
427 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("keyword"),
428 GURL(), NULL));
429 ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("b"), GURL(), NULL));
430 cloned_url = *loaded_url;
431 BlockTillServiceProcessesRequests();
432 ResetModel(true);
433 ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
434 loaded_url = model()->GetTemplateURLForKeyword(ASCIIToUTF16("b"));
435 ASSERT_TRUE(loaded_url != NULL);
436 AssertEquals(cloned_url, *loaded_url);
437
438 // Remove an element and verify it succeeded.
439 model()->Remove(loaded_url);
440 VerifyObserverCount(1);
441 ResetModel(true);
442 ASSERT_EQ(initial_count, model()->GetTemplateURLs().size());
443 EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("b")) == NULL);
444 }
445
TEST_F(TemplateURLModelTest,GenerateKeyword)446 TEST_F(TemplateURLModelTest, GenerateKeyword) {
447 ASSERT_EQ(string16(), TemplateURLModel::GenerateKeyword(GURL(), true));
448 // Shouldn't generate keywords for https.
449 ASSERT_EQ(string16(),
450 TemplateURLModel::GenerateKeyword(GURL("https://blah"), true));
451 ASSERT_EQ(ASCIIToUTF16("foo"),
452 TemplateURLModel::GenerateKeyword(GURL("http://foo"), true));
453 // www. should be stripped.
454 ASSERT_EQ(ASCIIToUTF16("foo"),
455 TemplateURLModel::GenerateKeyword(GURL("http://www.foo"), true));
456 // Shouldn't generate keywords with paths, if autodetected.
457 ASSERT_EQ(string16(),
458 TemplateURLModel::GenerateKeyword(GURL("http://blah/foo"), true));
459 ASSERT_EQ(ASCIIToUTF16("blah"),
460 TemplateURLModel::GenerateKeyword(GURL("http://blah/foo"), false));
461 // FTP shouldn't generate a keyword.
462 ASSERT_EQ(string16(),
463 TemplateURLModel::GenerateKeyword(GURL("ftp://blah/"), true));
464 // Make sure we don't get a trailing /
465 ASSERT_EQ(ASCIIToUTF16("blah"),
466 TemplateURLModel::GenerateKeyword(GURL("http://blah/"), true));
467 }
468
TEST_F(TemplateURLModelTest,GenerateSearchURL)469 TEST_F(TemplateURLModelTest, GenerateSearchURL) {
470 scoped_refptr<TestGenerateSearchURL> test_generate_search_url(
471 new TestGenerateSearchURL(NULL));
472 test_generate_search_url->RunTest();
473 EXPECT_TRUE(test_generate_search_url->passed());
474 }
475
TEST_F(TemplateURLModelTest,GenerateSearchURLUsingTermsData)476 TEST_F(TemplateURLModelTest, GenerateSearchURLUsingTermsData) {
477 // Run the test for GenerateSearchURLUsingTermsData on the "IO" thread and
478 // wait for it to finish.
479 TestSearchTermsData search_terms_data("http://google.com/");
480 scoped_refptr<TestGenerateSearchURL> test_generate_search_url(
481 new TestGenerateSearchURL(&search_terms_data));
482
483 test_util_.StartIOThread();
484 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)->PostTask(
485 FROM_HERE,
486 NewRunnableMethod(test_generate_search_url.get(),
487 &TestGenerateSearchURL::RunTest));
488 TemplateURLModelTestUtil::BlockTillIOThreadProcessesRequests();
489 EXPECT_TRUE(test_generate_search_url->passed());
490 }
491
TEST_F(TemplateURLModelTest,ClearBrowsingData_Keywords)492 TEST_F(TemplateURLModelTest, ClearBrowsingData_Keywords) {
493 Time now = Time::Now();
494 TimeDelta one_day = TimeDelta::FromDays(1);
495 Time month_ago = now - TimeDelta::FromDays(30);
496
497 // Nothing has been added.
498 EXPECT_EQ(0U, model()->GetTemplateURLs().size());
499
500 // Create one with a 0 time.
501 AddKeywordWithDate("key1", false, "http://foo1", "http://suggest1",
502 "http://icon1", "UTF-8;UTF-16", "name1", true, Time());
503 // Create one for now and +/- 1 day.
504 AddKeywordWithDate("key2", false, "http://foo2", "http://suggest2",
505 "http://icon2", "UTF-8;UTF-16", "name2", true,
506 now - one_day);
507 AddKeywordWithDate("key3", false, "http://foo3", "", "", "", "name3",
508 true, now);
509 AddKeywordWithDate("key4", false, "http://foo4", "", "", "", "name4",
510 true, now + one_day);
511 // Try the other three states.
512 AddKeywordWithDate("key5", false, "http://foo5", "http://suggest5",
513 "http://icon5", "UTF-8;UTF-16", "name5", false, now);
514 AddKeywordWithDate("key6", false, "http://foo6", "http://suggest6",
515 "http://icon6", "UTF-8;UTF-16", "name6", false,
516 month_ago);
517
518 // We just added a few items, validate them.
519 EXPECT_EQ(6U, model()->GetTemplateURLs().size());
520
521 // Try removing from current timestamp. This should delete the one in the
522 // future and one very recent one.
523 model()->RemoveAutoGeneratedSince(now);
524 EXPECT_EQ(4U, model()->GetTemplateURLs().size());
525
526 // Try removing from two months ago. This should only delete items that are
527 // auto-generated.
528 model()->RemoveAutoGeneratedSince(now - TimeDelta::FromDays(60));
529 EXPECT_EQ(3U, model()->GetTemplateURLs().size());
530
531 // Make sure the right values remain.
532 EXPECT_EQ(ASCIIToUTF16("key1"), model()->GetTemplateURLs()[0]->keyword());
533 EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
534 EXPECT_EQ(0U,
535 model()->GetTemplateURLs()[0]->date_created().ToInternalValue());
536
537 EXPECT_EQ(ASCIIToUTF16("key5"), model()->GetTemplateURLs()[1]->keyword());
538 EXPECT_FALSE(model()->GetTemplateURLs()[1]->safe_for_autoreplace());
539 EXPECT_EQ(now.ToInternalValue(),
540 model()->GetTemplateURLs()[1]->date_created().ToInternalValue());
541
542 EXPECT_EQ(ASCIIToUTF16("key6"), model()->GetTemplateURLs()[2]->keyword());
543 EXPECT_FALSE(model()->GetTemplateURLs()[2]->safe_for_autoreplace());
544 EXPECT_EQ(month_ago.ToInternalValue(),
545 model()->GetTemplateURLs()[2]->date_created().ToInternalValue());
546
547 // Try removing from Time=0. This should delete one more.
548 model()->RemoveAutoGeneratedSince(Time());
549 EXPECT_EQ(2U, model()->GetTemplateURLs().size());
550 }
551
TEST_F(TemplateURLModelTest,Reset)552 TEST_F(TemplateURLModelTest, Reset) {
553 // Add a new TemplateURL.
554 VerifyLoad();
555 const size_t initial_count = model()->GetTemplateURLs().size();
556 TemplateURL* t_url = new TemplateURL();
557 t_url->SetURL("http://www.google.com/foo/bar", 0, 0);
558 t_url->set_keyword(ASCIIToUTF16("keyword"));
559 t_url->set_short_name(ASCIIToUTF16("google"));
560 GURL favicon_url("http://favicon.url");
561 t_url->SetFaviconURL(favicon_url);
562 t_url->set_date_created(Time::FromTimeT(100));
563 model()->Add(t_url);
564
565 VerifyObserverCount(1);
566 BlockTillServiceProcessesRequests();
567
568 // Reset the short name, keyword, url and make sure it takes.
569 const string16 new_short_name(ASCIIToUTF16("a"));
570 const string16 new_keyword(ASCIIToUTF16("b"));
571 const std::string new_url("c");
572 model()->ResetTemplateURL(t_url, new_short_name, new_keyword, new_url);
573 ASSERT_EQ(new_short_name, t_url->short_name());
574 ASSERT_EQ(new_keyword, t_url->keyword());
575 ASSERT_EQ(new_url, t_url->url()->url());
576
577 // Make sure the mappings in the model were updated.
578 ASSERT_TRUE(model()->GetTemplateURLForKeyword(new_keyword) == t_url);
579 ASSERT_TRUE(
580 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")) == NULL);
581
582 TemplateURL last_url = *t_url;
583
584 // Reload the model from the database and make sure the change took.
585 ResetModel(true);
586 t_url = NULL;
587 EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
588 const TemplateURL* read_url = model()->GetTemplateURLForKeyword(new_keyword);
589 ASSERT_TRUE(read_url);
590 AssertEquals(last_url, *read_url);
591 }
592
TEST_F(TemplateURLModelTest,DefaultSearchProvider)593 TEST_F(TemplateURLModelTest, DefaultSearchProvider) {
594 // Add a new TemplateURL.
595 VerifyLoad();
596 const size_t initial_count = model()->GetTemplateURLs().size();
597 TemplateURL* t_url = AddKeywordWithDate("key1", false, "http://foo1",
598 "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time());
599
600 test_util_.ResetObserverCount();
601 model()->SetDefaultSearchProvider(t_url);
602
603 ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());
604
605 ASSERT_TRUE(t_url->safe_for_autoreplace());
606 ASSERT_TRUE(t_url->show_in_default_list());
607
608 // Setting the default search provider should have caused notification.
609 VerifyObserverCount(1);
610
611 BlockTillServiceProcessesRequests();
612
613 TemplateURL cloned_url = *t_url;
614
615 ResetModel(true);
616 t_url = NULL;
617
618 // Make sure when we reload we get a default search provider.
619 EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
620 ASSERT_TRUE(model()->GetDefaultSearchProvider());
621 AssertEquals(cloned_url, *model()->GetDefaultSearchProvider());
622 }
623
TEST_F(TemplateURLModelTest,TemplateURLWithNoKeyword)624 TEST_F(TemplateURLModelTest, TemplateURLWithNoKeyword) {
625 VerifyLoad();
626
627 const size_t initial_count = model()->GetTemplateURLs().size();
628
629 AddKeywordWithDate("", false, "http://foo1", "http://sugg1",
630 "http://icon1", "UTF-8;UTF-16", "name1", true, Time());
631
632 // We just added a few items, validate them.
633 ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
634
635 // Reload the model from the database and make sure we get the url back.
636 ResetModel(true);
637
638 ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
639
640 bool found_keyword = false;
641 for (size_t i = 0; i < initial_count + 1; ++i) {
642 if (model()->GetTemplateURLs()[i]->keyword().empty()) {
643 found_keyword = true;
644 break;
645 }
646 }
647 ASSERT_TRUE(found_keyword);
648 }
649
TEST_F(TemplateURLModelTest,CantReplaceWithSameKeyword)650 TEST_F(TemplateURLModelTest, CantReplaceWithSameKeyword) {
651 ChangeModelToLoadState();
652 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"), GURL(), NULL));
653 TemplateURL* t_url = AddKeywordWithDate("foo", false, "http://foo1",
654 "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time());
655
656 // Can still replace, newly added template url is marked safe to replace.
657 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
658 GURL("http://foo2"), NULL));
659
660 // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
661 // no longer be replaceable.
662 model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
663 t_url->url()->url());
664
665 ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
666 GURL("http://foo2"), NULL));
667 }
668
TEST_F(TemplateURLModelTest,CantReplaceWithSameHosts)669 TEST_F(TemplateURLModelTest, CantReplaceWithSameHosts) {
670 ChangeModelToLoadState();
671 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("foo"),
672 GURL("http://foo.com"), NULL));
673 TemplateURL* t_url = AddKeywordWithDate("foo", false, "http://foo.com",
674 "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1", true, Time());
675
676 // Can still replace, newly added template url is marked safe to replace.
677 ASSERT_TRUE(model()->CanReplaceKeyword(ASCIIToUTF16("bar"),
678 GURL("http://foo.com"), NULL));
679
680 // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
681 // no longer be replaceable.
682 model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
683 t_url->url()->url());
684
685 ASSERT_FALSE(model()->CanReplaceKeyword(ASCIIToUTF16("bar"),
686 GURL("http://foo.com"), NULL));
687 }
688
TEST_F(TemplateURLModelTest,HasDefaultSearchProvider)689 TEST_F(TemplateURLModelTest, HasDefaultSearchProvider) {
690 // We should have a default search provider even if we haven't loaded.
691 ASSERT_TRUE(model()->GetDefaultSearchProvider());
692
693 // Now force the model to load and make sure we still have a default.
694 VerifyLoad();
695
696 ASSERT_TRUE(model()->GetDefaultSearchProvider());
697 }
698
TEST_F(TemplateURLModelTest,DefaultSearchProviderLoadedFromPrefs)699 TEST_F(TemplateURLModelTest, DefaultSearchProviderLoadedFromPrefs) {
700 VerifyLoad();
701
702 TemplateURL* template_url = new TemplateURL();
703 template_url->SetURL("http://url", 0, 0);
704 template_url->SetSuggestionsURL("http://url2", 0, 0);
705 template_url->SetInstantURL("http://instant", 0, 0);
706 template_url->set_short_name(ASCIIToUTF16("a"));
707 template_url->set_safe_for_autoreplace(true);
708 template_url->set_date_created(Time::FromTimeT(100));
709
710 model()->Add(template_url);
711
712 const TemplateURLID id = template_url->id();
713
714 model()->SetDefaultSearchProvider(template_url);
715
716 BlockTillServiceProcessesRequests();
717
718 TemplateURL first_default_search_provider = *template_url;
719
720 template_url = NULL;
721
722 // Reset the model and don't load it. The template url we set as the default
723 // should be pulled from prefs now.
724 ResetModel(false);
725
726 // NOTE: This doesn't use AssertEquals as only a subset of the TemplateURLs
727 // value are persisted to prefs.
728 const TemplateURL* default_turl = model()->GetDefaultSearchProvider();
729 ASSERT_TRUE(default_turl);
730 ASSERT_TRUE(default_turl->url());
731 ASSERT_EQ("http://url", default_turl->url()->url());
732 ASSERT_TRUE(default_turl->suggestions_url());
733 ASSERT_EQ("http://url2", default_turl->suggestions_url()->url());
734 ASSERT_TRUE(default_turl->instant_url());
735 EXPECT_EQ("http://instant", default_turl->instant_url()->url());
736 ASSERT_EQ(ASCIIToUTF16("a"), default_turl->short_name());
737 ASSERT_EQ(id, default_turl->id());
738
739 // Now do a load and make sure the default search provider really takes.
740 VerifyLoad();
741
742 ASSERT_TRUE(model()->GetDefaultSearchProvider());
743 AssertEquals(first_default_search_provider,
744 *model()->GetDefaultSearchProvider());
745 }
746
TEST_F(TemplateURLModelTest,BuildQueryTerms)747 TEST_F(TemplateURLModelTest, BuildQueryTerms) {
748 struct TestData {
749 const std::string url;
750 const bool result;
751 // Keys and values are a semicolon separated list of expected values in the
752 // map.
753 const std::string keys;
754 const std::string values;
755 } data[] = {
756 // No query should return false.
757 { "http://blah/", false, "", "" },
758
759 // Query with empty key should return false.
760 { "http://blah/foo?=y", false, "", "" },
761
762 // Query with key occurring multiple times should return false.
763 { "http://blah/foo?x=y&x=z", false, "", "" },
764
765 { "http://blah/foo?x=y", true, "x", "y" },
766 { "http://blah/foo?x=y&y=z", true, "x;y", "y;z" },
767
768 // Key occurring multiple times should get an empty string.
769 { "http://blah/foo?x=y&x=z&y=z", true, "x;y", ";z" },
770 };
771
772 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
773 TemplateURLModel::QueryTerms terms;
774 ASSERT_EQ(data[i].result,
775 TemplateURLModel::BuildQueryTerms(GURL(data[i].url), &terms));
776 if (data[i].result) {
777 std::vector<std::string> keys;
778 std::vector<std::string> values;
779 base::SplitString(data[i].keys, ';', &keys);
780 base::SplitString(data[i].values, ';', &values);
781 ASSERT_TRUE(keys.size() == values.size());
782 ASSERT_EQ(keys.size(), terms.size());
783 for (size_t j = 0; j < keys.size(); ++j) {
784 TemplateURLModel::QueryTerms::iterator term_iterator =
785 terms.find(keys[j]);
786 ASSERT_TRUE(term_iterator != terms.end());
787 ASSERT_EQ(values[j], term_iterator->second);
788 }
789 }
790 }
791 }
792
TEST_F(TemplateURLModelTest,UpdateKeywordSearchTermsForURL)793 TEST_F(TemplateURLModelTest, UpdateKeywordSearchTermsForURL) {
794 struct TestData {
795 const std::string url;
796 const string16 term;
797 } data[] = {
798 { "http://foo/", string16() },
799 { "http://foo/foo?q=xx", string16() },
800 { "http://x/bar?q=xx", string16() },
801 { "http://x/foo?y=xx", string16() },
802 { "http://x/foo?q=xx", ASCIIToUTF16("xx") },
803 { "http://x/foo?a=b&q=xx", ASCIIToUTF16("xx") },
804 { "http://x/foo?q=b&q=xx", string16() },
805 };
806
807 ChangeModelToLoadState();
808 AddKeywordWithDate("x", false, "http://x/foo?q={searchTerms}",
809 "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name", false, Time());
810
811 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
812 history::URLVisitedDetails details;
813 details.row = history::URLRow(GURL(data[i].url));
814 details.transition = 0;
815 model()->UpdateKeywordSearchTermsForURL(details);
816 EXPECT_EQ(data[i].term, GetAndClearSearchTerm());
817 }
818 }
819
TEST_F(TemplateURLModelTest,DontUpdateKeywordSearchForNonReplaceable)820 TEST_F(TemplateURLModelTest, DontUpdateKeywordSearchForNonReplaceable) {
821 struct TestData {
822 const std::string url;
823 } data[] = {
824 { "http://foo/" },
825 { "http://x/bar?q=xx" },
826 { "http://x/foo?y=xx" },
827 };
828
829 ChangeModelToLoadState();
830 AddKeywordWithDate("x", false, "http://x/foo", "http://sugg1",
831 "http://icon1", "UTF-8;UTF-16", "name", false, Time());
832
833 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
834 history::URLVisitedDetails details;
835 details.row = history::URLRow(GURL(data[i].url));
836 details.transition = 0;
837 model()->UpdateKeywordSearchTermsForURL(details);
838 ASSERT_EQ(string16(), GetAndClearSearchTerm());
839 }
840 }
841
TEST_F(TemplateURLModelTest,ChangeGoogleBaseValue)842 TEST_F(TemplateURLModelTest, ChangeGoogleBaseValue) {
843 // NOTE: Do not do a VerifyLoad() here as it will load the prepopulate data,
844 // which also has a {google:baseURL} keyword in it, which will confuse this
845 // test.
846 ChangeModelToLoadState();
847 SetGoogleBaseURL("http://google.com/");
848 const TemplateURL* t_url = AddKeywordWithDate("", true,
849 "{google:baseURL}?q={searchTerms}", "http://sugg1", "http://icon1",
850 "UTF-8;UTF-16", "name", false, Time());
851 ASSERT_EQ(t_url, model()->GetTemplateURLForHost("google.com"));
852 EXPECT_EQ("google.com", t_url->url()->GetHost());
853 EXPECT_EQ(ASCIIToUTF16("google.com"), t_url->keyword());
854
855 // Change the Google base url.
856 test_util_.ResetObserverCount();
857 SetGoogleBaseURL("http://foo.com/");
858 VerifyObserverCount(1);
859
860 // Make sure the host->TemplateURL map was updated appropriately.
861 ASSERT_EQ(t_url, model()->GetTemplateURLForHost("foo.com"));
862 EXPECT_TRUE(model()->GetTemplateURLForHost("google.com") == NULL);
863 EXPECT_EQ("foo.com", t_url->url()->GetHost());
864 EXPECT_EQ(ASCIIToUTF16("foo.com"), t_url->keyword());
865 EXPECT_EQ("http://foo.com/?q=x", t_url->url()->ReplaceSearchTerms(*t_url,
866 ASCIIToUTF16("x"), TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16()));
867 }
868
869 struct QueryHistoryCallbackImpl {
QueryHistoryCallbackImplQueryHistoryCallbackImpl870 QueryHistoryCallbackImpl() : success(false) {}
871
CallbackQueryHistoryCallbackImpl872 void Callback(HistoryService::Handle handle,
873 bool success, const history::URLRow* row,
874 history::VisitVector* visits) {
875 this->success = success;
876 if (row)
877 this->row = *row;
878 if (visits)
879 this->visits = *visits;
880 }
881
882 bool success;
883 history::URLRow row;
884 history::VisitVector visits;
885 };
886
887 // Make sure TemplateURLModel generates a KEYWORD_GENERATED visit for
888 // KEYWORD visits.
TEST_F(TemplateURLModelTest,GenerateVisitOnKeyword)889 TEST_F(TemplateURLModelTest, GenerateVisitOnKeyword) {
890 VerifyLoad();
891 profile()->CreateHistoryService(true, false);
892
893 // Create a keyword.
894 TemplateURL* t_url = AddKeywordWithDate(
895 "keyword", false, "http://foo.com/foo?query={searchTerms}",
896 "http://sugg1", "http://icon1", "UTF-8;UTF-16", "keyword",
897 true, base::Time::Now());
898
899 // Add a visit that matches the url of the keyword.
900 HistoryService* history =
901 profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
902 history->AddPage(
903 GURL(t_url->url()->ReplaceSearchTerms(*t_url, ASCIIToUTF16("blah"), 0,
904 string16())),
905 NULL, 0, GURL(), PageTransition::KEYWORD, history::RedirectList(),
906 history::SOURCE_BROWSED, false);
907
908 // Wait for history to finish processing the request.
909 profile()->BlockUntilHistoryProcessesPendingRequests();
910
911 // Query history for the generated url.
912 CancelableRequestConsumer consumer;
913 QueryHistoryCallbackImpl callback;
914 history->QueryURL(GURL("http://keyword"), true, &consumer,
915 NewCallback(&callback, &QueryHistoryCallbackImpl::Callback));
916
917 // Wait for the request to be processed.
918 profile()->BlockUntilHistoryProcessesPendingRequests();
919
920 // And make sure the url and visit were added.
921 EXPECT_TRUE(callback.success);
922 EXPECT_NE(0, callback.row.id());
923 ASSERT_EQ(1U, callback.visits.size());
924 EXPECT_EQ(PageTransition::KEYWORD_GENERATED,
925 PageTransition::StripQualifier(callback.visits[0].transition));
926 }
927
928 // Make sure that the load routine deletes prepopulated engines that no longer
929 // exist in the prepopulate data.
TEST_F(TemplateURLModelTest,LoadDeletesUnusedProvider)930 TEST_F(TemplateURLModelTest, LoadDeletesUnusedProvider) {
931 // Create a preloaded template url. Add it to a loaded model and wait for the
932 // saves to finish.
933 TemplateURL* t_url = CreatePreloadedTemplateURL();
934 ChangeModelToLoadState();
935 model()->Add(t_url);
936 ASSERT_TRUE(
937 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) != NULL);
938 BlockTillServiceProcessesRequests();
939
940 // Ensure that merging clears this engine.
941 ResetModel(true);
942 ASSERT_TRUE(
943 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) == NULL);
944
945 // Wait for any saves to finish.
946 BlockTillServiceProcessesRequests();
947
948 // Reload the model to verify that the database was updated as a result of the
949 // merge.
950 ResetModel(true);
951 ASSERT_TRUE(
952 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) == NULL);
953 }
954
955 // Make sure that load routine doesn't delete prepopulated engines that no
956 // longer exist in the prepopulate data if it has been modified by the user.
TEST_F(TemplateURLModelTest,LoadRetainsModifiedProvider)957 TEST_F(TemplateURLModelTest, LoadRetainsModifiedProvider) {
958 // Create a preloaded template url and add it to a loaded model.
959 TemplateURL* t_url = CreatePreloadedTemplateURL();
960 t_url->set_safe_for_autoreplace(false);
961 ChangeModelToLoadState();
962 model()->Add(t_url);
963
964 // Do the copy after t_url is added so that the id is set.
965 TemplateURL copy_t_url = *t_url;
966 ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")));
967
968 // Wait for any saves to finish.
969 BlockTillServiceProcessesRequests();
970
971 // Ensure that merging won't clear it if the user has edited it.
972 ResetModel(true);
973 const TemplateURL* url_for_unittest =
974 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
975 ASSERT_TRUE(url_for_unittest != NULL);
976 AssertEquals(copy_t_url, *url_for_unittest);
977
978 // Wait for any saves to finish.
979 BlockTillServiceProcessesRequests();
980
981 // Reload the model to verify that save/reload retains the item.
982 ResetModel(true);
983 ASSERT_TRUE(
984 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")) != NULL);
985 }
986
987 // Make sure that load routine doesn't delete
988 // prepopulated engines that no longer exist in the prepopulate data if
989 // it has been modified by the user.
TEST_F(TemplateURLModelTest,LoadSavesPrepopulatedDefaultSearchProvider)990 TEST_F(TemplateURLModelTest, LoadSavesPrepopulatedDefaultSearchProvider) {
991 VerifyLoad();
992 // Verify that the default search provider is set to something.
993 ASSERT_TRUE(model()->GetDefaultSearchProvider() != NULL);
994 TemplateURL default_url = *model()->GetDefaultSearchProvider();
995
996 // Wait for any saves to finish.
997 BlockTillServiceProcessesRequests();
998
999 // Reload the model and check that the default search provider
1000 // was properly saved.
1001 ResetModel(true);
1002 ASSERT_TRUE(model()->GetDefaultSearchProvider() != NULL);
1003 AssertEquals(default_url, *model()->GetDefaultSearchProvider());
1004 }
1005
1006 // Make sure that the load routine doesn't delete
1007 // prepopulated engines that no longer exist in the prepopulate data if
1008 // it is the default search provider.
TEST_F(TemplateURLModelTest,LoadRetainsDefaultProvider)1009 TEST_F(TemplateURLModelTest, LoadRetainsDefaultProvider) {
1010 // Set the default search provider to a preloaded template url which
1011 // is not in the current set of preloaded template urls and save
1012 // the result.
1013 TemplateURL* t_url = CreatePreloadedTemplateURL();
1014 ChangeModelToLoadState();
1015 model()->Add(t_url);
1016 model()->SetDefaultSearchProvider(t_url);
1017 // Do the copy after t_url is added and set as default so that its
1018 // internal state is correct.
1019 TemplateURL copy_t_url = *t_url;
1020
1021 ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest")));
1022 ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());
1023 BlockTillServiceProcessesRequests();
1024
1025 // Ensure that merging won't clear the prepopulated template url
1026 // which is no longer present if it's the default engine.
1027 ResetModel(true);
1028 {
1029 const TemplateURL* keyword_url =
1030 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
1031 ASSERT_TRUE(keyword_url != NULL);
1032 AssertEquals(copy_t_url, *keyword_url);
1033 ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
1034 }
1035
1036 // Wait for any saves to finish.
1037 BlockTillServiceProcessesRequests();
1038
1039 // Reload the model to verify that the update was saved.
1040 ResetModel(true);
1041 {
1042 const TemplateURL* keyword_url =
1043 model()->GetTemplateURLForKeyword(ASCIIToUTF16("unittest"));
1044 ASSERT_TRUE(keyword_url != NULL);
1045 AssertEquals(copy_t_url, *keyword_url);
1046 ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
1047 }
1048 }
1049
1050 // Make sure that the load routine updates the url of a preexisting
1051 // default search engine provider and that the result is saved correctly.
TEST_F(TemplateURLModelTest,LoadUpdatesDefaultSearchURL)1052 TEST_F(TemplateURLModelTest, LoadUpdatesDefaultSearchURL) {
1053 TestLoadUpdatingPreloadedURL(0);
1054 }
1055
1056 // Make sure that the load routine updates the url of a preexisting
1057 // non-default search engine provider and that the result is saved correctly.
TEST_F(TemplateURLModelTest,LoadUpdatesSearchURL)1058 TEST_F(TemplateURLModelTest, LoadUpdatesSearchURL) {
1059 TestLoadUpdatingPreloadedURL(1);
1060 }
1061
1062 // Make sure that the load does update of auto-keywords correctly.
1063 // This test basically verifies that no asserts or crashes occur
1064 // during this operation.
TEST_F(TemplateURLModelTest,LoadDoesAutoKeywordUpdate)1065 TEST_F(TemplateURLModelTest, LoadDoesAutoKeywordUpdate) {
1066 string16 prepopulated_url;
1067 TemplateURL* t_url = CreateReplaceablePreloadedTemplateURL(
1068 0, &prepopulated_url);
1069 t_url->set_safe_for_autoreplace(false);
1070 t_url->SetURL("{google:baseURL}?q={searchTerms}", 0, 0);
1071 t_url->set_autogenerate_keyword(true);
1072
1073 // Then add it to the model and save it all.
1074 ChangeModelToLoadState();
1075 model()->Add(t_url);
1076 BlockTillServiceProcessesRequests();
1077
1078 // Now reload the model and verify that the merge updates the url.
1079 ResetModel(true);
1080
1081 // Wait for any saves to finish.
1082 BlockTillServiceProcessesRequests();
1083 }
1084
1085 // Simulates failing to load the webdb and makes sure the default search
1086 // provider is valid.
TEST_F(TemplateURLModelTest,FailedInit)1087 TEST_F(TemplateURLModelTest, FailedInit) {
1088 VerifyLoad();
1089
1090 test_util_.ClearModel();
1091 test_util_.GetWebDataService()->UnloadDatabase();
1092 test_util_.GetWebDataService()->set_failed_init(true);
1093
1094 ResetModel(false);
1095 model()->Load();
1096 BlockTillServiceProcessesRequests();
1097
1098 ASSERT_TRUE(model()->GetDefaultSearchProvider());
1099 }
1100
1101 // Verifies that if the default search URL preference is managed, we report
1102 // the default search as managed. Also check that we are getting the right
1103 // values.
TEST_F(TemplateURLModelTest,TestManagedDefaultSearch)1104 TEST_F(TemplateURLModelTest, TestManagedDefaultSearch) {
1105 VerifyLoad();
1106 const size_t initial_count = model()->GetTemplateURLs().size();
1107 test_util_.ResetObserverCount();
1108
1109 // Set a regular default search provider.
1110 TemplateURL* regular_default = AddKeywordWithDate("key1", false,
1111 "http://foo1", "http://sugg1", "http://icon1", "UTF-8;UTF-16", "name1",
1112 true, Time());
1113 VerifyObserverCount(1);
1114 model()->SetDefaultSearchProvider(regular_default);
1115 // Adding the URL and setting the default search provider should have caused
1116 // notifications.
1117 VerifyObserverCount(1);
1118 EXPECT_FALSE(model()->is_default_search_managed());
1119 EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
1120
1121 // Set a managed preference that establishes a default search provider.
1122 const char kName[] = "test1";
1123 const char kSearchURL[] = "http://test.com/search?t={searchTerms}";
1124 const char kIconURL[] = "http://test.com/icon.jpg";
1125 const char kEncodings[] = "UTF-16;UTF-32";
1126 SetManagedDefaultSearchPreferences(true, kName, kSearchURL, "", kIconURL,
1127 kEncodings, "");
1128 VerifyObserverFired();
1129 EXPECT_TRUE(model()->is_default_search_managed());
1130 EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());
1131
1132 // Verify that the default manager we are getting is the managed one.
1133 scoped_ptr<TemplateURL> expected_managed_default1(new TemplateURL());
1134 expected_managed_default1->SetURL(kSearchURL, 0, 0);
1135 expected_managed_default1->SetFaviconURL(GURL(kIconURL));
1136 expected_managed_default1->set_short_name(ASCIIToUTF16("test1"));
1137 std::vector<std::string> encodings_vector;
1138 base::SplitString(kEncodings, ';', &encodings_vector);
1139 expected_managed_default1->set_input_encodings(encodings_vector);
1140 expected_managed_default1->set_show_in_default_list(true);
1141 const TemplateURL* actual_managed_default =
1142 model()->GetDefaultSearchProvider();
1143 ExpectSimilar(actual_managed_default, expected_managed_default1.get());
1144 EXPECT_EQ(actual_managed_default->show_in_default_list(), true);
1145
1146 // Update the managed preference and check that the model has changed.
1147 const char kNewName[] = "test2";
1148 const char kNewSearchURL[] = "http://other.com/search?t={searchTerms}";
1149 const char kNewSuggestURL[] = "http://other.com/suggest?t={searchTerms}";
1150 SetManagedDefaultSearchPreferences(true, kNewName, kNewSearchURL,
1151 kNewSuggestURL, "", "", "");
1152 VerifyObserverFired();
1153 EXPECT_TRUE(model()->is_default_search_managed());
1154 EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());
1155
1156 // Verify that the default manager we are now getting is the correct one.
1157 scoped_ptr<TemplateURL> expected_managed_default2(new TemplateURL());
1158 expected_managed_default2->SetURL(kNewSearchURL, 0, 0);
1159 expected_managed_default2->SetSuggestionsURL(kNewSuggestURL, 0, 0);
1160 expected_managed_default2->set_short_name(ASCIIToUTF16("test2"));
1161 expected_managed_default2->set_show_in_default_list(true);
1162 actual_managed_default = model()->GetDefaultSearchProvider();
1163 ExpectSimilar(actual_managed_default, expected_managed_default2.get());
1164 EXPECT_EQ(actual_managed_default->show_in_default_list(), true);
1165
1166 // Remove all the managed prefs and check that we are no longer managed.
1167 RemoveManagedDefaultSearchPreferences();
1168 VerifyObserverFired();
1169 EXPECT_FALSE(model()->is_default_search_managed());
1170 EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
1171
1172 // The default should now be the first URL added
1173 const TemplateURL* actual_final_managed_default =
1174 model()->GetDefaultSearchProvider();
1175 ExpectSimilar(actual_final_managed_default,
1176 model()->GetTemplateURLs()[0]);
1177 EXPECT_EQ(actual_final_managed_default->show_in_default_list(), true);
1178
1179 // Disable the default search provider through policy.
1180 SetManagedDefaultSearchPreferences(false, "", "", "", "", "", "");
1181 VerifyObserverFired();
1182 EXPECT_TRUE(model()->is_default_search_managed());
1183 EXPECT_TRUE(NULL == model()->GetDefaultSearchProvider());
1184 EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
1185
1186 // Re-enable it.
1187 SetManagedDefaultSearchPreferences(true, kName, kSearchURL, "", kIconURL,
1188 kEncodings, "");
1189 VerifyObserverFired();
1190 EXPECT_TRUE(model()->is_default_search_managed());
1191 EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());
1192
1193 // Verify that the default manager we are getting is the managed one.
1194 actual_managed_default = model()->GetDefaultSearchProvider();
1195 ExpectSimilar(actual_managed_default, expected_managed_default1.get());
1196 EXPECT_EQ(actual_managed_default->show_in_default_list(), true);
1197 }
1198