Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / autocomplete / search_provider_unittest.cc
blob68cb6f0347d0ccbfdbcd5d5dabb2d867775714b3
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.
5 #include "components/omnibox/search_provider.h"
7 #include <string>
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/chrome_autocomplete_provider_client.h"
22 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
23 #include "chrome/browser/autocomplete/history_url_provider.h"
24 #include "chrome/browser/history/history_service_factory.h"
25 #include "chrome/browser/search_engines/template_url_service_factory.h"
26 #include "chrome/browser/signin/signin_manager_factory.h"
27 #include "chrome/browser/sync/profile_sync_service.h"
28 #include "chrome/browser/sync/profile_sync_service_factory.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/pref_names.h"
31 #include "chrome/test/base/testing_browser_process.h"
32 #include "chrome/test/base/testing_profile.h"
33 #include "components/google/core/browser/google_switches.h"
34 #include "components/history/core/browser/history_service.h"
35 #include "components/metrics/proto/omnibox_event.pb.h"
36 #include "components/omnibox/autocomplete_input.h"
37 #include "components/omnibox/autocomplete_match.h"
38 #include "components/omnibox/autocomplete_provider.h"
39 #include "components/omnibox/autocomplete_provider_listener.h"
40 #include "components/omnibox/omnibox_field_trial.h"
41 #include "components/omnibox/omnibox_switches.h"
42 #include "components/omnibox/suggestion_answer.h"
43 #include "components/search_engines/search_engine_type.h"
44 #include "components/search_engines/search_engines_switches.h"
45 #include "components/search_engines/search_terms_data.h"
46 #include "components/search_engines/template_url.h"
47 #include "components/search_engines/template_url_service.h"
48 #include "components/signin/core/browser/signin_manager.h"
49 #include "components/sync_driver/pref_names.h"
50 #include "components/variations/entropy_provider.h"
51 #include "components/variations/variations_associated_data.h"
52 #include "content/public/test/test_browser_thread_bundle.h"
53 #include "net/url_request/test_url_fetcher_factory.h"
54 #include "net/url_request/url_request_status.h"
55 #include "testing/gtest/include/gtest/gtest.h"
57 using base::ASCIIToUTF16;
59 namespace {
61 // Returns the first match in |matches| with |allowed_to_be_default_match|
62 // set to true.
63 ACMatches::const_iterator FindDefaultMatch(const ACMatches& matches) {
64 ACMatches::const_iterator it = matches.begin();
65 while ((it != matches.end()) && !it->allowed_to_be_default_match)
66 ++it;
67 return it;
70 class SuggestionDeletionHandler;
71 class SearchProviderForTest : public SearchProvider {
72 public:
73 SearchProviderForTest(AutocompleteProviderListener* listener,
74 TemplateURLService* template_url_service,
75 Profile* profile);
76 bool is_success() { return is_success_; }
78 protected:
79 ~SearchProviderForTest() override;
81 private:
82 void RecordDeletionResult(bool success) override;
83 bool is_success_;
84 DISALLOW_COPY_AND_ASSIGN(SearchProviderForTest);
87 SearchProviderForTest::SearchProviderForTest(
88 AutocompleteProviderListener* listener,
89 TemplateURLService* template_url_service,
90 Profile* profile)
91 : SearchProvider(listener, template_url_service,
92 scoped_ptr<AutocompleteProviderClient>(
93 new ChromeAutocompleteProviderClient(profile))),
94 is_success_(false) {
97 SearchProviderForTest::~SearchProviderForTest() {
100 void SearchProviderForTest::RecordDeletionResult(bool success) {
101 is_success_ = success;
104 } // namespace
106 // SearchProviderTest ---------------------------------------------------------
108 // The following environment is configured for these tests:
109 // . The TemplateURL default_t_url_ is set as the default provider.
110 // . The TemplateURL keyword_t_url_ is added to the TemplateURLService. This
111 // TemplateURL has a valid suggest and search URL.
112 // . The URL created by using the search term term1_ with default_t_url_ is
113 // added to history.
114 // . The URL created by using the search term keyword_term_ with keyword_t_url_
115 // is added to history.
116 // . test_factory_ is set as the URLFetcherFactory.
117 class SearchProviderTest : public testing::Test,
118 public AutocompleteProviderListener {
119 public:
120 struct ResultInfo {
121 ResultInfo() : result_type(AutocompleteMatchType::NUM_TYPES),
122 allowed_to_be_default_match(false) {
124 ResultInfo(GURL gurl,
125 AutocompleteMatch::Type result_type,
126 bool allowed_to_be_default_match,
127 base::string16 fill_into_edit)
128 : gurl(gurl),
129 result_type(result_type),
130 allowed_to_be_default_match(allowed_to_be_default_match),
131 fill_into_edit(fill_into_edit) {
134 const GURL gurl;
135 const AutocompleteMatch::Type result_type;
136 const bool allowed_to_be_default_match;
137 const base::string16 fill_into_edit;
140 struct TestData {
141 const base::string16 input;
142 const size_t num_results;
143 const ResultInfo output[3];
146 struct ExpectedMatch {
147 std::string contents;
148 bool allowed_to_be_default_match;
151 SearchProviderTest()
152 : default_t_url_(NULL),
153 term1_(ASCIIToUTF16("term1")),
154 keyword_t_url_(NULL),
155 keyword_term_(ASCIIToUTF16("keyword")),
156 run_loop_(NULL) {
157 ResetFieldTrialList();
160 // See description above class for what this registers.
161 void SetUp() override;
162 void TearDown() override;
164 void RunTest(TestData* cases, int num_cases, bool prefer_keyword);
166 protected:
167 // Needed for AutocompleteFieldTrial::ActivateStaticTrials();
168 scoped_ptr<base::FieldTrialList> field_trial_list_;
170 // Default values used for testing.
171 static const std::string kNotApplicable;
172 static const ExpectedMatch kEmptyExpectedMatch;
174 // Adds a search for |term|, using the engine |t_url| to the history, and
175 // returns the URL for that search.
176 GURL AddSearchToHistory(TemplateURL* t_url, base::string16 term, int visit_count);
178 // Looks for a match in |provider_| with |contents| equal to |contents|.
179 // Sets |match| to it if found. Returns whether |match| was set.
180 bool FindMatchWithContents(const base::string16& contents,
181 AutocompleteMatch* match);
183 // Looks for a match in |provider_| with destination |url|. Sets |match| to
184 // it if found. Returns whether |match| was set.
185 bool FindMatchWithDestination(const GURL& url, AutocompleteMatch* match);
187 // AutocompleteProviderListener:
188 // If we're waiting for the provider to finish, this exits the message loop.
189 void OnProviderUpdate(bool updated_matches) override;
191 // Runs a nested message loop until provider_ is done. The message loop is
192 // exited by way of OnProviderUpdate.
193 void RunTillProviderDone();
195 // Invokes Start on provider_, then runs all pending tasks.
196 void QueryForInput(const base::string16& text,
197 bool prevent_inline_autocomplete,
198 bool prefer_keyword);
200 // Calls QueryForInput(), finishes any suggest query, then if |wyt_match| is
201 // non-NULL, sets it to the "what you typed" entry for |text|.
202 void QueryForInputAndSetWYTMatch(const base::string16& text,
203 AutocompleteMatch* wyt_match);
205 // Calls QueryForInput(), sets the JSON responses for the default and keyword
206 // fetchers, and waits until the responses have been returned and the matches
207 // returned. Use empty responses for each fetcher that shouldn't be set up /
208 // configured.
209 void QueryForInputAndWaitForFetcherResponses(
210 const base::string16& text,
211 const bool prefer_keyword,
212 const std::string& default_fetcher_response,
213 const std::string& keyword_fetcher_response);
215 // Notifies the URLFetcher for the suggest query corresponding to the default
216 // search provider that it's done.
217 // Be sure and wrap calls to this in ASSERT_NO_FATAL_FAILURE.
218 void FinishDefaultSuggestQuery();
220 // Runs SearchProvider on |input|, for which the suggest server replies
221 // with |json|, and expects that the resulting matches' contents equals
222 // that in |matches|. An empty entry in |matches| means no match should
223 // be returned in that position. Reports any errors with a message that
224 // includes |error_description|.
225 void ForcedQueryTestHelper(const std::string& input,
226 const std::string& json,
227 const std::string matches[3],
228 const std::string& error_description);
230 // Verifies that |matches| and |expected_matches| agree on the first
231 // |num_expected_matches|, displaying an error message that includes
232 // |description| for any disagreement.
233 void CheckMatches(const std::string& description,
234 const size_t num_expected_matches,
235 const ExpectedMatch expected_matches[],
236 const ACMatches& matches);
238 void ResetFieldTrialList();
240 // Enable or disable the specified Omnibox field trial rule.
241 base::FieldTrial* CreateFieldTrial(const char* field_trial_rule,
242 bool enabled);
244 void ClearAllResults();
246 // See description above class for details of these fields.
247 TemplateURL* default_t_url_;
248 const base::string16 term1_;
249 GURL term1_url_;
250 TemplateURL* keyword_t_url_;
251 const base::string16 keyword_term_;
252 GURL keyword_url_;
254 content::TestBrowserThreadBundle thread_bundle_;
256 // URLFetcherFactory implementation registered.
257 net::TestURLFetcherFactory test_factory_;
259 // Profile we use.
260 TestingProfile profile_;
262 // The provider.
263 scoped_refptr<SearchProviderForTest> provider_;
265 // If non-NULL, OnProviderUpdate quits the current |run_loop_|.
266 base::RunLoop* run_loop_;
268 DISALLOW_COPY_AND_ASSIGN(SearchProviderTest);
271 // static
272 const std::string SearchProviderTest::kNotApplicable = "Not Applicable";
273 const SearchProviderTest::ExpectedMatch
274 SearchProviderTest::kEmptyExpectedMatch = { kNotApplicable, false };
276 void SearchProviderTest::SetUp() {
277 // Make sure that fetchers are automatically ungregistered upon destruction.
278 test_factory_.set_remove_fetcher_on_delete(true);
280 // We need both the history service and template url model loaded.
281 ASSERT_TRUE(profile_.CreateHistoryService(true, false));
282 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
283 &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
285 TemplateURLService* turl_model =
286 TemplateURLServiceFactory::GetForProfile(&profile_);
288 turl_model->Load();
290 // Reset the default TemplateURL.
291 TemplateURLData data;
292 data.short_name = ASCIIToUTF16("t");
293 data.SetURL("http://defaultturl/{searchTerms}");
294 data.suggestions_url = "http://defaultturl2/{searchTerms}";
295 data.instant_url = "http://does/not/exist?strk=1";
296 data.search_terms_replacement_key = "strk";
297 default_t_url_ = new TemplateURL(data);
298 turl_model->Add(default_t_url_);
299 turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
300 TemplateURLID default_provider_id = default_t_url_->id();
301 ASSERT_NE(0, default_provider_id);
303 // Add url1, with search term term1_.
304 term1_url_ = AddSearchToHistory(default_t_url_, term1_, 1);
306 // Create another TemplateURL.
307 data.short_name = ASCIIToUTF16("k");
308 data.SetKeyword(ASCIIToUTF16("k"));
309 data.SetURL("http://keyword/{searchTerms}");
310 data.suggestions_url = "http://suggest_keyword/{searchTerms}";
311 keyword_t_url_ = new TemplateURL(data);
312 turl_model->Add(keyword_t_url_);
313 ASSERT_NE(0, keyword_t_url_->id());
315 // Add a page and search term for keyword_t_url_.
316 keyword_url_ = AddSearchToHistory(keyword_t_url_, keyword_term_, 1);
318 // Keywords are updated by the InMemoryHistoryBackend only after the message
319 // has been processed on the history thread. Block until history processes all
320 // requests to ensure the InMemoryDatabase is the state we expect it.
321 profile_.BlockUntilHistoryProcessesPendingRequests();
323 AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
324 &profile_, &AutocompleteClassifierFactory::BuildInstanceFor);
326 provider_ = new SearchProviderForTest(this, turl_model, &profile_);
327 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs = 0;
330 void SearchProviderTest::TearDown() {
331 base::RunLoop().RunUntilIdle();
333 // Shutdown the provider before the profile.
334 provider_ = NULL;
337 void SearchProviderTest::RunTest(TestData* cases,
338 int num_cases,
339 bool prefer_keyword) {
340 ACMatches matches;
341 for (int i = 0; i < num_cases; ++i) {
342 AutocompleteInput input(cases[i].input, base::string16::npos,
343 std::string(), GURL(),
344 metrics::OmniboxEventProto::INVALID_SPEC, false,
345 prefer_keyword, true, true,
346 ChromeAutocompleteSchemeClassifier(&profile_));
347 provider_->Start(input, false, false);
348 matches = provider_->matches();
349 SCOPED_TRACE(
350 ASCIIToUTF16("Input was: ") +
351 cases[i].input +
352 ASCIIToUTF16("; prefer_keyword was: ") +
353 (prefer_keyword ? ASCIIToUTF16("true") : ASCIIToUTF16("false")));
354 EXPECT_EQ(cases[i].num_results, matches.size());
355 if (matches.size() == cases[i].num_results) {
356 for (size_t j = 0; j < cases[i].num_results; ++j) {
357 EXPECT_EQ(cases[i].output[j].gurl, matches[j].destination_url);
358 EXPECT_EQ(cases[i].output[j].result_type, matches[j].type);
359 EXPECT_EQ(cases[i].output[j].fill_into_edit,
360 matches[j].fill_into_edit);
361 EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match,
362 matches[j].allowed_to_be_default_match);
368 void SearchProviderTest::OnProviderUpdate(bool updated_matches) {
369 if (run_loop_ && provider_->done()) {
370 run_loop_->Quit();
371 run_loop_ = NULL;
375 void SearchProviderTest::RunTillProviderDone() {
376 if (provider_->done())
377 return;
379 base::RunLoop run_loop;
380 run_loop_ = &run_loop;
381 run_loop.Run();
384 void SearchProviderTest::QueryForInput(const base::string16& text,
385 bool prevent_inline_autocomplete,
386 bool prefer_keyword) {
387 // Start a query.
388 AutocompleteInput input(text, base::string16::npos, std::string(), GURL(),
389 metrics::OmniboxEventProto::INVALID_SPEC,
390 prevent_inline_autocomplete, prefer_keyword, true,
391 true, ChromeAutocompleteSchemeClassifier(&profile_));
392 provider_->Start(input, false, false);
394 // RunUntilIdle so that the task scheduled by SearchProvider to create the
395 // URLFetchers runs.
396 base::RunLoop().RunUntilIdle();
399 void SearchProviderTest::QueryForInputAndSetWYTMatch(
400 const base::string16& text,
401 AutocompleteMatch* wyt_match) {
402 QueryForInput(text, false, false);
403 profile_.BlockUntilHistoryProcessesPendingRequests();
404 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
405 if (!wyt_match)
406 return;
407 ASSERT_GE(provider_->matches().size(), 1u);
408 EXPECT_TRUE(FindMatchWithDestination(
409 GURL(default_t_url_->url_ref().ReplaceSearchTerms(
410 TemplateURLRef::SearchTermsArgs(base::CollapseWhitespace(
411 text, false)),
412 TemplateURLServiceFactory::GetForProfile(
413 &profile_)->search_terms_data())),
414 wyt_match));
417 void SearchProviderTest::QueryForInputAndWaitForFetcherResponses(
418 const base::string16& text,
419 const bool prefer_keyword,
420 const std::string& default_fetcher_response,
421 const std::string& keyword_fetcher_response) {
422 QueryForInput(text, false, prefer_keyword);
423 if (!default_fetcher_response.empty()) {
424 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
425 SearchProvider::kDefaultProviderURLFetcherID);
426 ASSERT_TRUE(fetcher);
427 fetcher->set_response_code(200);
428 fetcher->SetResponseString(default_fetcher_response);
429 fetcher->delegate()->OnURLFetchComplete(fetcher);
431 if (!keyword_fetcher_response.empty()) {
432 net::TestURLFetcher* keyword_fetcher = test_factory_.GetFetcherByID(
433 SearchProvider::kKeywordProviderURLFetcherID);
434 ASSERT_TRUE(keyword_fetcher);
435 keyword_fetcher->set_response_code(200);
436 keyword_fetcher->SetResponseString(keyword_fetcher_response);
437 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
439 RunTillProviderDone();
442 GURL SearchProviderTest::AddSearchToHistory(TemplateURL* t_url,
443 base::string16 term,
444 int visit_count) {
445 history::HistoryService* history = HistoryServiceFactory::GetForProfile(
446 &profile_, ServiceAccessType::EXPLICIT_ACCESS);
447 GURL search(t_url->url_ref().ReplaceSearchTerms(
448 TemplateURLRef::SearchTermsArgs(term),
449 TemplateURLServiceFactory::GetForProfile(
450 &profile_)->search_terms_data()));
451 static base::Time last_added_time;
452 last_added_time = std::max(base::Time::Now(),
453 last_added_time + base::TimeDelta::FromMicroseconds(1));
454 history->AddPageWithDetails(search, base::string16(), visit_count, visit_count,
455 last_added_time, false, history::SOURCE_BROWSED);
456 history->SetKeywordSearchTermsForURL(search, t_url->id(), term);
457 return search;
460 bool SearchProviderTest::FindMatchWithContents(const base::string16& contents,
461 AutocompleteMatch* match) {
462 for (ACMatches::const_iterator i = provider_->matches().begin();
463 i != provider_->matches().end(); ++i) {
464 if (i->contents == contents) {
465 *match = *i;
466 return true;
469 return false;
472 bool SearchProviderTest::FindMatchWithDestination(const GURL& url,
473 AutocompleteMatch* match) {
474 for (ACMatches::const_iterator i = provider_->matches().begin();
475 i != provider_->matches().end(); ++i) {
476 if (i->destination_url == url) {
477 *match = *i;
478 return true;
481 return false;
484 void SearchProviderTest::FinishDefaultSuggestQuery() {
485 net::TestURLFetcher* default_fetcher =
486 test_factory_.GetFetcherByID(
487 SearchProvider::kDefaultProviderURLFetcherID);
488 ASSERT_TRUE(default_fetcher);
490 // Tell the SearchProvider the default suggest query is done.
491 default_fetcher->set_response_code(200);
492 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
495 void SearchProviderTest::ForcedQueryTestHelper(
496 const std::string& input,
497 const std::string& json,
498 const std::string expected_matches[3],
499 const std::string& error_description) {
500 // Send the query twice in order to have a synchronous pass after the first
501 // response is received. This is necessary because SearchProvider doesn't
502 // allow an asynchronous response to change the default match.
503 for (size_t i = 0; i < 2; ++i) {
504 QueryForInputAndWaitForFetcherResponses(
505 ASCIIToUTF16(input), false, json, std::string());
508 const ACMatches& matches = provider_->matches();
509 ASSERT_LE(matches.size(), 3u);
510 size_t i = 0;
511 // Ensure that the returned matches equal the expectations.
512 for (; i < matches.size(); ++i) {
513 EXPECT_EQ(ASCIIToUTF16(expected_matches[i]), matches[i].contents) <<
514 error_description;
516 // Ensure that no expected matches are missing.
517 for (; i < 3u; ++i) {
518 EXPECT_EQ(std::string(), expected_matches[i]) <<
519 "Case #" << i << ": " << error_description;
523 void SearchProviderTest::CheckMatches(const std::string& description,
524 const size_t num_expected_matches,
525 const ExpectedMatch expected_matches[],
526 const ACMatches& matches) {
527 ASSERT_FALSE(matches.empty());
528 ASSERT_LE(matches.size(), num_expected_matches);
529 size_t i = 0;
530 SCOPED_TRACE(description);
531 // Ensure that the returned matches equal the expectations.
532 for (; i < matches.size(); ++i) {
533 SCOPED_TRACE(" Case # " + base::IntToString(i));
534 EXPECT_EQ(ASCIIToUTF16(expected_matches[i].contents), matches[i].contents);
535 EXPECT_EQ(expected_matches[i].allowed_to_be_default_match,
536 matches[i].allowed_to_be_default_match);
538 // Ensure that no expected matches are missing.
539 for (; i < num_expected_matches; ++i) {
540 SCOPED_TRACE(" Case # " + base::IntToString(i));
541 EXPECT_EQ(kNotApplicable, expected_matches[i].contents);
545 void SearchProviderTest::ResetFieldTrialList() {
546 // Destroy the existing FieldTrialList before creating a new one to avoid
547 // a DCHECK.
548 field_trial_list_.reset();
549 field_trial_list_.reset(new base::FieldTrialList(
550 new metrics::SHA1EntropyProvider("foo")));
551 variations::testing::ClearAllVariationParams();
552 base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
553 "AutocompleteDynamicTrial_0", "DefaultGroup");
554 trial->group();
556 base::FieldTrial* SearchProviderTest::CreateFieldTrial(
557 const char* field_trial_rule,
558 bool enabled) {
559 std::map<std::string, std::string> params;
560 params[std::string(field_trial_rule)] = enabled ?
561 "true" : "false";
562 variations::AssociateVariationParams(
563 OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params);
564 return base::FieldTrialList::CreateFieldTrial(
565 OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
568 void SearchProviderTest::ClearAllResults() {
569 provider_->ClearAllResults();
572 // Actual Tests ---------------------------------------------------------------
574 // Make sure we query history for the default provider and a URLFetcher is
575 // created for the default provider suggest results.
576 TEST_F(SearchProviderTest, QueryDefaultProvider) {
577 base::string16 term = term1_.substr(0, term1_.length() - 1);
578 QueryForInput(term, false, false);
580 // Make sure the default providers suggest service was queried.
581 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
582 SearchProvider::kDefaultProviderURLFetcherID);
583 ASSERT_TRUE(fetcher);
585 // And the URL matches what we expected.
586 GURL expected_url(default_t_url_->suggestions_url_ref().ReplaceSearchTerms(
587 TemplateURLRef::SearchTermsArgs(term),
588 TemplateURLServiceFactory::GetForProfile(
589 &profile_)->search_terms_data()));
590 ASSERT_TRUE(fetcher->GetOriginalURL() == expected_url);
592 // Tell the SearchProvider the suggest query is done.
593 fetcher->set_response_code(200);
594 fetcher->delegate()->OnURLFetchComplete(fetcher);
595 fetcher = NULL;
597 // Run till the history results complete.
598 RunTillProviderDone();
600 // The SearchProvider is done. Make sure it has a result for the history
601 // term term1.
602 AutocompleteMatch term1_match;
603 EXPECT_TRUE(FindMatchWithDestination(term1_url_, &term1_match));
604 // Term1 should not have a description, it's set later.
605 EXPECT_TRUE(term1_match.description.empty());
607 AutocompleteMatch wyt_match;
608 EXPECT_TRUE(FindMatchWithDestination(
609 GURL(default_t_url_->url_ref().ReplaceSearchTerms(
610 TemplateURLRef::SearchTermsArgs(term),
611 TemplateURLServiceFactory::GetForProfile(
612 &profile_)->search_terms_data())),
613 &wyt_match));
614 EXPECT_TRUE(wyt_match.description.empty());
616 // The match for term1 should be more relevant than the what you typed match.
617 EXPECT_GT(term1_match.relevance, wyt_match.relevance);
618 // This longer match should be inlineable.
619 EXPECT_TRUE(term1_match.allowed_to_be_default_match);
620 // The what you typed match should be too, of course.
621 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
624 // Make sure we get a query-what-you-typed result from the default search
625 // provider even if the default search provider's keyword is renamed in the
626 // middle of processing the query.
627 TEST_F(SearchProviderTest, HasQueryWhatYouTypedIfDefaultKeywordChanges) {
628 base::string16 query = ASCIIToUTF16("query");
629 QueryForInput(query, false, false);
631 // Make sure the default provider's suggest service was queried.
632 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
633 SearchProvider::kDefaultProviderURLFetcherID);
634 ASSERT_TRUE(fetcher);
636 // Look up the TemplateURL for the keyword and modify its keyword.
637 TemplateURLService* template_url_service =
638 TemplateURLServiceFactory::GetForProfile(&profile_);
639 TemplateURL* template_url =
640 template_url_service->GetTemplateURLForKeyword(default_t_url_->keyword());
641 EXPECT_TRUE(template_url);
642 template_url_service->ResetTemplateURL(
643 template_url, template_url->short_name(),
644 ASCIIToUTF16("new_keyword_asdf"), template_url->url());
646 // In resetting the default provider, the fetcher should've been canceled.
647 fetcher = test_factory_.GetFetcherByID(
648 SearchProvider::kDefaultProviderURLFetcherID);
649 EXPECT_TRUE(!fetcher);
650 RunTillProviderDone();
652 // Makes sure the query-what-you-typed match is there.
653 AutocompleteMatch wyt_match;
654 EXPECT_TRUE(FindMatchWithDestination(
655 GURL(default_t_url_->url_ref().ReplaceSearchTerms(
656 TemplateURLRef::SearchTermsArgs(query),
657 TemplateURLServiceFactory::GetForProfile(
658 &profile_)->search_terms_data())),
659 &wyt_match));
660 EXPECT_TRUE(wyt_match.description.empty());
661 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
664 TEST_F(SearchProviderTest, HonorPreventInlineAutocomplete) {
665 base::string16 term = term1_.substr(0, term1_.length() - 1);
666 QueryForInput(term, true, false);
668 ASSERT_FALSE(provider_->matches().empty());
669 ASSERT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
670 provider_->matches()[0].type);
671 EXPECT_TRUE(provider_->matches()[0].allowed_to_be_default_match);
674 // Issues a query that matches the registered keyword and makes sure history
675 // is queried as well as URLFetchers getting created.
676 TEST_F(SearchProviderTest, QueryKeywordProvider) {
677 base::string16 term = keyword_term_.substr(0, keyword_term_.length() - 1);
678 QueryForInput(keyword_t_url_->keyword() + ASCIIToUTF16(" ") + term,
679 false,
680 false);
682 // Make sure the default providers suggest service was queried.
683 net::TestURLFetcher* default_fetcher = test_factory_.GetFetcherByID(
684 SearchProvider::kDefaultProviderURLFetcherID);
685 ASSERT_TRUE(default_fetcher);
687 // Tell the SearchProvider the default suggest query is done.
688 default_fetcher->set_response_code(200);
689 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
690 default_fetcher = NULL;
692 // Make sure the keyword providers suggest service was queried.
693 net::TestURLFetcher* keyword_fetcher = test_factory_.GetFetcherByID(
694 SearchProvider::kKeywordProviderURLFetcherID);
695 ASSERT_TRUE(keyword_fetcher);
697 // And the URL matches what we expected.
698 GURL expected_url(keyword_t_url_->suggestions_url_ref().ReplaceSearchTerms(
699 TemplateURLRef::SearchTermsArgs(term),
700 TemplateURLServiceFactory::GetForProfile(
701 &profile_)->search_terms_data()));
702 ASSERT_TRUE(keyword_fetcher->GetOriginalURL() == expected_url);
704 // Tell the SearchProvider the keyword suggest query is done.
705 keyword_fetcher->set_response_code(200);
706 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
707 keyword_fetcher = NULL;
709 // Run till the history results complete.
710 RunTillProviderDone();
712 // The SearchProvider is done. Make sure it has a result for the history
713 // term keyword.
714 AutocompleteMatch match;
715 EXPECT_TRUE(FindMatchWithDestination(keyword_url_, &match));
717 // The match should have an associated keyword.
718 EXPECT_FALSE(match.keyword.empty());
720 // The fill into edit should contain the keyword.
721 EXPECT_EQ(keyword_t_url_->keyword() + base::char16(' ') + keyword_term_,
722 match.fill_into_edit);
725 TEST_F(SearchProviderTest, SendDataToSuggestAtAppropriateTimes) {
726 struct {
727 std::string input;
728 const bool expect_to_send_to_default_provider;
729 } cases[] = {
730 // None of the following input strings should be sent to the default
731 // suggest server because they may contain potentially private data.
732 { "username:password", false },
733 { "User:f", false },
734 { "http://username:password", false },
735 { "https://username:password", false },
736 { "username:password@hostname", false },
737 { "http://username:password@hostname/", false },
738 { "file://filename", false },
739 { "data://data", false },
740 { "unknownscheme:anything", false },
741 { "http://hostname/?query=q", false },
742 { "http://hostname/path#ref", false },
743 { "http://hostname/path #ref", false },
744 { "https://hostname/path", false },
745 // For all of the following input strings, it doesn't make much difference
746 // if we allow them to be sent to the default provider or not. The strings
747 // need to be in this list of test cases however so that they are tested
748 // against the keyword provider and verified that they are allowed to be
749 // sent to it.
750 { "User:", false },
751 { "User::", false },
752 { "User:!", false },
753 // All of the following input strings should be sent to the default suggest
754 // server because they should not get caught by the private data checks.
755 { "User", true },
756 { "query", true },
757 { "query with spaces", true },
758 { "http://hostname", true },
759 { "http://hostname/path", true },
760 { "http://hostname #ref", true },
761 { "www.hostname.com #ref", true },
762 { "https://hostname", true },
763 { "#hashtag", true },
764 { "foo https://hostname/path", true },
767 for (size_t i = 0; i < arraysize(cases); ++i) {
768 SCOPED_TRACE("for input=" + cases[i].input);
769 QueryForInput(ASCIIToUTF16(cases[i].input), false, false);
770 // Make sure the default provider's suggest service was or was not queried
771 // as appropriate.
772 EXPECT_EQ(
773 cases[i].expect_to_send_to_default_provider,
774 test_factory_.GetFetcherByID(
775 SearchProvider::kDefaultProviderURLFetcherID) != NULL);
776 // Send the same input with an explicitly invoked keyword. In all cases,
777 // it's okay to send the request to the keyword suggest server.
778 QueryForInput(ASCIIToUTF16("k ") + ASCIIToUTF16(cases[i].input), false,
779 false);
780 EXPECT_TRUE(test_factory_.GetFetcherByID(
781 SearchProvider::kKeywordProviderURLFetcherID) != NULL);
785 TEST_F(SearchProviderTest, DontAutocompleteURLLikeTerms) {
786 GURL url = AddSearchToHistory(default_t_url_,
787 ASCIIToUTF16("docs.google.com"), 1);
789 // Add the term as a url.
790 HistoryServiceFactory::GetForProfile(&profile_,
791 ServiceAccessType::EXPLICIT_ACCESS)
792 ->AddPageWithDetails(GURL("http://docs.google.com"), base::string16(), 1,
793 1, base::Time::Now(), false,
794 history::SOURCE_BROWSED);
795 profile_.BlockUntilHistoryProcessesPendingRequests();
797 AutocompleteMatch wyt_match;
798 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("docs"),
799 &wyt_match));
801 // There should be two matches, one for what you typed, the other for
802 // 'docs.google.com'. The search term should have a lower priority than the
803 // what you typed match.
804 ASSERT_EQ(2u, provider_->matches().size());
805 AutocompleteMatch term_match;
806 EXPECT_TRUE(FindMatchWithDestination(url, &term_match));
807 EXPECT_GT(wyt_match.relevance, term_match.relevance);
808 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
809 EXPECT_TRUE(term_match.allowed_to_be_default_match);
812 TEST_F(SearchProviderTest, DontGiveNavsuggestionsInForcedQueryMode) {
813 const std::string kEmptyMatch;
814 struct {
815 const std::string json;
816 const std::string matches_in_default_mode[3];
817 const std::string matches_in_forced_query_mode[3];
818 } cases[] = {
819 // Without suggested relevance scores.
820 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
821 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]}]",
822 { "a", "a1.com", "a2" },
823 { "a", "a2", kEmptyMatch } },
825 // With suggested relevance scores in a situation where navsuggest would
826 // go second.
827 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
828 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
829 "\"google:suggestrelevance\":[1250, 1200]}]",
830 { "a", "a1.com", "a2" },
831 { "a", "a2", kEmptyMatch } },
833 // With suggested relevance scores in a situation where navsuggest
834 // would go first.
835 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
836 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
837 "\"google:suggestrelevance\":[1350, 1250]}]",
838 { "a1.com", "a", "a2" },
839 { "a", "a2", kEmptyMatch } },
841 // With suggested relevance scores in a situation where navsuggest
842 // would go first only because verbatim has been demoted.
843 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
844 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
845 "\"google:suggestrelevance\":[1450, 1400],"
846 "\"google:verbatimrelevance\":1350}]",
847 { "a1.com", "a2", "a" },
848 { "a2", "a", kEmptyMatch } },
851 for (size_t i = 0; i < arraysize(cases); ++i) {
852 ForcedQueryTestHelper("a", cases[i].json, cases[i].matches_in_default_mode,
853 "regular input with json=" + cases[i].json);
854 ForcedQueryTestHelper("?a", cases[i].json,
855 cases[i].matches_in_forced_query_mode,
856 "forced query input with json=" + cases[i].json);
860 // A multiword search with one visit should not autocomplete until multiple
861 // words are typed.
862 TEST_F(SearchProviderTest, DontAutocompleteUntilMultipleWordsTyped) {
863 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("one search"),
864 1));
865 profile_.BlockUntilHistoryProcessesPendingRequests();
867 AutocompleteMatch wyt_match;
868 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("on"),
869 &wyt_match));
870 ASSERT_EQ(2u, provider_->matches().size());
871 AutocompleteMatch term_match;
872 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
873 EXPECT_GT(wyt_match.relevance, term_match.relevance);
874 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
875 EXPECT_TRUE(term_match.allowed_to_be_default_match);
877 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("one se"),
878 &wyt_match));
879 ASSERT_EQ(2u, provider_->matches().size());
880 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
881 EXPECT_GT(term_match.relevance, wyt_match.relevance);
882 EXPECT_TRUE(term_match.allowed_to_be_default_match);
883 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
886 // A multiword search with more than one visit should autocomplete immediately.
887 TEST_F(SearchProviderTest, AutocompleteMultipleVisitsImmediately) {
888 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches"),
889 2));
890 profile_.BlockUntilHistoryProcessesPendingRequests();
892 AutocompleteMatch wyt_match;
893 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("tw"),
894 &wyt_match));
895 ASSERT_EQ(2u, provider_->matches().size());
896 AutocompleteMatch term_match;
897 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
898 EXPECT_GT(term_match.relevance, wyt_match.relevance);
899 EXPECT_TRUE(term_match.allowed_to_be_default_match);
900 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
903 // Autocompletion should work at a word boundary after a space, and should
904 // offer a suggestion for the trimmed search query.
905 TEST_F(SearchProviderTest, AutocompleteAfterSpace) {
906 AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches "), 2);
907 GURL suggested_url(default_t_url_->url_ref().ReplaceSearchTerms(
908 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("two searches")),
909 TemplateURLServiceFactory::GetForProfile(
910 &profile_)->search_terms_data()));
911 profile_.BlockUntilHistoryProcessesPendingRequests();
913 AutocompleteMatch wyt_match;
914 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("two "),
915 &wyt_match));
916 ASSERT_EQ(2u, provider_->matches().size());
917 AutocompleteMatch term_match;
918 EXPECT_TRUE(FindMatchWithDestination(suggested_url, &term_match));
919 EXPECT_GT(term_match.relevance, wyt_match.relevance);
920 EXPECT_TRUE(term_match.allowed_to_be_default_match);
921 EXPECT_EQ(ASCIIToUTF16("searches"), term_match.inline_autocompletion);
922 EXPECT_EQ(ASCIIToUTF16("two searches"), term_match.fill_into_edit);
923 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
926 // Newer multiword searches should score more highly than older ones.
927 TEST_F(SearchProviderTest, ScoreNewerSearchesHigher) {
928 GURL term_url_a(AddSearchToHistory(default_t_url_,
929 ASCIIToUTF16("three searches aaa"), 1));
930 GURL term_url_b(AddSearchToHistory(default_t_url_,
931 ASCIIToUTF16("three searches bbb"), 1));
932 profile_.BlockUntilHistoryProcessesPendingRequests();
934 AutocompleteMatch wyt_match;
935 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("three se"),
936 &wyt_match));
937 ASSERT_EQ(3u, provider_->matches().size());
938 AutocompleteMatch term_match_a;
939 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
940 AutocompleteMatch term_match_b;
941 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
942 EXPECT_GT(term_match_b.relevance, term_match_a.relevance);
943 EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
944 EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
945 EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
946 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
949 // If ScoreHistoryResults doesn't properly clear its output vector it can skip
950 // scoring the actual results and just return results from a previous run.
951 TEST_F(SearchProviderTest, ResetResultsBetweenRuns) {
952 GURL term_url_a(AddSearchToHistory(default_t_url_,
953 ASCIIToUTF16("games"), 1));
954 GURL term_url_b(AddSearchToHistory(default_t_url_,
955 ASCIIToUTF16("gangnam style"), 1));
956 GURL term_url_c(AddSearchToHistory(default_t_url_,
957 ASCIIToUTF16("gundam"), 1));
958 profile_.BlockUntilHistoryProcessesPendingRequests();
960 AutocompleteMatch wyt_match;
961 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
962 &wyt_match));
963 ASSERT_EQ(1u, provider_->matches().size());
965 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("g"),
966 &wyt_match));
967 ASSERT_EQ(4u, provider_->matches().size());
969 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("ga"),
970 &wyt_match));
971 ASSERT_EQ(3u, provider_->matches().size());
973 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("gan"),
974 &wyt_match));
975 ASSERT_EQ(2u, provider_->matches().size());
977 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("gans"),
978 &wyt_match));
979 ASSERT_EQ(1u, provider_->matches().size());
982 // This test is identical to the previous one except that it enables the Answers
983 // in Suggest field trial which triggers a different code path in
984 // SearchProvider. When Answers launches, this can be removed.
985 TEST_F(SearchProviderTest, ResetResultsBetweenRunsAnswersInSuggestEnabled) {
986 CreateFieldTrial(OmniboxFieldTrial::kAnswersInSuggestRule, true);
988 GURL term_url_a(AddSearchToHistory(default_t_url_,
989 ASCIIToUTF16("games"), 1));
990 GURL term_url_b(AddSearchToHistory(default_t_url_,
991 ASCIIToUTF16("gangnam style"), 1));
992 GURL term_url_c(AddSearchToHistory(default_t_url_,
993 ASCIIToUTF16("gundam"), 1));
994 profile_.BlockUntilHistoryProcessesPendingRequests();
996 AutocompleteMatch wyt_match;
997 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
998 &wyt_match));
999 ASSERT_EQ(1u, provider_->matches().size());
1001 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("g"),
1002 &wyt_match));
1003 ASSERT_EQ(4u, provider_->matches().size());
1005 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("ga"),
1006 &wyt_match));
1007 ASSERT_EQ(3u, provider_->matches().size());
1009 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("gan"),
1010 &wyt_match));
1011 ASSERT_EQ(2u, provider_->matches().size());
1013 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("gans"),
1014 &wyt_match));
1015 ASSERT_EQ(1u, provider_->matches().size());
1018 // An autocompleted multiword search should not be replaced by a different
1019 // autocompletion while the user is still typing a valid prefix unless the
1020 // user has typed the prefix as a query before.
1021 TEST_F(SearchProviderTest, DontReplacePreviousAutocompletion) {
1022 GURL term_url_a(AddSearchToHistory(default_t_url_,
1023 ASCIIToUTF16("four searches aaa"), 3));
1024 GURL term_url_b(AddSearchToHistory(default_t_url_,
1025 ASCIIToUTF16("four searches bbb"), 1));
1026 GURL term_url_c(AddSearchToHistory(default_t_url_,
1027 ASCIIToUTF16("four searches"), 1));
1028 profile_.BlockUntilHistoryProcessesPendingRequests();
1030 AutocompleteMatch wyt_match;
1031 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fo"),
1032 &wyt_match));
1033 ASSERT_EQ(4u, provider_->matches().size());
1034 AutocompleteMatch term_match_a;
1035 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
1036 AutocompleteMatch term_match_b;
1037 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
1038 AutocompleteMatch term_match_c;
1039 EXPECT_TRUE(FindMatchWithDestination(term_url_c, &term_match_c));
1040 EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
1041 // We don't care about the relative order of b and c.
1042 EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
1043 EXPECT_GT(wyt_match.relevance, term_match_c.relevance);
1044 EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
1045 EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
1046 EXPECT_TRUE(term_match_c.allowed_to_be_default_match);
1047 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
1049 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("four se"),
1050 &wyt_match));
1051 ASSERT_EQ(4u, provider_->matches().size());
1052 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
1053 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
1054 EXPECT_TRUE(FindMatchWithDestination(term_url_c, &term_match_c));
1055 EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
1056 EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
1057 EXPECT_GT(wyt_match.relevance, term_match_c.relevance);
1058 EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
1059 EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
1060 EXPECT_TRUE(term_match_c.allowed_to_be_default_match);
1061 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
1063 // For the exact previously-issued query, the what-you-typed match should win.
1064 ASSERT_NO_FATAL_FAILURE(
1065 QueryForInputAndSetWYTMatch(ASCIIToUTF16("four searches"), &wyt_match));
1066 ASSERT_EQ(3u, provider_->matches().size());
1067 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
1068 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
1069 EXPECT_GT(wyt_match.relevance, term_match_a.relevance);
1070 EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
1071 EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
1072 EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
1073 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
1076 // Non-completable multiword searches should not crowd out single-word searches.
1077 TEST_F(SearchProviderTest, DontCrowdOutSingleWords) {
1078 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("five"), 1));
1079 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches bbb"), 1);
1080 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches ccc"), 1);
1081 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches ddd"), 1);
1082 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches eee"), 1);
1083 profile_.BlockUntilHistoryProcessesPendingRequests();
1085 AutocompleteMatch wyt_match;
1086 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fi"),
1087 &wyt_match));
1088 ASSERT_EQ(AutocompleteProvider::kMaxMatches + 1, provider_->matches().size());
1089 AutocompleteMatch term_match;
1090 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
1091 EXPECT_GT(term_match.relevance, wyt_match.relevance);
1092 EXPECT_TRUE(term_match.allowed_to_be_default_match);
1093 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
1096 // Inline autocomplete matches regardless of case differences from the input.
1097 TEST_F(SearchProviderTest, InlineMixedCaseMatches) {
1098 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("FOO"), 1));
1099 profile_.BlockUntilHistoryProcessesPendingRequests();
1101 AutocompleteMatch wyt_match;
1102 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
1103 &wyt_match));
1104 ASSERT_EQ(2u, provider_->matches().size());
1105 AutocompleteMatch term_match;
1106 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
1107 EXPECT_GT(term_match.relevance, wyt_match.relevance);
1108 EXPECT_EQ(ASCIIToUTF16("FOO"), term_match.fill_into_edit);
1109 EXPECT_EQ(ASCIIToUTF16("OO"), term_match.inline_autocompletion);
1110 EXPECT_TRUE(term_match.allowed_to_be_default_match);
1113 // Verifies AutocompleteControllers return results (including keyword
1114 // results) in the right order and set descriptions for them correctly.
1115 TEST_F(SearchProviderTest, KeywordOrderingAndDescriptions) {
1116 // Add an entry that corresponds to a keyword search with 'term2'.
1117 AddSearchToHistory(keyword_t_url_, ASCIIToUTF16("term2"), 1);
1118 profile_.BlockUntilHistoryProcessesPendingRequests();
1120 AutocompleteController controller(&profile_,
1121 TemplateURLServiceFactory::GetForProfile(&profile_),
1122 NULL, AutocompleteProvider::TYPE_SEARCH);
1123 controller.Start(AutocompleteInput(
1124 ASCIIToUTF16("k t"), base::string16::npos, std::string(), GURL(),
1125 metrics::OmniboxEventProto::INVALID_SPEC, false, false, true, true,
1126 ChromeAutocompleteSchemeClassifier(&profile_)));
1127 const AutocompleteResult& result = controller.result();
1129 // There should be three matches, one for the keyword history, one for
1130 // keyword provider's what-you-typed, and one for the default provider's
1131 // what you typed, in that order.
1132 ASSERT_EQ(3u, result.size());
1133 EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY, result.match_at(0).type);
1134 EXPECT_EQ(AutocompleteMatchType::SEARCH_OTHER_ENGINE,
1135 result.match_at(1).type);
1136 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1137 result.match_at(2).type);
1138 EXPECT_GT(result.match_at(0).relevance, result.match_at(1).relevance);
1139 EXPECT_GT(result.match_at(1).relevance, result.match_at(2).relevance);
1140 EXPECT_TRUE(result.match_at(0).allowed_to_be_default_match);
1141 EXPECT_TRUE(result.match_at(1).allowed_to_be_default_match);
1142 EXPECT_FALSE(result.match_at(2).allowed_to_be_default_match);
1144 // The two keyword results should come with the keyword we expect.
1145 EXPECT_EQ(ASCIIToUTF16("k"), result.match_at(0).keyword);
1146 EXPECT_EQ(ASCIIToUTF16("k"), result.match_at(1).keyword);
1147 // The default provider has a different keyword. (We don't explicitly
1148 // set it during this test, so all we do is assert that it's different.)
1149 EXPECT_NE(result.match_at(0).keyword, result.match_at(2).keyword);
1151 // The top result will always have a description. The third result,
1152 // coming from a different provider than the first two, should also.
1153 // Whether the second result has one doesn't matter much. (If it was
1154 // missing, people would infer that it's the same search provider as
1155 // the one above it.)
1156 EXPECT_FALSE(result.match_at(0).description.empty());
1157 EXPECT_FALSE(result.match_at(2).description.empty());
1158 EXPECT_NE(result.match_at(0).description, result.match_at(2).description);
1161 TEST_F(SearchProviderTest, KeywordVerbatim) {
1162 TestData cases[] = {
1163 // Test a simple keyword input.
1164 { ASCIIToUTF16("k foo"), 2,
1165 { ResultInfo(GURL("http://keyword/foo"),
1166 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
1167 true,
1168 ASCIIToUTF16("k foo")),
1169 ResultInfo(GURL("http://defaultturl/k%20foo"),
1170 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1171 false,
1172 ASCIIToUTF16("k foo") ) } },
1174 // Make sure extra whitespace after the keyword doesn't change the
1175 // keyword verbatim query. Also verify that interior consecutive
1176 // whitespace gets trimmed.
1177 { ASCIIToUTF16("k foo"), 2,
1178 { ResultInfo(GURL("http://keyword/foo"),
1179 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
1180 true,
1181 ASCIIToUTF16("k foo")),
1182 ResultInfo(GURL("http://defaultturl/k%20foo"),
1183 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1184 false,
1185 ASCIIToUTF16("k foo")) } },
1186 // Leading whitespace should be stripped before SearchProvider gets the
1187 // input; hence there are no tests here about how it handles those inputs.
1189 // Verify that interior consecutive whitespace gets trimmed in either case.
1190 { ASCIIToUTF16("k foo bar"), 2,
1191 { ResultInfo(GURL("http://keyword/foo%20bar"),
1192 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
1193 true,
1194 ASCIIToUTF16("k foo bar")),
1195 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
1196 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1197 false,
1198 ASCIIToUTF16("k foo bar")) } },
1200 // Verify that trailing whitespace gets trimmed.
1201 { ASCIIToUTF16("k foo bar "), 2,
1202 { ResultInfo(GURL("http://keyword/foo%20bar"),
1203 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
1204 true,
1205 ASCIIToUTF16("k foo bar")),
1206 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
1207 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1208 false,
1209 ASCIIToUTF16("k foo bar")) } },
1211 // Keywords can be prefixed by certain things that should get ignored
1212 // when constructing the keyword match.
1213 { ASCIIToUTF16("www.k foo"), 2,
1214 { ResultInfo(GURL("http://keyword/foo"),
1215 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
1216 true,
1217 ASCIIToUTF16("k foo")),
1218 ResultInfo(GURL("http://defaultturl/www.k%20foo"),
1219 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1220 false,
1221 ASCIIToUTF16("www.k foo")) } },
1222 { ASCIIToUTF16("http://k foo"), 2,
1223 { ResultInfo(GURL("http://keyword/foo"),
1224 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
1225 true,
1226 ASCIIToUTF16("k foo")),
1227 ResultInfo(GURL("http://defaultturl/http%3A//k%20foo"),
1228 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1229 false,
1230 ASCIIToUTF16("http://k foo")) } },
1231 { ASCIIToUTF16("http://www.k foo"), 2,
1232 { ResultInfo(GURL("http://keyword/foo"),
1233 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
1234 true,
1235 ASCIIToUTF16("k foo")),
1236 ResultInfo(GURL("http://defaultturl/http%3A//www.k%20foo"),
1237 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1238 false,
1239 ASCIIToUTF16("http://www.k foo")) } },
1241 // A keyword with no remaining input shouldn't get a keyword
1242 // verbatim match.
1243 { ASCIIToUTF16("k"), 1,
1244 { ResultInfo(GURL("http://defaultturl/k"),
1245 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1246 true,
1247 ASCIIToUTF16("k")) } },
1248 // Ditto. Trailing whitespace shouldn't make a difference.
1249 { ASCIIToUTF16("k "), 1,
1250 { ResultInfo(GURL("http://defaultturl/k"),
1251 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1252 true,
1253 ASCIIToUTF16("k")) } }
1255 // The fact that verbatim queries to keyword are handled by KeywordProvider
1256 // not SearchProvider is tested in
1257 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc.
1260 // Test not in keyword mode.
1261 RunTest(cases, arraysize(cases), false);
1263 // Test in keyword mode. (Both modes should give the same result.)
1264 RunTest(cases, arraysize(cases), true);
1267 // Ensures command-line flags are reflected in the URLs the search provider
1268 // generates.
1269 TEST_F(SearchProviderTest, CommandLineOverrides) {
1270 TemplateURLService* turl_model =
1271 TemplateURLServiceFactory::GetForProfile(&profile_);
1273 TemplateURLData data;
1274 data.short_name = ASCIIToUTF16("default");
1275 data.SetKeyword(data.short_name);
1276 data.SetURL("{google:baseURL}{searchTerms}");
1277 default_t_url_ = new TemplateURL(data);
1278 turl_model->Add(default_t_url_);
1279 turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
1281 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1282 switches::kGoogleBaseURL, "http://www.bar.com/");
1283 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1284 switches::kExtraSearchQueryParams, "a=b");
1286 TestData cases[] = {
1287 { ASCIIToUTF16("k a"), 2,
1288 { ResultInfo(GURL("http://keyword/a"),
1289 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
1290 true,
1291 ASCIIToUTF16("k a")),
1292 ResultInfo(GURL("http://www.bar.com/k%20a?a=b"),
1293 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1294 false,
1295 ASCIIToUTF16("k a")) } },
1298 RunTest(cases, arraysize(cases), false);
1301 // Verifies Navsuggest results don't set a TemplateURL, which Instant relies on.
1302 // Also verifies that just the *first* navigational result is listed as a match
1303 // if suggested relevance scores were not sent.
1304 TEST_F(SearchProviderTest, NavSuggestNoSuggestedRelevanceScores) {
1305 QueryForInputAndWaitForFetcherResponses(
1306 ASCIIToUTF16("a.c"), false,
1307 "[\"a.c\",[\"a.com\", \"a.com/b\"],[\"a\", \"b\"],[],"
1308 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1309 std::string());
1311 // Make sure the only match is 'a.com' and it doesn't have a template_url.
1312 AutocompleteMatch nav_match;
1313 EXPECT_TRUE(FindMatchWithDestination(GURL("http://a.com"), &nav_match));
1314 EXPECT_TRUE(nav_match.keyword.empty());
1315 EXPECT_FALSE(nav_match.allowed_to_be_default_match);
1316 EXPECT_FALSE(FindMatchWithDestination(GURL("http://a.com/b"), &nav_match));
1319 // Verifies that the most relevant suggest results are added properly.
1320 TEST_F(SearchProviderTest, SuggestRelevance) {
1321 QueryForInputAndWaitForFetcherResponses(
1322 ASCIIToUTF16("a"), false, "[\"a\",[\"a1\", \"a2\", \"a3\", \"a4\"]]",
1323 std::string());
1325 // Check the expected verbatim and (first 3) suggestions' relative relevances.
1326 AutocompleteMatch verbatim, match_a1, match_a2, match_a3, match_a4;
1327 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim));
1328 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a1"), &match_a1));
1329 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a2"), &match_a2));
1330 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a3"), &match_a3));
1331 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("a4"), &match_a4));
1332 EXPECT_GT(verbatim.relevance, match_a1.relevance);
1333 EXPECT_GT(match_a1.relevance, match_a2.relevance);
1334 EXPECT_GT(match_a2.relevance, match_a3.relevance);
1335 EXPECT_TRUE(verbatim.allowed_to_be_default_match);
1336 EXPECT_FALSE(match_a1.allowed_to_be_default_match);
1337 EXPECT_FALSE(match_a2.allowed_to_be_default_match);
1338 EXPECT_FALSE(match_a3.allowed_to_be_default_match);
1341 // Verifies that the default provider abandons suggested relevance scores
1342 // when in keyword mode. This should happen regardless of whether the
1343 // keyword provider returns suggested relevance scores.
1344 TEST_F(SearchProviderTest, DefaultProviderNoSuggestRelevanceInKeywordMode) {
1345 struct {
1346 const std::string default_provider_json;
1347 const std::string keyword_provider_json;
1348 const std::string matches[5];
1349 } cases[] = {
1350 // First, try an input where the keyword provider does not deliver
1351 // suggested relevance scores.
1352 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1353 "{\"google:verbatimrelevance\":9700,"
1354 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1355 "\"google:suggestrelevance\":[9900, 9800]}]",
1356 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"]}]",
1357 { "a", "akeyword-query", "k a", "adefault.com", "k adefault-query" } },
1359 // Now try with keyword provider suggested relevance scores.
1360 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1361 "{\"google:verbatimrelevance\":9700,"
1362 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1363 "\"google:suggestrelevance\":[9900, 9800]}]",
1364 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"],"
1365 "\"google:verbatimrelevance\":9500,"
1366 "\"google:suggestrelevance\":[9600]}]",
1367 { "akeyword-query", "a", "k a", "adefault.com", "k adefault-query" } }
1370 for (size_t i = 0; i < arraysize(cases); ++i) {
1371 // Send the query twice in order to have a synchronous pass after the first
1372 // response is received. This is necessary because SearchProvider doesn't
1373 // allow an asynchronous response to change the default match.
1374 for (size_t j = 0; j < 2; ++j) {
1375 QueryForInputAndWaitForFetcherResponses(
1376 ASCIIToUTF16("k a"), true, cases[i].default_provider_json,
1377 cases[i].keyword_provider_json);
1380 SCOPED_TRACE(
1381 "for input with default_provider_json=" +
1382 cases[i].default_provider_json + " and keyword_provider_json=" +
1383 cases[i].keyword_provider_json);
1384 const ACMatches& matches = provider_->matches();
1385 ASSERT_LE(matches.size(), arraysize(cases[i].matches));
1386 size_t j = 0;
1387 // Ensure that the returned matches equal the expectations.
1388 for (; j < matches.size(); ++j)
1389 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]), matches[j].contents);
1390 // Ensure that no expected matches are missing.
1391 for (; j < arraysize(cases[i].matches); ++j)
1392 EXPECT_EQ(std::string(), cases[i].matches[j]);
1396 // Verifies that suggest results with relevance scores are added
1397 // properly when using the default fetcher. When adding a new test
1398 // case to this test, please consider adding it to the tests in
1399 // KeywordFetcherSuggestRelevance below.
1400 TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevance) {
1401 struct {
1402 const std::string json;
1403 const ExpectedMatch matches[6];
1404 const std::string inline_autocompletion;
1405 } cases[] = {
1406 // Ensure that suggestrelevance scores reorder matches.
1407 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1408 { { "a", true }, { "c", false }, { "b", false }, kEmptyExpectedMatch,
1409 kEmptyExpectedMatch, kEmptyExpectedMatch },
1410 std::string() },
1411 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1412 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1413 "\"google:suggestrelevance\":[1, 2]}]",
1414 { { "a", true }, { "c.com", false }, { "b.com", false },
1415 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1416 std::string() },
1418 // Without suggested relevance scores, we should only allow one
1419 // navsuggest result to be be displayed.
1420 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1421 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1422 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch,
1423 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1424 std::string() },
1426 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1427 // Negative values will have no effect; the calculated value will be used.
1428 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1429 "\"google:suggestrelevance\":[9998]}]",
1430 { { "a", true}, { "a1", false }, kEmptyExpectedMatch,
1431 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1432 std::string() },
1433 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1434 "\"google:suggestrelevance\":[9999]}]",
1435 { { "a1", true }, { "a", true }, kEmptyExpectedMatch,
1436 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1437 "1" },
1438 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1439 "\"google:suggestrelevance\":[9999]}]",
1440 { { "a1", true }, kEmptyExpectedMatch, kEmptyExpectedMatch,
1441 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1442 "1" },
1443 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1444 "\"google:suggestrelevance\":[9999]}]",
1445 { { "a1", true }, { "a", true }, kEmptyExpectedMatch,
1446 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1447 "1" },
1448 { "[\"a\",[\"http://a.com\"],[],[],"
1449 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1450 "\"google:verbatimrelevance\":9999,"
1451 "\"google:suggestrelevance\":[9998]}]",
1452 { { "a", true }, { "a.com", false }, kEmptyExpectedMatch,
1453 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1454 std::string() },
1455 { "[\"a\",[\"http://a.com\"],[],[],"
1456 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1457 "\"google:verbatimrelevance\":9998,"
1458 "\"google:suggestrelevance\":[9999]}]",
1459 { { "a.com", true }, { "a", true }, kEmptyExpectedMatch,
1460 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1461 ".com" },
1462 { "[\"a\",[\"http://a.com\"],[],[],"
1463 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1464 "\"google:verbatimrelevance\":0,"
1465 "\"google:suggestrelevance\":[9999]}]",
1466 { { "a.com", true }, kEmptyExpectedMatch, kEmptyExpectedMatch,
1467 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1468 ".com" },
1469 { "[\"a\",[\"http://a.com\"],[],[],"
1470 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1471 "\"google:verbatimrelevance\":-1,"
1472 "\"google:suggestrelevance\":[9999]}]",
1473 { { "a.com", true }, { "a", true }, kEmptyExpectedMatch,
1474 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1475 ".com" },
1477 // Ensure that both types of relevance scores reorder matches together.
1478 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1479 "\"google:verbatimrelevance\":9998}]",
1480 { { "a1", true }, { "a", true }, { "a2", false }, kEmptyExpectedMatch,
1481 kEmptyExpectedMatch, kEmptyExpectedMatch },
1482 "1" },
1484 // Check that an inlineable result appears first regardless of its score.
1485 // Also, if the result set lacks a single inlineable result, abandon the
1486 // request to suppress verbatim (verbatim_relevance=0), which will then
1487 // cause verbatim to appear (first).
1488 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1489 { { "a", true }, { "b", false }, kEmptyExpectedMatch,
1490 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1491 std::string() },
1492 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1493 "\"google:verbatimrelevance\":0}]",
1494 { { "a", true }, { "b", false }, kEmptyExpectedMatch,
1495 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1496 std::string() },
1497 { "[\"a\",[\"http://b.com\"],[],[],"
1498 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1499 "\"google:suggestrelevance\":[9999]}]",
1500 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch,
1501 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1502 std::string() },
1503 { "[\"a\",[\"http://b.com\"],[],[],"
1504 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1505 "\"google:suggestrelevance\":[9999],"
1506 "\"google:verbatimrelevance\":0}]",
1507 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch,
1508 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1509 std::string() },
1511 // Allow low-scoring matches.
1512 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1513 { { "a1", true }, kEmptyExpectedMatch, kEmptyExpectedMatch,
1514 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1515 "1" },
1516 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":10}]",
1517 { { "a1", true }, { "a", true }, kEmptyExpectedMatch,
1518 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1519 "1" },
1520 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[10],"
1521 "\"google:verbatimrelevance\":0}]",
1522 { { "a1", true }, kEmptyExpectedMatch, kEmptyExpectedMatch,
1523 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1524 "1" },
1525 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 20],"
1526 "\"google:verbatimrelevance\":0}]",
1527 { { "a2", true }, { "a1", false }, kEmptyExpectedMatch,
1528 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1529 "2" },
1530 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 30],"
1531 "\"google:verbatimrelevance\":20}]",
1532 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch,
1533 kEmptyExpectedMatch, kEmptyExpectedMatch },
1534 "2" },
1535 { "[\"a\",[\"http://a.com\"],[],[],"
1536 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1537 "\"google:suggestrelevance\":[10],"
1538 "\"google:verbatimrelevance\":0}]",
1539 { { "a.com", true }, kEmptyExpectedMatch, kEmptyExpectedMatch,
1540 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1541 ".com" },
1542 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1543 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1544 "\"google:suggestrelevance\":[10, 20],"
1545 "\"google:verbatimrelevance\":0}]",
1546 { { "a2.com", true }, { "a1.com", false }, kEmptyExpectedMatch,
1547 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1548 "2.com" },
1550 // Ensure that all suggestions are considered, regardless of order.
1551 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1552 "{\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1553 { { "a", true }, { "h", false }, { "g", false }, { "f", false },
1554 { "e", false }, { "d", false } },
1555 std::string() },
1556 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1557 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1558 "\"http://h.com\"],[],[],"
1559 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1560 "\"NAVIGATION\", \"NAVIGATION\","
1561 "\"NAVIGATION\", \"NAVIGATION\","
1562 "\"NAVIGATION\"],"
1563 "\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1564 { { "a", true }, { "h.com", false }, { "g.com", false },
1565 { "f.com", false }, { "e.com", false }, { "d.com", false } },
1566 std::string() },
1568 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1569 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10]}]",
1570 { { "a", true }, { "a1", false }, { "a2", false }, kEmptyExpectedMatch,
1571 kEmptyExpectedMatch, kEmptyExpectedMatch },
1572 std::string() },
1573 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 10]}]",
1574 { { "a", true }, { "a1", false }, kEmptyExpectedMatch,
1575 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1576 std::string() },
1577 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1578 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1579 "\"google:suggestrelevance\":[10]}]",
1580 { { "a", true }, { "a1.com", false }, kEmptyExpectedMatch,
1581 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1582 std::string() },
1583 { "[\"a\",[\"http://a1.com\"],[],[],"
1584 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1585 "\"google:suggestrelevance\":[9999, 10]}]",
1586 { { "a", true }, { "a1.com", false }, kEmptyExpectedMatch,
1587 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1588 std::string() },
1590 // Ensure that all 'verbatim' results are merged with their maximum score.
1591 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1592 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1593 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch,
1594 kEmptyExpectedMatch, kEmptyExpectedMatch },
1595 "2" },
1596 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1597 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1598 "\"google:verbatimrelevance\":0}]",
1599 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch,
1600 kEmptyExpectedMatch, kEmptyExpectedMatch },
1601 "2" },
1603 // Ensure that verbatim is always generated without other suggestions.
1604 // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
1605 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1606 { { "a", true }, kEmptyExpectedMatch, kEmptyExpectedMatch,
1607 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1608 std::string() },
1609 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1610 { { "a", true }, kEmptyExpectedMatch, kEmptyExpectedMatch,
1611 kEmptyExpectedMatch, kEmptyExpectedMatch, kEmptyExpectedMatch },
1612 std::string() },
1615 for (size_t i = 0; i < arraysize(cases); ++i) {
1616 // Send the query twice in order to have a synchronous pass after the first
1617 // response is received. This is necessary because SearchProvider doesn't
1618 // allow an asynchronous response to change the default match.
1619 for (size_t j = 0; j < 2; ++j) {
1620 QueryForInputAndWaitForFetcherResponses(
1621 ASCIIToUTF16("a"), false, cases[i].json, std::string());
1624 const std::string description = "for input with json=" + cases[i].json;
1625 CheckMatches(description, arraysize(cases[i].matches), cases[i].matches,
1626 provider_->matches());
1630 // Verifies that suggest results with relevance scores are added
1631 // properly when using the keyword fetcher. This is similar to the
1632 // test DefaultFetcherSuggestRelevance above but this uses inputs that
1633 // trigger keyword suggestions (i.e., "k a" rather than "a") and has
1634 // different expectations (because now the results are a mix of
1635 // keyword suggestions and default provider suggestions). When a new
1636 // test is added to this TEST_F, please consider if it would be
1637 // appropriate to add to DefaultFetcherSuggestRelevance as well.
1638 TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
1639 struct KeywordFetcherMatch {
1640 std::string contents;
1641 bool from_keyword;
1642 bool allowed_to_be_default_match;
1644 const KeywordFetcherMatch kEmptyMatch = { kNotApplicable, false, false };
1645 struct {
1646 const std::string json;
1647 const KeywordFetcherMatch matches[6];
1648 const std::string inline_autocompletion;
1649 } cases[] = {
1650 // Ensure that suggest relevance scores reorder matches and that
1651 // the keyword verbatim (lacking a suggested verbatim score) beats
1652 // the default provider verbatim.
1653 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1654 { { "a", true, true },
1655 { "k a", false, false },
1656 { "c", true, false },
1657 { "b", true, false },
1658 kEmptyMatch, kEmptyMatch },
1659 std::string() },
1660 // Again, check that relevance scores reorder matches, just this
1661 // time with navigation matches. This also checks that with
1662 // suggested relevance scores we allow multiple navsuggest results.
1663 // Note that navsuggest results that come from a keyword provider
1664 // are marked as not a keyword result. (They don't go to a
1665 // keyword search engine.)
1666 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
1667 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1668 "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
1669 { { "a", true, true },
1670 { "d", true, false },
1671 { "c.com", false, false },
1672 { "b.com", false, false },
1673 { "k a", false, false },
1674 kEmptyMatch },
1675 std::string() },
1677 // Without suggested relevance scores, we should only allow one
1678 // navsuggest result to be be displayed.
1679 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1680 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1681 { { "a", true, true },
1682 { "b.com", false, false },
1683 { "k a", false, false },
1684 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1685 std::string() },
1687 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1688 // Negative values will have no effect; the calculated value will be used.
1689 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1690 "\"google:suggestrelevance\":[9998]}]",
1691 { { "a", true, true },
1692 { "a1", true, false },
1693 { "k a", false, false },
1694 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1695 std::string() },
1696 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1697 "\"google:suggestrelevance\":[9999]}]",
1698 { { "a1", true, true },
1699 { "a", true, true },
1700 { "k a", false, false },
1701 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1702 "1" },
1703 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1704 "\"google:suggestrelevance\":[9999]}]",
1705 { { "a1", true, true },
1706 { "k a", false, false },
1707 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1708 "1" },
1709 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1710 "\"google:suggestrelevance\":[9999]}]",
1711 { { "a1", true, true },
1712 { "a", true, true },
1713 { "k a", false, false },
1714 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1715 "1" },
1716 { "[\"a\",[\"http://a.com\"],[],[],"
1717 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1718 "\"google:verbatimrelevance\":9999,"
1719 "\"google:suggestrelevance\":[9998]}]",
1720 { { "a", true, true },
1721 { "a.com", false, false },
1722 { "k a", false, false },
1723 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1724 std::string() },
1726 // Ensure that both types of relevance scores reorder matches together.
1727 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1728 "\"google:verbatimrelevance\":9998}]",
1729 { { "a1", true, true },
1730 { "a", true, true },
1731 { "a2", true, false },
1732 { "k a", false, false },
1733 kEmptyMatch, kEmptyMatch },
1734 "1" },
1736 // Check that an inlineable match appears first regardless of its score.
1737 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1738 { { "a", true, true },
1739 { "b", true, false },
1740 { "k a", false, false },
1741 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1742 std::string() },
1743 { "[\"a\",[\"http://b.com\"],[],[],"
1744 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1745 "\"google:suggestrelevance\":[9999]}]",
1746 { { "a", true, true },
1747 { "b.com", false, false },
1748 { "k a", false, false },
1749 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1750 std::string() },
1751 // If there is no inlineable match, restore the keyword verbatim score.
1752 // The keyword verbatim match will then appear first.
1753 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1754 "\"google:verbatimrelevance\":0}]",
1755 { { "a", true, true },
1756 { "b", true, false },
1757 { "k a", false, false },
1758 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1759 std::string() },
1760 { "[\"a\",[\"http://b.com\"],[],[],"
1761 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1762 "\"google:suggestrelevance\":[9999],"
1763 "\"google:verbatimrelevance\":0}]",
1764 { { "a", true, true },
1765 { "b.com", false, false },
1766 { "k a", false, false },
1767 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1768 std::string() },
1770 // The top result does not have to score as highly as calculated
1771 // verbatim. i.e., there are no minimum score restrictions in
1772 // this provider.
1773 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1774 { { "a1", true, true },
1775 { "k a", false, false },
1776 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1777 "1" },
1778 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":10}]",
1779 { { "a1", true, true },
1780 { "k a", false, false },
1781 { "a", true, true },
1782 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1783 "1" },
1784 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[10],"
1785 "\"google:verbatimrelevance\":0}]",
1786 { { "a1", true, true },
1787 { "k a", false, false },
1788 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1789 "1" },
1790 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 20],"
1791 "\"google:verbatimrelevance\":0}]",
1792 { { "a2", true, true },
1793 { "k a", false, false },
1794 { "a1", true, false },
1795 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1796 "2" },
1797 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 30],"
1798 "\"google:verbatimrelevance\":20}]",
1799 { { "a2", true, true },
1800 { "k a", false, false },
1801 { "a", true, true },
1802 { "a1", true, false },
1803 kEmptyMatch, kEmptyMatch },
1804 "2" },
1806 // Ensure that all suggestions are considered, regardless of order.
1807 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1808 "{\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1809 { { "a", true, true },
1810 { "k a", false, false },
1811 { "h", true, false },
1812 { "g", true, false },
1813 { "f", true, false },
1814 { "e", true, false } },
1815 std::string() },
1816 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1817 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1818 "\"http://h.com\"],[],[],"
1819 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1820 "\"NAVIGATION\", \"NAVIGATION\","
1821 "\"NAVIGATION\", \"NAVIGATION\","
1822 "\"NAVIGATION\"],"
1823 "\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1824 { { "a", true, true },
1825 { "k a", false, false },
1826 { "h.com", false, false },
1827 { "g.com", false, false },
1828 { "f.com", false, false },
1829 { "e.com", false, false } },
1830 std::string() },
1832 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1833 // Note that keyword suggestions by default (not in suggested relevance
1834 // mode) score more highly than the default verbatim.
1835 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1836 { { "a", true, true },
1837 { "a1", true, false },
1838 { "a2", true, false },
1839 { "k a", false, false },
1840 kEmptyMatch, kEmptyMatch },
1841 std::string() },
1842 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1843 { { "a", true, true },
1844 { "a1", true, false },
1845 { "k a", false, false },
1846 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1847 std::string() },
1848 // In this case, ignoring the suggested relevance scores means we keep
1849 // only one navsuggest result.
1850 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1851 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1852 "\"google:suggestrelevance\":[1]}]",
1853 { { "a", true, true },
1854 { "a1.com", false, false },
1855 { "k a", false, false },
1856 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1857 std::string() },
1858 { "[\"a\",[\"http://a1.com\"],[],[],"
1859 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1860 "\"google:suggestrelevance\":[9999, 1]}]",
1861 { { "a", true, true },
1862 { "a1.com", false, false },
1863 { "k a", false, false },
1864 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1865 std::string() },
1867 // Ensure that all 'verbatim' results are merged with their maximum score.
1868 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1869 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1870 { { "a2", true, true },
1871 { "a", true, true },
1872 { "a1", true, false },
1873 { "k a", false, false },
1874 kEmptyMatch, kEmptyMatch },
1875 "2" },
1876 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1877 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1878 "\"google:verbatimrelevance\":0}]",
1879 { { "a2", true, true },
1880 { "a", true, true },
1881 { "a1", true, false },
1882 { "k a", false, false },
1883 kEmptyMatch, kEmptyMatch },
1884 "2" },
1886 // Ensure that verbatim is always generated without other suggestions.
1887 // TODO(mpearson): Ensure the value of verbatimrelevance is respected
1888 // (except when suggested relevances are ignored).
1889 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1890 { { "a", true, true },
1891 { "k a", false, false },
1892 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1893 std::string() },
1894 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1895 { { "a", true, true },
1896 { "k a", false, false },
1897 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1898 std::string() },
1900 // In reorder mode, navsuggestions will not need to be demoted (because
1901 // they are marked as not allowed to be default match and will be
1902 // reordered as necessary).
1903 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1904 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1905 "\"google:verbatimrelevance\":9990,"
1906 "\"google:suggestrelevance\":[9998, 9999]}]",
1907 { { "a", true, true },
1908 { "a2.com", false, false },
1909 { "a1.com", false, false },
1910 { "k a", false, false },
1911 kEmptyMatch, kEmptyMatch },
1912 std::string() },
1913 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1914 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1915 "\"google:verbatimrelevance\":9990,"
1916 "\"google:suggestrelevance\":[9999, 9998]}]",
1917 { { "a", true, true },
1918 { "a1.com", false, false },
1919 { "a2.com", false, false },
1920 { "k a", false, false },
1921 kEmptyMatch, kEmptyMatch },
1922 std::string() },
1923 { "[\"a\",[\"https://a/\"],[],[],"
1924 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1925 "\"google:suggestrelevance\":[9999]}]",
1926 { { "a", true, true },
1927 { "https://a", false, false },
1928 { "k a", false, false },
1929 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1930 std::string() },
1931 // Check when navsuggest scores more than verbatim and there is query
1932 // suggestion but it scores lower.
1933 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1934 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1935 "\"google:verbatimrelevance\":9990,"
1936 "\"google:suggestrelevance\":[9998, 9999, 1300]}]",
1937 { { "a", true, true },
1938 { "a2.com", false, false },
1939 { "a1.com", false, false },
1940 { "a3", true, false },
1941 { "k a", false, false },
1942 kEmptyMatch },
1943 std::string() },
1944 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1945 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1946 "\"google:verbatimrelevance\":9990,"
1947 "\"google:suggestrelevance\":[9999, 9998, 1300]}]",
1948 { { "a", true, true },
1949 { "a1.com", false, false },
1950 { "a2.com", false, false },
1951 { "a3", true, false },
1952 { "k a", false, false },
1953 kEmptyMatch },
1954 std::string() },
1955 // Check when navsuggest scores more than a query suggestion. There is
1956 // a verbatim but it scores lower.
1957 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1958 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1959 "\"google:verbatimrelevance\":9990,"
1960 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1961 { { "a3", true, true },
1962 { "a2.com", false, false },
1963 { "a1.com", false, false },
1964 { "a", true, true },
1965 { "k a", false, false },
1966 kEmptyMatch },
1967 "3" },
1968 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1969 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1970 "\"google:verbatimrelevance\":9990,"
1971 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1972 { { "a3", true, true },
1973 { "a1.com", false, false },
1974 { "a2.com", false, false },
1975 { "a", true, true },
1976 { "k a", false, false },
1977 kEmptyMatch },
1978 "3" },
1979 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1980 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1981 "\"google:verbatimrelevance\":0,"
1982 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1983 { { "a3", true, true },
1984 { "a2.com", false, false },
1985 { "a1.com", false, false },
1986 { "k a", false, false },
1987 kEmptyMatch, kEmptyMatch },
1988 "3" },
1989 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1990 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1991 "\"google:verbatimrelevance\":0,"
1992 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1993 { { "a3", true, true },
1994 { "a1.com", false, false },
1995 { "a2.com", false, false },
1996 { "k a", false, false },
1997 kEmptyMatch, kEmptyMatch },
1998 "3" },
1999 // Check when there is neither verbatim nor a query suggestion that,
2000 // because we can't demote navsuggestions below a query suggestion,
2001 // we restore the keyword verbatim score.
2002 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
2003 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2004 "\"google:verbatimrelevance\":0,"
2005 "\"google:suggestrelevance\":[9998, 9999]}]",
2006 { { "a", true, true },
2007 { "a2.com", false, false },
2008 { "a1.com", false, false },
2009 { "k a", false, false },
2010 kEmptyMatch, kEmptyMatch },
2011 std::string() },
2012 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
2013 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2014 "\"google:verbatimrelevance\":0,"
2015 "\"google:suggestrelevance\":[9999, 9998]}]",
2016 { { "a", true, true },
2017 { "a1.com", false, false },
2018 { "a2.com", false, false },
2019 { "k a", false, false },
2020 kEmptyMatch, kEmptyMatch },
2021 std::string() },
2022 // More checks that everything works when it's not necessary to demote.
2023 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2024 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2025 "\"google:verbatimrelevance\":9990,"
2026 "\"google:suggestrelevance\":[9997, 9998, 9999]}]",
2027 { { "a3", true, true },
2028 { "a2.com", false, false },
2029 { "a1.com", false, false },
2030 { "a", true, true },
2031 { "k a", false, false },
2032 kEmptyMatch },
2033 "3" },
2034 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2035 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2036 "\"google:verbatimrelevance\":9990,"
2037 "\"google:suggestrelevance\":[9998, 9997, 9999]}]",
2038 { { "a3", true, true },
2039 { "a1.com", false, false },
2040 { "a2.com", false, false },
2041 { "a", true, true },
2042 { "k a", false, false },
2043 kEmptyMatch },
2044 "3" },
2047 for (size_t i = 0; i < arraysize(cases); ++i) {
2048 // Send the query twice in order to have a synchronous pass after the first
2049 // response is received. This is necessary because SearchProvider doesn't
2050 // allow an asynchronous response to change the default match.
2051 for (size_t j = 0; j < 2; ++j) {
2052 QueryForInput(ASCIIToUTF16("k a"), false, true);
2054 // Set up a default fetcher with no results.
2055 net::TestURLFetcher* default_fetcher =
2056 test_factory_.GetFetcherByID(
2057 SearchProvider::kDefaultProviderURLFetcherID);
2058 ASSERT_TRUE(default_fetcher);
2059 default_fetcher->set_response_code(200);
2060 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
2061 default_fetcher = NULL;
2063 // Set up a keyword fetcher with provided results.
2064 net::TestURLFetcher* keyword_fetcher =
2065 test_factory_.GetFetcherByID(
2066 SearchProvider::kKeywordProviderURLFetcherID);
2067 ASSERT_TRUE(keyword_fetcher);
2068 keyword_fetcher->set_response_code(200);
2069 keyword_fetcher->SetResponseString(cases[i].json);
2070 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
2071 keyword_fetcher = NULL;
2072 RunTillProviderDone();
2075 SCOPED_TRACE("for input with json=" + cases[i].json);
2076 const ACMatches& matches = provider_->matches();
2077 ASSERT_FALSE(matches.empty());
2078 // Find the first match that's allowed to be the default match and check
2079 // its inline_autocompletion.
2080 ACMatches::const_iterator it = FindDefaultMatch(matches);
2081 ASSERT_NE(matches.end(), it);
2082 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
2083 it->inline_autocompletion);
2085 ASSERT_LE(matches.size(), arraysize(cases[i].matches));
2086 size_t j = 0;
2087 // Ensure that the returned matches equal the expectations.
2088 for (; j < matches.size(); ++j) {
2089 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents),
2090 matches[j].contents);
2091 EXPECT_EQ(cases[i].matches[j].from_keyword,
2092 matches[j].keyword == ASCIIToUTF16("k"));
2093 EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match,
2094 matches[j].allowed_to_be_default_match);
2096 // Ensure that no expected matches are missing.
2097 for (; j < arraysize(cases[i].matches); ++j) {
2098 SCOPED_TRACE(" Case # " + base::IntToString(i));
2099 EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents);
2104 TEST_F(SearchProviderTest, DontInlineAutocompleteAsynchronously) {
2105 // This test sends two separate queries, each receiving different JSON
2106 // replies, and checks that at each stage of processing (receiving first
2107 // asynchronous response, handling new keystroke synchronously / sending the
2108 // second request, and receiving the second asynchronous response) we have the
2109 // expected matches. In particular, receiving the second response shouldn't
2110 // cause an unexpected inline autcompletion.
2111 struct {
2112 const std::string first_json;
2113 const ExpectedMatch first_async_matches[4];
2114 const ExpectedMatch sync_matches[4];
2115 const std::string second_json;
2116 const ExpectedMatch second_async_matches[4];
2117 } cases[] = {
2118 // A simple test that verifies we don't inline autocomplete after the
2119 // first asynchronous response, but we do at the next keystroke if the
2120 // response's results were good enough. Furthermore, we should continue
2121 // inline autocompleting after the second asynchronous response if the new
2122 // top suggestion is the same as the old inline autocompleted suggestion.
2123 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2124 "{\"google:verbatimrelevance\":9000,"
2125 "\"google:suggestrelevance\":[9002, 9001]}]",
2126 { { "a", true }, { "ab1", false }, { "ab2", false },
2127 kEmptyExpectedMatch },
2128 { { "ab1", true }, { "ab2", true }, { "ab", true },
2129 kEmptyExpectedMatch },
2130 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2131 "{\"google:verbatimrelevance\":9000,"
2132 "\"google:suggestrelevance\":[9002, 9001]}]",
2133 { { "ab1", true }, { "ab2", false }, { "ab", true },
2134 kEmptyExpectedMatch } },
2135 // Ditto, just for a navigation suggestion.
2136 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2137 "{\"google:verbatimrelevance\":9000,"
2138 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2139 "\"google:suggestrelevance\":[9002, 9001]}]",
2140 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2141 kEmptyExpectedMatch },
2142 { { "ab1.com", true }, { "ab2.com", true }, { "ab", true },
2143 kEmptyExpectedMatch },
2144 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2145 "{\"google:verbatimrelevance\":9000,"
2146 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2147 "\"google:suggestrelevance\":[9002, 9001]}]",
2148 { { "ab1.com", true }, { "ab2.com", false }, { "ab", true },
2149 kEmptyExpectedMatch } },
2150 // A more realistic test of the same situation.
2151 { "[\"a\",[\"abcdef\", \"abcdef.com\", \"abc\"],[],[],"
2152 "{\"google:verbatimrelevance\":900,"
2153 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"QUERY\"],"
2154 "\"google:suggestrelevance\":[1250, 1200, 1000]}]",
2155 { { "a", true }, { "abcdef", false }, { "abcdef.com", false },
2156 { "abc", false } },
2157 { { "abcdef", true }, { "abcdef.com", true }, { "abc", true },
2158 { "ab", true } },
2159 "[\"ab\",[\"abcdef\", \"abcdef.com\", \"abc\"],[],[],"
2160 "{\"google:verbatimrelevance\":900,"
2161 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"QUERY\"],"
2162 "\"google:suggestrelevance\":[1250, 1200, 1000]}]",
2163 { { "abcdef", true }, { "abcdef.com", false }, { "abc", false },
2164 { "ab", true } } },
2166 // Without an original inline autcompletion, a new inline autcompletion
2167 // should be rejected.
2168 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2169 "{\"google:verbatimrelevance\":9000,"
2170 "\"google:suggestrelevance\":[8000, 7000]}]",
2171 { { "a", true }, { "ab1", false }, { "ab2", false },
2172 kEmptyExpectedMatch },
2173 { { "ab", true }, { "ab1", true }, { "ab2", true },
2174 kEmptyExpectedMatch },
2175 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2176 "{\"google:verbatimrelevance\":9000,"
2177 "\"google:suggestrelevance\":[9002, 9001]}]",
2178 { { "ab", true }, { "ab1", false }, { "ab2", false },
2179 kEmptyExpectedMatch } },
2180 // For the same test except with the queries scored in the opposite order
2181 // on the second JSON response, the queries should be ordered by the second
2182 // response's scores, not the first.
2183 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2184 "{\"google:verbatimrelevance\":9000,"
2185 "\"google:suggestrelevance\":[8000, 7000]}]",
2186 { { "a", true }, { "ab1", false }, { "ab2", false },
2187 kEmptyExpectedMatch },
2188 { { "ab", true }, { "ab1", true }, { "ab2", true },
2189 kEmptyExpectedMatch },
2190 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2191 "{\"google:verbatimrelevance\":9000,"
2192 "\"google:suggestrelevance\":[9001, 9002]}]",
2193 { { "ab", true }, { "ab2", false }, { "ab1", false },
2194 kEmptyExpectedMatch } },
2195 // Now, the same verifications but with the new inline autocompletion as a
2196 // navsuggestion. The new autocompletion should still be rejected.
2197 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2198 "{\"google:verbatimrelevance\":9000,"
2199 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2200 "\"google:suggestrelevance\":[8000, 7000]}]",
2201 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2202 kEmptyExpectedMatch },
2203 { { "ab", true }, { "ab1.com", true }, { "ab2.com", true },
2204 kEmptyExpectedMatch },
2205 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2206 "{\"google:verbatimrelevance\":9000,"
2207 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2208 "\"google:suggestrelevance\":[9002, 9001]}]",
2209 { { "ab", true }, { "ab1.com", false }, { "ab2.com", false },
2210 kEmptyExpectedMatch } },
2211 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2212 "{\"google:verbatimrelevance\":9000,"
2213 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2214 "\"google:suggestrelevance\":[8000, 7000]}]",
2215 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2216 kEmptyExpectedMatch },
2217 { { "ab", true }, { "ab1.com", true }, { "ab2.com", true },
2218 kEmptyExpectedMatch },
2219 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2220 "{\"google:verbatimrelevance\":9000,"
2221 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2222 "\"google:suggestrelevance\":[9001, 9002]}]",
2223 { { "ab", true }, { "ab2.com", false }, { "ab1.com", false },
2224 kEmptyExpectedMatch } },
2226 // It's okay to abandon an inline autocompletion asynchronously.
2227 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2228 "{\"google:verbatimrelevance\":9000,"
2229 "\"google:suggestrelevance\":[9002, 9001]}]",
2230 { { "a", true }, { "ab1", false }, { "ab2", false },
2231 kEmptyExpectedMatch },
2232 { { "ab1", true }, { "ab2", true }, { "ab", true },
2233 kEmptyExpectedMatch },
2234 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2235 "{\"google:verbatimrelevance\":9000,"
2236 "\"google:suggestrelevance\":[8000, 7000]}]",
2237 { { "ab", true }, { "ab1", true }, { "ab2", false },
2238 kEmptyExpectedMatch } },
2240 // Note: it's possible that the suggest server returns a suggestion with
2241 // an inline autocompletion (that as usual we delay in allowing it to
2242 // be displayed as an inline autocompletion until the next keystroke),
2243 // then, in response to the next keystroke, the server returns a different
2244 // suggestion as an inline autocompletion. This is not likely to happen.
2245 // Regardless, if it does, one could imagine three different behaviors:
2246 // - keep the original inline autocompletion until the next keystroke
2247 // (i.e., don't abandon an inline autocompletion asynchronously), then
2248 // use the new suggestion
2249 // - abandon all inline autocompletions upon the server response, then use
2250 // the new suggestion on the next keystroke
2251 // - ignore the new inline autocompletion provided by the server, yet
2252 // possibly keep the original if it scores well in the most recent
2253 // response, then use the new suggestion on the next keystroke
2254 // All of these behaviors are reasonable. The main thing we want to
2255 // ensure is that the second asynchronous response shouldn't cause *a new*
2256 // inline autocompletion to be displayed. We test that here.
2257 // The current implementation does the third bullet, but all of these
2258 // behaviors seem reasonable.
2259 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2260 "{\"google:verbatimrelevance\":9000,"
2261 "\"google:suggestrelevance\":[9002, 9001]}]",
2262 { { "a", true }, { "ab1", false }, { "ab2", false },
2263 kEmptyExpectedMatch },
2264 { { "ab1", true }, { "ab2", true }, { "ab", true },
2265 kEmptyExpectedMatch },
2266 "[\"ab\",[\"ab1\", \"ab3\"],[],[],"
2267 "{\"google:verbatimrelevance\":9000,"
2268 "\"google:suggestrelevance\":[9002, 9900]}]",
2269 { { "ab1", true }, { "ab3", false }, { "ab", true },
2270 kEmptyExpectedMatch } },
2271 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2272 "{\"google:verbatimrelevance\":9000,"
2273 "\"google:suggestrelevance\":[9002, 9001]}]",
2274 { { "a", true }, { "ab1", false }, { "ab2", false },
2275 kEmptyExpectedMatch },
2276 { { "ab1", true }, { "ab2", true }, { "ab", true },
2277 kEmptyExpectedMatch },
2278 "[\"ab\",[\"ab1\", \"ab3\"],[],[],"
2279 "{\"google:verbatimrelevance\":9000,"
2280 "\"google:suggestrelevance\":[8000, 9500]}]",
2281 { { "ab", true }, { "ab3", false }, { "ab1", true },
2282 kEmptyExpectedMatch } },
2285 for (size_t i = 0; i < arraysize(cases); ++i) {
2286 // First, send the query "a" and receive the JSON response |first_json|.
2287 ClearAllResults();
2288 QueryForInputAndWaitForFetcherResponses(
2289 ASCIIToUTF16("a"), false, cases[i].first_json, std::string());
2291 // Verify that the matches after the asynchronous results are as expected.
2292 std::string description = "first asynchronous response for input with "
2293 "first_json=" + cases[i].first_json;
2294 CheckMatches(description, arraysize(cases[i].first_async_matches),
2295 cases[i].first_async_matches, provider_->matches());
2297 // Then, send the query "ab" and check the synchronous matches.
2298 description = "synchronous response after the first keystroke after input "
2299 "with first_json=" + cases[i].first_json;
2300 QueryForInput(ASCIIToUTF16("ab"), false, false);
2301 CheckMatches(description, arraysize(cases[i].sync_matches),
2302 cases[i].sync_matches, provider_->matches());
2304 // Finally, get the provided JSON response, |second_json|, and verify the
2305 // matches after the second asynchronous response are as expected.
2306 description = "second asynchronous response after input with first_json=" +
2307 cases[i].first_json + " and second_json=" + cases[i].second_json;
2308 net::TestURLFetcher* second_fetcher =
2309 test_factory_.GetFetcherByID(
2310 SearchProvider::kDefaultProviderURLFetcherID);
2311 ASSERT_TRUE(second_fetcher);
2312 second_fetcher->set_response_code(200);
2313 second_fetcher->SetResponseString(cases[i].second_json);
2314 second_fetcher->delegate()->OnURLFetchComplete(second_fetcher);
2315 RunTillProviderDone();
2316 CheckMatches(description, arraysize(cases[i].second_async_matches),
2317 cases[i].second_async_matches, provider_->matches());
2321 TEST_F(SearchProviderTest, LocalAndRemoteRelevances) {
2322 // We hardcode the string "term1" below, so ensure that the search term that
2323 // got added to history already is that string.
2324 ASSERT_EQ(ASCIIToUTF16("term1"), term1_);
2325 base::string16 term = term1_.substr(0, term1_.length() - 1);
2327 AddSearchToHistory(default_t_url_, term + ASCIIToUTF16("2"), 2);
2328 profile_.BlockUntilHistoryProcessesPendingRequests();
2330 struct {
2331 const base::string16 input;
2332 const std::string json;
2333 const std::string matches[6];
2334 } cases[] = {
2335 // The history results outscore the default verbatim score. term2 has more
2336 // visits so it outscores term1. The suggestions are still returned since
2337 // they're server-scored.
2338 { term,
2339 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
2340 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
2341 "\"google:suggestrelevance\":[1, 2, 3]}]",
2342 { "term2", "term1", "term", "a3", "a2", "a1" } },
2343 // Because we already have three suggestions by the time we see the history
2344 // results, they don't get returned.
2345 { term,
2346 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
2347 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
2348 "\"google:verbatimrelevance\":1450,"
2349 "\"google:suggestrelevance\":[1440, 1430, 1420]}]",
2350 { "term", "a1", "a2", "a3", kNotApplicable, kNotApplicable } },
2351 // If we only have two suggestions, we have room for a history result.
2352 { term,
2353 "[\"term\",[\"a1\", \"a2\"],[],[],"
2354 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2355 "\"google:verbatimrelevance\":1450,"
2356 "\"google:suggestrelevance\":[1430, 1410]}]",
2357 { "term", "a1", "a2", "term2", kNotApplicable, kNotApplicable } },
2358 // If we have more than three suggestions, they should all be returned as
2359 // long as we have enough total space for them.
2360 { term,
2361 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
2362 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
2363 "\"google:verbatimrelevance\":1450,"
2364 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410]}]",
2365 { "term", "a1", "a2", "a3", "a4", kNotApplicable } },
2366 { term,
2367 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\", \"a5\", \"a6\"],[],[],"
2368 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\","
2369 "\"QUERY\", \"QUERY\"],"
2370 "\"google:verbatimrelevance\":1450,"
2371 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410, 1400, 1390]}]",
2372 { "term", "a1", "a2", "a3", "a4", "a5" } },
2373 { term,
2374 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
2375 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
2376 "\"google:verbatimrelevance\":1450,"
2377 "\"google:suggestrelevance\":[1430, 1410, 1390, 1370]}]",
2378 { "term", "a1", "a2", "term2", "a3", "a4" } }
2381 for (size_t i = 0; i < arraysize(cases); ++i) {
2382 QueryForInputAndWaitForFetcherResponses(
2383 cases[i].input, false, cases[i].json, std::string());
2385 const std::string description = "for input with json=" + cases[i].json;
2386 const ACMatches& matches = provider_->matches();
2388 // Ensure no extra matches are present.
2389 ASSERT_LE(matches.size(), arraysize(cases[i].matches));
2391 size_t j = 0;
2392 // Ensure that the returned matches equal the expectations.
2393 for (; j < matches.size(); ++j)
2394 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]),
2395 matches[j].contents) << description;
2396 // Ensure that no expected matches are missing.
2397 for (; j < arraysize(cases[i].matches); ++j)
2398 EXPECT_EQ(kNotApplicable, cases[i].matches[j]) <<
2399 "Case # " << i << " " << description;
2403 // Verifies suggest relevance behavior for URL input.
2404 TEST_F(SearchProviderTest, DefaultProviderSuggestRelevanceScoringUrlInput) {
2405 struct DefaultFetcherUrlInputMatch {
2406 const std::string match_contents;
2407 AutocompleteMatch::Type match_type;
2408 bool allowed_to_be_default_match;
2410 const DefaultFetcherUrlInputMatch kEmptyMatch =
2411 { kNotApplicable, AutocompleteMatchType::NUM_TYPES, false };
2412 struct {
2413 const std::string input;
2414 const std::string json;
2415 const DefaultFetcherUrlInputMatch output[4];
2416 } cases[] = {
2417 // Ensure NAVIGATION matches are allowed to be listed first for URL input.
2418 // Non-inlineable matches should not be allowed to be the default match.
2419 // Note that the top-scoring inlineable match is moved to the top
2420 // regardless of its score.
2421 { "a.com", "[\"a.com\",[\"http://b.com/\"],[],[],"
2422 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2423 "\"google:suggestrelevance\":[9999]}]",
2424 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2425 { "b.com", AutocompleteMatchType::NAVSUGGEST, false },
2426 kEmptyMatch, kEmptyMatch } },
2427 { "a.com", "[\"a.com\",[\"https://b.com\"],[],[],"
2428 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2429 "\"google:suggestrelevance\":[9999]}]",
2430 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2431 { "https://b.com", AutocompleteMatchType::NAVSUGGEST, false },
2432 kEmptyMatch, kEmptyMatch } },
2433 { "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[],"
2434 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2435 "\"google:suggestrelevance\":[9999]}]",
2436 { { "a.com/a", AutocompleteMatchType::NAVSUGGEST, true },
2437 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2438 kEmptyMatch, kEmptyMatch } },
2439 { "a.com", "[\"a.com\",[\"https://a.com\"],[],[],"
2440 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2441 "\"google:suggestrelevance\":[9999]}]",
2442 { { "https://a.com", AutocompleteMatchType::NAVSUGGEST, true },
2443 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2444 kEmptyMatch, kEmptyMatch } },
2446 // Ensure topmost inlineable SUGGEST matches are NOT allowed for URL
2447 // input. SearchProvider disregards search and verbatim suggested
2448 // relevances.
2449 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2450 "{\"google:suggestrelevance\":[9999]}]",
2451 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2452 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, false },
2453 kEmptyMatch, kEmptyMatch } },
2454 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2455 "{\"google:suggestrelevance\":[9999]}]",
2456 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2457 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, false },
2458 kEmptyMatch, kEmptyMatch } },
2460 // Ensure the fallback mechanism allows inlineable NAVIGATION matches.
2461 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2462 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2463 "\"google:suggestrelevance\":[9999, 9998]}]",
2464 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true },
2465 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, false },
2466 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2467 kEmptyMatch } },
2468 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2469 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2470 "\"google:suggestrelevance\":[9998, 9997],"
2471 "\"google:verbatimrelevance\":9999}]",
2472 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true },
2473 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2474 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, false },
2475 kEmptyMatch } },
2477 // Ensure non-inlineable SUGGEST matches are allowed for URL input
2478 // assuming the best inlineable match is not a query (i.e., is a
2479 // NAVSUGGEST). The best inlineable match will be at the top of the
2480 // list regardless of its score.
2481 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2482 "{\"google:suggestrelevance\":[9999]}]",
2483 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2484 { "info", AutocompleteMatchType::SEARCH_SUGGEST, false },
2485 kEmptyMatch, kEmptyMatch } },
2486 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2487 "{\"google:suggestrelevance\":[9999]}]",
2488 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2489 { "info", AutocompleteMatchType::SEARCH_SUGGEST, false },
2490 kEmptyMatch, kEmptyMatch } },
2493 for (size_t i = 0; i < arraysize(cases); ++i) {
2494 // Send the query twice in order to have a synchronous pass after the first
2495 // response is received. This is necessary because SearchProvider doesn't
2496 // allow an asynchronous response to change the default match.
2497 for (size_t j = 0; j < 2; ++j) {
2498 QueryForInputAndWaitForFetcherResponses(
2499 ASCIIToUTF16(cases[i].input), false, cases[i].json, std::string());
2502 SCOPED_TRACE("input=" + cases[i].input + " json=" + cases[i].json);
2503 size_t j = 0;
2504 const ACMatches& matches = provider_->matches();
2505 ASSERT_LE(matches.size(), arraysize(cases[i].output));
2506 // Ensure that the returned matches equal the expectations.
2507 for (; j < matches.size(); ++j) {
2508 EXPECT_EQ(ASCIIToUTF16(cases[i].output[j].match_contents),
2509 matches[j].contents);
2510 EXPECT_EQ(cases[i].output[j].match_type, matches[j].type);
2511 EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match,
2512 matches[j].allowed_to_be_default_match);
2514 // Ensure that no expected matches are missing.
2515 for (; j < arraysize(cases[i].output); ++j) {
2516 EXPECT_EQ(kNotApplicable, cases[i].output[j].match_contents);
2517 EXPECT_EQ(AutocompleteMatchType::NUM_TYPES,
2518 cases[i].output[j].match_type);
2519 EXPECT_FALSE(cases[i].output[j].allowed_to_be_default_match);
2524 // A basic test that verifies the field trial triggered parsing logic.
2525 TEST_F(SearchProviderTest, FieldTrialTriggeredParsing) {
2526 QueryForInputAndWaitForFetcherResponses(
2527 ASCIIToUTF16("foo"), false,
2528 "[\"foo\",[\"foo bar\"],[\"\"],[],"
2529 "{\"google:suggesttype\":[\"QUERY\"],"
2530 "\"google:fieldtrialtriggered\":true}]",
2531 std::string());
2534 // Check for the match and field trial triggered bits.
2535 AutocompleteMatch match;
2536 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("foo bar"), &match));
2537 ProvidersInfo providers_info;
2538 provider_->AddProviderInfo(&providers_info);
2539 ASSERT_EQ(1U, providers_info.size());
2540 EXPECT_EQ(1, providers_info[0].field_trial_triggered_size());
2541 EXPECT_EQ(1, providers_info[0].field_trial_triggered_in_session_size());
2544 // Reset the session and check that bits are reset.
2545 provider_->ResetSession();
2546 ProvidersInfo providers_info;
2547 provider_->AddProviderInfo(&providers_info);
2548 ASSERT_EQ(1U, providers_info.size());
2549 EXPECT_EQ(1, providers_info[0].field_trial_triggered_size());
2550 EXPECT_EQ(0, providers_info[0].field_trial_triggered_in_session_size());
2554 // Verifies inline autocompletion of navigational results.
2555 TEST_F(SearchProviderTest, NavigationInline) {
2556 struct {
2557 const std::string input;
2558 const std::string url;
2559 // Test the expected fill_into_edit, which may drop "http://".
2560 // Some cases do not trim "http://" to match from the start of the scheme.
2561 const std::string fill_into_edit;
2562 const std::string inline_autocompletion;
2563 const bool allowed_to_be_default_match_in_regular_mode;
2564 const bool allowed_to_be_default_match_in_prevent_inline_mode;
2565 } cases[] = {
2566 // Do not inline matches that do not contain the input; trim http as needed.
2567 { "x", "http://www.abc.com",
2568 "www.abc.com", std::string(), false, false },
2569 { "https:", "http://www.abc.com",
2570 "www.abc.com", std::string(), false, false },
2571 { "http://www.abc.com/a", "http://www.abc.com",
2572 "http://www.abc.com", std::string(), false,
2573 false },
2575 // Do not inline matches with invalid input prefixes; trim http as needed.
2576 { "ttp", "http://www.abc.com",
2577 "www.abc.com", std::string(), false, false },
2578 { "://w", "http://www.abc.com",
2579 "www.abc.com", std::string(), false, false },
2580 { "ww.", "http://www.abc.com",
2581 "www.abc.com", std::string(), false, false },
2582 { ".ab", "http://www.abc.com",
2583 "www.abc.com", std::string(), false, false },
2584 { "bc", "http://www.abc.com",
2585 "www.abc.com", std::string(), false, false },
2586 { ".com", "http://www.abc.com",
2587 "www.abc.com", std::string(), false, false },
2589 // Do not inline matches that omit input domain labels; trim http as needed.
2590 { "www.a", "http://a.com",
2591 "a.com", std::string(), false, false },
2592 { "http://www.a", "http://a.com",
2593 "http://a.com", std::string(), false, false },
2594 { "www.a", "ftp://a.com",
2595 "ftp://a.com", std::string(), false, false },
2596 { "ftp://www.a", "ftp://a.com",
2597 "ftp://a.com", std::string(), false, false },
2599 // Input matching but with nothing to inline will not yield an offset, but
2600 // will be allowed to be default.
2601 { "abc.com", "http://www.abc.com",
2602 "www.abc.com", std::string(), true, true },
2603 { "abc.com/", "http://www.abc.com",
2604 "www.abc.com", std::string(), true, true },
2605 { "http://www.abc.com", "http://www.abc.com",
2606 "http://www.abc.com", std::string(), true, true },
2607 { "http://www.abc.com/", "http://www.abc.com",
2608 "http://www.abc.com", std::string(), true, true },
2610 // Inputs with trailing whitespace should inline when possible.
2611 { "abc.com ", "http://www.abc.com",
2612 "www.abc.com", std::string(), true, true },
2613 { "abc.com/ ", "http://www.abc.com",
2614 "www.abc.com", std::string(), true, true },
2615 { "abc.com ", "http://www.abc.com/bar",
2616 "www.abc.com/bar", "/bar", false, false },
2618 // A suggestion that's equivalent to what the input gets fixed up to
2619 // should be inlined.
2620 { "abc.com:", "http://abc.com/",
2621 "abc.com", std::string(), true, true },
2622 { "abc.com:", "http://www.abc.com",
2623 "www.abc.com", std::string(), true, true },
2625 // Inline matches when the input is a leading substring of the scheme.
2626 { "h", "http://www.abc.com",
2627 "http://www.abc.com", "ttp://www.abc.com", true, false },
2628 { "http", "http://www.abc.com",
2629 "http://www.abc.com", "://www.abc.com", true, false },
2631 // Inline matches when the input is a leading substring of the full URL.
2632 { "http:", "http://www.abc.com",
2633 "http://www.abc.com", "//www.abc.com", true, false },
2634 { "http://w", "http://www.abc.com",
2635 "http://www.abc.com", "ww.abc.com", true, false },
2636 { "http://www.", "http://www.abc.com",
2637 "http://www.abc.com", "abc.com", true, false },
2638 { "http://www.ab", "http://www.abc.com",
2639 "http://www.abc.com", "c.com", true, false },
2640 { "http://www.abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2641 "http://www.abc.com/path/file.htm?q=x#foo",
2642 "ath/file.htm?q=x#foo",
2643 true, false },
2644 { "http://abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2645 "http://abc.com/path/file.htm?q=x#foo",
2646 "ath/file.htm?q=x#foo",
2647 true, false},
2649 // Inline matches with valid URLPrefixes; only trim "http://".
2650 { "w", "http://www.abc.com",
2651 "www.abc.com", "ww.abc.com", true, false },
2652 { "www.a", "http://www.abc.com",
2653 "www.abc.com", "bc.com", true, false },
2654 { "abc", "http://www.abc.com",
2655 "www.abc.com", ".com", true, false },
2656 { "abc.c", "http://www.abc.com",
2657 "www.abc.com", "om", true, false },
2658 { "abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2659 "www.abc.com/path/file.htm?q=x#foo",
2660 "ath/file.htm?q=x#foo",
2661 true, false },
2662 { "abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2663 "abc.com/path/file.htm?q=x#foo",
2664 "ath/file.htm?q=x#foo",
2665 true, false },
2667 // Inline matches using the maximal URLPrefix components.
2668 { "h", "http://help.com",
2669 "help.com", "elp.com", true, false },
2670 { "http", "http://http.com",
2671 "http.com", ".com", true, false },
2672 { "h", "http://www.help.com",
2673 "www.help.com", "elp.com", true, false },
2674 { "http", "http://www.http.com",
2675 "www.http.com", ".com", true, false },
2676 { "w", "http://www.www.com",
2677 "www.www.com", "ww.com", true, false },
2679 // Test similar behavior for the ftp and https schemes.
2680 { "ftp://www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2681 "ftp://www.abc.com/path/file.htm?q=x#foo",
2682 "c.com/path/file.htm?q=x#foo", true, false },
2683 { "www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2684 "ftp://www.abc.com/path/file.htm?q=x#foo",
2685 "c.com/path/file.htm?q=x#foo", true, false },
2686 { "ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2687 "ftp://www.abc.com/path/file.htm?q=x#foo",
2688 "c.com/path/file.htm?q=x#foo", true, false },
2689 { "ab", "ftp://abc.com/path/file.htm?q=x#foo",
2690 "ftp://abc.com/path/file.htm?q=x#foo",
2691 "c.com/path/file.htm?q=x#foo", true, false },
2692 { "https://www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2693 "https://www.abc.com/path/file.htm?q=x#foo",
2694 "c.com/path/file.htm?q=x#foo",
2695 true, false },
2696 { "www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2697 "https://www.abc.com/path/file.htm?q=x#foo",
2698 "c.com/path/file.htm?q=x#foo", true, false },
2699 { "ab", "https://www.abc.com/path/file.htm?q=x#foo",
2700 "https://www.abc.com/path/file.htm?q=x#foo",
2701 "c.com/path/file.htm?q=x#foo", true, false },
2702 { "ab", "https://abc.com/path/file.htm?q=x#foo",
2703 "https://abc.com/path/file.htm?q=x#foo",
2704 "c.com/path/file.htm?q=x#foo", true, false },
2706 // Forced query input should inline and retain the "?" prefix.
2707 { "?http://www.ab", "http://www.abc.com",
2708 "?http://www.abc.com", "c.com", true, false },
2709 { "?www.ab", "http://www.abc.com",
2710 "?www.abc.com", "c.com", true, false },
2711 { "?ab", "http://www.abc.com",
2712 "?www.abc.com", "c.com", true, false },
2713 { "?abc.com", "http://www.abc.com",
2714 "?www.abc.com", std::string(), true, true },
2717 for (size_t i = 0; i < arraysize(cases); ++i) {
2718 // First test regular mode.
2719 QueryForInput(ASCIIToUTF16(cases[i].input), false, false);
2720 SearchSuggestionParser::NavigationResult result(
2721 ChromeAutocompleteSchemeClassifier(&profile_), GURL(cases[i].url),
2722 AutocompleteMatchType::NAVSUGGEST, base::string16(), std::string(),
2723 false, 0, false, ASCIIToUTF16(cases[i].input), std::string());
2724 result.set_received_after_last_keystroke(false);
2725 AutocompleteMatch match(provider_->NavigationToMatch(result));
2726 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
2727 match.inline_autocompletion);
2728 EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit), match.fill_into_edit);
2729 EXPECT_EQ(cases[i].allowed_to_be_default_match_in_regular_mode,
2730 match.allowed_to_be_default_match);
2732 // Then test prevent-inline-autocomplete mode.
2733 QueryForInput(ASCIIToUTF16(cases[i].input), true, false);
2734 SearchSuggestionParser::NavigationResult result_prevent_inline(
2735 ChromeAutocompleteSchemeClassifier(&profile_), GURL(cases[i].url),
2736 AutocompleteMatchType::NAVSUGGEST, base::string16(), std::string(),
2737 false, 0, false, ASCIIToUTF16(cases[i].input), std::string());
2738 result_prevent_inline.set_received_after_last_keystroke(false);
2739 AutocompleteMatch match_prevent_inline(
2740 provider_->NavigationToMatch(result_prevent_inline));
2741 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
2742 match_prevent_inline.inline_autocompletion);
2743 EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit),
2744 match_prevent_inline.fill_into_edit);
2745 EXPECT_EQ(cases[i].allowed_to_be_default_match_in_prevent_inline_mode,
2746 match_prevent_inline.allowed_to_be_default_match);
2750 // Verifies that "http://" is not trimmed for input that is a leading substring.
2751 TEST_F(SearchProviderTest, NavigationInlineSchemeSubstring) {
2752 const base::string16 input(ASCIIToUTF16("ht"));
2753 const base::string16 url(ASCIIToUTF16("http://a.com"));
2754 SearchSuggestionParser::NavigationResult result(
2755 ChromeAutocompleteSchemeClassifier(&profile_), GURL(url),
2756 AutocompleteMatchType::NAVSUGGEST,
2757 base::string16(), std::string(), false, 0, false, input, std::string());
2758 result.set_received_after_last_keystroke(false);
2760 // Check the offset and strings when inline autocompletion is allowed.
2761 QueryForInput(input, false, false);
2762 AutocompleteMatch match_inline(provider_->NavigationToMatch(result));
2763 EXPECT_EQ(url, match_inline.fill_into_edit);
2764 EXPECT_EQ(url.substr(2), match_inline.inline_autocompletion);
2765 EXPECT_TRUE(match_inline.allowed_to_be_default_match);
2766 EXPECT_EQ(url, match_inline.contents);
2768 // Check the same strings when inline autocompletion is prevented.
2769 QueryForInput(input, true, false);
2770 AutocompleteMatch match_prevent(provider_->NavigationToMatch(result));
2771 EXPECT_EQ(url, match_prevent.fill_into_edit);
2772 EXPECT_FALSE(match_prevent.allowed_to_be_default_match);
2773 EXPECT_EQ(url, match_prevent.contents);
2776 // Verifies that input "w" marks a more significant domain label than "www.".
2777 TEST_F(SearchProviderTest, NavigationInlineDomainClassify) {
2778 QueryForInput(ASCIIToUTF16("w"), false, false);
2779 SearchSuggestionParser::NavigationResult result(
2780 ChromeAutocompleteSchemeClassifier(&profile_),
2781 GURL("http://www.wow.com"), AutocompleteMatchType::NAVSUGGEST,
2782 base::string16(), std::string(), false, 0, false, ASCIIToUTF16("w"),
2783 std::string());
2784 result.set_received_after_last_keystroke(false);
2785 AutocompleteMatch match(provider_->NavigationToMatch(result));
2786 EXPECT_EQ(ASCIIToUTF16("ow.com"), match.inline_autocompletion);
2787 EXPECT_TRUE(match.allowed_to_be_default_match);
2788 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.fill_into_edit);
2789 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.contents);
2791 // Ensure that the match for input "w" is marked on "wow" and not "www".
2792 ASSERT_EQ(3U, match.contents_class.size());
2793 EXPECT_EQ(0U, match.contents_class[0].offset);
2794 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL,
2795 match.contents_class[0].style);
2796 EXPECT_EQ(4U, match.contents_class[1].offset);
2797 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL |
2798 AutocompleteMatch::ACMatchClassification::MATCH,
2799 match.contents_class[1].style);
2800 EXPECT_EQ(5U, match.contents_class[2].offset);
2801 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL,
2802 match.contents_class[2].style);
2805 #if !defined(OS_WIN)
2806 // Verify entity suggestion parsing.
2807 TEST_F(SearchProviderTest, ParseEntitySuggestion) {
2808 struct Match {
2809 std::string contents;
2810 std::string description;
2811 std::string query_params;
2812 std::string fill_into_edit;
2813 AutocompleteMatchType::Type type;
2815 const Match kEmptyMatch = {
2816 kNotApplicable, kNotApplicable, kNotApplicable, kNotApplicable,
2817 AutocompleteMatchType::NUM_TYPES};
2819 struct {
2820 const std::string input_text;
2821 const std::string response_json;
2822 const Match matches[5];
2823 } cases[] = {
2824 // A query and an entity suggestion with different search terms.
2825 { "x",
2826 "[\"x\",[\"xy\", \"yy\"],[\"\",\"\"],[],"
2827 " {\"google:suggestdetail\":[{},"
2828 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2829 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2830 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2831 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST },
2832 { "xy", "A", "p=v", "yy",
2833 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY },
2834 kEmptyMatch,
2835 kEmptyMatch
2838 // A query and an entity suggestion with same search terms.
2839 { "x",
2840 "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
2841 " {\"google:suggestdetail\":[{},"
2842 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2843 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2844 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2845 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST },
2846 { "xy", "A", "p=v", "xy",
2847 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY },
2848 kEmptyMatch,
2849 kEmptyMatch
2853 for (size_t i = 0; i < arraysize(cases); ++i) {
2854 QueryForInputAndWaitForFetcherResponses(
2855 ASCIIToUTF16(cases[i].input_text), false, cases[i].response_json,
2856 std::string());
2858 const ACMatches& matches = provider_->matches();
2859 ASSERT_FALSE(matches.empty());
2861 SCOPED_TRACE("for input with json = " + cases[i].response_json);
2863 ASSERT_LE(matches.size(), arraysize(cases[i].matches));
2864 size_t j = 0;
2865 // Ensure that the returned matches equal the expectations.
2866 for (; j < matches.size(); ++j) {
2867 const Match& match = cases[i].matches[j];
2868 SCOPED_TRACE(" and match index: " + base::IntToString(j));
2869 EXPECT_EQ(match.contents,
2870 base::UTF16ToUTF8(matches[j].contents));
2871 EXPECT_EQ(match.description,
2872 base::UTF16ToUTF8(matches[j].description));
2873 EXPECT_EQ(match.query_params,
2874 matches[j].search_terms_args->suggest_query_params);
2875 EXPECT_EQ(match.fill_into_edit,
2876 base::UTF16ToUTF8(matches[j].fill_into_edit));
2877 EXPECT_EQ(match.type, matches[j].type);
2879 // Ensure that no expected matches are missing.
2880 for (; j < arraysize(cases[i].matches); ++j) {
2881 SCOPED_TRACE(" and match index: " + base::IntToString(j));
2882 EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
2883 EXPECT_EQ(cases[i].matches[j].description, kNotApplicable);
2884 EXPECT_EQ(cases[i].matches[j].query_params, kNotApplicable);
2885 EXPECT_EQ(cases[i].matches[j].fill_into_edit, kNotApplicable);
2886 EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
2890 #endif // !defined(OS_WIN)
2893 // A basic test that verifies the prefetch metadata parsing logic.
2894 TEST_F(SearchProviderTest, PrefetchMetadataParsing) {
2895 struct Match {
2896 std::string contents;
2897 bool allowed_to_be_prefetched;
2898 AutocompleteMatchType::Type type;
2899 bool from_keyword;
2901 const Match kEmptyMatch = { kNotApplicable,
2902 false,
2903 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2904 false };
2906 struct {
2907 const std::string input_text;
2908 bool prefer_keyword_provider_results;
2909 const std::string default_provider_response_json;
2910 const std::string keyword_provider_response_json;
2911 const Match matches[5];
2912 } cases[] = {
2913 // Default provider response does not have prefetch details. Ensure that the
2914 // suggestions are not marked as prefetch query.
2915 { "a",
2916 false,
2917 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2918 std::string(),
2919 { { "a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2920 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2921 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2922 kEmptyMatch,
2923 kEmptyMatch
2926 // Ensure that default provider suggest response prefetch details are
2927 // parsed and recorded in AutocompleteMatch.
2928 { "ab",
2929 false,
2930 "[\"ab\",[\"abc\", \"http://b.com\", \"http://c.com\"],[],[],"
2931 "{\"google:clientdata\":{\"phi\": 0},"
2932 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"NAVIGATION\"],"
2933 "\"google:suggestrelevance\":[999, 12, 1]}]",
2934 std::string(),
2935 { { "ab", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2936 { "abc", true, AutocompleteMatchType::SEARCH_SUGGEST, false },
2937 { "b.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2938 { "c.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2939 kEmptyMatch
2942 // Default provider suggest response has prefetch details.
2943 // SEARCH_WHAT_YOU_TYPE suggestion outranks SEARCH_SUGGEST suggestion for
2944 // the same query string. Ensure that the prefetch details from
2945 // SEARCH_SUGGEST match are set onto SEARCH_WHAT_YOU_TYPE match.
2946 { "ab",
2947 false,
2948 "[\"ab\",[\"ab\", \"http://ab.com\"],[],[],"
2949 "{\"google:clientdata\":{\"phi\": 0},"
2950 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2951 "\"google:suggestrelevance\":[99, 98]}]",
2952 std::string(),
2953 { {"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2954 {"ab.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2955 kEmptyMatch,
2956 kEmptyMatch,
2957 kEmptyMatch
2960 // Default provider response has prefetch details. We prefer keyword
2961 // provider results. Ensure that prefetch bit for a suggestion from the
2962 // default search provider does not get copied onto a higher-scoring match
2963 // for the same query string from the keyword provider.
2964 { "k a",
2965 true,
2966 "[\"k a\",[\"a\", \"ab\"],[],[], {\"google:clientdata\":{\"phi\": 0},"
2967 "\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2968 "\"google:suggestrelevance\":[9, 12]}]",
2969 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2970 { { "a", false, AutocompleteMatchType::SEARCH_OTHER_ENGINE, true},
2971 { "k a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2972 { "ab", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2973 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST, true },
2974 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST, true }
2979 for (size_t i = 0; i < arraysize(cases); ++i) {
2980 QueryForInputAndWaitForFetcherResponses(
2981 ASCIIToUTF16(cases[i].input_text),
2982 cases[i].prefer_keyword_provider_results,
2983 cases[i].default_provider_response_json,
2984 cases[i].prefer_keyword_provider_results ?
2985 cases[i].keyword_provider_response_json : std::string());
2987 const std::string description =
2988 "for input with json =" + cases[i].default_provider_response_json;
2989 const ACMatches& matches = provider_->matches();
2990 // The top match must inline and score as highly as calculated verbatim.
2991 ASSERT_FALSE(matches.empty());
2992 EXPECT_GE(matches[0].relevance, 1300);
2994 ASSERT_LE(matches.size(), arraysize(cases[i].matches));
2995 // Ensure that the returned matches equal the expectations.
2996 for (size_t j = 0; j < matches.size(); ++j) {
2997 SCOPED_TRACE(description);
2998 EXPECT_EQ(cases[i].matches[j].contents,
2999 base::UTF16ToUTF8(matches[j].contents));
3000 EXPECT_EQ(cases[i].matches[j].allowed_to_be_prefetched,
3001 SearchProvider::ShouldPrefetch(matches[j]));
3002 EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
3003 EXPECT_EQ(cases[i].matches[j].from_keyword,
3004 matches[j].keyword == ASCIIToUTF16("k"));
3009 TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_InvalidResponse) {
3010 ClearAllResults();
3012 std::string input_str("abc");
3013 QueryForInputAndWaitForFetcherResponses(
3014 ASCIIToUTF16(input_str), false, "this is a bad non-json response",
3015 std::string());
3017 const ACMatches& matches = provider_->matches();
3019 // Should have exactly one "search what you typed" match
3020 ASSERT_TRUE(matches.size() == 1);
3021 EXPECT_EQ(input_str, base::UTF16ToUTF8(matches[0].contents));
3022 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
3023 matches[0].type);
3026 // A basic test that verifies that the XSSI guarded JSON response is parsed
3027 // correctly.
3028 TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_ValidResponses) {
3029 struct Match {
3030 std::string contents;
3031 AutocompleteMatchType::Type type;
3033 const Match kEmptyMatch = {
3034 kNotApplicable, AutocompleteMatchType::NUM_TYPES
3037 struct {
3038 const std::string input_text;
3039 const std::string default_provider_response_json;
3040 const Match matches[4];
3041 } cases[] = {
3042 // No XSSI guard.
3043 { "a",
3044 "[\"a\",[\"b\", \"c\"],[],[],"
3045 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
3046 "\"google:suggestrelevance\":[1, 2]}]",
3047 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
3048 { "c", AutocompleteMatchType::SEARCH_SUGGEST },
3049 { "b", AutocompleteMatchType::SEARCH_SUGGEST },
3050 kEmptyMatch,
3053 // Standard XSSI guard - )]}'\n.
3054 { "a",
3055 ")]}'\n[\"a\",[\"b\", \"c\"],[],[],"
3056 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
3057 "\"google:suggestrelevance\":[1, 2]}]",
3058 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
3059 { "c", AutocompleteMatchType::SEARCH_SUGGEST },
3060 { "b", AutocompleteMatchType::SEARCH_SUGGEST },
3061 kEmptyMatch,
3064 // Modified XSSI guard - contains "[".
3065 { "a",
3066 ")]}'\n[)\"[\"a\",[\"b\", \"c\"],[],[],"
3067 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
3068 "\"google:suggestrelevance\":[1, 2]}]",
3069 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
3070 { "c", AutocompleteMatchType::SEARCH_SUGGEST },
3071 { "b", AutocompleteMatchType::SEARCH_SUGGEST },
3072 kEmptyMatch,
3077 for (size_t i = 0; i < arraysize(cases); ++i) {
3078 ClearAllResults();
3079 QueryForInputAndWaitForFetcherResponses(
3080 ASCIIToUTF16(cases[i].input_text), false,
3081 cases[i].default_provider_response_json, std::string());
3083 const ACMatches& matches = provider_->matches();
3084 // The top match must inline and score as highly as calculated verbatim.
3085 ASSERT_FALSE(matches.empty());
3086 EXPECT_GE(matches[0].relevance, 1300);
3088 SCOPED_TRACE("for case: " + base::IntToString(i));
3089 ASSERT_LE(matches.size(), arraysize(cases[i].matches));
3090 size_t j = 0;
3091 // Ensure that the returned matches equal the expectations.
3092 for (; j < matches.size(); ++j) {
3093 SCOPED_TRACE("and match: " + base::IntToString(j));
3094 EXPECT_EQ(cases[i].matches[j].contents,
3095 base::UTF16ToUTF8(matches[j].contents));
3096 EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
3098 for (; j < arraysize(cases[i].matches); ++j) {
3099 SCOPED_TRACE("and match: " + base::IntToString(j));
3100 EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
3101 EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
3106 // Test that deletion url gets set on an AutocompleteMatch when available for a
3107 // personalized query or a personalized URL.
3108 TEST_F(SearchProviderTest, ParseDeletionUrl) {
3109 struct Match {
3110 std::string contents;
3111 std::string deletion_url;
3112 AutocompleteMatchType::Type type;
3115 const Match kEmptyMatch = {
3116 kNotApplicable, std::string(), AutocompleteMatchType::NUM_TYPES
3119 const char* url[] = {
3120 "http://defaultturl/complete/deleteitems"
3121 "?delq=ab&client=chrome&deltok=xsrf124",
3122 "http://defaultturl/complete/deleteitems"
3123 "?delq=www.amazon.com&client=chrome&deltok=xsrf123",
3126 struct {
3127 const std::string input_text;
3128 const std::string response_json;
3129 const Match matches[5];
3130 } cases[] = {
3131 // A deletion URL on a personalized query should be reflected in the
3132 // resulting AutocompleteMatch.
3133 { "a",
3134 "[\"a\",[\"ab\", \"ac\",\"www.amazon.com\"],[],[],"
3135 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3136 "\"PERSONALIZED_NAVIGATION\"],"
3137 "\"google:suggestrelevance\":[3, 2, 1],"
3138 "\"google:suggestdetail\":[{\"du\":"
3139 "\"/complete/deleteitems?delq=ab&client=chrome"
3140 "&deltok=xsrf124\"}, {}, {\"du\":"
3141 "\"/complete/deleteitems?delq=www.amazon.com&"
3142 "client=chrome&deltok=xsrf123\"}]}]",
3143 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
3144 { "ab", url[0], AutocompleteMatchType::SEARCH_SUGGEST },
3145 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
3146 { "www.amazon.com", url[1],
3147 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
3148 kEmptyMatch,
3151 // Personalized queries or a personalized URL without deletion URLs
3152 // shouldn't cause errors.
3153 { "a",
3154 "[\"a\",[\"ab\", \"ac\"],[],[],"
3155 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3156 "\"PERSONALIZED_NAVIGATION\"],"
3157 "\"google:suggestrelevance\":[1, 2],"
3158 "\"google:suggestdetail\":[{}, {}]}]",
3159 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
3160 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
3161 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST },
3162 { "www.amazon.com", "",
3163 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
3164 kEmptyMatch,
3167 // Personalized queries or a personalized URL without
3168 // google:suggestdetail shouldn't cause errors.
3169 { "a",
3170 "[\"a\",[\"ab\", \"ac\"],[],[],"
3171 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3172 "\"PERSONALIZED_NAVIGATION\"],"
3173 "\"google:suggestrelevance\":[1, 2]}]",
3174 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
3175 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
3176 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST },
3177 { "www.amazon.com", "",
3178 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
3179 kEmptyMatch,
3184 for (size_t i = 0; i < arraysize(cases); ++i) {
3185 QueryForInputAndWaitForFetcherResponses(
3186 ASCIIToUTF16(cases[i].input_text), false, cases[i].response_json,
3187 std::string());
3189 const ACMatches& matches = provider_->matches();
3190 ASSERT_FALSE(matches.empty());
3192 SCOPED_TRACE("for input with json = " + cases[i].response_json);
3194 for (size_t j = 0; j < matches.size(); ++j) {
3195 const Match& match = cases[i].matches[j];
3196 SCOPED_TRACE(" and match index: " + base::IntToString(j));
3197 EXPECT_EQ(match.contents, base::UTF16ToUTF8(matches[j].contents));
3198 EXPECT_EQ(match.deletion_url, matches[j].GetAdditionalInfo(
3199 "deletion_url"));
3204 TEST_F(SearchProviderTest, ReflectsBookmarkBarState) {
3205 profile_.GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, false);
3206 base::string16 term = term1_.substr(0, term1_.length() - 1);
3207 QueryForInput(term, true, false);
3208 ASSERT_FALSE(provider_->matches().empty());
3209 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
3210 provider_->matches()[0].type);
3211 ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL);
3212 EXPECT_FALSE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned);
3214 profile_.GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
3215 term = term1_.substr(0, term1_.length() - 1);
3216 QueryForInput(term, true, false);
3217 ASSERT_FALSE(provider_->matches().empty());
3218 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
3219 provider_->matches()[0].type);
3220 ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL);
3221 EXPECT_TRUE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned);
3224 TEST_F(SearchProviderTest, CanSendURL) {
3225 TemplateURLData template_url_data;
3226 template_url_data.short_name = ASCIIToUTF16("t");
3227 template_url_data.SetURL("http://www.google.com/{searchTerms}");
3228 template_url_data.suggestions_url = "http://www.google.com/{searchTerms}";
3229 template_url_data.instant_url = "http://does/not/exist?strk=1";
3230 template_url_data.search_terms_replacement_key = "strk";
3231 template_url_data.id = SEARCH_ENGINE_GOOGLE;
3232 TemplateURL google_template_url(template_url_data);
3234 // Create field trial.
3235 CreateFieldTrial(OmniboxFieldTrial::kZeroSuggestRule, true);
3237 ChromeAutocompleteProviderClient client(&profile_);
3239 // Not signed in.
3240 EXPECT_FALSE(SearchProvider::CanSendURL(
3241 GURL("http://www.google.com/search"),
3242 GURL("https://www.google.com/complete/search"), &google_template_url,
3243 metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client));
3244 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(&profile_);
3245 signin->SetAuthenticatedUsername("test");
3247 // All conditions should be met.
3248 EXPECT_TRUE(SearchProvider::CanSendURL(
3249 GURL("http://www.google.com/search"),
3250 GURL("https://www.google.com/complete/search"), &google_template_url,
3251 metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client));
3253 // Not in field trial.
3254 ResetFieldTrialList();
3255 CreateFieldTrial(OmniboxFieldTrial::kZeroSuggestRule, false);
3256 EXPECT_FALSE(SearchProvider::CanSendURL(
3257 GURL("http://www.google.com/search"),
3258 GURL("https://www.google.com/complete/search"), &google_template_url,
3259 metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client));
3260 ResetFieldTrialList();
3261 CreateFieldTrial(OmniboxFieldTrial::kZeroSuggestRule, true);
3263 // Invalid page URL.
3264 EXPECT_FALSE(SearchProvider::CanSendURL(
3265 GURL("badpageurl"),
3266 GURL("https://www.google.com/complete/search"), &google_template_url,
3267 metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client));
3269 // Invalid page classification.
3270 EXPECT_FALSE(SearchProvider::CanSendURL(
3271 GURL("http://www.google.com/search"),
3272 GURL("https://www.google.com/complete/search"), &google_template_url,
3273 metrics::OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS,
3274 SearchTermsData(), &client));
3276 // Invalid page classification.
3277 EXPECT_FALSE(SearchProvider::CanSendURL(
3278 GURL("http://www.google.com/search"),
3279 GURL("https://www.google.com/complete/search"), &google_template_url,
3280 metrics::OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS,
3281 SearchTermsData(), &client));
3283 // HTTPS page URL on same domain as provider.
3284 EXPECT_TRUE(SearchProvider::CanSendURL(
3285 GURL("https://www.google.com/search"),
3286 GURL("https://www.google.com/complete/search"),
3287 &google_template_url, metrics::OmniboxEventProto::OTHER,
3288 SearchTermsData(), &client));
3290 // Non-HTTP[S] page URL on same domain as provider.
3291 EXPECT_FALSE(SearchProvider::CanSendURL(
3292 GURL("ftp://www.google.com/search"),
3293 GURL("https://www.google.com/complete/search"), &google_template_url,
3294 metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client));
3296 // Non-HTTP page URL on different domain.
3297 EXPECT_FALSE(SearchProvider::CanSendURL(
3298 GURL("https://www.notgoogle.com/search"),
3299 GURL("https://www.google.com/complete/search"), &google_template_url,
3300 metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client));
3302 // Non-HTTPS provider.
3303 EXPECT_FALSE(SearchProvider::CanSendURL(
3304 GURL("http://www.google.com/search"),
3305 GURL("http://www.google.com/complete/search"), &google_template_url,
3306 metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client));
3308 // Suggest disabled.
3309 profile_.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false);
3310 EXPECT_FALSE(SearchProvider::CanSendURL(
3311 GURL("http://www.google.com/search"),
3312 GURL("https://www.google.com/complete/search"), &google_template_url,
3313 metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client));
3314 profile_.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
3316 // Incognito.
3317 ChromeAutocompleteProviderClient client_incognito(
3318 profile_.GetOffTheRecordProfile());
3319 EXPECT_FALSE(SearchProvider::CanSendURL(
3320 GURL("http://www.google.com/search"),
3321 GURL("https://www.google.com/complete/search"), &google_template_url,
3322 metrics::OmniboxEventProto::OTHER, SearchTermsData(),
3323 &client_incognito));
3325 // Tab sync not enabled.
3326 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncKeepEverythingSynced,
3327 false);
3328 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs, false);
3329 EXPECT_FALSE(SearchProvider::CanSendURL(
3330 GURL("http://www.google.com/search"),
3331 GURL("https://www.google.com/complete/search"), &google_template_url,
3332 metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client));
3333 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs, true);
3335 // Tab sync is encrypted.
3336 ProfileSyncService* service =
3337 ProfileSyncServiceFactory::GetInstance()->GetForProfile(&profile_);
3338 syncer::ModelTypeSet encrypted_types = service->GetEncryptedDataTypes();
3339 encrypted_types.Put(syncer::SESSIONS);
3340 service->OnEncryptedTypesChanged(encrypted_types, false);
3341 EXPECT_FALSE(SearchProvider::CanSendURL(
3342 GURL("http://www.google.com/search"),
3343 GURL("https://www.google.com/complete/search"), &google_template_url,
3344 metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client));
3345 encrypted_types.Remove(syncer::SESSIONS);
3346 service->OnEncryptedTypesChanged(encrypted_types, false);
3348 // Check that there were no side effects from previous tests.
3349 EXPECT_TRUE(SearchProvider::CanSendURL(
3350 GURL("http://www.google.com/search"),
3351 GURL("https://www.google.com/complete/search"), &google_template_url,
3352 metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client));
3355 TEST_F(SearchProviderTest, TestDeleteMatch) {
3356 AutocompleteMatch match(
3357 provider_.get(), 0, true, AutocompleteMatchType::SEARCH_SUGGEST);
3358 match.RecordAdditionalInfo(
3359 SearchProvider::kDeletionUrlKey,
3360 "https://www.google.com/complete/deleteitem?q=foo");
3362 // Test a successful deletion request.
3363 provider_->matches_.push_back(match);
3364 provider_->DeleteMatch(match);
3365 EXPECT_FALSE(provider_->deletion_handlers_.empty());
3366 EXPECT_TRUE(provider_->matches_.empty());
3367 // Set up a default fetcher with provided results.
3368 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
3369 SearchProvider::kDeletionURLFetcherID);
3370 ASSERT_TRUE(fetcher);
3371 fetcher->set_response_code(200);
3372 fetcher->delegate()->OnURLFetchComplete(fetcher);
3373 EXPECT_TRUE(provider_->deletion_handlers_.empty());
3374 EXPECT_TRUE(provider_->is_success());
3376 // Test a failing deletion request.
3377 provider_->matches_.push_back(match);
3378 provider_->DeleteMatch(match);
3379 EXPECT_FALSE(provider_->deletion_handlers_.empty());
3380 // Set up a default fetcher with provided results.
3381 fetcher = test_factory_.GetFetcherByID(
3382 SearchProvider::kDeletionURLFetcherID);
3383 ASSERT_TRUE(fetcher);
3384 fetcher->set_response_code(500);
3385 fetcher->delegate()->OnURLFetchComplete(fetcher);
3386 EXPECT_TRUE(provider_->deletion_handlers_.empty());
3387 EXPECT_FALSE(provider_->is_success());
3390 TEST_F(SearchProviderTest, TestDeleteHistoryQueryMatch) {
3391 GURL term_url(
3392 AddSearchToHistory(default_t_url_, ASCIIToUTF16("flash games"), 1));
3393 profile_.BlockUntilHistoryProcessesPendingRequests();
3395 AutocompleteMatch games;
3396 QueryForInput(ASCIIToUTF16("fla"), false, false);
3397 profile_.BlockUntilHistoryProcessesPendingRequests();
3398 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3399 ASSERT_TRUE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games));
3401 size_t matches_before = provider_->matches().size();
3402 provider_->DeleteMatch(games);
3403 EXPECT_EQ(matches_before - 1, provider_->matches().size());
3405 // Process history deletions.
3406 profile_.BlockUntilHistoryProcessesPendingRequests();
3408 // Check that the match is gone.
3409 QueryForInput(ASCIIToUTF16("fla"), false, false);
3410 profile_.BlockUntilHistoryProcessesPendingRequests();
3411 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3412 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games));
3415 // Verifies that duplicates are preserved in AddMatchToMap().
3416 TEST_F(SearchProviderTest, CheckDuplicateMatchesSaved) {
3417 AddSearchToHistory(default_t_url_, ASCIIToUTF16("a"), 1);
3418 AddSearchToHistory(default_t_url_, ASCIIToUTF16("alpha"), 1);
3419 AddSearchToHistory(default_t_url_, ASCIIToUTF16("avid"), 1);
3421 profile_.BlockUntilHistoryProcessesPendingRequests();
3422 QueryForInputAndWaitForFetcherResponses(
3423 ASCIIToUTF16("a"), false,
3424 "[\"a\",[\"a\", \"alpha\", \"avid\", \"apricot\"],[],[],"
3425 "{\"google:suggestrelevance\":[1450, 1200, 1150, 1100],"
3426 "\"google:verbatimrelevance\":1350}]",
3427 std::string());
3429 AutocompleteMatch verbatim, match_alpha, match_apricot, match_avid;
3430 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim));
3431 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("alpha"), &match_alpha));
3432 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("apricot"), &match_apricot));
3433 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("avid"), &match_avid));
3435 // Verbatim match duplicates are added such that each one has a higher
3436 // relevance than the previous one.
3437 EXPECT_EQ(2U, verbatim.duplicate_matches.size());
3439 // Other match duplicates are added in descending relevance order.
3440 EXPECT_EQ(1U, match_alpha.duplicate_matches.size());
3441 EXPECT_EQ(1U, match_avid.duplicate_matches.size());
3443 EXPECT_EQ(0U, match_apricot.duplicate_matches.size());
3446 TEST_F(SearchProviderTest, SuggestQueryUsesToken) {
3447 TemplateURLService* turl_model =
3448 TemplateURLServiceFactory::GetForProfile(&profile_);
3450 TemplateURLData data;
3451 data.short_name = ASCIIToUTF16("default");
3452 data.SetKeyword(data.short_name);
3453 data.SetURL("http://example/{searchTerms}{google:sessionToken}");
3454 data.suggestions_url =
3455 "http://suggest/?q={searchTerms}&{google:sessionToken}";
3456 default_t_url_ = new TemplateURL(data);
3457 turl_model->Add(default_t_url_);
3458 turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
3460 base::string16 term = term1_.substr(0, term1_.length() - 1);
3461 QueryForInput(term, false, false);
3463 // Make sure the default provider's suggest service was queried.
3464 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
3465 SearchProvider::kDefaultProviderURLFetcherID);
3466 ASSERT_TRUE(fetcher);
3468 // And the URL matches what we expected.
3469 TemplateURLRef::SearchTermsArgs search_terms_args(term);
3470 search_terms_args.session_token = provider_->current_token_;
3471 GURL expected_url(default_t_url_->suggestions_url_ref().ReplaceSearchTerms(
3472 search_terms_args, turl_model->search_terms_data()));
3473 EXPECT_EQ(fetcher->GetOriginalURL().spec(), expected_url.spec());
3475 // Complete running the fetcher to clean up.
3476 fetcher->set_response_code(200);
3477 fetcher->delegate()->OnURLFetchComplete(fetcher);
3478 RunTillProviderDone();
3481 TEST_F(SearchProviderTest, SessionToken) {
3482 // Subsequent calls always get the same token.
3483 std::string token = provider_->GetSessionToken();
3484 std::string token2 = provider_->GetSessionToken();
3485 EXPECT_EQ(token, token2);
3486 EXPECT_FALSE(token.empty());
3488 // Calls do not regenerate a token.
3489 provider_->current_token_ = "PRE-EXISTING TOKEN";
3490 token = provider_->GetSessionToken();
3491 EXPECT_EQ(token, "PRE-EXISTING TOKEN");
3493 // ... unless the token has expired.
3494 provider_->current_token_.clear();
3495 const base::TimeDelta kSmallDelta = base::TimeDelta::FromMilliseconds(1);
3496 provider_->token_expiration_time_ = base::TimeTicks::Now() - kSmallDelta;
3497 token = provider_->GetSessionToken();
3498 EXPECT_FALSE(token.empty());
3499 EXPECT_EQ(token, provider_->current_token_);
3501 // The expiration time is always updated.
3502 provider_->GetSessionToken();
3503 base::TimeTicks expiration_time_1 = provider_->token_expiration_time_;
3504 base::PlatformThread::Sleep(kSmallDelta);
3505 provider_->GetSessionToken();
3506 base::TimeTicks expiration_time_2 = provider_->token_expiration_time_;
3507 EXPECT_GT(expiration_time_2, expiration_time_1);
3508 EXPECT_GE(expiration_time_2, expiration_time_1 + kSmallDelta);
3511 TEST_F(SearchProviderTest, AnswersCache) {
3512 AutocompleteResult result;
3513 ACMatches matches;
3514 AutocompleteMatch match1;
3515 match1.answer_contents = base::ASCIIToUTF16("m1");
3516 match1.answer_type = base::ASCIIToUTF16("2334");
3517 match1.fill_into_edit = base::ASCIIToUTF16("weather los angeles");
3519 AutocompleteMatch non_answer_match1;
3520 non_answer_match1.fill_into_edit = base::ASCIIToUTF16("weather laguna beach");
3522 // Test that an answer in the first slot populates the cache.
3523 matches.push_back(match1);
3524 matches.push_back(non_answer_match1);
3525 result.AppendMatches(matches);
3526 provider_->RegisterDisplayedAnswers(result);
3527 ASSERT_FALSE(provider_->answers_cache_.empty());
3529 // Without scored results, no answers will be retrieved.
3530 AnswersQueryData answer = provider_->FindAnswersPrefetchData();
3531 EXPECT_TRUE(answer.full_query_text.empty());
3532 EXPECT_TRUE(answer.query_type.empty());
3534 // Inject a scored result, which will trigger answer retrieval.
3535 base::string16 query = base::ASCIIToUTF16("weather los angeles");
3536 SearchSuggestionParser::SuggestResult suggest_result(
3537 query, AutocompleteMatchType::SEARCH_HISTORY, query, base::string16(),
3538 base::string16(), base::string16(), base::string16(), nullptr,
3539 std::string(), std::string(), false, 1200, false, false, query);
3540 QueryForInput(ASCIIToUTF16("weather l"), false, false);
3541 provider_->transformed_default_history_results_.push_back(suggest_result);
3542 answer = provider_->FindAnswersPrefetchData();
3543 EXPECT_EQ(base::ASCIIToUTF16("weather los angeles"), answer.full_query_text);
3544 EXPECT_EQ(base::ASCIIToUTF16("2334"), answer.query_type);
3547 TEST_F(SearchProviderTest, RemoveExtraAnswers) {
3548 SuggestionAnswer answer1;
3549 answer1.set_type(42);
3550 SuggestionAnswer answer2;
3551 answer2.set_type(1983);
3552 SuggestionAnswer answer3;
3553 answer3.set_type(423);
3555 ACMatches matches;
3556 AutocompleteMatch match1, match2, match3, match4, match5;
3557 match1.answer = SuggestionAnswer::copy(&answer1);
3558 match1.answer_contents = base::ASCIIToUTF16("the answer");
3559 match1.answer_type = base::ASCIIToUTF16("42");
3560 match3.answer = SuggestionAnswer::copy(&answer2);
3561 match3.answer_contents = base::ASCIIToUTF16("not to play");
3562 match3.answer_type = base::ASCIIToUTF16("1983");
3563 match5.answer = SuggestionAnswer::copy(&answer3);
3564 match5.answer_contents = base::ASCIIToUTF16("a man");
3565 match5.answer_type = base::ASCIIToUTF16("423");
3567 matches.push_back(match1);
3568 matches.push_back(match2);
3569 matches.push_back(match3);
3570 matches.push_back(match4);
3571 matches.push_back(match5);
3573 SearchProvider::RemoveExtraAnswers(&matches);
3574 EXPECT_EQ(base::ASCIIToUTF16("the answer"), matches[0].answer_contents);
3575 EXPECT_EQ(base::ASCIIToUTF16("42"), matches[0].answer_type);
3576 EXPECT_TRUE(answer1.Equals(*matches[0].answer));
3577 EXPECT_TRUE(matches[1].answer_contents.empty());
3578 EXPECT_TRUE(matches[1].answer_type.empty());
3579 EXPECT_FALSE(matches[1].answer);
3580 EXPECT_TRUE(matches[2].answer_contents.empty());
3581 EXPECT_TRUE(matches[2].answer_type.empty());
3582 EXPECT_FALSE(matches[2].answer);
3583 EXPECT_TRUE(matches[3].answer_contents.empty());
3584 EXPECT_TRUE(matches[3].answer_type.empty());
3585 EXPECT_FALSE(matches[3].answer);
3586 EXPECT_TRUE(matches[4].answer_contents.empty());
3587 EXPECT_TRUE(matches[4].answer_type.empty());
3588 EXPECT_FALSE(matches[4].answer);
3591 TEST_F(SearchProviderTest, DoesNotProvideOnFocus) {
3592 AutocompleteInput input(base::ASCIIToUTF16("f"), base::string16::npos,
3593 std::string(), GURL(),
3594 metrics::OmniboxEventProto::INVALID_SPEC, false,
3595 true, true, true,
3596 ChromeAutocompleteSchemeClassifier(&profile_));
3597 provider_->Start(input, false, true);
3598 EXPECT_TRUE(provider_->matches().empty());