search_provider_unittest.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
1// Copyright 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 "chrome/browser/autocomplete/search_provider.h" 6 7#include <string> 8 9#include "base/command_line.h" 10#include "base/metrics/field_trial.h" 11#include "base/prefs/pref_service.h" 12#include "base/run_loop.h" 13#include "base/strings/string16.h" 14#include "base/strings/string_number_conversions.h" 15#include "base/strings/string_util.h" 16#include "base/strings/utf_string_conversions.h" 17#include "base/time/time.h" 18#include "build/build_config.h" 19#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" 20#include "chrome/browser/autocomplete/autocomplete_controller.h" 21#include "chrome/browser/autocomplete/autocomplete_input.h" 22#include "chrome/browser/autocomplete/autocomplete_match.h" 23#include "chrome/browser/autocomplete/autocomplete_provider.h" 24#include "chrome/browser/autocomplete/autocomplete_provider_listener.h" 25#include "chrome/browser/autocomplete/history_url_provider.h" 26#include "chrome/browser/history/history_service.h" 27#include "chrome/browser/history/history_service_factory.h" 28#include "chrome/browser/omnibox/omnibox_field_trial.h" 29#include "chrome/browser/search_engines/search_engine_type.h" 30#include "chrome/browser/search_engines/template_url.h" 31#include "chrome/browser/search_engines/template_url_service.h" 32#include "chrome/browser/search_engines/template_url_service_factory.h" 33#include "chrome/browser/signin/signin_manager_factory.h" 34#include "chrome/browser/sync/profile_sync_service.h" 35#include "chrome/browser/sync/profile_sync_service_factory.h" 36#include "chrome/common/chrome_switches.h" 37#include "chrome/common/metrics/variations/variations_util.h" 38#include "chrome/common/pref_names.h" 39#include "chrome/test/base/testing_browser_process.h" 40#include "chrome/test/base/testing_profile.h" 41#include "components/signin/core/browser/signin_manager.h" 42#include "components/sync_driver/pref_names.h" 43#include "components/variations/entropy_provider.h" 44#include "content/public/test/test_browser_thread_bundle.h" 45#include "net/url_request/test_url_fetcher_factory.h" 46#include "net/url_request/url_request_status.h" 47#include "testing/gtest/include/gtest/gtest.h" 48 49using base::ASCIIToUTF16; 50 51namespace { 52 53// Returns the first match in |matches| with |allowed_to_be_default_match| 54// set to true. 55ACMatches::const_iterator FindDefaultMatch(const ACMatches& matches) { 56 ACMatches::const_iterator it = matches.begin(); 57 while ((it != matches.end()) && !it->allowed_to_be_default_match) 58 ++it; 59 return it; 60} 61 62class SuggestionDeletionHandler; 63class SearchProviderForTest : public SearchProvider { 64 public: 65 SearchProviderForTest( 66 AutocompleteProviderListener* listener, 67 Profile* profile); 68 bool is_success() { return is_success_; }; 69 70 protected: 71 virtual ~SearchProviderForTest(); 72 73 private: 74 virtual void RecordDeletionResult(bool success) OVERRIDE; 75 bool is_success_; 76 DISALLOW_COPY_AND_ASSIGN(SearchProviderForTest); 77}; 78 79SearchProviderForTest::SearchProviderForTest( 80 AutocompleteProviderListener* listener, 81 Profile* profile) 82 : SearchProvider(listener, profile), is_success_(false) { 83} 84 85SearchProviderForTest::~SearchProviderForTest() { 86} 87 88void SearchProviderForTest::RecordDeletionResult(bool success) { 89 is_success_ = success; 90} 91 92} // namespace 93 94// SearchProviderTest --------------------------------------------------------- 95 96// The following environment is configured for these tests: 97// . The TemplateURL default_t_url_ is set as the default provider. 98// . The TemplateURL keyword_t_url_ is added to the TemplateURLService. This 99// TemplateURL has a valid suggest and search URL. 100// . The URL created by using the search term term1_ with default_t_url_ is 101// added to history. 102// . The URL created by using the search term keyword_term_ with keyword_t_url_ 103// is added to history. 104// . test_factory_ is set as the URLFetcherFactory. 105class SearchProviderTest : public testing::Test, 106 public AutocompleteProviderListener { 107 public: 108 struct ResultInfo { 109 ResultInfo() : result_type(AutocompleteMatchType::NUM_TYPES), 110 allowed_to_be_default_match(false) { 111 } 112 ResultInfo(GURL gurl, 113 AutocompleteMatch::Type result_type, 114 bool allowed_to_be_default_match, 115 base::string16 fill_into_edit) 116 : gurl(gurl), 117 result_type(result_type), 118 allowed_to_be_default_match(allowed_to_be_default_match), 119 fill_into_edit(fill_into_edit) { 120 } 121 122 const GURL gurl; 123 const AutocompleteMatch::Type result_type; 124 const bool allowed_to_be_default_match; 125 const base::string16 fill_into_edit; 126 }; 127 128 struct TestData { 129 const base::string16 input; 130 const size_t num_results; 131 const ResultInfo output[3]; 132 }; 133 134 SearchProviderTest() 135 : default_t_url_(NULL), 136 term1_(ASCIIToUTF16("term1")), 137 keyword_t_url_(NULL), 138 keyword_term_(ASCIIToUTF16("keyword")), 139 run_loop_(NULL) { 140 ResetFieldTrialList(); 141 } 142 143 // See description above class for what this registers. 144 virtual void SetUp() OVERRIDE; 145 virtual void TearDown() OVERRIDE; 146 147 void RunTest(TestData* cases, int num_cases, bool prefer_keyword); 148 149 protected: 150 // Needed for AutocompleteFieldTrial::ActivateStaticTrials(); 151 scoped_ptr<base::FieldTrialList> field_trial_list_; 152 153 // Default value used for testing. 154 static const std::string kNotApplicable; 155 156 // Adds a search for |term|, using the engine |t_url| to the history, and 157 // returns the URL for that search. 158 GURL AddSearchToHistory(TemplateURL* t_url, base::string16 term, int visit_count); 159 160 // Looks for a match in |provider_| with |contents| equal to |contents|. 161 // Sets |match| to it if found. Returns whether |match| was set. 162 bool FindMatchWithContents(const base::string16& contents, 163 AutocompleteMatch* match); 164 165 // Looks for a match in |provider_| with destination |url|. Sets |match| to 166 // it if found. Returns whether |match| was set. 167 bool FindMatchWithDestination(const GURL& url, AutocompleteMatch* match); 168 169 // AutocompleteProviderListener: 170 // If we're waiting for the provider to finish, this exits the message loop. 171 virtual void OnProviderUpdate(bool updated_matches) OVERRIDE; 172 173 // Runs a nested message loop until provider_ is done. The message loop is 174 // exited by way of OnProviderUpdate. 175 void RunTillProviderDone(); 176 177 // Invokes Start on provider_, then runs all pending tasks. 178 void QueryForInput(const base::string16& text, 179 bool prevent_inline_autocomplete, 180 bool prefer_keyword); 181 182 // Calls QueryForInput(), finishes any suggest query, then if |wyt_match| is 183 // non-NULL, sets it to the "what you typed" entry for |text|. 184 void QueryForInputAndSetWYTMatch(const base::string16& text, 185 AutocompleteMatch* wyt_match); 186 187 // Notifies the URLFetcher for the suggest query corresponding to the default 188 // search provider that it's done. 189 // Be sure and wrap calls to this in ASSERT_NO_FATAL_FAILURE. 190 void FinishDefaultSuggestQuery(); 191 192 // Runs SearchProvider on |input|, for which the suggest server replies 193 // with |json|, and expects that the resulting matches' contents equals 194 // that in |matches|. An empty entry in |matches| means no match should 195 // be returned in that position. Reports any errors with a message that 196 // includes |error_description|. 197 void ForcedQueryTestHelper(const std::string& input, 198 const std::string& json, 199 const std::string matches[3], 200 const std::string& error_description); 201 202 void ResetFieldTrialList(); 203 204 void ClearAllResults(); 205 206 // See description above class for details of these fields. 207 TemplateURL* default_t_url_; 208 const base::string16 term1_; 209 GURL term1_url_; 210 TemplateURL* keyword_t_url_; 211 const base::string16 keyword_term_; 212 GURL keyword_url_; 213 214 content::TestBrowserThreadBundle thread_bundle_; 215 216 // URLFetcherFactory implementation registered. 217 net::TestURLFetcherFactory test_factory_; 218 219 // Profile we use. 220 TestingProfile profile_; 221 222 // The provider. 223 scoped_refptr<SearchProviderForTest> provider_; 224 225 // If non-NULL, OnProviderUpdate quits the current |run_loop_|. 226 base::RunLoop* run_loop_; 227 228 DISALLOW_COPY_AND_ASSIGN(SearchProviderTest); 229}; 230 231// static 232const std::string SearchProviderTest::kNotApplicable = "Not Applicable"; 233 234void SearchProviderTest::SetUp() { 235 // Make sure that fetchers are automatically ungregistered upon destruction. 236 test_factory_.set_remove_fetcher_on_delete(true); 237 238 // We need both the history service and template url model loaded. 239 ASSERT_TRUE(profile_.CreateHistoryService(true, false)); 240 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( 241 &profile_, &TemplateURLServiceFactory::BuildInstanceFor); 242 243 TemplateURLService* turl_model = 244 TemplateURLServiceFactory::GetForProfile(&profile_); 245 246 turl_model->Load(); 247 248 // Reset the default TemplateURL. 249 TemplateURLData data; 250 data.short_name = ASCIIToUTF16("t"); 251 data.SetURL("http://defaultturl/{searchTerms}"); 252 data.suggestions_url = "http://defaultturl2/{searchTerms}"; 253 data.instant_url = "http://does/not/exist?strk=1"; 254 data.search_terms_replacement_key = "strk"; 255 default_t_url_ = new TemplateURL(&profile_, data); 256 turl_model->Add(default_t_url_); 257 turl_model->SetDefaultSearchProvider(default_t_url_); 258 TemplateURLID default_provider_id = default_t_url_->id(); 259 ASSERT_NE(0, default_provider_id); 260 261 // Add url1, with search term term1_. 262 term1_url_ = AddSearchToHistory(default_t_url_, term1_, 1); 263 264 // Create another TemplateURL. 265 data.short_name = ASCIIToUTF16("k"); 266 data.SetKeyword(ASCIIToUTF16("k")); 267 data.SetURL("http://keyword/{searchTerms}"); 268 data.suggestions_url = "http://suggest_keyword/{searchTerms}"; 269 keyword_t_url_ = new TemplateURL(&profile_, data); 270 turl_model->Add(keyword_t_url_); 271 ASSERT_NE(0, keyword_t_url_->id()); 272 273 // Add a page and search term for keyword_t_url_. 274 keyword_url_ = AddSearchToHistory(keyword_t_url_, keyword_term_, 1); 275 276 // Keywords are updated by the InMemoryHistoryBackend only after the message 277 // has been processed on the history thread. Block until history processes all 278 // requests to ensure the InMemoryDatabase is the state we expect it. 279 profile_.BlockUntilHistoryProcessesPendingRequests(); 280 281 provider_ = new SearchProviderForTest(this, &profile_); 282 provider_->kMinimumTimeBetweenSuggestQueriesMs = 0; 283} 284 285void SearchProviderTest::TearDown() { 286 base::RunLoop().RunUntilIdle(); 287 288 // Shutdown the provider before the profile. 289 provider_ = NULL; 290} 291 292void SearchProviderTest::RunTest(TestData* cases, 293 int num_cases, 294 bool prefer_keyword) { 295 ACMatches matches; 296 for (int i = 0; i < num_cases; ++i) { 297 AutocompleteInput input(cases[i].input, base::string16::npos, 298 base::string16(), GURL(), 299 AutocompleteInput::INVALID_SPEC, false, 300 prefer_keyword, true, 301 AutocompleteInput::ALL_MATCHES); 302 provider_->Start(input, false); 303 matches = provider_->matches(); 304 base::string16 diagnostic_details = 305 ASCIIToUTF16("Input was: ") + 306 cases[i].input + 307 ASCIIToUTF16("; prefer_keyword was: ") + 308 (prefer_keyword ? ASCIIToUTF16("true") : ASCIIToUTF16("false")); 309 EXPECT_EQ(cases[i].num_results, matches.size()) << diagnostic_details; 310 if (matches.size() == cases[i].num_results) { 311 for (size_t j = 0; j < cases[i].num_results; ++j) { 312 EXPECT_EQ(cases[i].output[j].gurl, matches[j].destination_url) << 313 diagnostic_details; 314 EXPECT_EQ(cases[i].output[j].result_type, matches[j].type) << 315 diagnostic_details; 316 EXPECT_EQ(cases[i].output[j].fill_into_edit, 317 matches[j].fill_into_edit) << diagnostic_details; 318 EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match, 319 matches[j].allowed_to_be_default_match) << diagnostic_details; 320 } 321 } 322 } 323} 324 325void SearchProviderTest::OnProviderUpdate(bool updated_matches) { 326 if (run_loop_ && provider_->done()) { 327 run_loop_->Quit(); 328 run_loop_ = NULL; 329 } 330} 331 332void SearchProviderTest::RunTillProviderDone() { 333 if (provider_->done()) 334 return; 335 336 base::RunLoop run_loop; 337 run_loop_ = &run_loop; 338 run_loop.Run(); 339} 340 341void SearchProviderTest::QueryForInput(const base::string16& text, 342 bool prevent_inline_autocomplete, 343 bool prefer_keyword) { 344 // Start a query. 345 AutocompleteInput input(text, base::string16::npos, base::string16(), GURL(), 346 AutocompleteInput::INVALID_SPEC, 347 prevent_inline_autocomplete, prefer_keyword, true, 348 AutocompleteInput::ALL_MATCHES); 349 provider_->Start(input, false); 350 351 // RunUntilIdle so that the task scheduled by SearchProvider to create the 352 // URLFetchers runs. 353 base::RunLoop().RunUntilIdle(); 354} 355 356void SearchProviderTest::QueryForInputAndSetWYTMatch( 357 const base::string16& text, 358 AutocompleteMatch* wyt_match) { 359 QueryForInput(text, false, false); 360 profile_.BlockUntilHistoryProcessesPendingRequests(); 361 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery()); 362 if (!wyt_match) 363 return; 364 ASSERT_GE(provider_->matches().size(), 1u); 365 EXPECT_TRUE(FindMatchWithDestination(GURL( 366 default_t_url_->url_ref().ReplaceSearchTerms( 367 TemplateURLRef::SearchTermsArgs(base::CollapseWhitespace( 368 text, false)))), 369 wyt_match)); 370} 371 372GURL SearchProviderTest::AddSearchToHistory(TemplateURL* t_url, 373 base::string16 term, 374 int visit_count) { 375 HistoryService* history = 376 HistoryServiceFactory::GetForProfile(&profile_, 377 Profile::EXPLICIT_ACCESS); 378 GURL search(t_url->url_ref().ReplaceSearchTerms( 379 TemplateURLRef::SearchTermsArgs(term))); 380 static base::Time last_added_time; 381 last_added_time = std::max(base::Time::Now(), 382 last_added_time + base::TimeDelta::FromMicroseconds(1)); 383 history->AddPageWithDetails(search, base::string16(), visit_count, visit_count, 384 last_added_time, false, history::SOURCE_BROWSED); 385 history->SetKeywordSearchTermsForURL(search, t_url->id(), term); 386 return search; 387} 388 389bool SearchProviderTest::FindMatchWithContents(const base::string16& contents, 390 AutocompleteMatch* match) { 391 for (ACMatches::const_iterator i = provider_->matches().begin(); 392 i != provider_->matches().end(); ++i) { 393 if (i->contents == contents) { 394 *match = *i; 395 return true; 396 } 397 } 398 return false; 399} 400 401bool SearchProviderTest::FindMatchWithDestination(const GURL& url, 402 AutocompleteMatch* match) { 403 for (ACMatches::const_iterator i = provider_->matches().begin(); 404 i != provider_->matches().end(); ++i) { 405 if (i->destination_url == url) { 406 *match = *i; 407 return true; 408 } 409 } 410 return false; 411} 412 413void SearchProviderTest::FinishDefaultSuggestQuery() { 414 net::TestURLFetcher* default_fetcher = 415 test_factory_.GetFetcherByID( 416 SearchProvider::kDefaultProviderURLFetcherID); 417 ASSERT_TRUE(default_fetcher); 418 419 // Tell the SearchProvider the default suggest query is done. 420 default_fetcher->set_response_code(200); 421 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher); 422} 423 424void SearchProviderTest::ForcedQueryTestHelper( 425 const std::string& input, 426 const std::string& json, 427 const std::string expected_matches[3], 428 const std::string& error_description) { 429 QueryForInput(ASCIIToUTF16(input), false, false); 430 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID( 431 SearchProvider::kDefaultProviderURLFetcherID); 432 ASSERT_TRUE(fetcher); 433 fetcher->set_response_code(200); 434 fetcher->SetResponseString(json); 435 fetcher->delegate()->OnURLFetchComplete(fetcher); 436 RunTillProviderDone(); 437 438 const ACMatches& matches = provider_->matches(); 439 ASSERT_LE(matches.size(), 3u); 440 size_t i = 0; 441 // Ensure that the returned matches equal the expectations. 442 for (; i < matches.size(); ++i) { 443 EXPECT_EQ(ASCIIToUTF16(expected_matches[i]), matches[i].contents) << 444 error_description; 445 } 446 // Ensure that no expected matches are missing. 447 for (; i < 3u; ++i) { 448 EXPECT_EQ(std::string(), expected_matches[i]) << 449 "Case #" << i << ": " << error_description; 450 } 451} 452 453void SearchProviderTest::ResetFieldTrialList() { 454 // Destroy the existing FieldTrialList before creating a new one to avoid 455 // a DCHECK. 456 field_trial_list_.reset(); 457 field_trial_list_.reset(new base::FieldTrialList( 458 new metrics::SHA1EntropyProvider("foo"))); 459 chrome_variations::testing::ClearAllVariationParams(); 460 base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial( 461 "AutocompleteDynamicTrial_0", "DefaultGroup"); 462 trial->group(); 463} 464 465void SearchProviderTest::ClearAllResults() { 466 provider_->ClearAllResults(); 467} 468 469// Actual Tests --------------------------------------------------------------- 470 471// Make sure we query history for the default provider and a URLFetcher is 472// created for the default provider suggest results. 473TEST_F(SearchProviderTest, QueryDefaultProvider) { 474 base::string16 term = term1_.substr(0, term1_.length() - 1); 475 QueryForInput(term, false, false); 476 477 // Make sure the default providers suggest service was queried. 478 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID( 479 SearchProvider::kDefaultProviderURLFetcherID); 480 ASSERT_TRUE(fetcher); 481 482 // And the URL matches what we expected. 483 GURL expected_url(default_t_url_->suggestions_url_ref().ReplaceSearchTerms( 484 TemplateURLRef::SearchTermsArgs(term))); 485 ASSERT_TRUE(fetcher->GetOriginalURL() == expected_url); 486 487 // Tell the SearchProvider the suggest query is done. 488 fetcher->set_response_code(200); 489 fetcher->delegate()->OnURLFetchComplete(fetcher); 490 fetcher = NULL; 491 492 // Run till the history results complete. 493 RunTillProviderDone(); 494 495 // The SearchProvider is done. Make sure it has a result for the history 496 // term term1. 497 AutocompleteMatch term1_match; 498 EXPECT_TRUE(FindMatchWithDestination(term1_url_, &term1_match)); 499 // Term1 should not have a description, it's set later. 500 EXPECT_TRUE(term1_match.description.empty()); 501 502 AutocompleteMatch wyt_match; 503 EXPECT_TRUE(FindMatchWithDestination( 504 GURL(default_t_url_->url_ref().ReplaceSearchTerms( 505 TemplateURLRef::SearchTermsArgs(term))), &wyt_match)); 506 EXPECT_TRUE(wyt_match.description.empty()); 507 508 // The match for term1 should be more relevant than the what you typed match. 509 EXPECT_GT(term1_match.relevance, wyt_match.relevance); 510 // This longer match should be inlineable. 511 EXPECT_TRUE(term1_match.allowed_to_be_default_match); 512 // The what you typed match should be too, of course. 513 EXPECT_TRUE(wyt_match.allowed_to_be_default_match); 514} 515 516TEST_F(SearchProviderTest, HonorPreventInlineAutocomplete) { 517 base::string16 term = term1_.substr(0, term1_.length() - 1); 518 QueryForInput(term, true, false); 519 520 ASSERT_FALSE(provider_->matches().empty()); 521 ASSERT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 522 provider_->matches()[0].type); 523 EXPECT_TRUE(provider_->matches()[0].allowed_to_be_default_match); 524} 525 526// Issues a query that matches the registered keyword and makes sure history 527// is queried as well as URLFetchers getting created. 528TEST_F(SearchProviderTest, QueryKeywordProvider) { 529 base::string16 term = keyword_term_.substr(0, keyword_term_.length() - 1); 530 QueryForInput(keyword_t_url_->keyword() + ASCIIToUTF16(" ") + term, 531 false, 532 false); 533 534 // Make sure the default providers suggest service was queried. 535 net::TestURLFetcher* default_fetcher = test_factory_.GetFetcherByID( 536 SearchProvider::kDefaultProviderURLFetcherID); 537 ASSERT_TRUE(default_fetcher); 538 539 // Tell the SearchProvider the default suggest query is done. 540 default_fetcher->set_response_code(200); 541 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher); 542 default_fetcher = NULL; 543 544 // Make sure the keyword providers suggest service was queried. 545 net::TestURLFetcher* keyword_fetcher = test_factory_.GetFetcherByID( 546 SearchProvider::kKeywordProviderURLFetcherID); 547 ASSERT_TRUE(keyword_fetcher); 548 549 // And the URL matches what we expected. 550 GURL expected_url(keyword_t_url_->suggestions_url_ref().ReplaceSearchTerms( 551 TemplateURLRef::SearchTermsArgs(term))); 552 ASSERT_TRUE(keyword_fetcher->GetOriginalURL() == expected_url); 553 554 // Tell the SearchProvider the keyword suggest query is done. 555 keyword_fetcher->set_response_code(200); 556 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher); 557 keyword_fetcher = NULL; 558 559 // Run till the history results complete. 560 RunTillProviderDone(); 561 562 // The SearchProvider is done. Make sure it has a result for the history 563 // term keyword. 564 AutocompleteMatch match; 565 EXPECT_TRUE(FindMatchWithDestination(keyword_url_, &match)); 566 567 // The match should have an associated keyword. 568 EXPECT_FALSE(match.keyword.empty()); 569 570 // The fill into edit should contain the keyword. 571 EXPECT_EQ(keyword_t_url_->keyword() + base::char16(' ') + keyword_term_, 572 match.fill_into_edit); 573} 574 575TEST_F(SearchProviderTest, DontSendPrivateDataToSuggest) { 576 // None of the following input strings should be sent to the suggest server, 577 // because they may contain private data. 578 const char* inputs[] = { 579 "username:password", 580 "http://username:password", 581 "https://username:password", 582 "username:password@hostname", 583 "http://username:password@hostname/", 584 "file://filename", 585 "data://data", 586 "unknownscheme:anything", 587 "http://hostname/?query=q", 588 "http://hostname/path#ref", 589 "http://hostname/path #ref", 590 "https://hostname/path", 591 }; 592 593 for (size_t i = 0; i < arraysize(inputs); ++i) { 594 QueryForInput(ASCIIToUTF16(inputs[i]), false, false); 595 // Make sure the default provider's suggest service was not queried. 596 ASSERT_TRUE(test_factory_.GetFetcherByID( 597 SearchProvider::kDefaultProviderURLFetcherID) == NULL); 598 // Run till the history results complete. 599 RunTillProviderDone(); 600 } 601} 602 603TEST_F(SearchProviderTest, SendNonPrivateDataToSuggest) { 604 // All of the following input strings should be sent to the suggest server, 605 // because they should not get caught by the private data checks. 606 const char* inputs[] = { 607 "query", 608 "query with spaces", 609 "http://hostname", 610 "http://hostname/path", 611 "http://hostname #ref", 612 "www.hostname.com #ref", 613 "https://hostname", 614 "#hashtag", 615 "foo https://hostname/path" 616 }; 617 618 profile_.BlockUntilHistoryProcessesPendingRequests(); 619 for (size_t i = 0; i < arraysize(inputs); ++i) { 620 QueryForInput(ASCIIToUTF16(inputs[i]), false, false); 621 // Make sure the default provider's suggest service was queried. 622 ASSERT_TRUE(test_factory_.GetFetcherByID( 623 SearchProvider::kDefaultProviderURLFetcherID) != NULL); 624 } 625} 626 627TEST_F(SearchProviderTest, DontAutocompleteURLLikeTerms) { 628 AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse( 629 &profile_, &AutocompleteClassifierFactory::BuildInstanceFor); 630 GURL url = AddSearchToHistory(default_t_url_, 631 ASCIIToUTF16("docs.google.com"), 1); 632 633 // Add the term as a url. 634 HistoryServiceFactory::GetForProfile(&profile_, Profile::EXPLICIT_ACCESS)-> 635 AddPageWithDetails(GURL("http://docs.google.com"), base::string16(), 1, 1, 636 base::Time::Now(), false, history::SOURCE_BROWSED); 637 profile_.BlockUntilHistoryProcessesPendingRequests(); 638 639 AutocompleteMatch wyt_match; 640 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("docs"), 641 &wyt_match)); 642 643 // There should be two matches, one for what you typed, the other for 644 // 'docs.google.com'. The search term should have a lower priority than the 645 // what you typed match. 646 ASSERT_EQ(2u, provider_->matches().size()); 647 AutocompleteMatch term_match; 648 EXPECT_TRUE(FindMatchWithDestination(url, &term_match)); 649 EXPECT_GT(wyt_match.relevance, term_match.relevance); 650 EXPECT_TRUE(wyt_match.allowed_to_be_default_match); 651 EXPECT_TRUE(term_match.allowed_to_be_default_match); 652} 653 654TEST_F(SearchProviderTest, DontGiveNavsuggestionsInForcedQueryMode) { 655 const std::string kEmptyMatch; 656 struct { 657 const std::string json; 658 const std::string matches_in_default_mode[3]; 659 const std::string matches_in_forced_query_mode[3]; 660 } cases[] = { 661 // Without suggested relevance scores. 662 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[]," 663 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]}]", 664 { "a", "a1.com", "a2" }, 665 { "a", "a2", kEmptyMatch } }, 666 667 // With suggested relevance scores in a situation where navsuggest would 668 // go second. 669 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[]," 670 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]," 671 "\"google:suggestrelevance\":[1250, 1200]}]", 672 { "a", "a1.com", "a2" }, 673 { "a", "a2", kEmptyMatch } }, 674 675 // With suggested relevance scores in a situation where navsuggest 676 // would go first. 677 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[]," 678 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]," 679 "\"google:suggestrelevance\":[1350, 1250]}]", 680 { "a1.com", "a", "a2" }, 681 { "a", "a2", kEmptyMatch } }, 682 683 // With suggested relevance scores in a situation where navsuggest 684 // would go first only because verbatim has been demoted. 685 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[]," 686 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]," 687 "\"google:suggestrelevance\":[1450, 1400]," 688 "\"google:verbatimrelevance\":1350}]", 689 { "a1.com", "a2", "a" }, 690 { "a2", "a", kEmptyMatch } }, 691 }; 692 693 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 694 ForcedQueryTestHelper("a", cases[i].json, cases[i].matches_in_default_mode, 695 "regular input with json=" + cases[i].json); 696 ForcedQueryTestHelper("?a", cases[i].json, 697 cases[i].matches_in_forced_query_mode, 698 "forced query input with json=" + cases[i].json); 699 } 700} 701 702// A multiword search with one visit should not autocomplete until multiple 703// words are typed. 704TEST_F(SearchProviderTest, DontAutocompleteUntilMultipleWordsTyped) { 705 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("one search"), 706 1)); 707 profile_.BlockUntilHistoryProcessesPendingRequests(); 708 709 AutocompleteMatch wyt_match; 710 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("on"), 711 &wyt_match)); 712 ASSERT_EQ(2u, provider_->matches().size()); 713 AutocompleteMatch term_match; 714 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match)); 715 EXPECT_GT(wyt_match.relevance, term_match.relevance); 716 EXPECT_TRUE(wyt_match.allowed_to_be_default_match); 717 EXPECT_TRUE(term_match.allowed_to_be_default_match); 718 719 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("one se"), 720 &wyt_match)); 721 ASSERT_EQ(2u, provider_->matches().size()); 722 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match)); 723 EXPECT_GT(term_match.relevance, wyt_match.relevance); 724 EXPECT_TRUE(term_match.allowed_to_be_default_match); 725 EXPECT_TRUE(wyt_match.allowed_to_be_default_match); 726} 727 728// A multiword search with more than one visit should autocomplete immediately. 729TEST_F(SearchProviderTest, AutocompleteMultipleVisitsImmediately) { 730 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches"), 731 2)); 732 profile_.BlockUntilHistoryProcessesPendingRequests(); 733 734 AutocompleteMatch wyt_match; 735 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("tw"), 736 &wyt_match)); 737 ASSERT_EQ(2u, provider_->matches().size()); 738 AutocompleteMatch term_match; 739 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match)); 740 EXPECT_GT(term_match.relevance, wyt_match.relevance); 741 EXPECT_TRUE(term_match.allowed_to_be_default_match); 742 EXPECT_TRUE(wyt_match.allowed_to_be_default_match); 743} 744 745// Autocompletion should work at a word boundary after a space, and should 746// offer a suggestion for the trimmed search query. 747TEST_F(SearchProviderTest, AutocompleteAfterSpace) { 748 AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches "), 2); 749 GURL suggested_url(default_t_url_->url_ref().ReplaceSearchTerms( 750 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("two searches")))); 751 profile_.BlockUntilHistoryProcessesPendingRequests(); 752 753 AutocompleteMatch wyt_match; 754 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("two "), 755 &wyt_match)); 756 ASSERT_EQ(2u, provider_->matches().size()); 757 AutocompleteMatch term_match; 758 EXPECT_TRUE(FindMatchWithDestination(suggested_url, &term_match)); 759 EXPECT_GT(term_match.relevance, wyt_match.relevance); 760 EXPECT_TRUE(term_match.allowed_to_be_default_match); 761 EXPECT_EQ(ASCIIToUTF16("searches"), term_match.inline_autocompletion); 762 EXPECT_EQ(ASCIIToUTF16("two searches"), term_match.fill_into_edit); 763 EXPECT_TRUE(wyt_match.allowed_to_be_default_match); 764} 765 766// Newer multiword searches should score more highly than older ones. 767TEST_F(SearchProviderTest, ScoreNewerSearchesHigher) { 768 GURL term_url_a(AddSearchToHistory(default_t_url_, 769 ASCIIToUTF16("three searches aaa"), 1)); 770 GURL term_url_b(AddSearchToHistory(default_t_url_, 771 ASCIIToUTF16("three searches bbb"), 1)); 772 profile_.BlockUntilHistoryProcessesPendingRequests(); 773 774 AutocompleteMatch wyt_match; 775 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("three se"), 776 &wyt_match)); 777 ASSERT_EQ(3u, provider_->matches().size()); 778 AutocompleteMatch term_match_a; 779 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a)); 780 AutocompleteMatch term_match_b; 781 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b)); 782 EXPECT_GT(term_match_b.relevance, term_match_a.relevance); 783 EXPECT_GT(term_match_a.relevance, wyt_match.relevance); 784 EXPECT_TRUE(term_match_b.allowed_to_be_default_match); 785 EXPECT_TRUE(term_match_a.allowed_to_be_default_match); 786 EXPECT_TRUE(wyt_match.allowed_to_be_default_match); 787} 788 789// An autocompleted multiword search should not be replaced by a different 790// autocompletion while the user is still typing a valid prefix. 791TEST_F(SearchProviderTest, DontReplacePreviousAutocompletion) { 792 GURL term_url_a(AddSearchToHistory(default_t_url_, 793 ASCIIToUTF16("four searches aaa"), 2)); 794 GURL term_url_b(AddSearchToHistory(default_t_url_, 795 ASCIIToUTF16("four searches bbb"), 1)); 796 profile_.BlockUntilHistoryProcessesPendingRequests(); 797 798 AutocompleteMatch wyt_match; 799 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fo"), 800 &wyt_match)); 801 ASSERT_EQ(3u, provider_->matches().size()); 802 AutocompleteMatch term_match_a; 803 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a)); 804 AutocompleteMatch term_match_b; 805 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b)); 806 EXPECT_GT(term_match_a.relevance, wyt_match.relevance); 807 EXPECT_GT(wyt_match.relevance, term_match_b.relevance); 808 EXPECT_TRUE(term_match_a.allowed_to_be_default_match); 809 EXPECT_TRUE(term_match_b.allowed_to_be_default_match); 810 EXPECT_TRUE(wyt_match.allowed_to_be_default_match); 811 812 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("four se"), 813 &wyt_match)); 814 ASSERT_EQ(3u, provider_->matches().size()); 815 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a)); 816 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b)); 817 EXPECT_GT(term_match_a.relevance, wyt_match.relevance); 818 EXPECT_GT(wyt_match.relevance, term_match_b.relevance); 819 EXPECT_TRUE(term_match_a.allowed_to_be_default_match); 820 EXPECT_TRUE(term_match_b.allowed_to_be_default_match); 821 EXPECT_TRUE(wyt_match.allowed_to_be_default_match); 822} 823 824// Non-completable multiword searches should not crowd out single-word searches. 825TEST_F(SearchProviderTest, DontCrowdOutSingleWords) { 826 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("five"), 1)); 827 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches bbb"), 1); 828 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches ccc"), 1); 829 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches ddd"), 1); 830 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches eee"), 1); 831 profile_.BlockUntilHistoryProcessesPendingRequests(); 832 833 AutocompleteMatch wyt_match; 834 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fi"), 835 &wyt_match)); 836 ASSERT_EQ(AutocompleteProvider::kMaxMatches + 1, provider_->matches().size()); 837 AutocompleteMatch term_match; 838 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match)); 839 EXPECT_GT(term_match.relevance, wyt_match.relevance); 840 EXPECT_TRUE(term_match.allowed_to_be_default_match); 841 EXPECT_TRUE(wyt_match.allowed_to_be_default_match); 842} 843 844// Inline autocomplete matches regardless of case differences from the input. 845TEST_F(SearchProviderTest, InlineMixedCaseMatches) { 846 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("FOO"), 1)); 847 profile_.BlockUntilHistoryProcessesPendingRequests(); 848 849 AutocompleteMatch wyt_match; 850 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"), 851 &wyt_match)); 852 ASSERT_EQ(2u, provider_->matches().size()); 853 AutocompleteMatch term_match; 854 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match)); 855 EXPECT_GT(term_match.relevance, wyt_match.relevance); 856 EXPECT_EQ(ASCIIToUTF16("FOO"), term_match.fill_into_edit); 857 EXPECT_EQ(ASCIIToUTF16("OO"), term_match.inline_autocompletion); 858 EXPECT_TRUE(term_match.allowed_to_be_default_match); 859} 860 861// Verifies AutocompleteControllers return results (including keyword 862// results) in the right order and set descriptions for them correctly. 863TEST_F(SearchProviderTest, KeywordOrderingAndDescriptions) { 864 // Add an entry that corresponds to a keyword search with 'term2'. 865 AddSearchToHistory(keyword_t_url_, ASCIIToUTF16("term2"), 1); 866 profile_.BlockUntilHistoryProcessesPendingRequests(); 867 868 AutocompleteController controller(&profile_, NULL, 869 AutocompleteProvider::TYPE_SEARCH); 870 controller.Start(AutocompleteInput( 871 ASCIIToUTF16("k t"), base::string16::npos, base::string16(), GURL(), 872 AutocompleteInput::INVALID_SPEC, false, false, true, 873 AutocompleteInput::ALL_MATCHES)); 874 const AutocompleteResult& result = controller.result(); 875 876 // There should be three matches, one for the keyword history, one for 877 // keyword provider's what-you-typed, and one for the default provider's 878 // what you typed, in that order. 879 ASSERT_EQ(3u, result.size()); 880 EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY, result.match_at(0).type); 881 EXPECT_EQ(AutocompleteMatchType::SEARCH_OTHER_ENGINE, 882 result.match_at(1).type); 883 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 884 result.match_at(2).type); 885 EXPECT_GT(result.match_at(0).relevance, result.match_at(1).relevance); 886 EXPECT_GT(result.match_at(1).relevance, result.match_at(2).relevance); 887 EXPECT_TRUE(result.match_at(0).allowed_to_be_default_match); 888 EXPECT_TRUE(result.match_at(1).allowed_to_be_default_match); 889 EXPECT_FALSE(result.match_at(2).allowed_to_be_default_match); 890 891 // The two keyword results should come with the keyword we expect. 892 EXPECT_EQ(ASCIIToUTF16("k"), result.match_at(0).keyword); 893 EXPECT_EQ(ASCIIToUTF16("k"), result.match_at(1).keyword); 894 // The default provider has a different keyword. (We don't explicitly 895 // set it during this test, so all we do is assert that it's different.) 896 EXPECT_NE(result.match_at(0).keyword, result.match_at(2).keyword); 897 898 // The top result will always have a description. The third result, 899 // coming from a different provider than the first two, should also. 900 // Whether the second result has one doesn't matter much. (If it was 901 // missing, people would infer that it's the same search provider as 902 // the one above it.) 903 EXPECT_FALSE(result.match_at(0).description.empty()); 904 EXPECT_FALSE(result.match_at(2).description.empty()); 905 EXPECT_NE(result.match_at(0).description, result.match_at(2).description); 906} 907 908TEST_F(SearchProviderTest, KeywordVerbatim) { 909 TestData cases[] = { 910 // Test a simple keyword input. 911 { ASCIIToUTF16("k foo"), 2, 912 { ResultInfo(GURL("http://keyword/foo"), 913 AutocompleteMatchType::SEARCH_OTHER_ENGINE, 914 true, 915 ASCIIToUTF16("k foo")), 916 ResultInfo(GURL("http://defaultturl/k%20foo"), 917 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 918 false, 919 ASCIIToUTF16("k foo") ) } }, 920 921 // Make sure extra whitespace after the keyword doesn't change the 922 // keyword verbatim query. Also verify that interior consecutive 923 // whitespace gets trimmed. 924 { ASCIIToUTF16("k foo"), 2, 925 { ResultInfo(GURL("http://keyword/foo"), 926 AutocompleteMatchType::SEARCH_OTHER_ENGINE, 927 true, 928 ASCIIToUTF16("k foo")), 929 ResultInfo(GURL("http://defaultturl/k%20foo"), 930 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 931 false, 932 ASCIIToUTF16("k foo")) } }, 933 // Leading whitespace should be stripped before SearchProvider gets the 934 // input; hence there are no tests here about how it handles those inputs. 935 936 // Verify that interior consecutive whitespace gets trimmed in either case. 937 { ASCIIToUTF16("k foo bar"), 2, 938 { ResultInfo(GURL("http://keyword/foo%20bar"), 939 AutocompleteMatchType::SEARCH_OTHER_ENGINE, 940 true, 941 ASCIIToUTF16("k foo bar")), 942 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"), 943 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 944 false, 945 ASCIIToUTF16("k foo bar")) } }, 946 947 // Verify that trailing whitespace gets trimmed. 948 { ASCIIToUTF16("k foo bar "), 2, 949 { ResultInfo(GURL("http://keyword/foo%20bar"), 950 AutocompleteMatchType::SEARCH_OTHER_ENGINE, 951 true, 952 ASCIIToUTF16("k foo bar")), 953 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"), 954 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 955 false, 956 ASCIIToUTF16("k foo bar")) } }, 957 958 // Keywords can be prefixed by certain things that should get ignored 959 // when constructing the keyword match. 960 { ASCIIToUTF16("www.k foo"), 2, 961 { ResultInfo(GURL("http://keyword/foo"), 962 AutocompleteMatchType::SEARCH_OTHER_ENGINE, 963 true, 964 ASCIIToUTF16("k foo")), 965 ResultInfo(GURL("http://defaultturl/www.k%20foo"), 966 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 967 false, 968 ASCIIToUTF16("www.k foo")) } }, 969 { ASCIIToUTF16("http://k foo"), 2, 970 { ResultInfo(GURL("http://keyword/foo"), 971 AutocompleteMatchType::SEARCH_OTHER_ENGINE, 972 true, 973 ASCIIToUTF16("k foo")), 974 ResultInfo(GURL("http://defaultturl/http%3A//k%20foo"), 975 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 976 false, 977 ASCIIToUTF16("http://k foo")) } }, 978 { ASCIIToUTF16("http://www.k foo"), 2, 979 { ResultInfo(GURL("http://keyword/foo"), 980 AutocompleteMatchType::SEARCH_OTHER_ENGINE, 981 true, 982 ASCIIToUTF16("k foo")), 983 ResultInfo(GURL("http://defaultturl/http%3A//www.k%20foo"), 984 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 985 false, 986 ASCIIToUTF16("http://www.k foo")) } }, 987 988 // A keyword with no remaining input shouldn't get a keyword 989 // verbatim match. 990 { ASCIIToUTF16("k"), 1, 991 { ResultInfo(GURL("http://defaultturl/k"), 992 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 993 true, 994 ASCIIToUTF16("k")) } }, 995 // Ditto. Trailing whitespace shouldn't make a difference. 996 { ASCIIToUTF16("k "), 1, 997 { ResultInfo(GURL("http://defaultturl/k"), 998 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 999 true, 1000 ASCIIToUTF16("k")) } } 1001 1002 // The fact that verbatim queries to keyword are handled by KeywordProvider 1003 // not SearchProvider is tested in 1004 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc. 1005 }; 1006 1007 // Test not in keyword mode. 1008 RunTest(cases, arraysize(cases), false); 1009 1010 // Test in keyword mode. (Both modes should give the same result.) 1011 RunTest(cases, arraysize(cases), true); 1012} 1013 1014// Ensures command-line flags are reflected in the URLs the search provider 1015// generates. 1016TEST_F(SearchProviderTest, CommandLineOverrides) { 1017 TemplateURLService* turl_model = 1018 TemplateURLServiceFactory::GetForProfile(&profile_); 1019 1020 TemplateURLData data; 1021 data.short_name = ASCIIToUTF16("default"); 1022 data.SetKeyword(data.short_name); 1023 data.SetURL("{google:baseURL}{searchTerms}"); 1024 default_t_url_ = new TemplateURL(&profile_, data); 1025 turl_model->Add(default_t_url_); 1026 turl_model->SetDefaultSearchProvider(default_t_url_); 1027 1028 CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL, 1029 "http://www.bar.com/"); 1030 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 1031 switches::kExtraSearchQueryParams, "a=b"); 1032 1033 TestData cases[] = { 1034 { ASCIIToUTF16("k a"), 2, 1035 { ResultInfo(GURL("http://keyword/a"), 1036 AutocompleteMatchType::SEARCH_OTHER_ENGINE, 1037 true, 1038 ASCIIToUTF16("k a")), 1039 ResultInfo(GURL("http://www.bar.com/k%20a?a=b"), 1040 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 1041 false, 1042 ASCIIToUTF16("k a")) } }, 1043 }; 1044 1045 RunTest(cases, arraysize(cases), false); 1046} 1047 1048// Verifies Navsuggest results don't set a TemplateURL, which Instant relies on. 1049// Also verifies that just the *first* navigational result is listed as a match 1050// if suggested relevance scores were not sent. 1051TEST_F(SearchProviderTest, NavSuggestNoSuggestedRelevanceScores) { 1052 QueryForInput(ASCIIToUTF16("a.c"), false, false); 1053 1054 // Make sure the default providers suggest service was queried. 1055 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID( 1056 SearchProvider::kDefaultProviderURLFetcherID); 1057 ASSERT_TRUE(fetcher); 1058 1059 // Tell the SearchProvider the suggest query is done. 1060 fetcher->set_response_code(200); 1061 fetcher->SetResponseString( 1062 "[\"a.c\",[\"a.com\", \"a.com/b\"],[\"a\", \"b\"],[]," 1063 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]"); 1064 fetcher->delegate()->OnURLFetchComplete(fetcher); 1065 fetcher = NULL; 1066 1067 // Run till the history results complete. 1068 RunTillProviderDone(); 1069 1070 // Make sure the only match is 'a.com' and it doesn't have a template_url. 1071 AutocompleteMatch nav_match; 1072 EXPECT_TRUE(FindMatchWithDestination(GURL("http://a.com"), &nav_match)); 1073 EXPECT_TRUE(nav_match.keyword.empty()); 1074 EXPECT_TRUE(nav_match.allowed_to_be_default_match); 1075 EXPECT_FALSE(FindMatchWithDestination(GURL("http://a.com/b"), &nav_match)); 1076} 1077 1078// Verifies that the most relevant suggest results are added properly. 1079TEST_F(SearchProviderTest, SuggestRelevance) { 1080 QueryForInput(ASCIIToUTF16("a"), false, false); 1081 1082 // Make sure the default provider's suggest service was queried. 1083 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID( 1084 SearchProvider::kDefaultProviderURLFetcherID); 1085 ASSERT_TRUE(fetcher); 1086 1087 // Tell the SearchProvider the suggest query is done. 1088 fetcher->set_response_code(200); 1089 fetcher->SetResponseString("[\"a\",[\"a1\", \"a2\", \"a3\", \"a4\"]]"); 1090 fetcher->delegate()->OnURLFetchComplete(fetcher); 1091 fetcher = NULL; 1092 1093 // Run till the history results complete. 1094 RunTillProviderDone(); 1095 1096 // Check the expected verbatim and (first 3) suggestions' relative relevances. 1097 AutocompleteMatch verbatim, match_a1, match_a2, match_a3, match_a4; 1098 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim)); 1099 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a1"), &match_a1)); 1100 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a2"), &match_a2)); 1101 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a3"), &match_a3)); 1102 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("a4"), &match_a4)); 1103 EXPECT_GT(verbatim.relevance, match_a1.relevance); 1104 EXPECT_GT(match_a1.relevance, match_a2.relevance); 1105 EXPECT_GT(match_a2.relevance, match_a3.relevance); 1106 EXPECT_TRUE(verbatim.allowed_to_be_default_match); 1107 EXPECT_TRUE(match_a1.allowed_to_be_default_match); 1108 EXPECT_TRUE(match_a2.allowed_to_be_default_match); 1109 EXPECT_TRUE(match_a3.allowed_to_be_default_match); 1110} 1111 1112// Verifies that the default provider abandons suggested relevance scores 1113// when in keyword mode. This should happen regardless of whether the 1114// keyword provider returns suggested relevance scores. 1115TEST_F(SearchProviderTest, DefaultProviderNoSuggestRelevanceInKeywordMode) { 1116 struct { 1117 const std::string default_provider_json; 1118 const std::string keyword_provider_json; 1119 const std::string matches[5]; 1120 } cases[] = { 1121 // First, try an input where the keyword provider does not deliver 1122 // suggested relevance scores. 1123 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[]," 1124 "{\"google:verbatimrelevance\":9700," 1125 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"]," 1126 "\"google:suggestrelevance\":[9900, 9800]}]", 1127 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"]}]", 1128 { "a", "akeyword-query", "k a", "adefault.com", "k adefault-query" } }, 1129 1130 // Now try with keyword provider suggested relevance scores. 1131 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[]," 1132 "{\"google:verbatimrelevance\":9700," 1133 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"]," 1134 "\"google:suggestrelevance\":[9900, 9800]}]", 1135 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"]," 1136 "\"google:verbatimrelevance\":9500," 1137 "\"google:suggestrelevance\":[9600]}]", 1138 { "akeyword-query", "a", "k a", "adefault.com", "k adefault-query" } } 1139 }; 1140 1141 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { 1142 QueryForInput(ASCIIToUTF16("k a"), false, true); 1143 net::TestURLFetcher* default_fetcher = 1144 test_factory_.GetFetcherByID( 1145 SearchProvider::kDefaultProviderURLFetcherID); 1146 ASSERT_TRUE(default_fetcher); 1147 default_fetcher->set_response_code(200); 1148 default_fetcher->SetResponseString(cases[i].default_provider_json); 1149 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher); 1150 net::TestURLFetcher* keyword_fetcher = 1151 test_factory_.GetFetcherByID( 1152 SearchProvider::kKeywordProviderURLFetcherID); 1153 ASSERT_TRUE(keyword_fetcher); 1154 keyword_fetcher->set_response_code(200); 1155 keyword_fetcher->SetResponseString(cases[i].keyword_provider_json); 1156 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher); 1157 RunTillProviderDone(); 1158 1159 const std::string description = "for input with default_provider_json=" + 1160 cases[i].default_provider_json + " and keyword_provider_json=" + 1161 cases[i].keyword_provider_json; 1162 const ACMatches& matches = provider_->matches(); 1163 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches)); 1164 size_t j = 0; 1165 // Ensure that the returned matches equal the expectations. 1166 for (; j < matches.size(); ++j) { 1167 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]), matches[j].contents) << 1168 description; 1169 } 1170 // Ensure that no expected matches are missing. 1171 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) 1172 EXPECT_EQ(std::string(), cases[i].matches[j]) << description; 1173 } 1174} 1175 1176// Verifies that suggest results with relevance scores are added 1177// properly when using the default fetcher. When adding a new test 1178// case to this test, please consider adding it to the tests in 1179// KeywordFetcherSuggestRelevance below. 1180TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevance) { 1181 struct DefaultFetcherMatch { 1182 std::string contents; 1183 bool allowed_to_be_default_match; 1184 }; 1185 const DefaultFetcherMatch kEmptyMatch = { kNotApplicable, false }; 1186 struct { 1187 const std::string json; 1188 const DefaultFetcherMatch matches[6]; 1189 const std::string inline_autocompletion; 1190 } cases[] = { 1191 // Ensure that suggestrelevance scores reorder matches. 1192 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]", 1193 { { "a", true }, { "c", false }, { "b", false }, kEmptyMatch, kEmptyMatch, 1194 kEmptyMatch }, 1195 std::string() }, 1196 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[]," 1197 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]," 1198 "\"google:suggestrelevance\":[1, 2]}]", 1199 { { "a", true }, { "c.com", false }, { "b.com", false }, kEmptyMatch, 1200 kEmptyMatch, kEmptyMatch }, 1201 std::string() }, 1202 1203 // Without suggested relevance scores, we should only allow one 1204 // navsuggest result to be be displayed. 1205 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[]," 1206 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]", 1207 { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch, 1208 kEmptyMatch, kEmptyMatch }, 1209 std::string() }, 1210 1211 // Ensure that verbatimrelevance scores reorder or suppress verbatim. 1212 // Negative values will have no effect; the calculated value will be used. 1213 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999," 1214 "\"google:suggestrelevance\":[9998]}]", 1215 { { "a", true}, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1216 kEmptyMatch }, 1217 std::string() }, 1218 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998," 1219 "\"google:suggestrelevance\":[9999]}]", 1220 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1221 kEmptyMatch }, 1222 "1" }, 1223 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0," 1224 "\"google:suggestrelevance\":[9999]}]", 1225 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1226 kEmptyMatch }, 1227 "1" }, 1228 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1," 1229 "\"google:suggestrelevance\":[9999]}]", 1230 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1231 kEmptyMatch }, 1232 "1" }, 1233 { "[\"a\",[\"http://a.com\"],[],[]," 1234 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1235 "\"google:verbatimrelevance\":9999," 1236 "\"google:suggestrelevance\":[9998]}]", 1237 { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1238 kEmptyMatch }, 1239 std::string() }, 1240 { "[\"a\",[\"http://a.com\"],[],[]," 1241 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1242 "\"google:verbatimrelevance\":9998," 1243 "\"google:suggestrelevance\":[9999]}]", 1244 { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1245 kEmptyMatch }, 1246 ".com" }, 1247 { "[\"a\",[\"http://a.com\"],[],[]," 1248 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1249 "\"google:verbatimrelevance\":0," 1250 "\"google:suggestrelevance\":[9999]}]", 1251 { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1252 kEmptyMatch }, 1253 ".com" }, 1254 { "[\"a\",[\"http://a.com\"],[],[]," 1255 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1256 "\"google:verbatimrelevance\":-1," 1257 "\"google:suggestrelevance\":[9999]}]", 1258 { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1259 kEmptyMatch }, 1260 ".com" }, 1261 1262 // Ensure that both types of relevance scores reorder matches together. 1263 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997]," 1264 "\"google:verbatimrelevance\":9998}]", 1265 { { "a1", true }, { "a", true }, { "a2", true }, kEmptyMatch, kEmptyMatch, 1266 kEmptyMatch }, 1267 "1" }, 1268 1269 // Allow non-inlineable matches to be the highest-scoring match but, 1270 // if the result set lacks a single inlineable result, abandon suggested 1271 // relevance scores entirely. 1272 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]", 1273 { { "b", false }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1274 kEmptyMatch }, 1275 std::string() }, 1276 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]," 1277 "\"google:verbatimrelevance\":0}]", 1278 { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1279 kEmptyMatch }, 1280 std::string() }, 1281 { "[\"a\",[\"http://b.com\"],[],[]," 1282 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1283 "\"google:suggestrelevance\":[9999]}]", 1284 { { "b.com", false }, { "a", true }, kEmptyMatch, kEmptyMatch, 1285 kEmptyMatch, kEmptyMatch }, 1286 std::string() }, 1287 { "[\"a\",[\"http://b.com\"],[],[]," 1288 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1289 "\"google:suggestrelevance\":[9999]," 1290 "\"google:verbatimrelevance\":0}]", 1291 { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch, 1292 kEmptyMatch, kEmptyMatch }, 1293 std::string() }, 1294 1295 // Allow low-scoring matches. 1296 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]", 1297 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1298 kEmptyMatch }, 1299 "1" }, 1300 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]", 1301 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1302 kEmptyMatch }, 1303 "1" }, 1304 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1]," 1305 "\"google:verbatimrelevance\":0}]", 1306 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1307 kEmptyMatch }, 1308 "1" }, 1309 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2]," 1310 "\"google:verbatimrelevance\":0}]", 1311 { { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1312 kEmptyMatch }, 1313 "2" }, 1314 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3]," 1315 "\"google:verbatimrelevance\":2}]", 1316 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, 1317 kEmptyMatch }, 1318 "2" }, 1319 { "[\"a\",[\"http://a.com\"],[],[]," 1320 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1321 "\"google:suggestrelevance\":[1]," 1322 "\"google:verbatimrelevance\":0}]", 1323 { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1324 kEmptyMatch }, 1325 ".com" }, 1326 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[]," 1327 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]," 1328 "\"google:suggestrelevance\":[1, 2]," 1329 "\"google:verbatimrelevance\":0}]", 1330 { { "a2.com", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch, 1331 kEmptyMatch, kEmptyMatch }, 1332 "2.com" }, 1333 1334 // Ensure that all suggestions are considered, regardless of order. 1335 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[]," 1336 "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]", 1337 { { "a", true }, { "h", false }, { "g", false }, { "f", false }, 1338 { "e", false }, { "d", false } }, 1339 std::string() }, 1340 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\"," 1341 "\"http://e.com\", \"http://f.com\", \"http://g.com\"," 1342 "\"http://h.com\"],[],[]," 1343 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"," 1344 "\"NAVIGATION\", \"NAVIGATION\"," 1345 "\"NAVIGATION\", \"NAVIGATION\"," 1346 "\"NAVIGATION\"]," 1347 "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]", 1348 { { "a", true }, { "h.com", false }, { "g.com", false }, 1349 { "f.com", false }, { "e.com", false }, { "d.com", false } }, 1350 std::string() }, 1351 1352 // Ensure that incorrectly sized suggestion relevance lists are ignored. 1353 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]", 1354 { { "a", true }, { "a1", true }, { "a2", true }, kEmptyMatch, kEmptyMatch, 1355 kEmptyMatch }, 1356 std::string() }, 1357 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]", 1358 { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1359 kEmptyMatch }, 1360 std::string() }, 1361 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[]," 1362 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]," 1363 "\"google:suggestrelevance\":[1]}]", 1364 { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch, 1365 kEmptyMatch, kEmptyMatch }, 1366 std::string() }, 1367 { "[\"a\",[\"http://a1.com\"],[],[]," 1368 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1369 "\"google:suggestrelevance\":[9999, 1]}]", 1370 { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch, 1371 kEmptyMatch, kEmptyMatch }, 1372 std::string() }, 1373 1374 // Ensure that all 'verbatim' results are merged with their maximum score. 1375 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[]," 1376 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]", 1377 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, 1378 kEmptyMatch }, 1379 "2" }, 1380 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[]," 1381 "{\"google:suggestrelevance\":[9998, 9997, 9999]," 1382 "\"google:verbatimrelevance\":0}]", 1383 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, 1384 kEmptyMatch }, 1385 "2" }, 1386 1387 // Ensure that verbatim is always generated without other suggestions. 1388 // TODO(msw): Ensure verbatimrelevance is respected (except suppression). 1389 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]", 1390 { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1391 kEmptyMatch }, 1392 std::string() }, 1393 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]", 1394 { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, 1395 kEmptyMatch }, 1396 std::string() }, 1397 }; 1398 1399 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { 1400 QueryForInput(ASCIIToUTF16("a"), false, false); 1401 net::TestURLFetcher* fetcher = 1402 test_factory_.GetFetcherByID( 1403 SearchProvider::kDefaultProviderURLFetcherID); 1404 ASSERT_TRUE(fetcher); 1405 fetcher->set_response_code(200); 1406 fetcher->SetResponseString(cases[i].json); 1407 fetcher->delegate()->OnURLFetchComplete(fetcher); 1408 RunTillProviderDone(); 1409 1410 const std::string description = "for input with json=" + cases[i].json; 1411 const ACMatches& matches = provider_->matches(); 1412 ASSERT_FALSE(matches.empty()); 1413 // Find the first match that's allowed to be the default match and check 1414 // its inline_autocompletion. 1415 ACMatches::const_iterator it = FindDefaultMatch(matches); 1416 ASSERT_NE(matches.end(), it); 1417 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion), 1418 it->inline_autocompletion) << description; 1419 1420 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches)); 1421 size_t j = 0; 1422 // Ensure that the returned matches equal the expectations. 1423 for (; j < matches.size(); ++j) { 1424 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents), 1425 matches[j].contents) << description; 1426 EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match, 1427 matches[j].allowed_to_be_default_match) << description; 1428 } 1429 // Ensure that no expected matches are missing. 1430 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) 1431 EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) << 1432 "Case # " << i << " " << description; 1433 } 1434} 1435 1436// Verifies that suggest results with relevance scores are added 1437// properly when using the keyword fetcher. This is similar to the 1438// test DefaultFetcherSuggestRelevance above but this uses inputs that 1439// trigger keyword suggestions (i.e., "k a" rather than "a") and has 1440// different expectations (because now the results are a mix of 1441// keyword suggestions and default provider suggestions). When a new 1442// test is added to this TEST_F, please consider if it would be 1443// appropriate to add to DefaultFetcherSuggestRelevance as well. 1444TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) { 1445 struct KeywordFetcherMatch { 1446 std::string contents; 1447 bool from_keyword; 1448 bool allowed_to_be_default_match; 1449 }; 1450 const KeywordFetcherMatch kEmptyMatch = { kNotApplicable, false, false }; 1451 struct { 1452 const std::string json; 1453 const KeywordFetcherMatch matches[6]; 1454 const std::string inline_autocompletion; 1455 } cases[] = { 1456 // Ensure that suggest relevance scores reorder matches and that 1457 // the keyword verbatim (lacking a suggested verbatim score) beats 1458 // the default provider verbatim. 1459 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]", 1460 { { "a", true, true }, 1461 { "k a", false, false }, 1462 { "c", true, false }, 1463 { "b", true, false }, 1464 kEmptyMatch, kEmptyMatch }, 1465 std::string() }, 1466 // Again, check that relevance scores reorder matches, just this 1467 // time with navigation matches. This also checks that with 1468 // suggested relevance scores we allow multiple navsuggest results. 1469 // Note that navsuggest results that come from a keyword provider 1470 // are marked as not a keyword result. (They don't go to a 1471 // keyword search engine.) 1472 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[]," 1473 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"]," 1474 "\"google:suggestrelevance\":[1301, 1302, 1303]}]", 1475 { { "a", true, true }, 1476 { "d", true, false }, 1477 { "c.com", false, false }, 1478 { "b.com", false, false }, 1479 { "k a", false, false }, 1480 kEmptyMatch }, 1481 std::string() }, 1482 1483 // Without suggested relevance scores, we should only allow one 1484 // navsuggest result to be be displayed. 1485 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[]," 1486 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]", 1487 { { "a", true, true }, 1488 { "b.com", false, false }, 1489 { "k a", false, false }, 1490 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1491 std::string() }, 1492 1493 // Ensure that verbatimrelevance scores reorder or suppress verbatim. 1494 // Negative values will have no effect; the calculated value will be used. 1495 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999," 1496 "\"google:suggestrelevance\":[9998]}]", 1497 { { "a", true, true }, 1498 { "a1", true, true }, 1499 { "k a", false, false }, 1500 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1501 std::string() }, 1502 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998," 1503 "\"google:suggestrelevance\":[9999]}]", 1504 { { "a1", true, true }, 1505 { "a", true, true }, 1506 { "k a", false, false }, 1507 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1508 "1" }, 1509 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0," 1510 "\"google:suggestrelevance\":[9999]}]", 1511 { { "a1", true, true }, 1512 { "k a", false, false }, 1513 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1514 "1" }, 1515 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1," 1516 "\"google:suggestrelevance\":[9999]}]", 1517 { { "a1", true, true }, 1518 { "a", true, true }, 1519 { "k a", false, false }, 1520 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1521 "1" }, 1522 { "[\"a\",[\"http://a.com\"],[],[]," 1523 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1524 "\"google:verbatimrelevance\":9999," 1525 "\"google:suggestrelevance\":[9998]}]", 1526 { { "a", true, true }, 1527 { "a.com", false, false }, 1528 { "k a", false, false }, 1529 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1530 std::string() }, 1531 1532 // Ensure that both types of relevance scores reorder matches together. 1533 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997]," 1534 "\"google:verbatimrelevance\":9998}]", 1535 { { "a1", true, true }, 1536 { "a", true, true }, 1537 { "a2", true, true }, 1538 { "k a", false, false }, 1539 kEmptyMatch, kEmptyMatch }, 1540 "1" }, 1541 1542 // Check that non-inlinable matches may be ranked as the highest result 1543 // if there is at least one inlineable match. 1544 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]", 1545 { { "b", true, false }, 1546 { "a", true, true }, 1547 { "k a", false, false }, 1548 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1549 std::string() }, 1550 { "[\"a\",[\"http://b.com\"],[],[]," 1551 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1552 "\"google:suggestrelevance\":[9999]}]", 1553 { { "b.com", false, false }, 1554 { "a", true, true }, 1555 { "k a", false, false }, 1556 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1557 std::string() }, 1558 // On the other hand, if there is no inlineable match, restore 1559 // the keyword verbatim score. 1560 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]," 1561 "\"google:verbatimrelevance\":0}]", 1562 { { "b", true, false }, 1563 { "a", true, true }, 1564 { "k a", false, false }, 1565 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1566 std::string() }, 1567 { "[\"a\",[\"http://b.com\"],[],[]," 1568 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1569 "\"google:suggestrelevance\":[9999]," 1570 "\"google:verbatimrelevance\":0}]", 1571 { { "b.com", false, false }, 1572 { "a", true, true }, 1573 { "k a", false, false }, 1574 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1575 std::string() }, 1576 1577 // The top result does not have to score as highly as calculated 1578 // verbatim. i.e., there are no minimum score restrictions in 1579 // this provider. 1580 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]", 1581 { { "a1", true, true }, 1582 { "k a", false, false }, 1583 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1584 "1" }, 1585 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]", 1586 { { "a1", true, true }, 1587 { "k a", false, false }, 1588 { "a", true, true }, 1589 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1590 "1" }, 1591 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1]," 1592 "\"google:verbatimrelevance\":0}]", 1593 { { "k a", false, false }, 1594 { "a1", true, true }, 1595 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1596 "1" }, 1597 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2]," 1598 "\"google:verbatimrelevance\":0}]", 1599 { 1600 { "k a", false, false }, 1601 { "a2", true, true }, 1602 { "a1", true, true }, 1603 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1604 "2" }, 1605 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3]," 1606 "\"google:verbatimrelevance\":2}]", 1607 { { "k a", false, false }, 1608 { "a2", true, true }, 1609 { "a", true, true }, 1610 { "a1", true, true }, 1611 kEmptyMatch, kEmptyMatch }, 1612 "2" }, 1613 1614 // Ensure that all suggestions are considered, regardless of order. 1615 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[]," 1616 "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]", 1617 { { "a", true, true }, 1618 { "k a", false, false }, 1619 { "h", true, false }, 1620 { "g", true, false }, 1621 { "f", true, false }, 1622 { "e", true, false } }, 1623 std::string() }, 1624 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\"," 1625 "\"http://e.com\", \"http://f.com\", \"http://g.com\"," 1626 "\"http://h.com\"],[],[]," 1627 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"," 1628 "\"NAVIGATION\", \"NAVIGATION\"," 1629 "\"NAVIGATION\", \"NAVIGATION\"," 1630 "\"NAVIGATION\"]," 1631 "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]", 1632 { { "a", true, true }, 1633 { "k a", false, false }, 1634 { "h.com", false, false }, 1635 { "g.com", false, false }, 1636 { "f.com", false, false }, 1637 { "e.com", false, false } }, 1638 std::string() }, 1639 1640 // Ensure that incorrectly sized suggestion relevance lists are ignored. 1641 // Note that keyword suggestions by default (not in suggested relevance 1642 // mode) score more highly than the default verbatim. 1643 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]", 1644 { { "a", true, true }, 1645 { "a1", true, true }, 1646 { "a2", true, true }, 1647 { "k a", false, false }, 1648 kEmptyMatch, kEmptyMatch }, 1649 std::string() }, 1650 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]", 1651 { { "a", true, true }, 1652 { "a1", true, true }, 1653 { "k a", false, false }, 1654 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1655 std::string() }, 1656 // In this case, ignoring the suggested relevance scores means we keep 1657 // only one navsuggest result. 1658 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[]," 1659 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]," 1660 "\"google:suggestrelevance\":[1]}]", 1661 { { "a", true, true }, 1662 { "a1.com", false, false }, 1663 { "k a", false, false }, 1664 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1665 std::string() }, 1666 { "[\"a\",[\"http://a1.com\"],[],[]," 1667 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1668 "\"google:suggestrelevance\":[9999, 1]}]", 1669 { { "a", true, true }, 1670 { "a1.com", false, false }, 1671 { "k a", false, false }, 1672 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1673 std::string() }, 1674 1675 // Ensure that all 'verbatim' results are merged with their maximum score. 1676 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[]," 1677 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]", 1678 { { "a2", true, true }, 1679 { "a", true, true }, 1680 { "a1", true, true }, 1681 { "k a", false, false }, 1682 kEmptyMatch, kEmptyMatch }, 1683 "2" }, 1684 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[]," 1685 "{\"google:suggestrelevance\":[9998, 9997, 9999]," 1686 "\"google:verbatimrelevance\":0}]", 1687 { { "a2", true, true }, 1688 { "a", true, true }, 1689 { "a1", true, true }, 1690 { "k a", false, false }, 1691 kEmptyMatch, kEmptyMatch }, 1692 "2" }, 1693 1694 // Ensure that verbatim is always generated without other suggestions. 1695 // TODO(mpearson): Ensure the value of verbatimrelevance is respected 1696 // (except when suggested relevances are ignored). 1697 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]", 1698 { { "k a", false, false }, 1699 { "a", true, true }, 1700 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1701 std::string() }, 1702 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]", 1703 { { "a", true, true }, 1704 { "k a", false, false }, 1705 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1706 std::string() }, 1707 1708 // In reorder mode, navsuggestions will not need to be demoted (because 1709 // they are marked as not allowed to be default match and will be 1710 // reordered as necessary). 1711 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[]," 1712 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]," 1713 "\"google:verbatimrelevance\":9990," 1714 "\"google:suggestrelevance\":[9998, 9999]}]", 1715 { { "a2.com", false, false }, 1716 { "a1.com", false, false }, 1717 { "a", true, true }, 1718 { "k a", false, false }, 1719 kEmptyMatch, kEmptyMatch }, 1720 std::string() }, 1721 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[]," 1722 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]," 1723 "\"google:verbatimrelevance\":9990," 1724 "\"google:suggestrelevance\":[9999, 9998]}]", 1725 { { "a1.com", false, false }, 1726 { "a2.com", false, false }, 1727 { "a", true, true }, 1728 { "k a", false, false }, 1729 kEmptyMatch, kEmptyMatch }, 1730 std::string() }, 1731 { "[\"a\",[\"https://a/\"],[],[]," 1732 "{\"google:suggesttype\":[\"NAVIGATION\"]," 1733 "\"google:suggestrelevance\":[9999]}]", 1734 { { "https://a", false, false }, 1735 { "a", true, true }, 1736 { "k a", false, false }, 1737 kEmptyMatch, kEmptyMatch, kEmptyMatch }, 1738 std::string() }, 1739 // Check when navsuggest scores more than verbatim and there is query 1740 // suggestion but it scores lower. 1741 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[]," 1742 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"]," 1743 "\"google:verbatimrelevance\":9990," 1744 "\"google:suggestrelevance\":[9998, 9999, 1300]}]", 1745 { { "a2.com", false, false }, 1746 { "a1.com", false, false }, 1747 { "a", true, true }, 1748 { "a3", true, true }, 1749 { "k a", false, false }, 1750 kEmptyMatch }, 1751 std::string() }, 1752 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[]," 1753 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"]," 1754 "\"google:verbatimrelevance\":9990," 1755 "\"google:suggestrelevance\":[9999, 9998, 1300]}]", 1756 { { "a1.com", false, false }, 1757 { "a2.com", false, false }, 1758 { "a", true, true }, 1759 { "a3", true, true }, 1760 { "k a", false, false }, 1761 kEmptyMatch }, 1762 std::string() }, 1763 // Check when navsuggest scores more than a query suggestion. There is 1764 // a verbatim but it scores lower. 1765 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[]," 1766 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"]," 1767 "\"google:verbatimrelevance\":9990," 1768 "\"google:suggestrelevance\":[9998, 9999, 9997]}]", 1769 { { "a2.com", false, false }, 1770 { "a1.com", false, false }, 1771 { "a3", true, true }, 1772 { "a", true, true }, 1773 { "k a", false, false }, 1774 kEmptyMatch }, 1775 "3" }, 1776 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[]," 1777 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"]," 1778 "\"google:verbatimrelevance\":9990," 1779 "\"google:suggestrelevance\":[9999, 9998, 9997]}]", 1780 { { "a1.com", false, false }, 1781 { "a2.com", false, false }, 1782 { "a3", true, true }, 1783 { "a", true, true }, 1784 { "k a", false, false }, 1785 kEmptyMatch }, 1786 "3" }, 1787 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[]," 1788 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"]," 1789 "\"google:verbatimrelevance\":0," 1790 "\"google:suggestrelevance\":[9998, 9999, 9997]}]", 1791 { { "a2.com", false, false }, 1792 { "a1.com", false, false }, 1793 { "a3", true, true }, 1794 { "k a", false, false }, 1795 kEmptyMatch, kEmptyMatch }, 1796 "3" }, 1797 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[]," 1798 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"]," 1799 "\"google:verbatimrelevance\":0," 1800 "\"google:suggestrelevance\":[9999, 9998, 9997]}]", 1801 { { "a1.com", false, false }, 1802 { "a2.com", false, false }, 1803 { "a3", true, true }, 1804 { "k a", false, false }, 1805 kEmptyMatch, kEmptyMatch }, 1806 "3" }, 1807 // Check when there is neither verbatim nor a query suggestion that, 1808 // because we can't demote navsuggestions below a query suggestion, 1809 // we restore the keyword verbatim score. 1810 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[]," 1811 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]," 1812 "\"google:verbatimrelevance\":0," 1813 "\"google:suggestrelevance\":[9998, 9999]}]", 1814 { { "a2.com", false, false }, 1815 { "a1.com", false, false }, 1816 { "a", true, true }, 1817 { "k a", false, false }, 1818 kEmptyMatch, kEmptyMatch }, 1819 std::string() }, 1820 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[]," 1821 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]," 1822 "\"google:verbatimrelevance\":0," 1823 "\"google:suggestrelevance\":[9999, 9998]}]", 1824 { { "a1.com", false, false }, 1825 { "a2.com", false, false }, 1826 { "a", true, true }, 1827 { "k a", false, false }, 1828 kEmptyMatch, kEmptyMatch }, 1829 std::string() }, 1830 // More checks that everything works when it's not necessary to demote. 1831 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[]," 1832 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"]," 1833 "\"google:verbatimrelevance\":9990," 1834 "\"google:suggestrelevance\":[9997, 9998, 9999]}]", 1835 { { "a3", true, true }, 1836 { "a2.com", false, false }, 1837 { "a1.com", false, false }, 1838 { "a", true, true }, 1839 { "k a", false, false }, 1840 kEmptyMatch }, 1841 "3" }, 1842 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[]," 1843 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"]," 1844 "\"google:verbatimrelevance\":9990," 1845 "\"google:suggestrelevance\":[9998, 9997, 9999]}]", 1846 { { "a3", true, true }, 1847 { "a1.com", false, false }, 1848 { "a2.com", false, false }, 1849 { "a", true, true }, 1850 { "k a", false, false }, 1851 kEmptyMatch }, 1852 "3" }, 1853 }; 1854 1855 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { 1856 QueryForInput(ASCIIToUTF16("k a"), false, true); 1857 1858 // Set up a default fetcher with no results. 1859 net::TestURLFetcher* default_fetcher = 1860 test_factory_.GetFetcherByID( 1861 SearchProvider::kDefaultProviderURLFetcherID); 1862 ASSERT_TRUE(default_fetcher); 1863 default_fetcher->set_response_code(200); 1864 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher); 1865 default_fetcher = NULL; 1866 1867 // Set up a keyword fetcher with provided results. 1868 net::TestURLFetcher* keyword_fetcher = 1869 test_factory_.GetFetcherByID( 1870 SearchProvider::kKeywordProviderURLFetcherID); 1871 ASSERT_TRUE(keyword_fetcher); 1872 keyword_fetcher->set_response_code(200); 1873 keyword_fetcher->SetResponseString(cases[i].json); 1874 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher); 1875 keyword_fetcher = NULL; 1876 RunTillProviderDone(); 1877 1878 const std::string description = "for input with json=" + cases[i].json; 1879 const ACMatches& matches = provider_->matches(); 1880 ASSERT_FALSE(matches.empty()); 1881 // Find the first match that's allowed to be the default match and check 1882 // its inline_autocompletion. 1883 ACMatches::const_iterator it = FindDefaultMatch(matches); 1884 ASSERT_NE(matches.end(), it); 1885 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion), 1886 it->inline_autocompletion) << description; 1887 1888 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches)); 1889 size_t j = 0; 1890 // Ensure that the returned matches equal the expectations. 1891 for (; j < matches.size(); ++j) { 1892 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents), 1893 matches[j].contents) << description; 1894 EXPECT_EQ(cases[i].matches[j].from_keyword, 1895 matches[j].keyword == ASCIIToUTF16("k")) << description; 1896 EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match, 1897 matches[j].allowed_to_be_default_match) << description; 1898 } 1899 // Ensure that no expected matches are missing. 1900 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) 1901 EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) << 1902 "Case # " << i << " " << description; 1903 } 1904} 1905 1906TEST_F(SearchProviderTest, LocalAndRemoteRelevances) { 1907 // We hardcode the string "term1" below, so ensure that the search term that 1908 // got added to history already is that string. 1909 ASSERT_EQ(ASCIIToUTF16("term1"), term1_); 1910 base::string16 term = term1_.substr(0, term1_.length() - 1); 1911 1912 AddSearchToHistory(default_t_url_, term + ASCIIToUTF16("2"), 2); 1913 profile_.BlockUntilHistoryProcessesPendingRequests(); 1914 1915 struct { 1916 const base::string16 input; 1917 const std::string json; 1918 const std::string matches[6]; 1919 } cases[] = { 1920 // The history results outscore the default verbatim score. term2 has more 1921 // visits so it outscores term1. The suggestions are still returned since 1922 // they're server-scored. 1923 { term, 1924 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[]," 1925 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"]," 1926 "\"google:suggestrelevance\":[1, 2, 3]}]", 1927 { "term2", "term1", "term", "a3", "a2", "a1" } }, 1928 // Because we already have three suggestions by the time we see the history 1929 // results, they don't get returned. 1930 { term, 1931 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[]," 1932 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"]," 1933 "\"google:verbatimrelevance\":1450," 1934 "\"google:suggestrelevance\":[1440, 1430, 1420]}]", 1935 { "term", "a1", "a2", "a3", kNotApplicable, kNotApplicable } }, 1936 // If we only have two suggestions, we have room for a history result. 1937 { term, 1938 "[\"term\",[\"a1\", \"a2\"],[],[]," 1939 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"]," 1940 "\"google:verbatimrelevance\":1450," 1941 "\"google:suggestrelevance\":[1430, 1410]}]", 1942 { "term", "a1", "a2", "term2", kNotApplicable, kNotApplicable } }, 1943 // If we have more than three suggestions, they should all be returned as 1944 // long as we have enough total space for them. 1945 { term, 1946 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[]," 1947 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"]," 1948 "\"google:verbatimrelevance\":1450," 1949 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410]}]", 1950 { "term", "a1", "a2", "a3", "a4", kNotApplicable } }, 1951 { term, 1952 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\", \"a5\", \"a6\"],[],[]," 1953 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"," 1954 "\"QUERY\", \"QUERY\"]," 1955 "\"google:verbatimrelevance\":1450," 1956 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410, 1400, 1390]}]", 1957 { "term", "a1", "a2", "a3", "a4", "a5" } }, 1958 { term, 1959 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[]," 1960 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"]," 1961 "\"google:verbatimrelevance\":1450," 1962 "\"google:suggestrelevance\":[1430, 1410, 1390, 1370]}]", 1963 { "term", "a1", "a2", "term2", "a3", "a4" } } 1964 }; 1965 1966 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { 1967 QueryForInput(cases[i].input, false, false); 1968 net::TestURLFetcher* fetcher = 1969 test_factory_.GetFetcherByID( 1970 SearchProvider::kDefaultProviderURLFetcherID); 1971 ASSERT_TRUE(fetcher); 1972 fetcher->set_response_code(200); 1973 fetcher->SetResponseString(cases[i].json); 1974 fetcher->delegate()->OnURLFetchComplete(fetcher); 1975 RunTillProviderDone(); 1976 1977 const std::string description = "for input with json=" + cases[i].json; 1978 const ACMatches& matches = provider_->matches(); 1979 1980 // Ensure no extra matches are present. 1981 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches)); 1982 1983 size_t j = 0; 1984 // Ensure that the returned matches equal the expectations. 1985 for (; j < matches.size(); ++j) 1986 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]), 1987 matches[j].contents) << description; 1988 // Ensure that no expected matches are missing. 1989 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) 1990 EXPECT_EQ(kNotApplicable, cases[i].matches[j]) << 1991 "Case # " << i << " " << description; 1992 } 1993} 1994 1995// Verifies suggest relevance behavior for URL input. 1996TEST_F(SearchProviderTest, DefaultProviderSuggestRelevanceScoringUrlInput) { 1997 struct DefaultFetcherUrlInputMatch { 1998 const std::string match_contents; 1999 AutocompleteMatch::Type match_type; 2000 bool allowed_to_be_default_match; 2001 }; 2002 const DefaultFetcherUrlInputMatch kEmptyMatch = 2003 { kNotApplicable, AutocompleteMatchType::NUM_TYPES, false }; 2004 struct { 2005 const std::string input; 2006 const std::string json; 2007 const DefaultFetcherUrlInputMatch output[4]; 2008 } cases[] = { 2009 // Ensure NAVIGATION matches are allowed to be listed first for URL 2010 // input regardless of whether the match is inlineable. Note that 2011 // non-inlineable matches should not be allowed to be the default match. 2012 { "a.com", "[\"a.com\",[\"http://b.com/\"],[],[]," 2013 "{\"google:suggesttype\":[\"NAVIGATION\"]," 2014 "\"google:suggestrelevance\":[9999]}]", 2015 { { "b.com", AutocompleteMatchType::NAVSUGGEST, false }, 2016 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true }, 2017 kEmptyMatch, kEmptyMatch } }, 2018 { "a.com", "[\"a.com\",[\"https://b.com\"],[],[]," 2019 "{\"google:suggesttype\":[\"NAVIGATION\"]," 2020 "\"google:suggestrelevance\":[9999]}]", 2021 { { "https://b.com", AutocompleteMatchType::NAVSUGGEST, false }, 2022 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true }, 2023 kEmptyMatch, kEmptyMatch } }, 2024 { "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[]," 2025 "{\"google:suggesttype\":[\"NAVIGATION\"]," 2026 "\"google:suggestrelevance\":[9999]}]", 2027 { { "a.com/a", AutocompleteMatchType::NAVSUGGEST, true }, 2028 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true }, 2029 kEmptyMatch, kEmptyMatch } }, 2030 { "a.com", "[\"a.com\",[\"https://a.com\"],[],[]," 2031 "{\"google:suggesttype\":[\"NAVIGATION\"]," 2032 "\"google:suggestrelevance\":[9999]}]", 2033 { { "https://a.com", AutocompleteMatchType::NAVSUGGEST, true }, 2034 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true }, 2035 kEmptyMatch, kEmptyMatch } }, 2036 2037 // Ensure topmost inlineable SUGGEST matches are NOT allowed for URL 2038 // input. SearchProvider disregards search and verbatim suggested 2039 // relevances. 2040 { "a.com", "[\"a.com\",[\"a.com info\"],[],[]," 2041 "{\"google:suggestrelevance\":[9999]}]", 2042 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true }, 2043 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true }, 2044 kEmptyMatch, kEmptyMatch } }, 2045 { "a.com", "[\"a.com\",[\"a.com info\"],[],[]," 2046 "{\"google:suggestrelevance\":[9999]}]", 2047 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true }, 2048 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true }, 2049 kEmptyMatch, kEmptyMatch } }, 2050 2051 // Ensure the fallback mechanism allows inlinable NAVIGATION matches. 2052 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[]," 2053 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"]," 2054 "\"google:suggestrelevance\":[9999, 9998]}]", 2055 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true }, 2056 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true }, 2057 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true }, 2058 kEmptyMatch } }, 2059 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[]," 2060 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"]," 2061 "\"google:suggestrelevance\":[9998, 9997]," 2062 "\"google:verbatimrelevance\":9999}]", 2063 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true }, 2064 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true }, 2065 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true }, 2066 kEmptyMatch } }, 2067 2068 // Ensure topmost non-inlineable SUGGEST matches are allowed for URL 2069 // input assuming the top inlineable match is not a query (i.e., is a 2070 // NAVSUGGEST). 2071 { "a.com", "[\"a.com\",[\"info\"],[],[]," 2072 "{\"google:suggestrelevance\":[9999]}]", 2073 { { "info", AutocompleteMatchType::SEARCH_SUGGEST, false }, 2074 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true }, 2075 kEmptyMatch, kEmptyMatch } }, 2076 { "a.com", "[\"a.com\",[\"info\"],[],[]," 2077 "{\"google:suggestrelevance\":[9999]}]", 2078 { { "info", AutocompleteMatchType::SEARCH_SUGGEST, false }, 2079 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true }, 2080 kEmptyMatch, kEmptyMatch } }, 2081 }; 2082 2083 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { 2084 QueryForInput(ASCIIToUTF16(cases[i].input), false, false); 2085 net::TestURLFetcher* fetcher = 2086 test_factory_.GetFetcherByID( 2087 SearchProvider::kDefaultProviderURLFetcherID); 2088 ASSERT_TRUE(fetcher); 2089 fetcher->set_response_code(200); 2090 fetcher->SetResponseString(cases[i].json); 2091 fetcher->delegate()->OnURLFetchComplete(fetcher); 2092 RunTillProviderDone(); 2093 2094 size_t j = 0; 2095 const ACMatches& matches = provider_->matches(); 2096 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].output)); 2097 // Ensure that the returned matches equal the expectations. 2098 for (; j < matches.size(); ++j) { 2099 EXPECT_EQ(ASCIIToUTF16(cases[i].output[j].match_contents), 2100 matches[j].contents); 2101 EXPECT_EQ(cases[i].output[j].match_type, matches[j].type); 2102 EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match, 2103 matches[j].allowed_to_be_default_match); 2104 } 2105 // Ensure that no expected matches are missing. 2106 for (; j < ARRAYSIZE_UNSAFE(cases[i].output); ++j) { 2107 EXPECT_EQ(kNotApplicable, cases[i].output[j].match_contents); 2108 EXPECT_EQ(AutocompleteMatchType::NUM_TYPES, 2109 cases[i].output[j].match_type); 2110 EXPECT_FALSE(cases[i].output[j].allowed_to_be_default_match); 2111 } 2112 } 2113} 2114 2115// A basic test that verifies the field trial triggered parsing logic. 2116TEST_F(SearchProviderTest, FieldTrialTriggeredParsing) { 2117 QueryForInput(ASCIIToUTF16("foo"), false, false); 2118 2119 // Make sure the default providers suggest service was queried. 2120 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID( 2121 SearchProvider::kDefaultProviderURLFetcherID); 2122 ASSERT_TRUE(fetcher); 2123 2124 // Tell the SearchProvider the suggest query is done. 2125 fetcher->set_response_code(200); 2126 fetcher->SetResponseString( 2127 "[\"foo\",[\"foo bar\"],[\"\"],[]," 2128 "{\"google:suggesttype\":[\"QUERY\"]," 2129 "\"google:fieldtrialtriggered\":true}]"); 2130 fetcher->delegate()->OnURLFetchComplete(fetcher); 2131 fetcher = NULL; 2132 2133 // Run till the history results complete. 2134 RunTillProviderDone(); 2135 2136 { 2137 // Check for the match and field trial triggered bits. 2138 AutocompleteMatch match; 2139 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("foo bar"), &match)); 2140 ProvidersInfo providers_info; 2141 provider_->AddProviderInfo(&providers_info); 2142 ASSERT_EQ(1U, providers_info.size()); 2143 EXPECT_EQ(1, providers_info[0].field_trial_triggered_size()); 2144 EXPECT_EQ(1, providers_info[0].field_trial_triggered_in_session_size()); 2145 } 2146 { 2147 // Reset the session and check that bits are reset. 2148 provider_->ResetSession(); 2149 ProvidersInfo providers_info; 2150 provider_->AddProviderInfo(&providers_info); 2151 ASSERT_EQ(1U, providers_info.size()); 2152 EXPECT_EQ(1, providers_info[0].field_trial_triggered_size()); 2153 EXPECT_EQ(0, providers_info[0].field_trial_triggered_in_session_size()); 2154 } 2155} 2156 2157// Verifies inline autocompletion of navigational results. 2158TEST_F(SearchProviderTest, NavigationInline) { 2159 struct { 2160 const std::string input; 2161 const std::string url; 2162 // Test the expected fill_into_edit, which may drop "http://". 2163 // Some cases do not trim "http://" to match from the start of the scheme. 2164 const std::string fill_into_edit; 2165 const std::string inline_autocompletion; 2166 const bool allowed_to_be_default_match_in_regular_mode; 2167 const bool allowed_to_be_default_match_in_prevent_inline_mode; 2168 } cases[] = { 2169 // Do not inline matches that do not contain the input; trim http as needed. 2170 { "x", "http://www.abc.com", 2171 "www.abc.com", std::string(), false, false }, 2172 { "https:", "http://www.abc.com", 2173 "www.abc.com", std::string(), false, false }, 2174 { "http://www.abc.com/a", "http://www.abc.com", 2175 "http://www.abc.com", std::string(), false, 2176 false }, 2177 { "http://www.abc.com", "https://www.abc.com", 2178 "https://www.abc.com", std::string(), false, 2179 false }, 2180 { "http://abc.com", "ftp://abc.com", 2181 "ftp://abc.com", std::string(), false, 2182 false }, 2183 { "https://www.abc.com", "http://www.abc.com", 2184 "www.abc.com", std::string(), false, 2185 false }, 2186 { "ftp://abc.com", "http://abc.com", 2187 "abc.com", std::string(), false, 2188 false }, 2189 2190 // Do not inline matches with invalid input prefixes; trim http as needed. 2191 { "ttp", "http://www.abc.com", 2192 "www.abc.com", std::string(), false, false }, 2193 { "://w", "http://www.abc.com", 2194 "www.abc.com", std::string(), false, false }, 2195 { "ww.", "http://www.abc.com", 2196 "www.abc.com", std::string(), false, false }, 2197 { ".ab", "http://www.abc.com", 2198 "www.abc.com", std::string(), false, false }, 2199 { "bc", "http://www.abc.com", 2200 "www.abc.com", std::string(), false, false }, 2201 { ".com", "http://www.abc.com", 2202 "www.abc.com", std::string(), false, false }, 2203 2204 // Do not inline matches that omit input domain labels; trim http as needed. 2205 { "www.a", "http://a.com", 2206 "a.com", std::string(), false, false }, 2207 { "http://www.a", "http://a.com", 2208 "http://a.com", std::string(), false, false }, 2209 { "www.a", "ftp://a.com", 2210 "ftp://a.com", std::string(), false, false }, 2211 { "ftp://www.a", "ftp://a.com", 2212 "ftp://a.com", std::string(), false, false }, 2213 2214 // Input matching but with nothing to inline will not yield an offset, but 2215 // will be allowed to be default. 2216 { "abc.com", "http://www.abc.com", 2217 "www.abc.com", std::string(), true, true }, 2218 { "abc.com/", "http://www.abc.com", 2219 "www.abc.com", std::string(), true, true }, 2220 { "http://www.abc.com", "http://www.abc.com", 2221 "http://www.abc.com", std::string(), true, true }, 2222 { "http://www.abc.com/", "http://www.abc.com", 2223 "http://www.abc.com", std::string(), true, true }, 2224 2225 // Inputs with trailing whitespace should inline when possible. 2226 { "abc.com ", "http://www.abc.com", 2227 "www.abc.com", std::string(), true, true }, 2228 { "abc.com/ ", "http://www.abc.com", 2229 "www.abc.com", std::string(), true, true }, 2230 { "abc.com ", "http://www.abc.com/bar", 2231 "www.abc.com/bar", "/bar", false, false }, 2232 2233 // Inline matches when the input is a leading substring of the scheme. 2234 { "h", "http://www.abc.com", 2235 "http://www.abc.com", "ttp://www.abc.com", true, false }, 2236 { "http", "http://www.abc.com", 2237 "http://www.abc.com", "://www.abc.com", true, false }, 2238 2239 // Inline matches when the input is a leading substring of the full URL. 2240 { "http:", "http://www.abc.com", 2241 "http://www.abc.com", "//www.abc.com", true, false }, 2242 { "http://w", "http://www.abc.com", 2243 "http://www.abc.com", "ww.abc.com", true, false }, 2244 { "http://www.", "http://www.abc.com", 2245 "http://www.abc.com", "abc.com", true, false }, 2246 { "http://www.ab", "http://www.abc.com", 2247 "http://www.abc.com", "c.com", true, false }, 2248 { "http://www.abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo", 2249 "http://www.abc.com/path/file.htm?q=x#foo", 2250 "ath/file.htm?q=x#foo", 2251 true, false }, 2252 { "http://abc.com/p", "http://abc.com/path/file.htm?q=x#foo", 2253 "http://abc.com/path/file.htm?q=x#foo", 2254 "ath/file.htm?q=x#foo", 2255 true, false}, 2256 2257 // Inline matches with valid URLPrefixes; only trim "http://". 2258 { "w", "http://www.abc.com", 2259 "www.abc.com", "ww.abc.com", true, false }, 2260 { "www.a", "http://www.abc.com", 2261 "www.abc.com", "bc.com", true, false }, 2262 { "abc", "http://www.abc.com", 2263 "www.abc.com", ".com", true, false }, 2264 { "abc.c", "http://www.abc.com", 2265 "www.abc.com", "om", true, false }, 2266 { "abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo", 2267 "www.abc.com/path/file.htm?q=x#foo", 2268 "ath/file.htm?q=x#foo", 2269 true, false }, 2270 { "abc.com/p", "http://abc.com/path/file.htm?q=x#foo", 2271 "abc.com/path/file.htm?q=x#foo", 2272 "ath/file.htm?q=x#foo", 2273 true, false }, 2274 2275 // Inline matches using the maximal URLPrefix components. 2276 { "h", "http://help.com", 2277 "help.com", "elp.com", true, false }, 2278 { "http", "http://http.com", 2279 "http.com", ".com", true, false }, 2280 { "h", "http://www.help.com", 2281 "www.help.com", "elp.com", true, false }, 2282 { "http", "http://www.http.com", 2283 "www.http.com", ".com", true, false }, 2284 { "w", "http://www.www.com", 2285 "www.www.com", "ww.com", true, false }, 2286 2287 // Test similar behavior for the ftp and https schemes. 2288 { "ftp://www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo", 2289 "ftp://www.abc.com/path/file.htm?q=x#foo", 2290 "c.com/path/file.htm?q=x#foo", true, false }, 2291 { "www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo", 2292 "ftp://www.abc.com/path/file.htm?q=x#foo", 2293 "c.com/path/file.htm?q=x#foo", true, false }, 2294 { "ab", "ftp://www.abc.com/path/file.htm?q=x#foo", 2295 "ftp://www.abc.com/path/file.htm?q=x#foo", 2296 "c.com/path/file.htm?q=x#foo", true, false }, 2297 { "ab", "ftp://abc.com/path/file.htm?q=x#foo", 2298 "ftp://abc.com/path/file.htm?q=x#foo", 2299 "c.com/path/file.htm?q=x#foo", true, false }, 2300 { "https://www.ab", "https://www.abc.com/path/file.htm?q=x#foo", 2301 "https://www.abc.com/path/file.htm?q=x#foo", 2302 "c.com/path/file.htm?q=x#foo", 2303 true, false }, 2304 { "www.ab", "https://www.abc.com/path/file.htm?q=x#foo", 2305 "https://www.abc.com/path/file.htm?q=x#foo", 2306 "c.com/path/file.htm?q=x#foo", true, false }, 2307 { "ab", "https://www.abc.com/path/file.htm?q=x#foo", 2308 "https://www.abc.com/path/file.htm?q=x#foo", 2309 "c.com/path/file.htm?q=x#foo", true, false }, 2310 { "ab", "https://abc.com/path/file.htm?q=x#foo", 2311 "https://abc.com/path/file.htm?q=x#foo", 2312 "c.com/path/file.htm?q=x#foo", true, false }, 2313 2314 // Forced query input should inline and retain the "?" prefix. 2315 { "?http://www.ab", "http://www.abc.com", 2316 "?http://www.abc.com", "c.com", true, false }, 2317 { "?www.ab", "http://www.abc.com", 2318 "?www.abc.com", "c.com", true, false }, 2319 { "?ab", "http://www.abc.com", 2320 "?www.abc.com", "c.com", true, false }, 2321 { "?abc.com", "http://www.abc.com", 2322 "?www.abc.com", "", true, true }, 2323 }; 2324 2325 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { 2326 // First test regular mode. 2327 QueryForInput(ASCIIToUTF16(cases[i].input), false, false); 2328 AutocompleteMatch match( 2329 provider_->NavigationToMatch(SearchProvider::NavigationResult( 2330 *provider_.get(), GURL(cases[i].url), base::string16(), false, 0, 2331 false, ASCIIToUTF16(cases[i].input), std::string()))); 2332 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion), 2333 match.inline_autocompletion); 2334 EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit), match.fill_into_edit); 2335 EXPECT_EQ(cases[i].allowed_to_be_default_match_in_regular_mode, 2336 match.allowed_to_be_default_match); 2337 2338 // Then test prevent-inline-autocomplete mode. 2339 QueryForInput(ASCIIToUTF16(cases[i].input), true, false); 2340 AutocompleteMatch match_prevent_inline( 2341 provider_->NavigationToMatch(SearchProvider::NavigationResult( 2342 *provider_.get(), GURL(cases[i].url), base::string16(), false, 0, 2343 false, ASCIIToUTF16(cases[i].input), std::string()))); 2344 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion), 2345 match_prevent_inline.inline_autocompletion); 2346 EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit), 2347 match_prevent_inline.fill_into_edit); 2348 EXPECT_EQ(cases[i].allowed_to_be_default_match_in_prevent_inline_mode, 2349 match_prevent_inline.allowed_to_be_default_match); 2350 } 2351} 2352 2353// Verifies that "http://" is not trimmed for input that is a leading substring. 2354TEST_F(SearchProviderTest, NavigationInlineSchemeSubstring) { 2355 const base::string16 input(ASCIIToUTF16("ht")); 2356 const base::string16 url(ASCIIToUTF16("http://a.com")); 2357 const SearchProvider::NavigationResult result( 2358 *provider_.get(), GURL(url), base::string16(), false, 0, false, 2359 input, std::string()); 2360 2361 // Check the offset and strings when inline autocompletion is allowed. 2362 QueryForInput(input, false, false); 2363 AutocompleteMatch match_inline(provider_->NavigationToMatch(result)); 2364 EXPECT_EQ(url, match_inline.fill_into_edit); 2365 EXPECT_EQ(url.substr(2), match_inline.inline_autocompletion); 2366 EXPECT_TRUE(match_inline.allowed_to_be_default_match); 2367 EXPECT_EQ(url, match_inline.contents); 2368 2369 // Check the same strings when inline autocompletion is prevented. 2370 QueryForInput(input, true, false); 2371 AutocompleteMatch match_prevent(provider_->NavigationToMatch(result)); 2372 EXPECT_EQ(url, match_prevent.fill_into_edit); 2373 EXPECT_FALSE(match_prevent.allowed_to_be_default_match); 2374 EXPECT_EQ(url, match_prevent.contents); 2375} 2376 2377// Verifies that input "w" marks a more significant domain label than "www.". 2378TEST_F(SearchProviderTest, NavigationInlineDomainClassify) { 2379 QueryForInput(ASCIIToUTF16("w"), false, false); 2380 AutocompleteMatch match( 2381 provider_->NavigationToMatch(SearchProvider::NavigationResult( 2382 *provider_.get(), GURL("http://www.wow.com"), base::string16(), false, 2383 0, false, ASCIIToUTF16("w"), std::string()))); 2384 EXPECT_EQ(ASCIIToUTF16("ow.com"), match.inline_autocompletion); 2385 EXPECT_TRUE(match.allowed_to_be_default_match); 2386 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.fill_into_edit); 2387 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.contents); 2388 2389 // Ensure that the match for input "w" is marked on "wow" and not "www". 2390 ASSERT_EQ(3U, match.contents_class.size()); 2391 EXPECT_EQ(0U, match.contents_class[0].offset); 2392 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL, 2393 match.contents_class[0].style); 2394 EXPECT_EQ(4U, match.contents_class[1].offset); 2395 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL | 2396 AutocompleteMatch::ACMatchClassification::MATCH, 2397 match.contents_class[1].style); 2398 EXPECT_EQ(5U, match.contents_class[2].offset); 2399 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL, 2400 match.contents_class[2].style); 2401} 2402 2403#if !defined(OS_WIN) 2404// Verify entity suggestion parsing. 2405TEST_F(SearchProviderTest, ParseEntitySuggestion) { 2406 struct Match { 2407 std::string contents; 2408 std::string description; 2409 std::string query_params; 2410 std::string fill_into_edit; 2411 AutocompleteMatchType::Type type; 2412 }; 2413 const Match kEmptyMatch = { 2414 kNotApplicable, kNotApplicable, kNotApplicable, kNotApplicable, 2415 AutocompleteMatchType::NUM_TYPES}; 2416 2417 struct { 2418 const std::string input_text; 2419 const std::string response_json; 2420 const Match matches[5]; 2421 } cases[] = { 2422 // A query and an entity suggestion with different search terms. 2423 { "x", 2424 "[\"x\",[\"xy\", \"yy\"],[\"\",\"\"],[]," 2425 " {\"google:suggestdetail\":[{}," 2426 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}]," 2427 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]", 2428 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED }, 2429 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST }, 2430 { "xy", "A", "p=v", "yy", 2431 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY }, 2432 kEmptyMatch, 2433 kEmptyMatch 2434 }, 2435 }, 2436 // A query and an entity suggestion with same search terms. 2437 { "x", 2438 "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[]," 2439 " {\"google:suggestdetail\":[{}," 2440 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}]," 2441 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]", 2442 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED }, 2443 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST }, 2444 { "xy", "A", "p=v", "xy", 2445 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY }, 2446 kEmptyMatch, 2447 kEmptyMatch 2448 }, 2449 }, 2450 }; 2451 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { 2452 QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false); 2453 2454 // Set up a default fetcher with provided results. 2455 net::TestURLFetcher* fetcher = 2456 test_factory_.GetFetcherByID( 2457 SearchProvider::kDefaultProviderURLFetcherID); 2458 ASSERT_TRUE(fetcher); 2459 fetcher->set_response_code(200); 2460 fetcher->SetResponseString(cases[i].response_json); 2461 fetcher->delegate()->OnURLFetchComplete(fetcher); 2462 2463 RunTillProviderDone(); 2464 2465 const ACMatches& matches = provider_->matches(); 2466 ASSERT_FALSE(matches.empty()); 2467 2468 SCOPED_TRACE("for input with json = " + cases[i].response_json); 2469 2470 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches)); 2471 size_t j = 0; 2472 // Ensure that the returned matches equal the expectations. 2473 for (; j < matches.size(); ++j) { 2474 const Match& match = cases[i].matches[j]; 2475 SCOPED_TRACE(" and match index: " + base::IntToString(j)); 2476 EXPECT_EQ(match.contents, 2477 base::UTF16ToUTF8(matches[j].contents)); 2478 EXPECT_EQ(match.description, 2479 base::UTF16ToUTF8(matches[j].description)); 2480 EXPECT_EQ(match.query_params, 2481 matches[j].search_terms_args->suggest_query_params); 2482 EXPECT_EQ(match.fill_into_edit, 2483 base::UTF16ToUTF8(matches[j].fill_into_edit)); 2484 EXPECT_EQ(match.type, matches[j].type); 2485 } 2486 // Ensure that no expected matches are missing. 2487 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) { 2488 SCOPED_TRACE(" and match index: " + base::IntToString(j)); 2489 EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable); 2490 EXPECT_EQ(cases[i].matches[j].description, kNotApplicable); 2491 EXPECT_EQ(cases[i].matches[j].query_params, kNotApplicable); 2492 EXPECT_EQ(cases[i].matches[j].fill_into_edit, kNotApplicable); 2493 EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES); 2494 } 2495 } 2496} 2497#endif // !defined(OS_WIN) 2498 2499 2500// A basic test that verifies the prefetch metadata parsing logic. 2501TEST_F(SearchProviderTest, PrefetchMetadataParsing) { 2502 struct Match { 2503 std::string contents; 2504 bool allowed_to_be_prefetched; 2505 AutocompleteMatchType::Type type; 2506 bool from_keyword; 2507 }; 2508 const Match kEmptyMatch = { kNotApplicable, 2509 false, 2510 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 2511 false }; 2512 2513 struct { 2514 const std::string input_text; 2515 bool prefer_keyword_provider_results; 2516 const std::string default_provider_response_json; 2517 const std::string keyword_provider_response_json; 2518 const Match matches[5]; 2519 } cases[] = { 2520 // Default provider response does not have prefetch details. Ensure that the 2521 // suggestions are not marked as prefetch query. 2522 { "a", 2523 false, 2524 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]", 2525 std::string(), 2526 { { "a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false }, 2527 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST, false }, 2528 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST, false }, 2529 kEmptyMatch, 2530 kEmptyMatch 2531 }, 2532 }, 2533 // Ensure that default provider suggest response prefetch details are 2534 // parsed and recorded in AutocompleteMatch. 2535 { "ab", 2536 false, 2537 "[\"ab\",[\"abc\", \"http://b.com\", \"http://c.com\"],[],[]," 2538 "{\"google:clientdata\":{\"phi\": 0}," 2539 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"NAVIGATION\"]," 2540 "\"google:suggestrelevance\":[999, 12, 1]}]", 2541 std::string(), 2542 { { "ab", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false }, 2543 { "abc", true, AutocompleteMatchType::SEARCH_SUGGEST, false }, 2544 { "b.com", false, AutocompleteMatchType::NAVSUGGEST, false }, 2545 { "c.com", false, AutocompleteMatchType::NAVSUGGEST, false }, 2546 kEmptyMatch 2547 }, 2548 }, 2549 // Default provider suggest response has prefetch details. 2550 // SEARCH_WHAT_YOU_TYPE suggestion outranks SEARCH_SUGGEST suggestion for 2551 // the same query string. Ensure that the prefetch details from 2552 // SEARCH_SUGGEST match are set onto SEARCH_WHAT_YOU_TYPE match. 2553 { "ab", 2554 false, 2555 "[\"ab\",[\"ab\", \"http://ab.com\"],[],[]," 2556 "{\"google:clientdata\":{\"phi\": 0}," 2557 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"]," 2558 "\"google:suggestrelevance\":[99, 98]}]", 2559 std::string(), 2560 { {"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false }, 2561 {"ab.com", false, AutocompleteMatchType::NAVSUGGEST, false }, 2562 kEmptyMatch, 2563 kEmptyMatch, 2564 kEmptyMatch 2565 }, 2566 }, 2567 // Default provider response has prefetch details. We prefer keyword 2568 // provider results. Ensure that prefetch bit for a suggestion from the 2569 // default search provider does not get copied onto a higher-scoring match 2570 // for the same query string from the keyword provider. 2571 { "k a", 2572 true, 2573 "[\"k a\",[\"a\", \"ab\"],[],[], {\"google:clientdata\":{\"phi\": 0}," 2574 "\"google:suggesttype\":[\"QUERY\", \"QUERY\"]," 2575 "\"google:suggestrelevance\":[9, 12]}]", 2576 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]", 2577 { { "a", false, AutocompleteMatchType::SEARCH_OTHER_ENGINE, true}, 2578 { "k a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false }, 2579 { "ab", false, AutocompleteMatchType::SEARCH_SUGGEST, false }, 2580 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST, true }, 2581 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST, true } 2582 }, 2583 } 2584 }; 2585 2586 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { 2587 QueryForInput(ASCIIToUTF16(cases[i].input_text), false, 2588 cases[i].prefer_keyword_provider_results); 2589 2590 // Set up a default fetcher with provided results. 2591 net::TestURLFetcher* fetcher = 2592 test_factory_.GetFetcherByID( 2593 SearchProvider::kDefaultProviderURLFetcherID); 2594 ASSERT_TRUE(fetcher); 2595 fetcher->set_response_code(200); 2596 fetcher->SetResponseString(cases[i].default_provider_response_json); 2597 fetcher->delegate()->OnURLFetchComplete(fetcher); 2598 2599 if (cases[i].prefer_keyword_provider_results) { 2600 // Set up a keyword fetcher with provided results. 2601 net::TestURLFetcher* keyword_fetcher = 2602 test_factory_.GetFetcherByID( 2603 SearchProvider::kKeywordProviderURLFetcherID); 2604 ASSERT_TRUE(keyword_fetcher); 2605 keyword_fetcher->set_response_code(200); 2606 keyword_fetcher->SetResponseString( 2607 cases[i].keyword_provider_response_json); 2608 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher); 2609 keyword_fetcher = NULL; 2610 } 2611 2612 RunTillProviderDone(); 2613 2614 const std::string description = 2615 "for input with json =" + cases[i].default_provider_response_json; 2616 const ACMatches& matches = provider_->matches(); 2617 // The top match must inline and score as highly as calculated verbatim. 2618 ASSERT_FALSE(matches.empty()); 2619 EXPECT_GE(matches[0].relevance, 1300); 2620 2621 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches)); 2622 // Ensure that the returned matches equal the expectations. 2623 for (size_t j = 0; j < matches.size(); ++j) { 2624 SCOPED_TRACE(description); 2625 EXPECT_EQ(cases[i].matches[j].contents, 2626 base::UTF16ToUTF8(matches[j].contents)); 2627 EXPECT_EQ(cases[i].matches[j].allowed_to_be_prefetched, 2628 SearchProvider::ShouldPrefetch(matches[j])); 2629 EXPECT_EQ(cases[i].matches[j].type, matches[j].type); 2630 EXPECT_EQ(cases[i].matches[j].from_keyword, 2631 matches[j].keyword == ASCIIToUTF16("k")); 2632 } 2633 } 2634} 2635 2636TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_InvalidResponse) { 2637 ClearAllResults(); 2638 2639 std::string input_str("abc"); 2640 QueryForInput(ASCIIToUTF16(input_str), false, false); 2641 2642 // Set up a default fetcher with provided results. 2643 net::TestURLFetcher* fetcher = 2644 test_factory_.GetFetcherByID( 2645 SearchProvider::kDefaultProviderURLFetcherID); 2646 ASSERT_TRUE(fetcher); 2647 fetcher->set_response_code(200); 2648 fetcher->SetResponseString("this is a bad non-json response"); 2649 fetcher->delegate()->OnURLFetchComplete(fetcher); 2650 2651 RunTillProviderDone(); 2652 2653 const ACMatches& matches = provider_->matches(); 2654 2655 // Should have exactly one "search what you typed" match 2656 ASSERT_TRUE(matches.size() == 1); 2657 EXPECT_EQ(input_str, base::UTF16ToUTF8(matches[0].contents)); 2658 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 2659 matches[0].type); 2660} 2661 2662// A basic test that verifies that the XSSI guarded JSON response is parsed 2663// correctly. 2664TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_ValidResponses) { 2665 struct Match { 2666 std::string contents; 2667 AutocompleteMatchType::Type type; 2668 }; 2669 const Match kEmptyMatch = { 2670 kNotApplicable, AutocompleteMatchType::NUM_TYPES 2671 }; 2672 2673 struct { 2674 const std::string input_text; 2675 const std::string default_provider_response_json; 2676 const Match matches[4]; 2677 } cases[] = { 2678 // No XSSI guard. 2679 { "a", 2680 "[\"a\",[\"b\", \"c\"],[],[]," 2681 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"]," 2682 "\"google:suggestrelevance\":[1, 2]}]", 2683 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED }, 2684 { "c", AutocompleteMatchType::SEARCH_SUGGEST }, 2685 { "b", AutocompleteMatchType::SEARCH_SUGGEST }, 2686 kEmptyMatch, 2687 }, 2688 }, 2689 // Standard XSSI guard - )]}'\n. 2690 { "a", 2691 ")]}'\n[\"a\",[\"b\", \"c\"],[],[]," 2692 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"]," 2693 "\"google:suggestrelevance\":[1, 2]}]", 2694 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED }, 2695 { "c", AutocompleteMatchType::SEARCH_SUGGEST }, 2696 { "b", AutocompleteMatchType::SEARCH_SUGGEST }, 2697 kEmptyMatch, 2698 }, 2699 }, 2700 // Modified XSSI guard - contains "[". 2701 { "a", 2702 ")]}'\n[)\"[\"a\",[\"b\", \"c\"],[],[]," 2703 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"]," 2704 "\"google:suggestrelevance\":[1, 2]}]", 2705 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED }, 2706 { "c", AutocompleteMatchType::SEARCH_SUGGEST }, 2707 { "b", AutocompleteMatchType::SEARCH_SUGGEST }, 2708 kEmptyMatch, 2709 }, 2710 }, 2711 }; 2712 2713 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { 2714 ClearAllResults(); 2715 QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false); 2716 2717 // Set up a default fetcher with provided results. 2718 net::TestURLFetcher* fetcher = 2719 test_factory_.GetFetcherByID( 2720 SearchProvider::kDefaultProviderURLFetcherID); 2721 ASSERT_TRUE(fetcher); 2722 fetcher->set_response_code(200); 2723 fetcher->SetResponseString(cases[i].default_provider_response_json); 2724 fetcher->delegate()->OnURLFetchComplete(fetcher); 2725 2726 RunTillProviderDone(); 2727 2728 const ACMatches& matches = provider_->matches(); 2729 // The top match must inline and score as highly as calculated verbatim. 2730 ASSERT_FALSE(matches.empty()); 2731 EXPECT_GE(matches[0].relevance, 1300); 2732 2733 SCOPED_TRACE("for case: " + base::IntToString(i)); 2734 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches)); 2735 size_t j = 0; 2736 // Ensure that the returned matches equal the expectations. 2737 for (; j < matches.size(); ++j) { 2738 SCOPED_TRACE("and match: " + base::IntToString(j)); 2739 EXPECT_EQ(cases[i].matches[j].contents, 2740 base::UTF16ToUTF8(matches[j].contents)); 2741 EXPECT_EQ(cases[i].matches[j].type, matches[j].type); 2742 } 2743 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) { 2744 SCOPED_TRACE("and match: " + base::IntToString(j)); 2745 EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable); 2746 EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES); 2747 } 2748 } 2749} 2750 2751// Test that deletion url gets set on an AutocompleteMatch when available for a 2752// personalized query. 2753TEST_F(SearchProviderTest, ParseDeletionUrl) { 2754 struct Match { 2755 std::string contents; 2756 std::string deletion_url; 2757 AutocompleteMatchType::Type type; 2758 }; 2759 2760 const Match kEmptyMatch = { 2761 kNotApplicable, "", AutocompleteMatchType::NUM_TYPES 2762 }; 2763 2764 const char url[] = "https://www.google.com/complete/deleteitems" 2765 "?delq=ab&client=chrome&deltok=xsrf123"; 2766 2767 struct { 2768 const std::string input_text; 2769 const std::string response_json; 2770 const Match matches[4]; 2771 } cases[] = { 2772 // A deletion URL on a personalized query should be reflected in the 2773 // resulting AutocompleteMatch. 2774 { "a", 2775 "[\"a\",[\"ab\", \"ac\"],[],[]," 2776 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\"]," 2777 "\"google:suggestrelevance\":[1, 2]," 2778 "\"google:suggestdetail\":[{\"du\":" 2779 "\"https://www.google.com/complete/deleteitems?delq=ab&client=chrome" 2780 "&deltok=xsrf123\"}, {}]}]", 2781 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED }, 2782 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST }, 2783 { "ab", url, AutocompleteMatchType::SEARCH_SUGGEST }, 2784 kEmptyMatch, 2785 }, 2786 }, 2787 // Personalized queries without deletion URLs shouldn't cause errors. 2788 { "a", 2789 "[\"a\",[\"ab\", \"ac\"],[],[]," 2790 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\"]," 2791 "\"google:suggestrelevance\":[1, 2]," 2792 "\"google:suggestdetail\":[{}, {}]}]", 2793 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED }, 2794 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST }, 2795 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST }, 2796 kEmptyMatch, 2797 }, 2798 }, 2799 }; 2800 2801 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { 2802 QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false); 2803 2804 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID( 2805 SearchProvider::kDefaultProviderURLFetcherID); 2806 ASSERT_TRUE(fetcher); 2807 fetcher->set_response_code(200); 2808 fetcher->SetResponseString(cases[i].response_json); 2809 fetcher->delegate()->OnURLFetchComplete(fetcher); 2810 2811 RunTillProviderDone(); 2812 2813 const ACMatches& matches = provider_->matches(); 2814 ASSERT_FALSE(matches.empty()); 2815 2816 SCOPED_TRACE("for input with json = " + cases[i].response_json); 2817 2818 for (size_t j = 0; j < matches.size(); ++j) { 2819 const Match& match = cases[i].matches[j]; 2820 SCOPED_TRACE(" and match index: " + base::IntToString(j)); 2821 EXPECT_EQ(match.contents, base::UTF16ToUTF8(matches[j].contents)); 2822 EXPECT_EQ(match.deletion_url, matches[j].GetAdditionalInfo( 2823 "deletion_url")); 2824 } 2825 } 2826} 2827 2828TEST_F(SearchProviderTest, ReflectsBookmarkBarState) { 2829 profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, false); 2830 base::string16 term = term1_.substr(0, term1_.length() - 1); 2831 QueryForInput(term, true, false); 2832 ASSERT_FALSE(provider_->matches().empty()); 2833 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 2834 provider_->matches()[0].type); 2835 ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL); 2836 EXPECT_FALSE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned); 2837 2838 profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, true); 2839 term = term1_.substr(0, term1_.length() - 1); 2840 QueryForInput(term, true, false); 2841 ASSERT_FALSE(provider_->matches().empty()); 2842 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 2843 provider_->matches()[0].type); 2844 ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL); 2845 EXPECT_TRUE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned); 2846} 2847 2848TEST_F(SearchProviderTest, CanSendURL) { 2849 TemplateURLData template_url_data; 2850 template_url_data.short_name = ASCIIToUTF16("t"); 2851 template_url_data.SetURL("http://www.google.com/{searchTerms}"); 2852 template_url_data.suggestions_url = "http://www.google.com/{searchTerms}"; 2853 template_url_data.instant_url = "http://does/not/exist?strk=1"; 2854 template_url_data.search_terms_replacement_key = "strk"; 2855 template_url_data.id = SEARCH_ENGINE_GOOGLE; 2856 TemplateURL google_template_url(&profile_, template_url_data); 2857 2858 // Create field trial. 2859 base::FieldTrial* field_trial = base::FieldTrialList::CreateFieldTrial( 2860 "AutocompleteDynamicTrial_2", "EnableZeroSuggest"); 2861 field_trial->group(); 2862 2863 // Not signed in. 2864 EXPECT_FALSE(SearchProvider::CanSendURL( 2865 GURL("http://www.google.com/search"), 2866 GURL("https://www.google.com/complete/search"), &google_template_url, 2867 AutocompleteInput::OTHER, &profile_)); 2868 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(&profile_); 2869 signin->SetAuthenticatedUsername("test"); 2870 2871 // All conditions should be met. 2872 EXPECT_TRUE(SearchProvider::CanSendURL( 2873 GURL("http://www.google.com/search"), 2874 GURL("https://www.google.com/complete/search"), &google_template_url, 2875 AutocompleteInput::OTHER, &profile_)); 2876 2877 // Not in field trial. 2878 ResetFieldTrialList(); 2879 EXPECT_FALSE(SearchProvider::CanSendURL( 2880 GURL("http://www.google.com/search"), 2881 GURL("https://www.google.com/complete/search"), &google_template_url, 2882 AutocompleteInput::OTHER, &profile_)); 2883 field_trial = base::FieldTrialList::CreateFieldTrial( 2884 "AutocompleteDynamicTrial_2", "EnableZeroSuggest"); 2885 field_trial->group(); 2886 2887 // Invalid page URL. 2888 EXPECT_FALSE(SearchProvider::CanSendURL( 2889 GURL("badpageurl"), 2890 GURL("https://www.google.com/complete/search"), &google_template_url, 2891 AutocompleteInput::OTHER, &profile_)); 2892 2893 // Invalid page classification. 2894 EXPECT_FALSE(SearchProvider::CanSendURL( 2895 GURL("http://www.google.com/search"), 2896 GURL("https://www.google.com/complete/search"), &google_template_url, 2897 AutocompleteInput::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS, 2898 &profile_)); 2899 2900 // Invalid page classification. 2901 EXPECT_FALSE(SearchProvider::CanSendURL( 2902 GURL("http://www.google.com/search"), 2903 GURL("https://www.google.com/complete/search"), &google_template_url, 2904 AutocompleteInput::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS, 2905 &profile_)); 2906 2907 // HTTPS page URL on same domain as provider. 2908 EXPECT_TRUE(SearchProvider::CanSendURL( 2909 GURL("https://www.google.com/search"), 2910 GURL("https://www.google.com/complete/search"), 2911 &google_template_url, AutocompleteInput::OTHER, &profile_)); 2912 2913 // Non-HTTP[S] page URL on same domain as provider. 2914 EXPECT_FALSE(SearchProvider::CanSendURL( 2915 GURL("ftp://www.google.com/search"), 2916 GURL("https://www.google.com/complete/search"), &google_template_url, 2917 AutocompleteInput::OTHER, &profile_)); 2918 2919 // Non-HTTP page URL on different domain. 2920 EXPECT_FALSE(SearchProvider::CanSendURL( 2921 GURL("https://www.notgoogle.com/search"), 2922 GURL("https://www.google.com/complete/search"), &google_template_url, 2923 AutocompleteInput::OTHER, &profile_)); 2924 2925 // Non-HTTPS provider. 2926 EXPECT_FALSE(SearchProvider::CanSendURL( 2927 GURL("http://www.google.com/search"), 2928 GURL("http://www.google.com/complete/search"), &google_template_url, 2929 AutocompleteInput::OTHER, &profile_)); 2930 2931 // Suggest disabled. 2932 profile_.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false); 2933 EXPECT_FALSE(SearchProvider::CanSendURL( 2934 GURL("http://www.google.com/search"), 2935 GURL("https://www.google.com/complete/search"), &google_template_url, 2936 AutocompleteInput::OTHER, &profile_)); 2937 profile_.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true); 2938 2939 // Incognito. 2940 EXPECT_FALSE(SearchProvider::CanSendURL( 2941 GURL("http://www.google.com/search"), 2942 GURL("https://www.google.com/complete/search"), &google_template_url, 2943 AutocompleteInput::OTHER, profile_.GetOffTheRecordProfile())); 2944 2945 // Tab sync not enabled. 2946 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncKeepEverythingSynced, 2947 false); 2948 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs, false); 2949 EXPECT_FALSE(SearchProvider::CanSendURL( 2950 GURL("http://www.google.com/search"), 2951 GURL("https://www.google.com/complete/search"), &google_template_url, 2952 AutocompleteInput::OTHER, &profile_)); 2953 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs, true); 2954 2955 // Tab sync is encrypted. 2956 ProfileSyncService* service = 2957 ProfileSyncServiceFactory::GetInstance()->GetForProfile(&profile_); 2958 syncer::ModelTypeSet encrypted_types = service->GetEncryptedDataTypes(); 2959 encrypted_types.Put(syncer::SESSIONS); 2960 service->OnEncryptedTypesChanged(encrypted_types, false); 2961 EXPECT_FALSE(SearchProvider::CanSendURL( 2962 GURL("http://www.google.com/search"), 2963 GURL("https://www.google.com/complete/search"), &google_template_url, 2964 AutocompleteInput::OTHER, &profile_)); 2965 encrypted_types.Remove(syncer::SESSIONS); 2966 service->OnEncryptedTypesChanged(encrypted_types, false); 2967 2968 // Check that there were no side effects from previous tests. 2969 EXPECT_TRUE(SearchProvider::CanSendURL( 2970 GURL("http://www.google.com/search"), 2971 GURL("https://www.google.com/complete/search"), &google_template_url, 2972 AutocompleteInput::OTHER, &profile_)); 2973} 2974 2975TEST_F(SearchProviderTest, TestDeleteMatch) { 2976 AutocompleteMatch match(provider_, 0, true, 2977 AutocompleteMatchType::SEARCH_SUGGEST); 2978 match.RecordAdditionalInfo( 2979 SearchProvider::kDeletionUrlKey, 2980 "https://www.google.com/complete/deleteitem?q=foo"); 2981 2982 // Test a successful deletion request. 2983 provider_->matches_.push_back(match); 2984 provider_->DeleteMatch(match); 2985 EXPECT_FALSE(provider_->deletion_handlers_.empty()); 2986 EXPECT_TRUE(provider_->matches_.empty()); 2987 // Set up a default fetcher with provided results. 2988 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID( 2989 SearchProvider::kDeletionURLFetcherID); 2990 ASSERT_TRUE(fetcher); 2991 fetcher->set_response_code(200); 2992 fetcher->delegate()->OnURLFetchComplete(fetcher); 2993 EXPECT_TRUE(provider_->deletion_handlers_.empty()); 2994 EXPECT_TRUE(provider_->is_success()); 2995 2996 // Test a failing deletion request. 2997 provider_->matches_.push_back(match); 2998 provider_->DeleteMatch(match); 2999 EXPECT_FALSE(provider_->deletion_handlers_.empty()); 3000 // Set up a default fetcher with provided results. 3001 fetcher = test_factory_.GetFetcherByID( 3002 SearchProvider::kDeletionURLFetcherID); 3003 ASSERT_TRUE(fetcher); 3004 fetcher->set_response_code(500); 3005 fetcher->delegate()->OnURLFetchComplete(fetcher); 3006 EXPECT_TRUE(provider_->deletion_handlers_.empty()); 3007 EXPECT_FALSE(provider_->is_success()); 3008} 3009 3010TEST_F(SearchProviderTest, TestDeleteHistoryQueryMatch) { 3011 GURL term_url( 3012 AddSearchToHistory(default_t_url_, ASCIIToUTF16("flash games"), 1)); 3013 profile_.BlockUntilHistoryProcessesPendingRequests(); 3014 3015 AutocompleteMatch games; 3016 QueryForInput(ASCIIToUTF16("fla"), false, false); 3017 profile_.BlockUntilHistoryProcessesPendingRequests(); 3018 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery()); 3019 ASSERT_TRUE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games)); 3020 3021 size_t matches_before = provider_->matches().size(); 3022 provider_->DeleteMatch(games); 3023 EXPECT_EQ(matches_before - 1, provider_->matches().size()); 3024 3025 // Process history deletions. 3026 profile_.BlockUntilHistoryProcessesPendingRequests(); 3027 3028 // Check that the match is gone. 3029 QueryForInput(ASCIIToUTF16("fla"), false, false); 3030 profile_.BlockUntilHistoryProcessesPendingRequests(); 3031 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery()); 3032 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games)); 3033} 3034 3035// Verifies that duplicates are preserved in AddMatchToMap(). 3036TEST_F(SearchProviderTest, CheckDuplicateMatchesSaved) { 3037 AddSearchToHistory(default_t_url_, ASCIIToUTF16("a"), 1); 3038 AddSearchToHistory(default_t_url_, ASCIIToUTF16("alpha"), 1); 3039 AddSearchToHistory(default_t_url_, ASCIIToUTF16("avid"), 1); 3040 3041 profile_.BlockUntilHistoryProcessesPendingRequests(); 3042 QueryForInput(ASCIIToUTF16("a"), false, false); 3043 3044 // Make sure the default provider's suggest service was queried. 3045 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID( 3046 SearchProvider::kDefaultProviderURLFetcherID); 3047 ASSERT_TRUE(fetcher); 3048 3049 // Tell the SearchProvider the suggest query is done. 3050 fetcher->set_response_code(200); 3051 fetcher->SetResponseString( 3052 "[\"a\",[\"a\", \"alpha\", \"avid\", \"apricot\"],[],[]," 3053 "{\"google:suggestrelevance\":[1450, 1200, 1150, 1100]," 3054 "\"google:verbatimrelevance\":1350}]"); 3055 fetcher->delegate()->OnURLFetchComplete(fetcher); 3056 fetcher = NULL; 3057 3058 // Run till the history results complete. 3059 RunTillProviderDone(); 3060 3061 AutocompleteMatch verbatim, match_alpha, match_apricot, match_avid; 3062 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim)); 3063 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("alpha"), &match_alpha)); 3064 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("apricot"), &match_apricot)); 3065 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("avid"), &match_avid)); 3066 3067 // Verbatim match duplicates are added such that each one has a higher 3068 // relevance than the previous one. 3069 EXPECT_EQ(2U, verbatim.duplicate_matches.size()); 3070 3071 // Other match duplicates are added in descending relevance order. 3072 EXPECT_EQ(1U, match_alpha.duplicate_matches.size()); 3073 EXPECT_EQ(1U, match_avid.duplicate_matches.size()); 3074 3075 EXPECT_EQ(0U, match_apricot.duplicate_matches.size()); 3076} 3077