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/command_line.h" 6 #include "base/files/scoped_temp_dir.h" 7 #include "base/memory/scoped_vector.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/browser/search_engines/prepopulated_engines.h" 10 #include "chrome/browser/search_engines/search_terms_data.h" 11 #include "chrome/browser/search_engines/template_url.h" 12 #include "chrome/browser/search_engines/template_url_prepopulate_data.h" 13 #include "chrome/browser/search_engines/template_url_service.h" 14 #include "chrome/common/chrome_switches.h" 15 #include "chrome/common/pref_names.h" 16 #include "chrome/test/base/testing_pref_service_syncable.h" 17 #include "chrome/test/base/testing_profile.h" 18 #include "grit/generated_resources.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 #include "ui/base/l10n/l10n_util.h" 21 22 namespace { 23 SearchEngineType GetEngineType(const std::string& url) { 24 TemplateURLData data; 25 data.SetURL(url); 26 return TemplateURLPrepopulateData::GetEngineType(TemplateURL(NULL, data)); 27 } 28 } // namespace 29 30 typedef testing::Test TemplateURLPrepopulateDataTest; 31 32 // Verifies the set of prepopulate data doesn't contain entries with duplicate 33 // ids. 34 TEST(TemplateURLPrepopulateDataTest, UniqueIDs) { 35 const int kCountryIds[] = { 36 'A'<<8|'D', 'A'<<8|'E', 'A'<<8|'F', 'A'<<8|'G', 'A'<<8|'I', 37 'A'<<8|'L', 'A'<<8|'M', 'A'<<8|'N', 'A'<<8|'O', 'A'<<8|'Q', 38 'A'<<8|'R', 'A'<<8|'S', 'A'<<8|'T', 'A'<<8|'U', 'A'<<8|'W', 39 'A'<<8|'X', 'A'<<8|'Z', 'B'<<8|'A', 'B'<<8|'B', 'B'<<8|'D', 40 'B'<<8|'E', 'B'<<8|'F', 'B'<<8|'G', 'B'<<8|'H', 'B'<<8|'I', 41 'B'<<8|'J', 'B'<<8|'M', 'B'<<8|'N', 'B'<<8|'O', 'B'<<8|'R', 42 'B'<<8|'S', 'B'<<8|'T', 'B'<<8|'V', 'B'<<8|'W', 'B'<<8|'Y', 43 'B'<<8|'Z', 'C'<<8|'A', 'C'<<8|'C', 'C'<<8|'D', 'C'<<8|'F', 44 'C'<<8|'G', 'C'<<8|'H', 'C'<<8|'I', 'C'<<8|'K', 'C'<<8|'L', 45 'C'<<8|'M', 'C'<<8|'N', 'C'<<8|'O', 'C'<<8|'R', 'C'<<8|'U', 46 'C'<<8|'V', 'C'<<8|'X', 'C'<<8|'Y', 'C'<<8|'Z', 'D'<<8|'E', 47 'D'<<8|'J', 'D'<<8|'K', 'D'<<8|'M', 'D'<<8|'O', 'D'<<8|'Z', 48 'E'<<8|'C', 'E'<<8|'E', 'E'<<8|'G', 'E'<<8|'R', 'E'<<8|'S', 49 'E'<<8|'T', 'F'<<8|'I', 'F'<<8|'J', 'F'<<8|'K', 'F'<<8|'M', 50 'F'<<8|'O', 'F'<<8|'R', 'G'<<8|'A', 'G'<<8|'B', 'G'<<8|'D', 51 'G'<<8|'E', 'G'<<8|'F', 'G'<<8|'G', 'G'<<8|'H', 'G'<<8|'I', 52 'G'<<8|'L', 'G'<<8|'M', 'G'<<8|'N', 'G'<<8|'P', 'G'<<8|'Q', 53 'G'<<8|'R', 'G'<<8|'S', 'G'<<8|'T', 'G'<<8|'U', 'G'<<8|'W', 54 'G'<<8|'Y', 'H'<<8|'K', 'H'<<8|'M', 'H'<<8|'N', 'H'<<8|'R', 55 'H'<<8|'T', 'H'<<8|'U', 'I'<<8|'D', 'I'<<8|'E', 'I'<<8|'L', 56 'I'<<8|'M', 'I'<<8|'N', 'I'<<8|'O', 'I'<<8|'P', 'I'<<8|'Q', 57 'I'<<8|'R', 'I'<<8|'S', 'I'<<8|'T', 'J'<<8|'E', 'J'<<8|'M', 58 'J'<<8|'O', 'J'<<8|'P', 'K'<<8|'E', 'K'<<8|'G', 'K'<<8|'H', 59 'K'<<8|'I', 'K'<<8|'M', 'K'<<8|'N', 'K'<<8|'P', 'K'<<8|'R', 60 'K'<<8|'W', 'K'<<8|'Y', 'K'<<8|'Z', 'L'<<8|'A', 'L'<<8|'B', 61 'L'<<8|'C', 'L'<<8|'I', 'L'<<8|'K', 'L'<<8|'R', 'L'<<8|'S', 62 'L'<<8|'T', 'L'<<8|'U', 'L'<<8|'V', 'L'<<8|'Y', 'M'<<8|'A', 63 'M'<<8|'C', 'M'<<8|'D', 'M'<<8|'E', 'M'<<8|'G', 'M'<<8|'H', 64 'M'<<8|'K', 'M'<<8|'L', 'M'<<8|'M', 'M'<<8|'N', 'M'<<8|'O', 65 'M'<<8|'P', 'M'<<8|'Q', 'M'<<8|'R', 'M'<<8|'S', 'M'<<8|'T', 66 'M'<<8|'U', 'M'<<8|'V', 'M'<<8|'W', 'M'<<8|'X', 'M'<<8|'Y', 67 'M'<<8|'Z', 'N'<<8|'A', 'N'<<8|'C', 'N'<<8|'E', 'N'<<8|'F', 68 'N'<<8|'G', 'N'<<8|'I', 'N'<<8|'L', 'N'<<8|'O', 'N'<<8|'P', 69 'N'<<8|'R', 'N'<<8|'U', 'N'<<8|'Z', 'O'<<8|'M', 'P'<<8|'A', 70 'P'<<8|'E', 'P'<<8|'F', 'P'<<8|'G', 'P'<<8|'H', 'P'<<8|'K', 71 'P'<<8|'L', 'P'<<8|'M', 'P'<<8|'N', 'P'<<8|'R', 'P'<<8|'S', 72 'P'<<8|'T', 'P'<<8|'W', 'P'<<8|'Y', 'Q'<<8|'A', 'R'<<8|'E', 73 'R'<<8|'O', 'R'<<8|'S', 'R'<<8|'U', 'R'<<8|'W', 'S'<<8|'A', 74 'S'<<8|'B', 'S'<<8|'C', 'S'<<8|'D', 'S'<<8|'E', 'S'<<8|'G', 75 'S'<<8|'H', 'S'<<8|'I', 'S'<<8|'J', 'S'<<8|'K', 'S'<<8|'L', 76 'S'<<8|'M', 'S'<<8|'N', 'S'<<8|'O', 'S'<<8|'R', 'S'<<8|'T', 77 'S'<<8|'V', 'S'<<8|'Y', 'S'<<8|'Z', 'T'<<8|'C', 'T'<<8|'D', 78 'T'<<8|'F', 'T'<<8|'G', 'T'<<8|'H', 'T'<<8|'J', 'T'<<8|'K', 79 'T'<<8|'L', 'T'<<8|'M', 'T'<<8|'N', 'T'<<8|'O', 'T'<<8|'R', 80 'T'<<8|'T', 'T'<<8|'V', 'T'<<8|'W', 'T'<<8|'Z', 'U'<<8|'A', 81 'U'<<8|'G', 'U'<<8|'M', 'U'<<8|'S', 'U'<<8|'Y', 'U'<<8|'Z', 82 'V'<<8|'A', 'V'<<8|'C', 'V'<<8|'E', 'V'<<8|'G', 'V'<<8|'I', 83 'V'<<8|'N', 'V'<<8|'U', 'W'<<8|'F', 'W'<<8|'S', 'Y'<<8|'E', 84 'Y'<<8|'T', 'Z'<<8|'A', 'Z'<<8|'M', 'Z'<<8|'W', -1 }; 85 86 TestingProfile profile; 87 for (size_t i = 0; i < arraysize(kCountryIds); ++i) { 88 profile.GetPrefs()->SetInteger(prefs::kCountryIDAtInstall, kCountryIds[i]); 89 ScopedVector<TemplateURL> urls; 90 size_t default_index; 91 TemplateURLPrepopulateData::GetPrepopulatedEngines(&profile, &urls.get(), 92 &default_index); 93 std::set<int> unique_ids; 94 for (size_t turl_i = 0; turl_i < urls.size(); ++turl_i) { 95 ASSERT_TRUE(unique_ids.find(urls[turl_i]->prepopulate_id()) == 96 unique_ids.end()); 97 unique_ids.insert(urls[turl_i]->prepopulate_id()); 98 } 99 } 100 } 101 102 // Verifies that default search providers from the preferences file 103 // override the built-in ones. 104 TEST(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) { 105 TestingProfile profile; 106 TestingPrefServiceSyncable* prefs = profile.GetTestingPrefService(); 107 prefs->SetUserPref(prefs::kSearchProviderOverridesVersion, 108 Value::CreateIntegerValue(1)); 109 ListValue* overrides = new ListValue; 110 scoped_ptr<DictionaryValue> entry(new DictionaryValue); 111 // Set only the minimal required settings for a search provider configuration. 112 entry->SetString("name", "foo"); 113 entry->SetString("keyword", "fook"); 114 entry->SetString("search_url", "http://foo.com/s?q={searchTerms}"); 115 entry->SetString("favicon_url", "http://foi.com/favicon.ico"); 116 entry->SetString("encoding", "UTF-8"); 117 entry->SetInteger("id", 1001); 118 overrides->Append(entry->DeepCopy()); 119 prefs->SetUserPref(prefs::kSearchProviderOverrides, overrides); 120 121 int version = TemplateURLPrepopulateData::GetDataVersion(prefs); 122 EXPECT_EQ(1, version); 123 124 ScopedVector<TemplateURL> t_urls; 125 size_t default_index; 126 TemplateURLPrepopulateData::GetPrepopulatedEngines(&profile, &t_urls.get(), 127 &default_index); 128 129 ASSERT_EQ(1u, t_urls.size()); 130 EXPECT_EQ(ASCIIToUTF16("foo"), t_urls[0]->short_name()); 131 EXPECT_EQ(ASCIIToUTF16("fook"), t_urls[0]->keyword()); 132 EXPECT_EQ("foo.com", t_urls[0]->url_ref().GetHost()); 133 EXPECT_EQ("foi.com", t_urls[0]->favicon_url().host()); 134 EXPECT_EQ(1u, t_urls[0]->input_encodings().size()); 135 EXPECT_EQ(1001, t_urls[0]->prepopulate_id()); 136 EXPECT_TRUE(t_urls[0]->suggestions_url().empty()); 137 EXPECT_TRUE(t_urls[0]->instant_url().empty()); 138 EXPECT_EQ(0u, t_urls[0]->alternate_urls().size()); 139 EXPECT_TRUE(t_urls[0]->search_terms_replacement_key().empty()); 140 141 // Test the optional settings too. 142 entry->SetString("suggest_url", "http://foo.com/suggest?q={searchTerms}"); 143 entry->SetString("instant_url", "http://foo.com/instant?q={searchTerms}"); 144 ListValue* alternate_urls = new ListValue; 145 alternate_urls->AppendString("http://foo.com/alternate?q={searchTerms}"); 146 entry->Set("alternate_urls", alternate_urls); 147 entry->SetString("search_terms_replacement_key", "espv"); 148 overrides = new ListValue; 149 overrides->Append(entry->DeepCopy()); 150 prefs->SetUserPref(prefs::kSearchProviderOverrides, overrides); 151 152 t_urls.clear(); 153 TemplateURLPrepopulateData::GetPrepopulatedEngines(&profile, &t_urls.get(), 154 &default_index); 155 ASSERT_EQ(1u, t_urls.size()); 156 EXPECT_EQ(ASCIIToUTF16("foo"), t_urls[0]->short_name()); 157 EXPECT_EQ(ASCIIToUTF16("fook"), t_urls[0]->keyword()); 158 EXPECT_EQ("foo.com", t_urls[0]->url_ref().GetHost()); 159 EXPECT_EQ("foi.com", t_urls[0]->favicon_url().host()); 160 EXPECT_EQ(1u, t_urls[0]->input_encodings().size()); 161 EXPECT_EQ(1001, t_urls[0]->prepopulate_id()); 162 EXPECT_EQ("http://foo.com/suggest?q={searchTerms}", 163 t_urls[0]->suggestions_url()); 164 EXPECT_EQ("http://foo.com/instant?q={searchTerms}", 165 t_urls[0]->instant_url()); 166 ASSERT_EQ(1u, t_urls[0]->alternate_urls().size()); 167 EXPECT_EQ("http://foo.com/alternate?q={searchTerms}", 168 t_urls[0]->alternate_urls()[0]); 169 EXPECT_EQ("espv", t_urls[0]->search_terms_replacement_key()); 170 171 // Test that subsequent providers are loaded even if an intermediate 172 // provider has an incomplete configuration. 173 overrides = new ListValue; 174 overrides->Append(entry->DeepCopy()); 175 entry->SetInteger("id", 1002); 176 entry->SetString("name", "bar"); 177 entry->SetString("keyword", "bark"); 178 entry->SetString("encoding", std::string()); 179 overrides->Append(entry->DeepCopy()); 180 entry->SetInteger("id", 1003); 181 entry->SetString("name", "baz"); 182 entry->SetString("keyword", "bazk"); 183 entry->SetString("encoding", "UTF-8"); 184 overrides->Append(entry->DeepCopy()); 185 prefs->SetUserPref(prefs::kSearchProviderOverrides, overrides); 186 187 t_urls.clear(); 188 TemplateURLPrepopulateData::GetPrepopulatedEngines(&profile, &t_urls.get(), 189 &default_index); 190 EXPECT_EQ(2u, t_urls.size()); 191 } 192 193 TEST(TemplateURLPrepopulateDataTest, ClearProvidersFromPrefs) { 194 TestingProfile profile; 195 TestingPrefServiceSyncable* prefs = profile.GetTestingPrefService(); 196 prefs->SetUserPref(prefs::kSearchProviderOverridesVersion, 197 Value::CreateIntegerValue(1)); 198 ListValue* overrides = new ListValue; 199 DictionaryValue* entry(new DictionaryValue); 200 // Set only the minimal required settings for a search provider configuration. 201 entry->SetString("name", "foo"); 202 entry->SetString("keyword", "fook"); 203 entry->SetString("search_url", "http://foo.com/s?q={searchTerms}"); 204 entry->SetString("favicon_url", "http://foi.com/favicon.ico"); 205 entry->SetString("encoding", "UTF-8"); 206 entry->SetInteger("id", 1001); 207 overrides->Append(entry); 208 prefs->SetUserPref(prefs::kSearchProviderOverrides, overrides); 209 210 int version = TemplateURLPrepopulateData::GetDataVersion(prefs); 211 EXPECT_EQ(1, version); 212 213 // This call removes the above search engine. 214 TemplateURLPrepopulateData::ClearPrepopulatedEnginesInPrefs(&profile); 215 216 version = TemplateURLPrepopulateData::GetDataVersion(prefs); 217 EXPECT_EQ(TemplateURLPrepopulateData::kCurrentDataVersion, version); 218 219 ScopedVector<TemplateURL> t_urls; 220 size_t default_index; 221 TemplateURLPrepopulateData::GetPrepopulatedEngines(&profile, &t_urls.get(), 222 &default_index); 223 ASSERT_FALSE(t_urls.empty()); 224 for (size_t i = 0; i < t_urls.size(); ++i) { 225 EXPECT_NE(ASCIIToUTF16("foo"), t_urls[i]->short_name()); 226 EXPECT_NE(ASCIIToUTF16("fook"), t_urls[i]->keyword()); 227 EXPECT_NE("foi.com", t_urls[i]->favicon_url().host()); 228 EXPECT_NE("foo.com", t_urls[i]->url_ref().GetHost()); 229 EXPECT_NE(1001, t_urls[i]->prepopulate_id()); 230 } 231 // Ensures the default URL is Google and has the optional fields filled. 232 EXPECT_EQ(ASCIIToUTF16("Google"), t_urls[default_index]->short_name()); 233 EXPECT_FALSE(t_urls[default_index]->suggestions_url().empty()); 234 EXPECT_FALSE(t_urls[default_index]->instant_url().empty()); 235 EXPECT_FALSE(t_urls[default_index]->image_url().empty()); 236 EXPECT_FALSE(t_urls[default_index]->image_url_post_params().empty()); 237 EXPECT_EQ(SEARCH_ENGINE_GOOGLE, 238 TemplateURLPrepopulateData::GetEngineType(*t_urls[default_index])); 239 } 240 241 // Verifies that built-in search providers are processed correctly. 242 TEST(TemplateURLPrepopulateDataTest, ProvidersFromPrepopulated) { 243 // Use United States. 244 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 245 switches::kCountry, "US"); 246 TestingProfile profile; 247 ScopedVector<TemplateURL> t_urls; 248 size_t default_index; 249 TemplateURLPrepopulateData::GetPrepopulatedEngines(&profile, &t_urls.get(), 250 &default_index); 251 252 // Ensure all the URLs have the required fields populated. 253 ASSERT_FALSE(t_urls.empty()); 254 for (size_t i = 0; i < t_urls.size(); ++i) { 255 ASSERT_FALSE(t_urls[i]->short_name().empty()); 256 ASSERT_FALSE(t_urls[i]->keyword().empty()); 257 ASSERT_FALSE(t_urls[i]->favicon_url().host().empty()); 258 ASSERT_FALSE(t_urls[i]->url_ref().GetHost().empty()); 259 ASSERT_FALSE(t_urls[i]->input_encodings().empty()); 260 EXPECT_GT(t_urls[i]->prepopulate_id(), 0); 261 } 262 263 // Ensures the default URL is Google and has the optional fields filled. 264 EXPECT_EQ(ASCIIToUTF16("Google"), t_urls[default_index]->short_name()); 265 EXPECT_FALSE(t_urls[default_index]->suggestions_url().empty()); 266 EXPECT_FALSE(t_urls[default_index]->instant_url().empty()); 267 EXPECT_FALSE(t_urls[default_index]->image_url().empty()); 268 EXPECT_FALSE(t_urls[default_index]->image_url_post_params().empty()); 269 // Expect at least 2 alternate_urls. 270 // This caught a bug with static initialization of arrays, so leave this in. 271 EXPECT_GT(t_urls[default_index]->alternate_urls().size(), 1u); 272 for (size_t i = 0; i < t_urls[default_index]->alternate_urls().size(); ++i) 273 EXPECT_FALSE(t_urls[default_index]->alternate_urls()[i].empty()); 274 EXPECT_EQ(SEARCH_ENGINE_GOOGLE, 275 TemplateURLPrepopulateData::GetEngineType(*t_urls[default_index])); 276 EXPECT_FALSE(t_urls[default_index]->search_terms_replacement_key().empty()); 277 } 278 279 TEST(TemplateURLPrepopulateDataTest, GetEngineTypeBasic) { 280 EXPECT_EQ(SEARCH_ENGINE_OTHER, GetEngineType("http://example.com/")); 281 EXPECT_EQ(SEARCH_ENGINE_ASK, GetEngineType("http://www.ask.com/")); 282 EXPECT_EQ(SEARCH_ENGINE_OTHER, GetEngineType("http://search.atlas.cz/")); 283 EXPECT_EQ(SEARCH_ENGINE_GOOGLE, GetEngineType("http://www.google.com/")); 284 } 285 286 TEST(TemplateURLPrepopulateDataTest, GetEngineTypeAdvanced) { 287 // Google URLs in different forms. 288 const char* kGoogleURLs[] = { 289 // Original with google:baseURL: 290 "{google:baseURL}search?q={searchTerms}&{google:RLZ}" 291 "{google:originalQueryForSuggestion}{google:searchFieldtrialParameter}" 292 "sourceid=chrome&ie={inputEncoding}", 293 // Custom with google.com and reordered query params: 294 "http://google.com/search?{google:RLZ}{google:originalQueryForSuggestion}" 295 "{google:searchFieldtrialParameter}" 296 "sourceid=chrome&ie={inputEncoding}&q={searchTerms}", 297 // Custom with a country TLD and almost no query params: 298 "http://www.google.ru/search?q={searchTerms}" 299 }; 300 for (size_t i = 0; i < arraysize(kGoogleURLs); ++i) { 301 EXPECT_EQ(SEARCH_ENGINE_GOOGLE, GetEngineType(kGoogleURLs[i])); 302 } 303 304 // Non-Google URLs. 305 const char* kYahooURLs[] = { 306 "http://search.yahoo.com/search?" 307 "ei={inputEncoding}&fr=crmas&p={searchTerms}", 308 "http://search.yahoo.com/search?p={searchTerms}", 309 // Aggressively match types by checking just TLD+1. 310 "http://someothersite.yahoo.com/", 311 }; 312 for (size_t i = 0; i < arraysize(kYahooURLs); ++i) { 313 EXPECT_EQ(SEARCH_ENGINE_YAHOO, GetEngineType(kYahooURLs[i])); 314 } 315 316 // URLs for engines not present in country-specific lists. 317 EXPECT_EQ(SEARCH_ENGINE_NIGMA, 318 GetEngineType("http://nigma.ru/?s={searchTerms}&arg1=value1")); 319 // Also test matching against alternate URLs (and TLD+1 matching). 320 EXPECT_EQ(SEARCH_ENGINE_SOFTONIC, 321 GetEngineType("http://test.softonic.com.br/?{searchTerms}")); 322 323 // Search URL for which no prepopulated search provider exists. 324 EXPECT_EQ(SEARCH_ENGINE_OTHER, 325 GetEngineType("http://example.net/search?q={searchTerms}")); 326 EXPECT_EQ(SEARCH_ENGINE_OTHER, GetEngineType("invalid:search:url")); 327 328 // URL that doesn't look Google-related, but matches a Google base URL 329 // specified on the command line. 330 const std::string foo_url("http://www.foo.com/search?q={searchTerms}"); 331 EXPECT_EQ(SEARCH_ENGINE_OTHER, GetEngineType(foo_url)); 332 CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL, 333 "http://www.foo.com/"); 334 EXPECT_EQ(SEARCH_ENGINE_GOOGLE, GetEngineType(foo_url)); 335 } 336 337 TEST(TemplateURLPrepopulateDataTest, GetLogoURLGoogle) { 338 TemplateURLData data; 339 data.SetURL("http://www.google.com/"); 340 TemplateURL turl(NULL, data); 341 GURL logo_100_url = TemplateURLPrepopulateData::GetLogoURL( 342 turl, TemplateURLPrepopulateData::LOGO_100_PERCENT); 343 GURL logo_200_url = TemplateURLPrepopulateData::GetLogoURL( 344 turl, TemplateURLPrepopulateData::LOGO_200_PERCENT); 345 346 EXPECT_EQ("www.google.com", logo_100_url.host()); 347 EXPECT_EQ("www.google.com", logo_200_url.host()); 348 EXPECT_NE(logo_100_url, logo_200_url); 349 } 350 351 TEST(TemplateURLPrepopulateDataTest, GetLogoURLUnknown) { 352 TemplateURLData data; 353 data.SetURL("http://webalta.ru/"); 354 TemplateURL turl(NULL, data); 355 GURL logo_url = TemplateURLPrepopulateData::GetLogoURL( 356 turl, TemplateURLPrepopulateData::LOGO_100_PERCENT); 357 358 EXPECT_TRUE(logo_url.is_empty()); 359 } 360 361 TEST(TemplateURLPrepopulateDataTest, GetLogoURLInvalid) { 362 TemplateURLData data; 363 data.SetURL("http://invalid:search:url/"); 364 TemplateURL turl(NULL, data); 365 GURL logo_url = TemplateURLPrepopulateData::GetLogoURL( 366 turl, TemplateURLPrepopulateData::LOGO_100_PERCENT); 367 368 EXPECT_TRUE(logo_url.is_empty()); 369 } 370