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"
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.h"
25 #include "chrome/browser/history/history_service_factory.h"
26 #include "chrome/browser/search_engines/template_url_service_factory.h"
27 #include "chrome/browser/signin/signin_manager_factory.h"
28 #include "chrome/browser/sync/profile_sync_service.h"
29 #include "chrome/browser/sync/profile_sync_service_factory.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/pref_names.h"
32 #include "chrome/test/base/testing_browser_process.h"
33 #include "chrome/test/base/testing_profile.h"
34 #include "components/google/core/browser/google_switches.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
;
61 // Returns the first match in |matches| with |allowed_to_be_default_match|
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
)
70 class SuggestionDeletionHandler
;
71 class SearchProviderForTest
: public SearchProvider
{
73 SearchProviderForTest(AutocompleteProviderListener
* listener
,
74 TemplateURLService
* template_url_service
,
76 bool is_success() { return is_success_
; }
79 ~SearchProviderForTest() override
;
82 void RecordDeletionResult(bool success
) override
;
84 DISALLOW_COPY_AND_ASSIGN(SearchProviderForTest
);
87 SearchProviderForTest::SearchProviderForTest(
88 AutocompleteProviderListener
* listener
,
89 TemplateURLService
* template_url_service
,
91 : SearchProvider(listener
, template_url_service
,
92 scoped_ptr
<AutocompleteProviderClient
>(
93 new ChromeAutocompleteProviderClient(profile
))),
97 SearchProviderForTest::~SearchProviderForTest() {
100 void SearchProviderForTest::RecordDeletionResult(bool success
) {
101 is_success_
= success
;
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
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
{
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
)
129 result_type(result_type
),
130 allowed_to_be_default_match(allowed_to_be_default_match
),
131 fill_into_edit(fill_into_edit
) {
135 const AutocompleteMatch::Type result_type
;
136 const bool allowed_to_be_default_match
;
137 const base::string16 fill_into_edit
;
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
;
152 : default_t_url_(NULL
),
153 term1_(ASCIIToUTF16("term1")),
154 keyword_t_url_(NULL
),
155 keyword_term_(ASCIIToUTF16("keyword")),
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
);
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 /
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
,
244 void ClearAllResults();
246 // See description above class for details of these fields.
247 TemplateURL
* default_t_url_
;
248 const base::string16 term1_
;
250 TemplateURL
* keyword_t_url_
;
251 const base::string16 keyword_term_
;
254 content::TestBrowserThreadBundle thread_bundle_
;
256 // URLFetcherFactory implementation registered.
257 net::TestURLFetcherFactory test_factory_
;
260 TestingProfile profile_
;
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
);
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_
);
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.
337 void SearchProviderTest::RunTest(TestData
* cases
,
339 bool prefer_keyword
) {
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();
350 ASCIIToUTF16("Input was: ") +
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()) {
375 void SearchProviderTest::RunTillProviderDone() {
376 if (provider_
->done())
379 base::RunLoop run_loop
;
380 run_loop_
= &run_loop
;
384 void SearchProviderTest::QueryForInput(const base::string16
& text
,
385 bool prevent_inline_autocomplete
,
386 bool prefer_keyword
) {
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
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());
407 ASSERT_GE(provider_
->matches().size(), 1u);
408 EXPECT_TRUE(FindMatchWithDestination(
409 GURL(default_t_url_
->url_ref().ReplaceSearchTerms(
410 TemplateURLRef::SearchTermsArgs(base::CollapseWhitespace(
412 TemplateURLServiceFactory::GetForProfile(
413 &profile_
)->search_terms_data())),
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
,
445 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
);
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
) {
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
) {
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);
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
) <<
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
);
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
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");
556 base::FieldTrial
* SearchProviderTest::CreateFieldTrial(
557 const char* field_trial_rule
,
559 std::map
<std::string
, std::string
> params
;
560 params
[std::string(field_trial_rule
)] = enabled
?
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
);
597 // Run till the history results complete.
598 RunTillProviderDone();
600 // The SearchProvider is done. Make sure it has a result for the history
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())),
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 TEST_F(SearchProviderTest
, HonorPreventInlineAutocomplete
) {
625 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
626 QueryForInput(term
, true, false);
628 ASSERT_FALSE(provider_
->matches().empty());
629 ASSERT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
630 provider_
->matches()[0].type
);
631 EXPECT_TRUE(provider_
->matches()[0].allowed_to_be_default_match
);
634 // Issues a query that matches the registered keyword and makes sure history
635 // is queried as well as URLFetchers getting created.
636 TEST_F(SearchProviderTest
, QueryKeywordProvider
) {
637 base::string16 term
= keyword_term_
.substr(0, keyword_term_
.length() - 1);
638 QueryForInput(keyword_t_url_
->keyword() + ASCIIToUTF16(" ") + term
,
642 // Make sure the default providers suggest service was queried.
643 net::TestURLFetcher
* default_fetcher
= test_factory_
.GetFetcherByID(
644 SearchProvider::kDefaultProviderURLFetcherID
);
645 ASSERT_TRUE(default_fetcher
);
647 // Tell the SearchProvider the default suggest query is done.
648 default_fetcher
->set_response_code(200);
649 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
650 default_fetcher
= NULL
;
652 // Make sure the keyword providers suggest service was queried.
653 net::TestURLFetcher
* keyword_fetcher
= test_factory_
.GetFetcherByID(
654 SearchProvider::kKeywordProviderURLFetcherID
);
655 ASSERT_TRUE(keyword_fetcher
);
657 // And the URL matches what we expected.
658 GURL
expected_url(keyword_t_url_
->suggestions_url_ref().ReplaceSearchTerms(
659 TemplateURLRef::SearchTermsArgs(term
),
660 TemplateURLServiceFactory::GetForProfile(
661 &profile_
)->search_terms_data()));
662 ASSERT_TRUE(keyword_fetcher
->GetOriginalURL() == expected_url
);
664 // Tell the SearchProvider the keyword suggest query is done.
665 keyword_fetcher
->set_response_code(200);
666 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
667 keyword_fetcher
= NULL
;
669 // Run till the history results complete.
670 RunTillProviderDone();
672 // The SearchProvider is done. Make sure it has a result for the history
674 AutocompleteMatch match
;
675 EXPECT_TRUE(FindMatchWithDestination(keyword_url_
, &match
));
677 // The match should have an associated keyword.
678 EXPECT_FALSE(match
.keyword
.empty());
680 // The fill into edit should contain the keyword.
681 EXPECT_EQ(keyword_t_url_
->keyword() + base::char16(' ') + keyword_term_
,
682 match
.fill_into_edit
);
685 TEST_F(SearchProviderTest
, DontSendPrivateDataToSuggest
) {
686 // None of the following input strings should be sent to the suggest server,
687 // because they may contain private data.
688 const char* inputs
[] = {
690 "http://username:password",
691 "https://username:password",
692 "username:password@hostname",
693 "http://username:password@hostname/",
696 "unknownscheme:anything",
697 "http://hostname/?query=q",
698 "http://hostname/path#ref",
699 "http://hostname/path #ref",
700 "https://hostname/path",
703 for (size_t i
= 0; i
< arraysize(inputs
); ++i
) {
704 QueryForInput(ASCIIToUTF16(inputs
[i
]), false, false);
705 // Make sure the default provider's suggest service was not queried.
706 ASSERT_TRUE(test_factory_
.GetFetcherByID(
707 SearchProvider::kDefaultProviderURLFetcherID
) == NULL
);
708 // Run till the history results complete.
709 RunTillProviderDone();
713 TEST_F(SearchProviderTest
, SendNonPrivateDataToSuggest
) {
714 // All of the following input strings should be sent to the suggest server,
715 // because they should not get caught by the private data checks.
716 const char* inputs
[] = {
720 "http://hostname/path",
721 "http://hostname #ref",
722 "www.hostname.com #ref",
725 "foo https://hostname/path"
728 profile_
.BlockUntilHistoryProcessesPendingRequests();
729 for (size_t i
= 0; i
< arraysize(inputs
); ++i
) {
730 QueryForInput(ASCIIToUTF16(inputs
[i
]), false, false);
731 // Make sure the default provider's suggest service was queried.
732 ASSERT_TRUE(test_factory_
.GetFetcherByID(
733 SearchProvider::kDefaultProviderURLFetcherID
) != NULL
);
737 TEST_F(SearchProviderTest
, DontAutocompleteURLLikeTerms
) {
738 GURL url
= AddSearchToHistory(default_t_url_
,
739 ASCIIToUTF16("docs.google.com"), 1);
741 // Add the term as a url.
742 HistoryServiceFactory::GetForProfile(&profile_
,
743 ServiceAccessType::EXPLICIT_ACCESS
)
744 ->AddPageWithDetails(GURL("http://docs.google.com"), base::string16(), 1,
745 1, base::Time::Now(), false,
746 history::SOURCE_BROWSED
);
747 profile_
.BlockUntilHistoryProcessesPendingRequests();
749 AutocompleteMatch wyt_match
;
750 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("docs"),
753 // There should be two matches, one for what you typed, the other for
754 // 'docs.google.com'. The search term should have a lower priority than the
755 // what you typed match.
756 ASSERT_EQ(2u, provider_
->matches().size());
757 AutocompleteMatch term_match
;
758 EXPECT_TRUE(FindMatchWithDestination(url
, &term_match
));
759 EXPECT_GT(wyt_match
.relevance
, term_match
.relevance
);
760 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
761 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
764 TEST_F(SearchProviderTest
, DontGiveNavsuggestionsInForcedQueryMode
) {
765 const std::string kEmptyMatch
;
767 const std::string json
;
768 const std::string matches_in_default_mode
[3];
769 const std::string matches_in_forced_query_mode
[3];
771 // Without suggested relevance scores.
772 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
773 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]}]",
774 { "a", "a1.com", "a2" },
775 { "a", "a2", kEmptyMatch
} },
777 // With suggested relevance scores in a situation where navsuggest would
779 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
780 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
781 "\"google:suggestrelevance\":[1250, 1200]}]",
782 { "a", "a1.com", "a2" },
783 { "a", "a2", kEmptyMatch
} },
785 // With suggested relevance scores in a situation where navsuggest
787 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
788 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
789 "\"google:suggestrelevance\":[1350, 1250]}]",
790 { "a1.com", "a", "a2" },
791 { "a", "a2", kEmptyMatch
} },
793 // With suggested relevance scores in a situation where navsuggest
794 // would go first only because verbatim has been demoted.
795 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
796 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
797 "\"google:suggestrelevance\":[1450, 1400],"
798 "\"google:verbatimrelevance\":1350}]",
799 { "a1.com", "a2", "a" },
800 { "a2", "a", kEmptyMatch
} },
803 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
804 ForcedQueryTestHelper("a", cases
[i
].json
, cases
[i
].matches_in_default_mode
,
805 "regular input with json=" + cases
[i
].json
);
806 ForcedQueryTestHelper("?a", cases
[i
].json
,
807 cases
[i
].matches_in_forced_query_mode
,
808 "forced query input with json=" + cases
[i
].json
);
812 // A multiword search with one visit should not autocomplete until multiple
814 TEST_F(SearchProviderTest
, DontAutocompleteUntilMultipleWordsTyped
) {
815 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("one search"),
817 profile_
.BlockUntilHistoryProcessesPendingRequests();
819 AutocompleteMatch wyt_match
;
820 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("on"),
822 ASSERT_EQ(2u, provider_
->matches().size());
823 AutocompleteMatch term_match
;
824 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
825 EXPECT_GT(wyt_match
.relevance
, term_match
.relevance
);
826 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
827 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
829 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("one se"),
831 ASSERT_EQ(2u, provider_
->matches().size());
832 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
833 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
834 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
835 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
838 // A multiword search with more than one visit should autocomplete immediately.
839 TEST_F(SearchProviderTest
, AutocompleteMultipleVisitsImmediately
) {
840 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("two searches"),
842 profile_
.BlockUntilHistoryProcessesPendingRequests();
844 AutocompleteMatch wyt_match
;
845 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("tw"),
847 ASSERT_EQ(2u, provider_
->matches().size());
848 AutocompleteMatch term_match
;
849 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
850 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
851 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
852 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
855 // Autocompletion should work at a word boundary after a space, and should
856 // offer a suggestion for the trimmed search query.
857 TEST_F(SearchProviderTest
, AutocompleteAfterSpace
) {
858 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("two searches "), 2);
859 GURL
suggested_url(default_t_url_
->url_ref().ReplaceSearchTerms(
860 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("two searches")),
861 TemplateURLServiceFactory::GetForProfile(
862 &profile_
)->search_terms_data()));
863 profile_
.BlockUntilHistoryProcessesPendingRequests();
865 AutocompleteMatch wyt_match
;
866 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("two "),
868 ASSERT_EQ(2u, provider_
->matches().size());
869 AutocompleteMatch term_match
;
870 EXPECT_TRUE(FindMatchWithDestination(suggested_url
, &term_match
));
871 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
872 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
873 EXPECT_EQ(ASCIIToUTF16("searches"), term_match
.inline_autocompletion
);
874 EXPECT_EQ(ASCIIToUTF16("two searches"), term_match
.fill_into_edit
);
875 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
878 // Newer multiword searches should score more highly than older ones.
879 TEST_F(SearchProviderTest
, ScoreNewerSearchesHigher
) {
880 GURL
term_url_a(AddSearchToHistory(default_t_url_
,
881 ASCIIToUTF16("three searches aaa"), 1));
882 GURL
term_url_b(AddSearchToHistory(default_t_url_
,
883 ASCIIToUTF16("three searches bbb"), 1));
884 profile_
.BlockUntilHistoryProcessesPendingRequests();
886 AutocompleteMatch wyt_match
;
887 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("three se"),
889 ASSERT_EQ(3u, provider_
->matches().size());
890 AutocompleteMatch term_match_a
;
891 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
892 AutocompleteMatch term_match_b
;
893 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
894 EXPECT_GT(term_match_b
.relevance
, term_match_a
.relevance
);
895 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
896 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
897 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
898 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
901 // If ScoreHistoryResults doesn't properly clear its output vector it can skip
902 // scoring the actual results and just return results from a previous run.
903 TEST_F(SearchProviderTest
, ResetResultsBetweenRuns
) {
904 GURL
term_url_a(AddSearchToHistory(default_t_url_
,
905 ASCIIToUTF16("games"), 1));
906 GURL
term_url_b(AddSearchToHistory(default_t_url_
,
907 ASCIIToUTF16("gangnam style"), 1));
908 GURL
term_url_c(AddSearchToHistory(default_t_url_
,
909 ASCIIToUTF16("gundam"), 1));
910 profile_
.BlockUntilHistoryProcessesPendingRequests();
912 AutocompleteMatch wyt_match
;
913 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
915 ASSERT_EQ(1u, provider_
->matches().size());
917 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("g"),
919 ASSERT_EQ(4u, provider_
->matches().size());
921 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("ga"),
923 ASSERT_EQ(3u, provider_
->matches().size());
925 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("gan"),
927 ASSERT_EQ(2u, provider_
->matches().size());
929 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("gans"),
931 ASSERT_EQ(1u, provider_
->matches().size());
934 // This test is identical to the previous one except that it enables the Answers
935 // in Suggest field trial which triggers a different code path in
936 // SearchProvider. When Answers launches, this can be removed.
937 TEST_F(SearchProviderTest
, ResetResultsBetweenRunsAnswersInSuggestEnabled
) {
938 CreateFieldTrial(OmniboxFieldTrial::kAnswersInSuggestRule
, true);
940 GURL
term_url_a(AddSearchToHistory(default_t_url_
,
941 ASCIIToUTF16("games"), 1));
942 GURL
term_url_b(AddSearchToHistory(default_t_url_
,
943 ASCIIToUTF16("gangnam style"), 1));
944 GURL
term_url_c(AddSearchToHistory(default_t_url_
,
945 ASCIIToUTF16("gundam"), 1));
946 profile_
.BlockUntilHistoryProcessesPendingRequests();
948 AutocompleteMatch wyt_match
;
949 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
951 ASSERT_EQ(1u, provider_
->matches().size());
953 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("g"),
955 ASSERT_EQ(4u, provider_
->matches().size());
957 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("ga"),
959 ASSERT_EQ(3u, provider_
->matches().size());
961 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("gan"),
963 ASSERT_EQ(2u, provider_
->matches().size());
965 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("gans"),
967 ASSERT_EQ(1u, provider_
->matches().size());
970 // An autocompleted multiword search should not be replaced by a different
971 // autocompletion while the user is still typing a valid prefix unless the
972 // user has typed the prefix as a query before.
973 TEST_F(SearchProviderTest
, DontReplacePreviousAutocompletion
) {
974 GURL
term_url_a(AddSearchToHistory(default_t_url_
,
975 ASCIIToUTF16("four searches aaa"), 3));
976 GURL
term_url_b(AddSearchToHistory(default_t_url_
,
977 ASCIIToUTF16("four searches bbb"), 1));
978 GURL
term_url_c(AddSearchToHistory(default_t_url_
,
979 ASCIIToUTF16("four searches"), 1));
980 profile_
.BlockUntilHistoryProcessesPendingRequests();
982 AutocompleteMatch wyt_match
;
983 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fo"),
985 ASSERT_EQ(4u, provider_
->matches().size());
986 AutocompleteMatch term_match_a
;
987 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
988 AutocompleteMatch term_match_b
;
989 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
990 AutocompleteMatch term_match_c
;
991 EXPECT_TRUE(FindMatchWithDestination(term_url_c
, &term_match_c
));
992 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
993 // We don't care about the relative order of b and c.
994 EXPECT_GT(wyt_match
.relevance
, term_match_b
.relevance
);
995 EXPECT_GT(wyt_match
.relevance
, term_match_c
.relevance
);
996 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
997 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
998 EXPECT_TRUE(term_match_c
.allowed_to_be_default_match
);
999 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
1001 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("four se"),
1003 ASSERT_EQ(4u, provider_
->matches().size());
1004 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
1005 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
1006 EXPECT_TRUE(FindMatchWithDestination(term_url_c
, &term_match_c
));
1007 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
1008 EXPECT_GT(wyt_match
.relevance
, term_match_b
.relevance
);
1009 EXPECT_GT(wyt_match
.relevance
, term_match_c
.relevance
);
1010 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
1011 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
1012 EXPECT_TRUE(term_match_c
.allowed_to_be_default_match
);
1013 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
1015 // For the exact previously-issued query, the what-you-typed match should win.
1016 ASSERT_NO_FATAL_FAILURE(
1017 QueryForInputAndSetWYTMatch(ASCIIToUTF16("four searches"), &wyt_match
));
1018 ASSERT_EQ(3u, provider_
->matches().size());
1019 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
1020 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
1021 EXPECT_GT(wyt_match
.relevance
, term_match_a
.relevance
);
1022 EXPECT_GT(wyt_match
.relevance
, term_match_b
.relevance
);
1023 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
1024 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
1025 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
1028 // Non-completable multiword searches should not crowd out single-word searches.
1029 TEST_F(SearchProviderTest
, DontCrowdOutSingleWords
) {
1030 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five"), 1));
1031 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches bbb"), 1);
1032 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches ccc"), 1);
1033 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches ddd"), 1);
1034 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches eee"), 1);
1035 profile_
.BlockUntilHistoryProcessesPendingRequests();
1037 AutocompleteMatch wyt_match
;
1038 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fi"),
1040 ASSERT_EQ(AutocompleteProvider::kMaxMatches
+ 1, provider_
->matches().size());
1041 AutocompleteMatch term_match
;
1042 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
1043 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
1044 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
1045 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
1048 // Inline autocomplete matches regardless of case differences from the input.
1049 TEST_F(SearchProviderTest
, InlineMixedCaseMatches
) {
1050 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("FOO"), 1));
1051 profile_
.BlockUntilHistoryProcessesPendingRequests();
1053 AutocompleteMatch wyt_match
;
1054 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
1056 ASSERT_EQ(2u, provider_
->matches().size());
1057 AutocompleteMatch term_match
;
1058 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
1059 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
1060 EXPECT_EQ(ASCIIToUTF16("FOO"), term_match
.fill_into_edit
);
1061 EXPECT_EQ(ASCIIToUTF16("OO"), term_match
.inline_autocompletion
);
1062 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
1065 // Verifies AutocompleteControllers return results (including keyword
1066 // results) in the right order and set descriptions for them correctly.
1067 TEST_F(SearchProviderTest
, KeywordOrderingAndDescriptions
) {
1068 // Add an entry that corresponds to a keyword search with 'term2'.
1069 AddSearchToHistory(keyword_t_url_
, ASCIIToUTF16("term2"), 1);
1070 profile_
.BlockUntilHistoryProcessesPendingRequests();
1072 AutocompleteController
controller(&profile_
,
1073 TemplateURLServiceFactory::GetForProfile(&profile_
),
1074 NULL
, AutocompleteProvider::TYPE_SEARCH
);
1075 controller
.Start(AutocompleteInput(
1076 ASCIIToUTF16("k t"), base::string16::npos
, std::string(), GURL(),
1077 metrics::OmniboxEventProto::INVALID_SPEC
, false, false, true, true,
1078 ChromeAutocompleteSchemeClassifier(&profile_
)));
1079 const AutocompleteResult
& result
= controller
.result();
1081 // There should be three matches, one for the keyword history, one for
1082 // keyword provider's what-you-typed, and one for the default provider's
1083 // what you typed, in that order.
1084 ASSERT_EQ(3u, result
.size());
1085 EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY
, result
.match_at(0).type
);
1086 EXPECT_EQ(AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1087 result
.match_at(1).type
);
1088 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1089 result
.match_at(2).type
);
1090 EXPECT_GT(result
.match_at(0).relevance
, result
.match_at(1).relevance
);
1091 EXPECT_GT(result
.match_at(1).relevance
, result
.match_at(2).relevance
);
1092 EXPECT_TRUE(result
.match_at(0).allowed_to_be_default_match
);
1093 EXPECT_TRUE(result
.match_at(1).allowed_to_be_default_match
);
1094 EXPECT_FALSE(result
.match_at(2).allowed_to_be_default_match
);
1096 // The two keyword results should come with the keyword we expect.
1097 EXPECT_EQ(ASCIIToUTF16("k"), result
.match_at(0).keyword
);
1098 EXPECT_EQ(ASCIIToUTF16("k"), result
.match_at(1).keyword
);
1099 // The default provider has a different keyword. (We don't explicitly
1100 // set it during this test, so all we do is assert that it's different.)
1101 EXPECT_NE(result
.match_at(0).keyword
, result
.match_at(2).keyword
);
1103 // The top result will always have a description. The third result,
1104 // coming from a different provider than the first two, should also.
1105 // Whether the second result has one doesn't matter much. (If it was
1106 // missing, people would infer that it's the same search provider as
1107 // the one above it.)
1108 EXPECT_FALSE(result
.match_at(0).description
.empty());
1109 EXPECT_FALSE(result
.match_at(2).description
.empty());
1110 EXPECT_NE(result
.match_at(0).description
, result
.match_at(2).description
);
1113 TEST_F(SearchProviderTest
, KeywordVerbatim
) {
1114 TestData cases
[] = {
1115 // Test a simple keyword input.
1116 { ASCIIToUTF16("k foo"), 2,
1117 { ResultInfo(GURL("http://keyword/foo"),
1118 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1120 ASCIIToUTF16("k foo")),
1121 ResultInfo(GURL("http://defaultturl/k%20foo"),
1122 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1124 ASCIIToUTF16("k foo") ) } },
1126 // Make sure extra whitespace after the keyword doesn't change the
1127 // keyword verbatim query. Also verify that interior consecutive
1128 // whitespace gets trimmed.
1129 { ASCIIToUTF16("k foo"), 2,
1130 { ResultInfo(GURL("http://keyword/foo"),
1131 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1133 ASCIIToUTF16("k foo")),
1134 ResultInfo(GURL("http://defaultturl/k%20foo"),
1135 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1137 ASCIIToUTF16("k foo")) } },
1138 // Leading whitespace should be stripped before SearchProvider gets the
1139 // input; hence there are no tests here about how it handles those inputs.
1141 // Verify that interior consecutive whitespace gets trimmed in either case.
1142 { ASCIIToUTF16("k foo bar"), 2,
1143 { ResultInfo(GURL("http://keyword/foo%20bar"),
1144 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1146 ASCIIToUTF16("k foo bar")),
1147 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
1148 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1150 ASCIIToUTF16("k foo bar")) } },
1152 // Verify that trailing whitespace gets trimmed.
1153 { ASCIIToUTF16("k foo bar "), 2,
1154 { ResultInfo(GURL("http://keyword/foo%20bar"),
1155 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1157 ASCIIToUTF16("k foo bar")),
1158 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
1159 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1161 ASCIIToUTF16("k foo bar")) } },
1163 // Keywords can be prefixed by certain things that should get ignored
1164 // when constructing the keyword match.
1165 { ASCIIToUTF16("www.k foo"), 2,
1166 { ResultInfo(GURL("http://keyword/foo"),
1167 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1169 ASCIIToUTF16("k foo")),
1170 ResultInfo(GURL("http://defaultturl/www.k%20foo"),
1171 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1173 ASCIIToUTF16("www.k foo")) } },
1174 { ASCIIToUTF16("http://k foo"), 2,
1175 { ResultInfo(GURL("http://keyword/foo"),
1176 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1178 ASCIIToUTF16("k foo")),
1179 ResultInfo(GURL("http://defaultturl/http%3A//k%20foo"),
1180 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1182 ASCIIToUTF16("http://k foo")) } },
1183 { ASCIIToUTF16("http://www.k foo"), 2,
1184 { ResultInfo(GURL("http://keyword/foo"),
1185 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1187 ASCIIToUTF16("k foo")),
1188 ResultInfo(GURL("http://defaultturl/http%3A//www.k%20foo"),
1189 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1191 ASCIIToUTF16("http://www.k foo")) } },
1193 // A keyword with no remaining input shouldn't get a keyword
1195 { ASCIIToUTF16("k"), 1,
1196 { ResultInfo(GURL("http://defaultturl/k"),
1197 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1199 ASCIIToUTF16("k")) } },
1200 // Ditto. Trailing whitespace shouldn't make a difference.
1201 { ASCIIToUTF16("k "), 1,
1202 { ResultInfo(GURL("http://defaultturl/k"),
1203 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1205 ASCIIToUTF16("k")) } }
1207 // The fact that verbatim queries to keyword are handled by KeywordProvider
1208 // not SearchProvider is tested in
1209 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc.
1212 // Test not in keyword mode.
1213 RunTest(cases
, arraysize(cases
), false);
1215 // Test in keyword mode. (Both modes should give the same result.)
1216 RunTest(cases
, arraysize(cases
), true);
1219 // Ensures command-line flags are reflected in the URLs the search provider
1221 TEST_F(SearchProviderTest
, CommandLineOverrides
) {
1222 TemplateURLService
* turl_model
=
1223 TemplateURLServiceFactory::GetForProfile(&profile_
);
1225 TemplateURLData data
;
1226 data
.short_name
= ASCIIToUTF16("default");
1227 data
.SetKeyword(data
.short_name
);
1228 data
.SetURL("{google:baseURL}{searchTerms}");
1229 default_t_url_
= new TemplateURL(data
);
1230 turl_model
->Add(default_t_url_
);
1231 turl_model
->SetUserSelectedDefaultSearchProvider(default_t_url_
);
1233 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1234 switches::kGoogleBaseURL
, "http://www.bar.com/");
1235 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1236 switches::kExtraSearchQueryParams
, "a=b");
1238 TestData cases
[] = {
1239 { ASCIIToUTF16("k a"), 2,
1240 { ResultInfo(GURL("http://keyword/a"),
1241 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1243 ASCIIToUTF16("k a")),
1244 ResultInfo(GURL("http://www.bar.com/k%20a?a=b"),
1245 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1247 ASCIIToUTF16("k a")) } },
1250 RunTest(cases
, arraysize(cases
), false);
1253 // Verifies Navsuggest results don't set a TemplateURL, which Instant relies on.
1254 // Also verifies that just the *first* navigational result is listed as a match
1255 // if suggested relevance scores were not sent.
1256 TEST_F(SearchProviderTest
, NavSuggestNoSuggestedRelevanceScores
) {
1257 QueryForInputAndWaitForFetcherResponses(
1258 ASCIIToUTF16("a.c"), false,
1259 "[\"a.c\",[\"a.com\", \"a.com/b\"],[\"a\", \"b\"],[],"
1260 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1263 // Make sure the only match is 'a.com' and it doesn't have a template_url.
1264 AutocompleteMatch nav_match
;
1265 EXPECT_TRUE(FindMatchWithDestination(GURL("http://a.com"), &nav_match
));
1266 EXPECT_TRUE(nav_match
.keyword
.empty());
1267 EXPECT_FALSE(nav_match
.allowed_to_be_default_match
);
1268 EXPECT_FALSE(FindMatchWithDestination(GURL("http://a.com/b"), &nav_match
));
1271 // Verifies that the most relevant suggest results are added properly.
1272 TEST_F(SearchProviderTest
, SuggestRelevance
) {
1273 QueryForInputAndWaitForFetcherResponses(
1274 ASCIIToUTF16("a"), false, "[\"a\",[\"a1\", \"a2\", \"a3\", \"a4\"]]",
1277 // Check the expected verbatim and (first 3) suggestions' relative relevances.
1278 AutocompleteMatch verbatim
, match_a1
, match_a2
, match_a3
, match_a4
;
1279 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim
));
1280 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a1"), &match_a1
));
1281 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a2"), &match_a2
));
1282 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a3"), &match_a3
));
1283 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("a4"), &match_a4
));
1284 EXPECT_GT(verbatim
.relevance
, match_a1
.relevance
);
1285 EXPECT_GT(match_a1
.relevance
, match_a2
.relevance
);
1286 EXPECT_GT(match_a2
.relevance
, match_a3
.relevance
);
1287 EXPECT_TRUE(verbatim
.allowed_to_be_default_match
);
1288 EXPECT_FALSE(match_a1
.allowed_to_be_default_match
);
1289 EXPECT_FALSE(match_a2
.allowed_to_be_default_match
);
1290 EXPECT_FALSE(match_a3
.allowed_to_be_default_match
);
1293 // Verifies that the default provider abandons suggested relevance scores
1294 // when in keyword mode. This should happen regardless of whether the
1295 // keyword provider returns suggested relevance scores.
1296 TEST_F(SearchProviderTest
, DefaultProviderNoSuggestRelevanceInKeywordMode
) {
1298 const std::string default_provider_json
;
1299 const std::string keyword_provider_json
;
1300 const std::string matches
[5];
1302 // First, try an input where the keyword provider does not deliver
1303 // suggested relevance scores.
1304 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1305 "{\"google:verbatimrelevance\":9700,"
1306 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1307 "\"google:suggestrelevance\":[9900, 9800]}]",
1308 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"]}]",
1309 { "a", "akeyword-query", "k a", "adefault.com", "k adefault-query" } },
1311 // Now try with keyword provider suggested relevance scores.
1312 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1313 "{\"google:verbatimrelevance\":9700,"
1314 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1315 "\"google:suggestrelevance\":[9900, 9800]}]",
1316 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"],"
1317 "\"google:verbatimrelevance\":9500,"
1318 "\"google:suggestrelevance\":[9600]}]",
1319 { "akeyword-query", "a", "k a", "adefault.com", "k adefault-query" } }
1322 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
1323 // Send the query twice in order to have a synchronous pass after the first
1324 // response is received. This is necessary because SearchProvider doesn't
1325 // allow an asynchronous response to change the default match.
1326 for (size_t j
= 0; j
< 2; ++j
) {
1327 QueryForInputAndWaitForFetcherResponses(
1328 ASCIIToUTF16("k a"), true, cases
[i
].default_provider_json
,
1329 cases
[i
].keyword_provider_json
);
1333 "for input with default_provider_json=" +
1334 cases
[i
].default_provider_json
+ " and keyword_provider_json=" +
1335 cases
[i
].keyword_provider_json
);
1336 const ACMatches
& matches
= provider_
->matches();
1337 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
1339 // Ensure that the returned matches equal the expectations.
1340 for (; j
< matches
.size(); ++j
)
1341 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
]), matches
[j
].contents
);
1342 // Ensure that no expected matches are missing.
1343 for (; j
< arraysize(cases
[i
].matches
); ++j
)
1344 EXPECT_EQ(std::string(), cases
[i
].matches
[j
]);
1348 // Verifies that suggest results with relevance scores are added
1349 // properly when using the default fetcher. When adding a new test
1350 // case to this test, please consider adding it to the tests in
1351 // KeywordFetcherSuggestRelevance below.
1352 TEST_F(SearchProviderTest
, DefaultFetcherSuggestRelevance
) {
1354 const std::string json
;
1355 const ExpectedMatch matches
[6];
1356 const std::string inline_autocompletion
;
1358 // Ensure that suggestrelevance scores reorder matches.
1359 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1360 { { "a", true }, { "c", false }, { "b", false }, kEmptyExpectedMatch
,
1361 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1363 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1364 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1365 "\"google:suggestrelevance\":[1, 2]}]",
1366 { { "a", true }, { "c.com", false }, { "b.com", false },
1367 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1370 // Without suggested relevance scores, we should only allow one
1371 // navsuggest result to be be displayed.
1372 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1373 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1374 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch
,
1375 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1378 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1379 // Negative values will have no effect; the calculated value will be used.
1380 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1381 "\"google:suggestrelevance\":[9998]}]",
1382 { { "a", true}, { "a1", false }, kEmptyExpectedMatch
,
1383 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1385 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1386 "\"google:suggestrelevance\":[9999]}]",
1387 { { "a1", true }, { "a", true }, kEmptyExpectedMatch
,
1388 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1390 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1391 "\"google:suggestrelevance\":[9999]}]",
1392 { { "a1", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1393 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1395 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1396 "\"google:suggestrelevance\":[9999]}]",
1397 { { "a1", true }, { "a", true }, kEmptyExpectedMatch
,
1398 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1400 { "[\"a\",[\"http://a.com\"],[],[],"
1401 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1402 "\"google:verbatimrelevance\":9999,"
1403 "\"google:suggestrelevance\":[9998]}]",
1404 { { "a", true }, { "a.com", false }, kEmptyExpectedMatch
,
1405 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1407 { "[\"a\",[\"http://a.com\"],[],[],"
1408 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1409 "\"google:verbatimrelevance\":9998,"
1410 "\"google:suggestrelevance\":[9999]}]",
1411 { { "a.com", true }, { "a", true }, kEmptyExpectedMatch
,
1412 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1414 { "[\"a\",[\"http://a.com\"],[],[],"
1415 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1416 "\"google:verbatimrelevance\":0,"
1417 "\"google:suggestrelevance\":[9999]}]",
1418 { { "a.com", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1419 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1421 { "[\"a\",[\"http://a.com\"],[],[],"
1422 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1423 "\"google:verbatimrelevance\":-1,"
1424 "\"google:suggestrelevance\":[9999]}]",
1425 { { "a.com", true }, { "a", true }, kEmptyExpectedMatch
,
1426 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1429 // Ensure that both types of relevance scores reorder matches together.
1430 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1431 "\"google:verbatimrelevance\":9998}]",
1432 { { "a1", true }, { "a", true }, { "a2", false }, kEmptyExpectedMatch
,
1433 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1436 // Check that an inlineable result appears first regardless of its score.
1437 // Also, if the result set lacks a single inlineable result, abandon the
1438 // request to suppress verbatim (verbatim_relevance=0), which will then
1439 // cause verbatim to appear (first).
1440 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1441 { { "a", true }, { "b", false }, kEmptyExpectedMatch
,
1442 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1444 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1445 "\"google:verbatimrelevance\":0}]",
1446 { { "a", true }, { "b", false }, kEmptyExpectedMatch
,
1447 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1449 { "[\"a\",[\"http://b.com\"],[],[],"
1450 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1451 "\"google:suggestrelevance\":[9999]}]",
1452 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch
,
1453 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1455 { "[\"a\",[\"http://b.com\"],[],[],"
1456 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1457 "\"google:suggestrelevance\":[9999],"
1458 "\"google:verbatimrelevance\":0}]",
1459 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch
,
1460 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1463 // Allow low-scoring matches.
1464 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1465 { { "a1", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1466 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1468 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":10}]",
1469 { { "a1", true }, { "a", true }, kEmptyExpectedMatch
,
1470 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1472 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[10],"
1473 "\"google:verbatimrelevance\":0}]",
1474 { { "a1", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1475 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1477 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 20],"
1478 "\"google:verbatimrelevance\":0}]",
1479 { { "a2", true }, { "a1", false }, kEmptyExpectedMatch
,
1480 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1482 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 30],"
1483 "\"google:verbatimrelevance\":20}]",
1484 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1485 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1487 { "[\"a\",[\"http://a.com\"],[],[],"
1488 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1489 "\"google:suggestrelevance\":[10],"
1490 "\"google:verbatimrelevance\":0}]",
1491 { { "a.com", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1492 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1494 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1495 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1496 "\"google:suggestrelevance\":[10, 20],"
1497 "\"google:verbatimrelevance\":0}]",
1498 { { "a2.com", true }, { "a1.com", false }, kEmptyExpectedMatch
,
1499 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1502 // Ensure that all suggestions are considered, regardless of order.
1503 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1504 "{\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1505 { { "a", true }, { "h", false }, { "g", false }, { "f", false },
1506 { "e", false }, { "d", false } },
1508 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1509 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1510 "\"http://h.com\"],[],[],"
1511 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1512 "\"NAVIGATION\", \"NAVIGATION\","
1513 "\"NAVIGATION\", \"NAVIGATION\","
1515 "\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1516 { { "a", true }, { "h.com", false }, { "g.com", false },
1517 { "f.com", false }, { "e.com", false }, { "d.com", false } },
1520 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1521 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10]}]",
1522 { { "a", true }, { "a1", false }, { "a2", false }, kEmptyExpectedMatch
,
1523 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1525 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 10]}]",
1526 { { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1527 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1529 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1530 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1531 "\"google:suggestrelevance\":[10]}]",
1532 { { "a", true }, { "a1.com", false }, kEmptyExpectedMatch
,
1533 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1535 { "[\"a\",[\"http://a1.com\"],[],[],"
1536 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1537 "\"google:suggestrelevance\":[9999, 10]}]",
1538 { { "a", true }, { "a1.com", false }, kEmptyExpectedMatch
,
1539 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1542 // Ensure that all 'verbatim' results are merged with their maximum score.
1543 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1544 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1545 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1546 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1548 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1549 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1550 "\"google:verbatimrelevance\":0}]",
1551 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1552 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1555 // Ensure that verbatim is always generated without other suggestions.
1556 // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
1557 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1558 { { "a", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1559 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1561 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1562 { { "a", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1563 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1567 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
1568 // Send the query twice in order to have a synchronous pass after the first
1569 // response is received. This is necessary because SearchProvider doesn't
1570 // allow an asynchronous response to change the default match.
1571 for (size_t j
= 0; j
< 2; ++j
) {
1572 QueryForInputAndWaitForFetcherResponses(
1573 ASCIIToUTF16("a"), false, cases
[i
].json
, std::string());
1576 const std::string description
= "for input with json=" + cases
[i
].json
;
1577 CheckMatches(description
, arraysize(cases
[i
].matches
), cases
[i
].matches
,
1578 provider_
->matches());
1582 // Verifies that suggest results with relevance scores are added
1583 // properly when using the keyword fetcher. This is similar to the
1584 // test DefaultFetcherSuggestRelevance above but this uses inputs that
1585 // trigger keyword suggestions (i.e., "k a" rather than "a") and has
1586 // different expectations (because now the results are a mix of
1587 // keyword suggestions and default provider suggestions). When a new
1588 // test is added to this TEST_F, please consider if it would be
1589 // appropriate to add to DefaultFetcherSuggestRelevance as well.
1590 TEST_F(SearchProviderTest
, KeywordFetcherSuggestRelevance
) {
1591 struct KeywordFetcherMatch
{
1592 std::string contents
;
1594 bool allowed_to_be_default_match
;
1596 const KeywordFetcherMatch kEmptyMatch
= { kNotApplicable
, false, false };
1598 const std::string json
;
1599 const KeywordFetcherMatch matches
[6];
1600 const std::string inline_autocompletion
;
1602 // Ensure that suggest relevance scores reorder matches and that
1603 // the keyword verbatim (lacking a suggested verbatim score) beats
1604 // the default provider verbatim.
1605 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1606 { { "a", true, true },
1607 { "k a", false, false },
1608 { "c", true, false },
1609 { "b", true, false },
1610 kEmptyMatch
, kEmptyMatch
},
1612 // Again, check that relevance scores reorder matches, just this
1613 // time with navigation matches. This also checks that with
1614 // suggested relevance scores we allow multiple navsuggest results.
1615 // Note that navsuggest results that come from a keyword provider
1616 // are marked as not a keyword result. (They don't go to a
1617 // keyword search engine.)
1618 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
1619 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1620 "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
1621 { { "a", true, true },
1622 { "d", true, false },
1623 { "c.com", false, false },
1624 { "b.com", false, false },
1625 { "k a", false, false },
1629 // Without suggested relevance scores, we should only allow one
1630 // navsuggest result to be be displayed.
1631 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1632 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1633 { { "a", true, true },
1634 { "b.com", false, false },
1635 { "k a", false, false },
1636 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1639 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1640 // Negative values will have no effect; the calculated value will be used.
1641 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1642 "\"google:suggestrelevance\":[9998]}]",
1643 { { "a", true, true },
1644 { "a1", true, false },
1645 { "k a", false, false },
1646 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1648 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1649 "\"google:suggestrelevance\":[9999]}]",
1650 { { "a1", true, true },
1651 { "a", true, true },
1652 { "k a", false, false },
1653 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1655 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1656 "\"google:suggestrelevance\":[9999]}]",
1657 { { "a1", true, true },
1658 { "k a", false, false },
1659 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1661 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1662 "\"google:suggestrelevance\":[9999]}]",
1663 { { "a1", true, true },
1664 { "a", true, true },
1665 { "k a", false, false },
1666 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1668 { "[\"a\",[\"http://a.com\"],[],[],"
1669 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1670 "\"google:verbatimrelevance\":9999,"
1671 "\"google:suggestrelevance\":[9998]}]",
1672 { { "a", true, true },
1673 { "a.com", false, false },
1674 { "k a", false, false },
1675 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1678 // Ensure that both types of relevance scores reorder matches together.
1679 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1680 "\"google:verbatimrelevance\":9998}]",
1681 { { "a1", true, true },
1682 { "a", true, true },
1683 { "a2", true, false },
1684 { "k a", false, false },
1685 kEmptyMatch
, kEmptyMatch
},
1688 // Check that an inlineable match appears first regardless of its score.
1689 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1690 { { "a", true, true },
1691 { "b", true, false },
1692 { "k a", false, false },
1693 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1695 { "[\"a\",[\"http://b.com\"],[],[],"
1696 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1697 "\"google:suggestrelevance\":[9999]}]",
1698 { { "a", true, true },
1699 { "b.com", false, false },
1700 { "k a", false, false },
1701 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1703 // If there is no inlineable match, restore the keyword verbatim score.
1704 // The keyword verbatim match will then appear first.
1705 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1706 "\"google:verbatimrelevance\":0}]",
1707 { { "a", true, true },
1708 { "b", true, false },
1709 { "k a", false, false },
1710 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1712 { "[\"a\",[\"http://b.com\"],[],[],"
1713 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1714 "\"google:suggestrelevance\":[9999],"
1715 "\"google:verbatimrelevance\":0}]",
1716 { { "a", true, true },
1717 { "b.com", false, false },
1718 { "k a", false, false },
1719 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1722 // The top result does not have to score as highly as calculated
1723 // verbatim. i.e., there are no minimum score restrictions in
1725 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1726 { { "a1", true, true },
1727 { "k a", false, false },
1728 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1730 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":10}]",
1731 { { "a1", true, true },
1732 { "k a", false, false },
1733 { "a", true, true },
1734 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1736 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[10],"
1737 "\"google:verbatimrelevance\":0}]",
1738 { { "a1", true, true },
1739 { "k a", false, false },
1740 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1742 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 20],"
1743 "\"google:verbatimrelevance\":0}]",
1744 { { "a2", true, true },
1745 { "k a", false, false },
1746 { "a1", true, false },
1747 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1749 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 30],"
1750 "\"google:verbatimrelevance\":20}]",
1751 { { "a2", true, true },
1752 { "k a", false, false },
1753 { "a", true, true },
1754 { "a1", true, false },
1755 kEmptyMatch
, kEmptyMatch
},
1758 // Ensure that all suggestions are considered, regardless of order.
1759 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1760 "{\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1761 { { "a", true, true },
1762 { "k a", false, false },
1763 { "h", true, false },
1764 { "g", true, false },
1765 { "f", true, false },
1766 { "e", true, false } },
1768 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1769 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1770 "\"http://h.com\"],[],[],"
1771 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1772 "\"NAVIGATION\", \"NAVIGATION\","
1773 "\"NAVIGATION\", \"NAVIGATION\","
1775 "\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1776 { { "a", true, true },
1777 { "k a", false, false },
1778 { "h.com", false, false },
1779 { "g.com", false, false },
1780 { "f.com", false, false },
1781 { "e.com", false, false } },
1784 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1785 // Note that keyword suggestions by default (not in suggested relevance
1786 // mode) score more highly than the default verbatim.
1787 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1788 { { "a", true, true },
1789 { "a1", true, false },
1790 { "a2", true, false },
1791 { "k a", false, false },
1792 kEmptyMatch
, kEmptyMatch
},
1794 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1795 { { "a", true, true },
1796 { "a1", true, false },
1797 { "k a", false, false },
1798 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1800 // In this case, ignoring the suggested relevance scores means we keep
1801 // only one navsuggest result.
1802 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1803 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1804 "\"google:suggestrelevance\":[1]}]",
1805 { { "a", true, true },
1806 { "a1.com", false, false },
1807 { "k a", false, false },
1808 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1810 { "[\"a\",[\"http://a1.com\"],[],[],"
1811 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1812 "\"google:suggestrelevance\":[9999, 1]}]",
1813 { { "a", true, true },
1814 { "a1.com", false, false },
1815 { "k a", false, false },
1816 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1819 // Ensure that all 'verbatim' results are merged with their maximum score.
1820 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1821 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1822 { { "a2", true, true },
1823 { "a", true, true },
1824 { "a1", true, false },
1825 { "k a", false, false },
1826 kEmptyMatch
, kEmptyMatch
},
1828 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1829 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1830 "\"google:verbatimrelevance\":0}]",
1831 { { "a2", true, true },
1832 { "a", true, true },
1833 { "a1", true, false },
1834 { "k a", false, false },
1835 kEmptyMatch
, kEmptyMatch
},
1838 // Ensure that verbatim is always generated without other suggestions.
1839 // TODO(mpearson): Ensure the value of verbatimrelevance is respected
1840 // (except when suggested relevances are ignored).
1841 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1842 { { "a", true, true },
1843 { "k a", false, false },
1844 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1846 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1847 { { "a", true, true },
1848 { "k a", false, false },
1849 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1852 // In reorder mode, navsuggestions will not need to be demoted (because
1853 // they are marked as not allowed to be default match and will be
1854 // reordered as necessary).
1855 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1856 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1857 "\"google:verbatimrelevance\":9990,"
1858 "\"google:suggestrelevance\":[9998, 9999]}]",
1859 { { "a", true, true },
1860 { "a2.com", false, false },
1861 { "a1.com", false, false },
1862 { "k a", false, false },
1863 kEmptyMatch
, kEmptyMatch
},
1865 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1866 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1867 "\"google:verbatimrelevance\":9990,"
1868 "\"google:suggestrelevance\":[9999, 9998]}]",
1869 { { "a", true, true },
1870 { "a1.com", false, false },
1871 { "a2.com", false, false },
1872 { "k a", false, false },
1873 kEmptyMatch
, kEmptyMatch
},
1875 { "[\"a\",[\"https://a/\"],[],[],"
1876 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1877 "\"google:suggestrelevance\":[9999]}]",
1878 { { "a", true, true },
1879 { "https://a", false, false },
1880 { "k a", false, false },
1881 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1883 // Check when navsuggest scores more than verbatim and there is query
1884 // suggestion but it scores lower.
1885 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1886 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1887 "\"google:verbatimrelevance\":9990,"
1888 "\"google:suggestrelevance\":[9998, 9999, 1300]}]",
1889 { { "a", true, true },
1890 { "a2.com", false, false },
1891 { "a1.com", false, false },
1892 { "a3", true, false },
1893 { "k a", false, false },
1896 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1897 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1898 "\"google:verbatimrelevance\":9990,"
1899 "\"google:suggestrelevance\":[9999, 9998, 1300]}]",
1900 { { "a", true, true },
1901 { "a1.com", false, false },
1902 { "a2.com", false, false },
1903 { "a3", true, false },
1904 { "k a", false, false },
1907 // Check when navsuggest scores more than a query suggestion. There is
1908 // a verbatim but it scores lower.
1909 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1910 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1911 "\"google:verbatimrelevance\":9990,"
1912 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1913 { { "a3", true, true },
1914 { "a2.com", false, false },
1915 { "a1.com", false, false },
1916 { "a", true, true },
1917 { "k a", false, false },
1920 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1921 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1922 "\"google:verbatimrelevance\":9990,"
1923 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1924 { { "a3", true, true },
1925 { "a1.com", false, false },
1926 { "a2.com", false, false },
1927 { "a", true, true },
1928 { "k a", false, false },
1931 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1932 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1933 "\"google:verbatimrelevance\":0,"
1934 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1935 { { "a3", true, true },
1936 { "a2.com", false, false },
1937 { "a1.com", false, false },
1938 { "k a", false, false },
1939 kEmptyMatch
, kEmptyMatch
},
1941 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1942 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1943 "\"google:verbatimrelevance\":0,"
1944 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1945 { { "a3", true, true },
1946 { "a1.com", false, false },
1947 { "a2.com", false, false },
1948 { "k a", false, false },
1949 kEmptyMatch
, kEmptyMatch
},
1951 // Check when there is neither verbatim nor a query suggestion that,
1952 // because we can't demote navsuggestions below a query suggestion,
1953 // we restore the keyword verbatim score.
1954 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1955 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1956 "\"google:verbatimrelevance\":0,"
1957 "\"google:suggestrelevance\":[9998, 9999]}]",
1958 { { "a", true, true },
1959 { "a2.com", false, false },
1960 { "a1.com", false, false },
1961 { "k a", false, false },
1962 kEmptyMatch
, kEmptyMatch
},
1964 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1965 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1966 "\"google:verbatimrelevance\":0,"
1967 "\"google:suggestrelevance\":[9999, 9998]}]",
1968 { { "a", true, true },
1969 { "a1.com", false, false },
1970 { "a2.com", false, false },
1971 { "k a", false, false },
1972 kEmptyMatch
, kEmptyMatch
},
1974 // More checks that everything works when it's not necessary to demote.
1975 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1976 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1977 "\"google:verbatimrelevance\":9990,"
1978 "\"google:suggestrelevance\":[9997, 9998, 9999]}]",
1979 { { "a3", true, true },
1980 { "a2.com", false, false },
1981 { "a1.com", false, false },
1982 { "a", true, true },
1983 { "k a", false, false },
1986 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1987 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1988 "\"google:verbatimrelevance\":9990,"
1989 "\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1990 { { "a3", true, true },
1991 { "a1.com", false, false },
1992 { "a2.com", false, false },
1993 { "a", true, true },
1994 { "k a", false, false },
1999 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2000 // Send the query twice in order to have a synchronous pass after the first
2001 // response is received. This is necessary because SearchProvider doesn't
2002 // allow an asynchronous response to change the default match.
2003 for (size_t j
= 0; j
< 2; ++j
) {
2004 QueryForInput(ASCIIToUTF16("k a"), false, true);
2006 // Set up a default fetcher with no results.
2007 net::TestURLFetcher
* default_fetcher
=
2008 test_factory_
.GetFetcherByID(
2009 SearchProvider::kDefaultProviderURLFetcherID
);
2010 ASSERT_TRUE(default_fetcher
);
2011 default_fetcher
->set_response_code(200);
2012 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
2013 default_fetcher
= NULL
;
2015 // Set up a keyword fetcher with provided results.
2016 net::TestURLFetcher
* keyword_fetcher
=
2017 test_factory_
.GetFetcherByID(
2018 SearchProvider::kKeywordProviderURLFetcherID
);
2019 ASSERT_TRUE(keyword_fetcher
);
2020 keyword_fetcher
->set_response_code(200);
2021 keyword_fetcher
->SetResponseString(cases
[i
].json
);
2022 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
2023 keyword_fetcher
= NULL
;
2024 RunTillProviderDone();
2027 SCOPED_TRACE("for input with json=" + cases
[i
].json
);
2028 const ACMatches
& matches
= provider_
->matches();
2029 ASSERT_FALSE(matches
.empty());
2030 // Find the first match that's allowed to be the default match and check
2031 // its inline_autocompletion.
2032 ACMatches::const_iterator it
= FindDefaultMatch(matches
);
2033 ASSERT_NE(matches
.end(), it
);
2034 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
2035 it
->inline_autocompletion
);
2037 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2039 // Ensure that the returned matches equal the expectations.
2040 for (; j
< matches
.size(); ++j
) {
2041 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
].contents
),
2042 matches
[j
].contents
);
2043 EXPECT_EQ(cases
[i
].matches
[j
].from_keyword
,
2044 matches
[j
].keyword
== ASCIIToUTF16("k"));
2045 EXPECT_EQ(cases
[i
].matches
[j
].allowed_to_be_default_match
,
2046 matches
[j
].allowed_to_be_default_match
);
2048 // Ensure that no expected matches are missing.
2049 for (; j
< arraysize(cases
[i
].matches
); ++j
) {
2050 SCOPED_TRACE(" Case # " + base::IntToString(i
));
2051 EXPECT_EQ(kNotApplicable
, cases
[i
].matches
[j
].contents
);
2056 TEST_F(SearchProviderTest
, DontInlineAutocompleteAsynchronously
) {
2057 // This test sends two separate queries, each receiving different JSON
2058 // replies, and checks that at each stage of processing (receiving first
2059 // asynchronous response, handling new keystroke synchronously / sending the
2060 // second request, and receiving the second asynchronous response) we have the
2061 // expected matches. In particular, receiving the second response shouldn't
2062 // cause an unexpected inline autcompletion.
2064 const std::string first_json
;
2065 const ExpectedMatch first_async_matches
[4];
2066 const ExpectedMatch sync_matches
[4];
2067 const std::string second_json
;
2068 const ExpectedMatch second_async_matches
[4];
2070 // A simple test that verifies we don't inline autocomplete after the
2071 // first asynchronous response, but we do at the next keystroke if the
2072 // response's results were good enough. Furthermore, we should continue
2073 // inline autocompleting after the second asynchronous response if the new
2074 // top suggestion is the same as the old inline autocompleted suggestion.
2075 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2076 "{\"google:verbatimrelevance\":9000,"
2077 "\"google:suggestrelevance\":[9002, 9001]}]",
2078 { { "a", true }, { "ab1", false }, { "ab2", false },
2079 kEmptyExpectedMatch
},
2080 { { "ab1", true }, { "ab2", true }, { "ab", true },
2081 kEmptyExpectedMatch
},
2082 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2083 "{\"google:verbatimrelevance\":9000,"
2084 "\"google:suggestrelevance\":[9002, 9001]}]",
2085 { { "ab1", true }, { "ab2", false }, { "ab", true },
2086 kEmptyExpectedMatch
} },
2087 // Ditto, just for a navigation suggestion.
2088 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2089 "{\"google:verbatimrelevance\":9000,"
2090 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2091 "\"google:suggestrelevance\":[9002, 9001]}]",
2092 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2093 kEmptyExpectedMatch
},
2094 { { "ab1.com", true }, { "ab2.com", true }, { "ab", true },
2095 kEmptyExpectedMatch
},
2096 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2097 "{\"google:verbatimrelevance\":9000,"
2098 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2099 "\"google:suggestrelevance\":[9002, 9001]}]",
2100 { { "ab1.com", true }, { "ab2.com", false }, { "ab", true },
2101 kEmptyExpectedMatch
} },
2102 // A more realistic test of the same situation.
2103 { "[\"a\",[\"abcdef\", \"abcdef.com\", \"abc\"],[],[],"
2104 "{\"google:verbatimrelevance\":900,"
2105 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"QUERY\"],"
2106 "\"google:suggestrelevance\":[1250, 1200, 1000]}]",
2107 { { "a", true }, { "abcdef", false }, { "abcdef.com", false },
2109 { { "abcdef", true }, { "abcdef.com", true }, { "abc", true },
2111 "[\"ab\",[\"abcdef\", \"abcdef.com\", \"abc\"],[],[],"
2112 "{\"google:verbatimrelevance\":900,"
2113 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"QUERY\"],"
2114 "\"google:suggestrelevance\":[1250, 1200, 1000]}]",
2115 { { "abcdef", true }, { "abcdef.com", false }, { "abc", false },
2118 // Without an original inline autcompletion, a new inline autcompletion
2119 // should be rejected.
2120 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2121 "{\"google:verbatimrelevance\":9000,"
2122 "\"google:suggestrelevance\":[8000, 7000]}]",
2123 { { "a", true }, { "ab1", false }, { "ab2", false },
2124 kEmptyExpectedMatch
},
2125 { { "ab", true }, { "ab1", true }, { "ab2", true },
2126 kEmptyExpectedMatch
},
2127 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2128 "{\"google:verbatimrelevance\":9000,"
2129 "\"google:suggestrelevance\":[9002, 9001]}]",
2130 { { "ab", true }, { "ab1", false }, { "ab2", false },
2131 kEmptyExpectedMatch
} },
2132 // For the same test except with the queries scored in the opposite order
2133 // on the second JSON response, the queries should be ordered by the second
2134 // response's scores, not the first.
2135 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2136 "{\"google:verbatimrelevance\":9000,"
2137 "\"google:suggestrelevance\":[8000, 7000]}]",
2138 { { "a", true }, { "ab1", false }, { "ab2", false },
2139 kEmptyExpectedMatch
},
2140 { { "ab", true }, { "ab1", true }, { "ab2", true },
2141 kEmptyExpectedMatch
},
2142 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2143 "{\"google:verbatimrelevance\":9000,"
2144 "\"google:suggestrelevance\":[9001, 9002]}]",
2145 { { "ab", true }, { "ab2", false }, { "ab1", false },
2146 kEmptyExpectedMatch
} },
2147 // Now, the same verifications but with the new inline autocompletion as a
2148 // navsuggestion. The new autocompletion should still be rejected.
2149 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2150 "{\"google:verbatimrelevance\":9000,"
2151 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2152 "\"google:suggestrelevance\":[8000, 7000]}]",
2153 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2154 kEmptyExpectedMatch
},
2155 { { "ab", true }, { "ab1.com", true }, { "ab2.com", true },
2156 kEmptyExpectedMatch
},
2157 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2158 "{\"google:verbatimrelevance\":9000,"
2159 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2160 "\"google:suggestrelevance\":[9002, 9001]}]",
2161 { { "ab", true }, { "ab1.com", false }, { "ab2.com", false },
2162 kEmptyExpectedMatch
} },
2163 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2164 "{\"google:verbatimrelevance\":9000,"
2165 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2166 "\"google:suggestrelevance\":[8000, 7000]}]",
2167 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2168 kEmptyExpectedMatch
},
2169 { { "ab", true }, { "ab1.com", true }, { "ab2.com", true },
2170 kEmptyExpectedMatch
},
2171 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2172 "{\"google:verbatimrelevance\":9000,"
2173 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2174 "\"google:suggestrelevance\":[9001, 9002]}]",
2175 { { "ab", true }, { "ab2.com", false }, { "ab1.com", false },
2176 kEmptyExpectedMatch
} },
2178 // It's okay to abandon an inline autocompletion asynchronously.
2179 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2180 "{\"google:verbatimrelevance\":9000,"
2181 "\"google:suggestrelevance\":[9002, 9001]}]",
2182 { { "a", true }, { "ab1", false }, { "ab2", false },
2183 kEmptyExpectedMatch
},
2184 { { "ab1", true }, { "ab2", true }, { "ab", true },
2185 kEmptyExpectedMatch
},
2186 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2187 "{\"google:verbatimrelevance\":9000,"
2188 "\"google:suggestrelevance\":[8000, 7000]}]",
2189 { { "ab", true }, { "ab1", true }, { "ab2", false },
2190 kEmptyExpectedMatch
} },
2192 // Note: it's possible that the suggest server returns a suggestion with
2193 // an inline autocompletion (that as usual we delay in allowing it to
2194 // be displayed as an inline autocompletion until the next keystroke),
2195 // then, in response to the next keystroke, the server returns a different
2196 // suggestion as an inline autocompletion. This is not likely to happen.
2197 // Regardless, if it does, one could imagine three different behaviors:
2198 // - keep the original inline autocompletion until the next keystroke
2199 // (i.e., don't abandon an inline autocompletion asynchronously), then
2200 // use the new suggestion
2201 // - abandon all inline autocompletions upon the server response, then use
2202 // the new suggestion on the next keystroke
2203 // - ignore the new inline autocompletion provided by the server, yet
2204 // possibly keep the original if it scores well in the most recent
2205 // response, then use the new suggestion on the next keystroke
2206 // All of these behaviors are reasonable. The main thing we want to
2207 // ensure is that the second asynchronous response shouldn't cause *a new*
2208 // inline autocompletion to be displayed. We test that here.
2209 // The current implementation does the third bullet, but all of these
2210 // behaviors seem reasonable.
2211 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2212 "{\"google:verbatimrelevance\":9000,"
2213 "\"google:suggestrelevance\":[9002, 9001]}]",
2214 { { "a", true }, { "ab1", false }, { "ab2", false },
2215 kEmptyExpectedMatch
},
2216 { { "ab1", true }, { "ab2", true }, { "ab", true },
2217 kEmptyExpectedMatch
},
2218 "[\"ab\",[\"ab1\", \"ab3\"],[],[],"
2219 "{\"google:verbatimrelevance\":9000,"
2220 "\"google:suggestrelevance\":[9002, 9900]}]",
2221 { { "ab1", true }, { "ab3", false }, { "ab", true },
2222 kEmptyExpectedMatch
} },
2223 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2224 "{\"google:verbatimrelevance\":9000,"
2225 "\"google:suggestrelevance\":[9002, 9001]}]",
2226 { { "a", true }, { "ab1", false }, { "ab2", false },
2227 kEmptyExpectedMatch
},
2228 { { "ab1", true }, { "ab2", true }, { "ab", true },
2229 kEmptyExpectedMatch
},
2230 "[\"ab\",[\"ab1\", \"ab3\"],[],[],"
2231 "{\"google:verbatimrelevance\":9000,"
2232 "\"google:suggestrelevance\":[8000, 9500]}]",
2233 { { "ab", true }, { "ab3", false }, { "ab1", true },
2234 kEmptyExpectedMatch
} },
2237 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2238 // First, send the query "a" and receive the JSON response |first_json|.
2240 QueryForInputAndWaitForFetcherResponses(
2241 ASCIIToUTF16("a"), false, cases
[i
].first_json
, std::string());
2243 // Verify that the matches after the asynchronous results are as expected.
2244 std::string description
= "first asynchronous response for input with "
2245 "first_json=" + cases
[i
].first_json
;
2246 CheckMatches(description
, arraysize(cases
[i
].first_async_matches
),
2247 cases
[i
].first_async_matches
, provider_
->matches());
2249 // Then, send the query "ab" and check the synchronous matches.
2250 description
= "synchronous response after the first keystroke after input "
2251 "with first_json=" + cases
[i
].first_json
;
2252 QueryForInput(ASCIIToUTF16("ab"), false, false);
2253 CheckMatches(description
, arraysize(cases
[i
].sync_matches
),
2254 cases
[i
].sync_matches
, provider_
->matches());
2256 // Finally, get the provided JSON response, |second_json|, and verify the
2257 // matches after the second asynchronous response are as expected.
2258 description
= "second asynchronous response after input with first_json=" +
2259 cases
[i
].first_json
+ " and second_json=" + cases
[i
].second_json
;
2260 net::TestURLFetcher
* second_fetcher
=
2261 test_factory_
.GetFetcherByID(
2262 SearchProvider::kDefaultProviderURLFetcherID
);
2263 ASSERT_TRUE(second_fetcher
);
2264 second_fetcher
->set_response_code(200);
2265 second_fetcher
->SetResponseString(cases
[i
].second_json
);
2266 second_fetcher
->delegate()->OnURLFetchComplete(second_fetcher
);
2267 RunTillProviderDone();
2268 CheckMatches(description
, arraysize(cases
[i
].second_async_matches
),
2269 cases
[i
].second_async_matches
, provider_
->matches());
2273 TEST_F(SearchProviderTest
, LocalAndRemoteRelevances
) {
2274 // We hardcode the string "term1" below, so ensure that the search term that
2275 // got added to history already is that string.
2276 ASSERT_EQ(ASCIIToUTF16("term1"), term1_
);
2277 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
2279 AddSearchToHistory(default_t_url_
, term
+ ASCIIToUTF16("2"), 2);
2280 profile_
.BlockUntilHistoryProcessesPendingRequests();
2283 const base::string16 input
;
2284 const std::string json
;
2285 const std::string matches
[6];
2287 // The history results outscore the default verbatim score. term2 has more
2288 // visits so it outscores term1. The suggestions are still returned since
2289 // they're server-scored.
2291 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
2292 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
2293 "\"google:suggestrelevance\":[1, 2, 3]}]",
2294 { "term2", "term1", "term", "a3", "a2", "a1" } },
2295 // Because we already have three suggestions by the time we see the history
2296 // results, they don't get returned.
2298 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
2299 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
2300 "\"google:verbatimrelevance\":1450,"
2301 "\"google:suggestrelevance\":[1440, 1430, 1420]}]",
2302 { "term", "a1", "a2", "a3", kNotApplicable
, kNotApplicable
} },
2303 // If we only have two suggestions, we have room for a history result.
2305 "[\"term\",[\"a1\", \"a2\"],[],[],"
2306 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2307 "\"google:verbatimrelevance\":1450,"
2308 "\"google:suggestrelevance\":[1430, 1410]}]",
2309 { "term", "a1", "a2", "term2", kNotApplicable
, kNotApplicable
} },
2310 // If we have more than three suggestions, they should all be returned as
2311 // long as we have enough total space for them.
2313 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
2314 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
2315 "\"google:verbatimrelevance\":1450,"
2316 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410]}]",
2317 { "term", "a1", "a2", "a3", "a4", kNotApplicable
} },
2319 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\", \"a5\", \"a6\"],[],[],"
2320 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\","
2321 "\"QUERY\", \"QUERY\"],"
2322 "\"google:verbatimrelevance\":1450,"
2323 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410, 1400, 1390]}]",
2324 { "term", "a1", "a2", "a3", "a4", "a5" } },
2326 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
2327 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
2328 "\"google:verbatimrelevance\":1450,"
2329 "\"google:suggestrelevance\":[1430, 1410, 1390, 1370]}]",
2330 { "term", "a1", "a2", "term2", "a3", "a4" } }
2333 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2334 QueryForInputAndWaitForFetcherResponses(
2335 cases
[i
].input
, false, cases
[i
].json
, std::string());
2337 const std::string description
= "for input with json=" + cases
[i
].json
;
2338 const ACMatches
& matches
= provider_
->matches();
2340 // Ensure no extra matches are present.
2341 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2344 // Ensure that the returned matches equal the expectations.
2345 for (; j
< matches
.size(); ++j
)
2346 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
]),
2347 matches
[j
].contents
) << description
;
2348 // Ensure that no expected matches are missing.
2349 for (; j
< arraysize(cases
[i
].matches
); ++j
)
2350 EXPECT_EQ(kNotApplicable
, cases
[i
].matches
[j
]) <<
2351 "Case # " << i
<< " " << description
;
2355 // Verifies suggest relevance behavior for URL input.
2356 TEST_F(SearchProviderTest
, DefaultProviderSuggestRelevanceScoringUrlInput
) {
2357 struct DefaultFetcherUrlInputMatch
{
2358 const std::string match_contents
;
2359 AutocompleteMatch::Type match_type
;
2360 bool allowed_to_be_default_match
;
2362 const DefaultFetcherUrlInputMatch kEmptyMatch
=
2363 { kNotApplicable
, AutocompleteMatchType::NUM_TYPES
, false };
2365 const std::string input
;
2366 const std::string json
;
2367 const DefaultFetcherUrlInputMatch output
[4];
2369 // Ensure NAVIGATION matches are allowed to be listed first for URL input.
2370 // Non-inlineable matches should not be allowed to be the default match.
2371 // Note that the top-scoring inlineable match is moved to the top
2372 // regardless of its score.
2373 { "a.com", "[\"a.com\",[\"http://b.com/\"],[],[],"
2374 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2375 "\"google:suggestrelevance\":[9999]}]",
2376 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2377 { "b.com", AutocompleteMatchType::NAVSUGGEST
, false },
2378 kEmptyMatch
, kEmptyMatch
} },
2379 { "a.com", "[\"a.com\",[\"https://b.com\"],[],[],"
2380 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2381 "\"google:suggestrelevance\":[9999]}]",
2382 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2383 { "https://b.com", AutocompleteMatchType::NAVSUGGEST
, false },
2384 kEmptyMatch
, kEmptyMatch
} },
2385 { "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[],"
2386 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2387 "\"google:suggestrelevance\":[9999]}]",
2388 { { "a.com/a", AutocompleteMatchType::NAVSUGGEST
, true },
2389 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2390 kEmptyMatch
, kEmptyMatch
} },
2391 { "a.com", "[\"a.com\",[\"https://a.com\"],[],[],"
2392 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2393 "\"google:suggestrelevance\":[9999]}]",
2394 { { "https://a.com", AutocompleteMatchType::NAVSUGGEST
, true },
2395 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2396 kEmptyMatch
, kEmptyMatch
} },
2398 // Ensure topmost inlineable SUGGEST matches are NOT allowed for URL
2399 // input. SearchProvider disregards search and verbatim suggested
2401 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2402 "{\"google:suggestrelevance\":[9999]}]",
2403 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2404 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2405 kEmptyMatch
, kEmptyMatch
} },
2406 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2407 "{\"google:suggestrelevance\":[9999]}]",
2408 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2409 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2410 kEmptyMatch
, kEmptyMatch
} },
2412 // Ensure the fallback mechanism allows inlineable NAVIGATION matches.
2413 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2414 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2415 "\"google:suggestrelevance\":[9999, 9998]}]",
2416 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST
, true },
2417 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2418 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2420 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2421 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2422 "\"google:suggestrelevance\":[9998, 9997],"
2423 "\"google:verbatimrelevance\":9999}]",
2424 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST
, true },
2425 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2426 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2429 // Ensure non-inlineable SUGGEST matches are allowed for URL input
2430 // assuming the best inlineable match is not a query (i.e., is a
2431 // NAVSUGGEST). The best inlineable match will be at the top of the
2432 // list regardless of its score.
2433 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2434 "{\"google:suggestrelevance\":[9999]}]",
2435 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2436 { "info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2437 kEmptyMatch
, kEmptyMatch
} },
2438 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2439 "{\"google:suggestrelevance\":[9999]}]",
2440 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2441 { "info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2442 kEmptyMatch
, kEmptyMatch
} },
2445 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2446 // Send the query twice in order to have a synchronous pass after the first
2447 // response is received. This is necessary because SearchProvider doesn't
2448 // allow an asynchronous response to change the default match.
2449 for (size_t j
= 0; j
< 2; ++j
) {
2450 QueryForInputAndWaitForFetcherResponses(
2451 ASCIIToUTF16(cases
[i
].input
), false, cases
[i
].json
, std::string());
2454 SCOPED_TRACE("input=" + cases
[i
].input
+ " json=" + cases
[i
].json
);
2456 const ACMatches
& matches
= provider_
->matches();
2457 ASSERT_LE(matches
.size(), arraysize(cases
[i
].output
));
2458 // Ensure that the returned matches equal the expectations.
2459 for (; j
< matches
.size(); ++j
) {
2460 EXPECT_EQ(ASCIIToUTF16(cases
[i
].output
[j
].match_contents
),
2461 matches
[j
].contents
);
2462 EXPECT_EQ(cases
[i
].output
[j
].match_type
, matches
[j
].type
);
2463 EXPECT_EQ(cases
[i
].output
[j
].allowed_to_be_default_match
,
2464 matches
[j
].allowed_to_be_default_match
);
2466 // Ensure that no expected matches are missing.
2467 for (; j
< arraysize(cases
[i
].output
); ++j
) {
2468 EXPECT_EQ(kNotApplicable
, cases
[i
].output
[j
].match_contents
);
2469 EXPECT_EQ(AutocompleteMatchType::NUM_TYPES
,
2470 cases
[i
].output
[j
].match_type
);
2471 EXPECT_FALSE(cases
[i
].output
[j
].allowed_to_be_default_match
);
2476 // A basic test that verifies the field trial triggered parsing logic.
2477 TEST_F(SearchProviderTest
, FieldTrialTriggeredParsing
) {
2478 QueryForInputAndWaitForFetcherResponses(
2479 ASCIIToUTF16("foo"), false,
2480 "[\"foo\",[\"foo bar\"],[\"\"],[],"
2481 "{\"google:suggesttype\":[\"QUERY\"],"
2482 "\"google:fieldtrialtriggered\":true}]",
2486 // Check for the match and field trial triggered bits.
2487 AutocompleteMatch match
;
2488 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("foo bar"), &match
));
2489 ProvidersInfo providers_info
;
2490 provider_
->AddProviderInfo(&providers_info
);
2491 ASSERT_EQ(1U, providers_info
.size());
2492 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_size());
2493 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_in_session_size());
2496 // Reset the session and check that bits are reset.
2497 provider_
->ResetSession();
2498 ProvidersInfo providers_info
;
2499 provider_
->AddProviderInfo(&providers_info
);
2500 ASSERT_EQ(1U, providers_info
.size());
2501 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_size());
2502 EXPECT_EQ(0, providers_info
[0].field_trial_triggered_in_session_size());
2506 // Verifies inline autocompletion of navigational results.
2507 TEST_F(SearchProviderTest
, NavigationInline
) {
2509 const std::string input
;
2510 const std::string url
;
2511 // Test the expected fill_into_edit, which may drop "http://".
2512 // Some cases do not trim "http://" to match from the start of the scheme.
2513 const std::string fill_into_edit
;
2514 const std::string inline_autocompletion
;
2515 const bool allowed_to_be_default_match_in_regular_mode
;
2516 const bool allowed_to_be_default_match_in_prevent_inline_mode
;
2518 // Do not inline matches that do not contain the input; trim http as needed.
2519 { "x", "http://www.abc.com",
2520 "www.abc.com", std::string(), false, false },
2521 { "https:", "http://www.abc.com",
2522 "www.abc.com", std::string(), false, false },
2523 { "http://www.abc.com/a", "http://www.abc.com",
2524 "http://www.abc.com", std::string(), false,
2527 // Do not inline matches with invalid input prefixes; trim http as needed.
2528 { "ttp", "http://www.abc.com",
2529 "www.abc.com", std::string(), false, false },
2530 { "://w", "http://www.abc.com",
2531 "www.abc.com", std::string(), false, false },
2532 { "ww.", "http://www.abc.com",
2533 "www.abc.com", std::string(), false, false },
2534 { ".ab", "http://www.abc.com",
2535 "www.abc.com", std::string(), false, false },
2536 { "bc", "http://www.abc.com",
2537 "www.abc.com", std::string(), false, false },
2538 { ".com", "http://www.abc.com",
2539 "www.abc.com", std::string(), false, false },
2541 // Do not inline matches that omit input domain labels; trim http as needed.
2542 { "www.a", "http://a.com",
2543 "a.com", std::string(), false, false },
2544 { "http://www.a", "http://a.com",
2545 "http://a.com", std::string(), false, false },
2546 { "www.a", "ftp://a.com",
2547 "ftp://a.com", std::string(), false, false },
2548 { "ftp://www.a", "ftp://a.com",
2549 "ftp://a.com", std::string(), false, false },
2551 // Input matching but with nothing to inline will not yield an offset, but
2552 // will be allowed to be default.
2553 { "abc.com", "http://www.abc.com",
2554 "www.abc.com", std::string(), true, true },
2555 { "abc.com/", "http://www.abc.com",
2556 "www.abc.com", std::string(), true, true },
2557 { "http://www.abc.com", "http://www.abc.com",
2558 "http://www.abc.com", std::string(), true, true },
2559 { "http://www.abc.com/", "http://www.abc.com",
2560 "http://www.abc.com", std::string(), true, true },
2562 // Inputs with trailing whitespace should inline when possible.
2563 { "abc.com ", "http://www.abc.com",
2564 "www.abc.com", std::string(), true, true },
2565 { "abc.com/ ", "http://www.abc.com",
2566 "www.abc.com", std::string(), true, true },
2567 { "abc.com ", "http://www.abc.com/bar",
2568 "www.abc.com/bar", "/bar", false, false },
2570 // A suggestion that's equivalent to what the input gets fixed up to
2571 // should be inlined.
2572 { "abc.com:", "http://abc.com/",
2573 "abc.com", std::string(), true, true },
2574 { "abc.com:", "http://www.abc.com",
2575 "www.abc.com", std::string(), true, true },
2577 // Inline matches when the input is a leading substring of the scheme.
2578 { "h", "http://www.abc.com",
2579 "http://www.abc.com", "ttp://www.abc.com", true, false },
2580 { "http", "http://www.abc.com",
2581 "http://www.abc.com", "://www.abc.com", true, false },
2583 // Inline matches when the input is a leading substring of the full URL.
2584 { "http:", "http://www.abc.com",
2585 "http://www.abc.com", "//www.abc.com", true, false },
2586 { "http://w", "http://www.abc.com",
2587 "http://www.abc.com", "ww.abc.com", true, false },
2588 { "http://www.", "http://www.abc.com",
2589 "http://www.abc.com", "abc.com", true, false },
2590 { "http://www.ab", "http://www.abc.com",
2591 "http://www.abc.com", "c.com", true, false },
2592 { "http://www.abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2593 "http://www.abc.com/path/file.htm?q=x#foo",
2594 "ath/file.htm?q=x#foo",
2596 { "http://abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2597 "http://abc.com/path/file.htm?q=x#foo",
2598 "ath/file.htm?q=x#foo",
2601 // Inline matches with valid URLPrefixes; only trim "http://".
2602 { "w", "http://www.abc.com",
2603 "www.abc.com", "ww.abc.com", true, false },
2604 { "www.a", "http://www.abc.com",
2605 "www.abc.com", "bc.com", true, false },
2606 { "abc", "http://www.abc.com",
2607 "www.abc.com", ".com", true, false },
2608 { "abc.c", "http://www.abc.com",
2609 "www.abc.com", "om", true, false },
2610 { "abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2611 "www.abc.com/path/file.htm?q=x#foo",
2612 "ath/file.htm?q=x#foo",
2614 { "abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2615 "abc.com/path/file.htm?q=x#foo",
2616 "ath/file.htm?q=x#foo",
2619 // Inline matches using the maximal URLPrefix components.
2620 { "h", "http://help.com",
2621 "help.com", "elp.com", true, false },
2622 { "http", "http://http.com",
2623 "http.com", ".com", true, false },
2624 { "h", "http://www.help.com",
2625 "www.help.com", "elp.com", true, false },
2626 { "http", "http://www.http.com",
2627 "www.http.com", ".com", true, false },
2628 { "w", "http://www.www.com",
2629 "www.www.com", "ww.com", true, false },
2631 // Test similar behavior for the ftp and https schemes.
2632 { "ftp://www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2633 "ftp://www.abc.com/path/file.htm?q=x#foo",
2634 "c.com/path/file.htm?q=x#foo", true, false },
2635 { "www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2636 "ftp://www.abc.com/path/file.htm?q=x#foo",
2637 "c.com/path/file.htm?q=x#foo", true, false },
2638 { "ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2639 "ftp://www.abc.com/path/file.htm?q=x#foo",
2640 "c.com/path/file.htm?q=x#foo", true, false },
2641 { "ab", "ftp://abc.com/path/file.htm?q=x#foo",
2642 "ftp://abc.com/path/file.htm?q=x#foo",
2643 "c.com/path/file.htm?q=x#foo", true, false },
2644 { "https://www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2645 "https://www.abc.com/path/file.htm?q=x#foo",
2646 "c.com/path/file.htm?q=x#foo",
2648 { "www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2649 "https://www.abc.com/path/file.htm?q=x#foo",
2650 "c.com/path/file.htm?q=x#foo", true, false },
2651 { "ab", "https://www.abc.com/path/file.htm?q=x#foo",
2652 "https://www.abc.com/path/file.htm?q=x#foo",
2653 "c.com/path/file.htm?q=x#foo", true, false },
2654 { "ab", "https://abc.com/path/file.htm?q=x#foo",
2655 "https://abc.com/path/file.htm?q=x#foo",
2656 "c.com/path/file.htm?q=x#foo", true, false },
2658 // Forced query input should inline and retain the "?" prefix.
2659 { "?http://www.ab", "http://www.abc.com",
2660 "?http://www.abc.com", "c.com", true, false },
2661 { "?www.ab", "http://www.abc.com",
2662 "?www.abc.com", "c.com", true, false },
2663 { "?ab", "http://www.abc.com",
2664 "?www.abc.com", "c.com", true, false },
2665 { "?abc.com", "http://www.abc.com",
2666 "?www.abc.com", std::string(), true, true },
2669 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2670 // First test regular mode.
2671 QueryForInput(ASCIIToUTF16(cases
[i
].input
), false, false);
2672 SearchSuggestionParser::NavigationResult
result(
2673 ChromeAutocompleteSchemeClassifier(&profile_
), GURL(cases
[i
].url
),
2674 AutocompleteMatchType::NAVSUGGEST
, base::string16(), std::string(),
2675 false, 0, false, ASCIIToUTF16(cases
[i
].input
), std::string());
2676 result
.set_received_after_last_keystroke(false);
2677 AutocompleteMatch
match(provider_
->NavigationToMatch(result
));
2678 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
2679 match
.inline_autocompletion
);
2680 EXPECT_EQ(ASCIIToUTF16(cases
[i
].fill_into_edit
), match
.fill_into_edit
);
2681 EXPECT_EQ(cases
[i
].allowed_to_be_default_match_in_regular_mode
,
2682 match
.allowed_to_be_default_match
);
2684 // Then test prevent-inline-autocomplete mode.
2685 QueryForInput(ASCIIToUTF16(cases
[i
].input
), true, false);
2686 SearchSuggestionParser::NavigationResult
result_prevent_inline(
2687 ChromeAutocompleteSchemeClassifier(&profile_
), GURL(cases
[i
].url
),
2688 AutocompleteMatchType::NAVSUGGEST
, base::string16(), std::string(),
2689 false, 0, false, ASCIIToUTF16(cases
[i
].input
), std::string());
2690 result_prevent_inline
.set_received_after_last_keystroke(false);
2691 AutocompleteMatch
match_prevent_inline(
2692 provider_
->NavigationToMatch(result_prevent_inline
));
2693 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
2694 match_prevent_inline
.inline_autocompletion
);
2695 EXPECT_EQ(ASCIIToUTF16(cases
[i
].fill_into_edit
),
2696 match_prevent_inline
.fill_into_edit
);
2697 EXPECT_EQ(cases
[i
].allowed_to_be_default_match_in_prevent_inline_mode
,
2698 match_prevent_inline
.allowed_to_be_default_match
);
2702 // Verifies that "http://" is not trimmed for input that is a leading substring.
2703 TEST_F(SearchProviderTest
, NavigationInlineSchemeSubstring
) {
2704 const base::string16
input(ASCIIToUTF16("ht"));
2705 const base::string16
url(ASCIIToUTF16("http://a.com"));
2706 SearchSuggestionParser::NavigationResult
result(
2707 ChromeAutocompleteSchemeClassifier(&profile_
), GURL(url
),
2708 AutocompleteMatchType::NAVSUGGEST
,
2709 base::string16(), std::string(), false, 0, false, input
, std::string());
2710 result
.set_received_after_last_keystroke(false);
2712 // Check the offset and strings when inline autocompletion is allowed.
2713 QueryForInput(input
, false, false);
2714 AutocompleteMatch
match_inline(provider_
->NavigationToMatch(result
));
2715 EXPECT_EQ(url
, match_inline
.fill_into_edit
);
2716 EXPECT_EQ(url
.substr(2), match_inline
.inline_autocompletion
);
2717 EXPECT_TRUE(match_inline
.allowed_to_be_default_match
);
2718 EXPECT_EQ(url
, match_inline
.contents
);
2720 // Check the same strings when inline autocompletion is prevented.
2721 QueryForInput(input
, true, false);
2722 AutocompleteMatch
match_prevent(provider_
->NavigationToMatch(result
));
2723 EXPECT_EQ(url
, match_prevent
.fill_into_edit
);
2724 EXPECT_FALSE(match_prevent
.allowed_to_be_default_match
);
2725 EXPECT_EQ(url
, match_prevent
.contents
);
2728 // Verifies that input "w" marks a more significant domain label than "www.".
2729 TEST_F(SearchProviderTest
, NavigationInlineDomainClassify
) {
2730 QueryForInput(ASCIIToUTF16("w"), false, false);
2731 SearchSuggestionParser::NavigationResult
result(
2732 ChromeAutocompleteSchemeClassifier(&profile_
),
2733 GURL("http://www.wow.com"), AutocompleteMatchType::NAVSUGGEST
,
2734 base::string16(), std::string(), false, 0, false, ASCIIToUTF16("w"),
2736 result
.set_received_after_last_keystroke(false);
2737 AutocompleteMatch
match(provider_
->NavigationToMatch(result
));
2738 EXPECT_EQ(ASCIIToUTF16("ow.com"), match
.inline_autocompletion
);
2739 EXPECT_TRUE(match
.allowed_to_be_default_match
);
2740 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match
.fill_into_edit
);
2741 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match
.contents
);
2743 // Ensure that the match for input "w" is marked on "wow" and not "www".
2744 ASSERT_EQ(3U, match
.contents_class
.size());
2745 EXPECT_EQ(0U, match
.contents_class
[0].offset
);
2746 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
,
2747 match
.contents_class
[0].style
);
2748 EXPECT_EQ(4U, match
.contents_class
[1].offset
);
2749 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
|
2750 AutocompleteMatch::ACMatchClassification::MATCH
,
2751 match
.contents_class
[1].style
);
2752 EXPECT_EQ(5U, match
.contents_class
[2].offset
);
2753 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
,
2754 match
.contents_class
[2].style
);
2757 #if !defined(OS_WIN)
2758 // Verify entity suggestion parsing.
2759 TEST_F(SearchProviderTest
, ParseEntitySuggestion
) {
2761 std::string contents
;
2762 std::string description
;
2763 std::string query_params
;
2764 std::string fill_into_edit
;
2765 AutocompleteMatchType::Type type
;
2767 const Match kEmptyMatch
= {
2768 kNotApplicable
, kNotApplicable
, kNotApplicable
, kNotApplicable
,
2769 AutocompleteMatchType::NUM_TYPES
};
2772 const std::string input_text
;
2773 const std::string response_json
;
2774 const Match matches
[5];
2776 // A query and an entity suggestion with different search terms.
2778 "[\"x\",[\"xy\", \"yy\"],[\"\",\"\"],[],"
2779 " {\"google:suggestdetail\":[{},"
2780 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2781 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2782 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
2783 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST
},
2784 { "xy", "A", "p=v", "yy",
2785 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY
},
2790 // A query and an entity suggestion with same search terms.
2792 "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
2793 " {\"google:suggestdetail\":[{},"
2794 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2795 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2796 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
2797 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST
},
2798 { "xy", "A", "p=v", "xy",
2799 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY
},
2805 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2806 QueryForInputAndWaitForFetcherResponses(
2807 ASCIIToUTF16(cases
[i
].input_text
), false, cases
[i
].response_json
,
2810 const ACMatches
& matches
= provider_
->matches();
2811 ASSERT_FALSE(matches
.empty());
2813 SCOPED_TRACE("for input with json = " + cases
[i
].response_json
);
2815 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2817 // Ensure that the returned matches equal the expectations.
2818 for (; j
< matches
.size(); ++j
) {
2819 const Match
& match
= cases
[i
].matches
[j
];
2820 SCOPED_TRACE(" and match index: " + base::IntToString(j
));
2821 EXPECT_EQ(match
.contents
,
2822 base::UTF16ToUTF8(matches
[j
].contents
));
2823 EXPECT_EQ(match
.description
,
2824 base::UTF16ToUTF8(matches
[j
].description
));
2825 EXPECT_EQ(match
.query_params
,
2826 matches
[j
].search_terms_args
->suggest_query_params
);
2827 EXPECT_EQ(match
.fill_into_edit
,
2828 base::UTF16ToUTF8(matches
[j
].fill_into_edit
));
2829 EXPECT_EQ(match
.type
, matches
[j
].type
);
2831 // Ensure that no expected matches are missing.
2832 for (; j
< arraysize(cases
[i
].matches
); ++j
) {
2833 SCOPED_TRACE(" and match index: " + base::IntToString(j
));
2834 EXPECT_EQ(cases
[i
].matches
[j
].contents
, kNotApplicable
);
2835 EXPECT_EQ(cases
[i
].matches
[j
].description
, kNotApplicable
);
2836 EXPECT_EQ(cases
[i
].matches
[j
].query_params
, kNotApplicable
);
2837 EXPECT_EQ(cases
[i
].matches
[j
].fill_into_edit
, kNotApplicable
);
2838 EXPECT_EQ(cases
[i
].matches
[j
].type
, AutocompleteMatchType::NUM_TYPES
);
2842 #endif // !defined(OS_WIN)
2845 // A basic test that verifies the prefetch metadata parsing logic.
2846 TEST_F(SearchProviderTest
, PrefetchMetadataParsing
) {
2848 std::string contents
;
2849 bool allowed_to_be_prefetched
;
2850 AutocompleteMatchType::Type type
;
2853 const Match kEmptyMatch
= { kNotApplicable
,
2855 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
2859 const std::string input_text
;
2860 bool prefer_keyword_provider_results
;
2861 const std::string default_provider_response_json
;
2862 const std::string keyword_provider_response_json
;
2863 const Match matches
[5];
2865 // Default provider response does not have prefetch details. Ensure that the
2866 // suggestions are not marked as prefetch query.
2869 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2871 { { "a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2872 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2873 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2878 // Ensure that default provider suggest response prefetch details are
2879 // parsed and recorded in AutocompleteMatch.
2882 "[\"ab\",[\"abc\", \"http://b.com\", \"http://c.com\"],[],[],"
2883 "{\"google:clientdata\":{\"phi\": 0},"
2884 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"NAVIGATION\"],"
2885 "\"google:suggestrelevance\":[999, 12, 1]}]",
2887 { { "ab", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2888 { "abc", true, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2889 { "b.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
2890 { "c.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
2894 // Default provider suggest response has prefetch details.
2895 // SEARCH_WHAT_YOU_TYPE suggestion outranks SEARCH_SUGGEST suggestion for
2896 // the same query string. Ensure that the prefetch details from
2897 // SEARCH_SUGGEST match are set onto SEARCH_WHAT_YOU_TYPE match.
2900 "[\"ab\",[\"ab\", \"http://ab.com\"],[],[],"
2901 "{\"google:clientdata\":{\"phi\": 0},"
2902 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2903 "\"google:suggestrelevance\":[99, 98]}]",
2905 { {"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2906 {"ab.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
2912 // Default provider response has prefetch details. We prefer keyword
2913 // provider results. Ensure that prefetch bit for a suggestion from the
2914 // default search provider does not get copied onto a higher-scoring match
2915 // for the same query string from the keyword provider.
2918 "[\"k a\",[\"a\", \"ab\"],[],[], {\"google:clientdata\":{\"phi\": 0},"
2919 "\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2920 "\"google:suggestrelevance\":[9, 12]}]",
2921 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2922 { { "a", false, AutocompleteMatchType::SEARCH_OTHER_ENGINE
, true},
2923 { "k a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2924 { "ab", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2925 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST
, true },
2926 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST
, true }
2931 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2932 QueryForInputAndWaitForFetcherResponses(
2933 ASCIIToUTF16(cases
[i
].input_text
),
2934 cases
[i
].prefer_keyword_provider_results
,
2935 cases
[i
].default_provider_response_json
,
2936 cases
[i
].prefer_keyword_provider_results
?
2937 cases
[i
].keyword_provider_response_json
: std::string());
2939 const std::string description
=
2940 "for input with json =" + cases
[i
].default_provider_response_json
;
2941 const ACMatches
& matches
= provider_
->matches();
2942 // The top match must inline and score as highly as calculated verbatim.
2943 ASSERT_FALSE(matches
.empty());
2944 EXPECT_GE(matches
[0].relevance
, 1300);
2946 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2947 // Ensure that the returned matches equal the expectations.
2948 for (size_t j
= 0; j
< matches
.size(); ++j
) {
2949 SCOPED_TRACE(description
);
2950 EXPECT_EQ(cases
[i
].matches
[j
].contents
,
2951 base::UTF16ToUTF8(matches
[j
].contents
));
2952 EXPECT_EQ(cases
[i
].matches
[j
].allowed_to_be_prefetched
,
2953 SearchProvider::ShouldPrefetch(matches
[j
]));
2954 EXPECT_EQ(cases
[i
].matches
[j
].type
, matches
[j
].type
);
2955 EXPECT_EQ(cases
[i
].matches
[j
].from_keyword
,
2956 matches
[j
].keyword
== ASCIIToUTF16("k"));
2961 TEST_F(SearchProviderTest
, XSSIGuardedJSONParsing_InvalidResponse
) {
2964 std::string
input_str("abc");
2965 QueryForInputAndWaitForFetcherResponses(
2966 ASCIIToUTF16(input_str
), false, "this is a bad non-json response",
2969 const ACMatches
& matches
= provider_
->matches();
2971 // Should have exactly one "search what you typed" match
2972 ASSERT_TRUE(matches
.size() == 1);
2973 EXPECT_EQ(input_str
, base::UTF16ToUTF8(matches
[0].contents
));
2974 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
2978 // A basic test that verifies that the XSSI guarded JSON response is parsed
2980 TEST_F(SearchProviderTest
, XSSIGuardedJSONParsing_ValidResponses
) {
2982 std::string contents
;
2983 AutocompleteMatchType::Type type
;
2985 const Match kEmptyMatch
= {
2986 kNotApplicable
, AutocompleteMatchType::NUM_TYPES
2990 const std::string input_text
;
2991 const std::string default_provider_response_json
;
2992 const Match matches
[4];
2996 "[\"a\",[\"b\", \"c\"],[],[],"
2997 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2998 "\"google:suggestrelevance\":[1, 2]}]",
2999 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3000 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
3001 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
3005 // Standard XSSI guard - )]}'\n.
3007 ")]}'\n[\"a\",[\"b\", \"c\"],[],[],"
3008 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
3009 "\"google:suggestrelevance\":[1, 2]}]",
3010 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3011 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
3012 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
3016 // Modified XSSI guard - contains "[".
3018 ")]}'\n[)\"[\"a\",[\"b\", \"c\"],[],[],"
3019 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
3020 "\"google:suggestrelevance\":[1, 2]}]",
3021 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3022 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
3023 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
3029 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
3031 QueryForInputAndWaitForFetcherResponses(
3032 ASCIIToUTF16(cases
[i
].input_text
), false,
3033 cases
[i
].default_provider_response_json
, std::string());
3035 const ACMatches
& matches
= provider_
->matches();
3036 // The top match must inline and score as highly as calculated verbatim.
3037 ASSERT_FALSE(matches
.empty());
3038 EXPECT_GE(matches
[0].relevance
, 1300);
3040 SCOPED_TRACE("for case: " + base::IntToString(i
));
3041 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
3043 // Ensure that the returned matches equal the expectations.
3044 for (; j
< matches
.size(); ++j
) {
3045 SCOPED_TRACE("and match: " + base::IntToString(j
));
3046 EXPECT_EQ(cases
[i
].matches
[j
].contents
,
3047 base::UTF16ToUTF8(matches
[j
].contents
));
3048 EXPECT_EQ(cases
[i
].matches
[j
].type
, matches
[j
].type
);
3050 for (; j
< arraysize(cases
[i
].matches
); ++j
) {
3051 SCOPED_TRACE("and match: " + base::IntToString(j
));
3052 EXPECT_EQ(cases
[i
].matches
[j
].contents
, kNotApplicable
);
3053 EXPECT_EQ(cases
[i
].matches
[j
].type
, AutocompleteMatchType::NUM_TYPES
);
3058 // Test that deletion url gets set on an AutocompleteMatch when available for a
3059 // personalized query or a personalized URL.
3060 TEST_F(SearchProviderTest
, ParseDeletionUrl
) {
3062 std::string contents
;
3063 std::string deletion_url
;
3064 AutocompleteMatchType::Type type
;
3067 const Match kEmptyMatch
= {
3068 kNotApplicable
, std::string(), AutocompleteMatchType::NUM_TYPES
3071 const char* url
[] = {
3072 "http://defaultturl/complete/deleteitems"
3073 "?delq=ab&client=chrome&deltok=xsrf124",
3074 "http://defaultturl/complete/deleteitems"
3075 "?delq=www.amazon.com&client=chrome&deltok=xsrf123",
3079 const std::string input_text
;
3080 const std::string response_json
;
3081 const Match matches
[5];
3083 // A deletion URL on a personalized query should be reflected in the
3084 // resulting AutocompleteMatch.
3086 "[\"a\",[\"ab\", \"ac\",\"www.amazon.com\"],[],[],"
3087 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3088 "\"PERSONALIZED_NAVIGATION\"],"
3089 "\"google:suggestrelevance\":[3, 2, 1],"
3090 "\"google:suggestdetail\":[{\"du\":"
3091 "\"/complete/deleteitems?delq=ab&client=chrome"
3092 "&deltok=xsrf124\"}, {}, {\"du\":"
3093 "\"/complete/deleteitems?delq=www.amazon.com&"
3094 "client=chrome&deltok=xsrf123\"}]}]",
3095 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3096 { "ab", url
[0], AutocompleteMatchType::SEARCH_SUGGEST
},
3097 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3098 { "www.amazon.com", url
[1],
3099 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED
},
3103 // Personalized queries or a personalized URL without deletion URLs
3104 // shouldn't cause errors.
3106 "[\"a\",[\"ab\", \"ac\"],[],[],"
3107 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3108 "\"PERSONALIZED_NAVIGATION\"],"
3109 "\"google:suggestrelevance\":[1, 2],"
3110 "\"google:suggestdetail\":[{}, {}]}]",
3111 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3112 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3113 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3114 { "www.amazon.com", "",
3115 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED
},
3119 // Personalized queries or a personalized URL without
3120 // google:suggestdetail shouldn't cause errors.
3122 "[\"a\",[\"ab\", \"ac\"],[],[],"
3123 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3124 "\"PERSONALIZED_NAVIGATION\"],"
3125 "\"google:suggestrelevance\":[1, 2]}]",
3126 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3127 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3128 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3129 { "www.amazon.com", "",
3130 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED
},
3136 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
3137 QueryForInputAndWaitForFetcherResponses(
3138 ASCIIToUTF16(cases
[i
].input_text
), false, cases
[i
].response_json
,
3141 const ACMatches
& matches
= provider_
->matches();
3142 ASSERT_FALSE(matches
.empty());
3144 SCOPED_TRACE("for input with json = " + cases
[i
].response_json
);
3146 for (size_t j
= 0; j
< matches
.size(); ++j
) {
3147 const Match
& match
= cases
[i
].matches
[j
];
3148 SCOPED_TRACE(" and match index: " + base::IntToString(j
));
3149 EXPECT_EQ(match
.contents
, base::UTF16ToUTF8(matches
[j
].contents
));
3150 EXPECT_EQ(match
.deletion_url
, matches
[j
].GetAdditionalInfo(
3156 TEST_F(SearchProviderTest
, ReflectsBookmarkBarState
) {
3157 profile_
.GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar
, false);
3158 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
3159 QueryForInput(term
, true, false);
3160 ASSERT_FALSE(provider_
->matches().empty());
3161 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
3162 provider_
->matches()[0].type
);
3163 ASSERT_TRUE(provider_
->matches()[0].search_terms_args
!= NULL
);
3164 EXPECT_FALSE(provider_
->matches()[0].search_terms_args
->bookmark_bar_pinned
);
3166 profile_
.GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar
, true);
3167 term
= term1_
.substr(0, term1_
.length() - 1);
3168 QueryForInput(term
, true, false);
3169 ASSERT_FALSE(provider_
->matches().empty());
3170 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
3171 provider_
->matches()[0].type
);
3172 ASSERT_TRUE(provider_
->matches()[0].search_terms_args
!= NULL
);
3173 EXPECT_TRUE(provider_
->matches()[0].search_terms_args
->bookmark_bar_pinned
);
3176 TEST_F(SearchProviderTest
, CanSendURL
) {
3177 TemplateURLData template_url_data
;
3178 template_url_data
.short_name
= ASCIIToUTF16("t");
3179 template_url_data
.SetURL("http://www.google.com/{searchTerms}");
3180 template_url_data
.suggestions_url
= "http://www.google.com/{searchTerms}";
3181 template_url_data
.instant_url
= "http://does/not/exist?strk=1";
3182 template_url_data
.search_terms_replacement_key
= "strk";
3183 template_url_data
.id
= SEARCH_ENGINE_GOOGLE
;
3184 TemplateURL
google_template_url(template_url_data
);
3186 // Create field trial.
3187 CreateFieldTrial(OmniboxFieldTrial::kZeroSuggestRule
, true);
3189 ChromeAutocompleteProviderClient
client(&profile_
);
3192 EXPECT_FALSE(SearchProvider::CanSendURL(
3193 GURL("http://www.google.com/search"),
3194 GURL("https://www.google.com/complete/search"), &google_template_url
,
3195 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3196 SigninManagerBase
* signin
= SigninManagerFactory::GetForProfile(&profile_
);
3197 signin
->SetAuthenticatedUsername("test");
3199 // All conditions should be met.
3200 EXPECT_TRUE(SearchProvider::CanSendURL(
3201 GURL("http://www.google.com/search"),
3202 GURL("https://www.google.com/complete/search"), &google_template_url
,
3203 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3205 // Not in field trial.
3206 ResetFieldTrialList();
3207 CreateFieldTrial(OmniboxFieldTrial::kZeroSuggestRule
, false);
3208 EXPECT_FALSE(SearchProvider::CanSendURL(
3209 GURL("http://www.google.com/search"),
3210 GURL("https://www.google.com/complete/search"), &google_template_url
,
3211 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3212 ResetFieldTrialList();
3213 CreateFieldTrial(OmniboxFieldTrial::kZeroSuggestRule
, true);
3215 // Invalid page URL.
3216 EXPECT_FALSE(SearchProvider::CanSendURL(
3218 GURL("https://www.google.com/complete/search"), &google_template_url
,
3219 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3221 // Invalid page classification.
3222 EXPECT_FALSE(SearchProvider::CanSendURL(
3223 GURL("http://www.google.com/search"),
3224 GURL("https://www.google.com/complete/search"), &google_template_url
,
3225 metrics::OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS
,
3226 SearchTermsData(), &client
));
3228 // Invalid page classification.
3229 EXPECT_FALSE(SearchProvider::CanSendURL(
3230 GURL("http://www.google.com/search"),
3231 GURL("https://www.google.com/complete/search"), &google_template_url
,
3232 metrics::OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS
,
3233 SearchTermsData(), &client
));
3235 // HTTPS page URL on same domain as provider.
3236 EXPECT_TRUE(SearchProvider::CanSendURL(
3237 GURL("https://www.google.com/search"),
3238 GURL("https://www.google.com/complete/search"),
3239 &google_template_url
, metrics::OmniboxEventProto::OTHER
,
3240 SearchTermsData(), &client
));
3242 // Non-HTTP[S] page URL on same domain as provider.
3243 EXPECT_FALSE(SearchProvider::CanSendURL(
3244 GURL("ftp://www.google.com/search"),
3245 GURL("https://www.google.com/complete/search"), &google_template_url
,
3246 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3248 // Non-HTTP page URL on different domain.
3249 EXPECT_FALSE(SearchProvider::CanSendURL(
3250 GURL("https://www.notgoogle.com/search"),
3251 GURL("https://www.google.com/complete/search"), &google_template_url
,
3252 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3254 // Non-HTTPS provider.
3255 EXPECT_FALSE(SearchProvider::CanSendURL(
3256 GURL("http://www.google.com/search"),
3257 GURL("http://www.google.com/complete/search"), &google_template_url
,
3258 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3260 // Suggest disabled.
3261 profile_
.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled
, false);
3262 EXPECT_FALSE(SearchProvider::CanSendURL(
3263 GURL("http://www.google.com/search"),
3264 GURL("https://www.google.com/complete/search"), &google_template_url
,
3265 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3266 profile_
.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled
, true);
3269 ChromeAutocompleteProviderClient
client_incognito(
3270 profile_
.GetOffTheRecordProfile());
3271 EXPECT_FALSE(SearchProvider::CanSendURL(
3272 GURL("http://www.google.com/search"),
3273 GURL("https://www.google.com/complete/search"), &google_template_url
,
3274 metrics::OmniboxEventProto::OTHER
, SearchTermsData(),
3275 &client_incognito
));
3277 // Tab sync not enabled.
3278 profile_
.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncKeepEverythingSynced
,
3280 profile_
.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs
, false);
3281 EXPECT_FALSE(SearchProvider::CanSendURL(
3282 GURL("http://www.google.com/search"),
3283 GURL("https://www.google.com/complete/search"), &google_template_url
,
3284 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3285 profile_
.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs
, true);
3287 // Tab sync is encrypted.
3288 ProfileSyncService
* service
=
3289 ProfileSyncServiceFactory::GetInstance()->GetForProfile(&profile_
);
3290 syncer::ModelTypeSet encrypted_types
= service
->GetEncryptedDataTypes();
3291 encrypted_types
.Put(syncer::SESSIONS
);
3292 service
->OnEncryptedTypesChanged(encrypted_types
, false);
3293 EXPECT_FALSE(SearchProvider::CanSendURL(
3294 GURL("http://www.google.com/search"),
3295 GURL("https://www.google.com/complete/search"), &google_template_url
,
3296 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3297 encrypted_types
.Remove(syncer::SESSIONS
);
3298 service
->OnEncryptedTypesChanged(encrypted_types
, false);
3300 // Check that there were no side effects from previous tests.
3301 EXPECT_TRUE(SearchProvider::CanSendURL(
3302 GURL("http://www.google.com/search"),
3303 GURL("https://www.google.com/complete/search"), &google_template_url
,
3304 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3307 TEST_F(SearchProviderTest
, TestDeleteMatch
) {
3308 AutocompleteMatch
match(
3309 provider_
.get(), 0, true, AutocompleteMatchType::SEARCH_SUGGEST
);
3310 match
.RecordAdditionalInfo(
3311 SearchProvider::kDeletionUrlKey
,
3312 "https://www.google.com/complete/deleteitem?q=foo");
3314 // Test a successful deletion request.
3315 provider_
->matches_
.push_back(match
);
3316 provider_
->DeleteMatch(match
);
3317 EXPECT_FALSE(provider_
->deletion_handlers_
.empty());
3318 EXPECT_TRUE(provider_
->matches_
.empty());
3319 // Set up a default fetcher with provided results.
3320 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
3321 SearchProvider::kDeletionURLFetcherID
);
3322 ASSERT_TRUE(fetcher
);
3323 fetcher
->set_response_code(200);
3324 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3325 EXPECT_TRUE(provider_
->deletion_handlers_
.empty());
3326 EXPECT_TRUE(provider_
->is_success());
3328 // Test a failing deletion request.
3329 provider_
->matches_
.push_back(match
);
3330 provider_
->DeleteMatch(match
);
3331 EXPECT_FALSE(provider_
->deletion_handlers_
.empty());
3332 // Set up a default fetcher with provided results.
3333 fetcher
= test_factory_
.GetFetcherByID(
3334 SearchProvider::kDeletionURLFetcherID
);
3335 ASSERT_TRUE(fetcher
);
3336 fetcher
->set_response_code(500);
3337 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3338 EXPECT_TRUE(provider_
->deletion_handlers_
.empty());
3339 EXPECT_FALSE(provider_
->is_success());
3342 TEST_F(SearchProviderTest
, TestDeleteHistoryQueryMatch
) {
3344 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("flash games"), 1));
3345 profile_
.BlockUntilHistoryProcessesPendingRequests();
3347 AutocompleteMatch games
;
3348 QueryForInput(ASCIIToUTF16("fla"), false, false);
3349 profile_
.BlockUntilHistoryProcessesPendingRequests();
3350 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3351 ASSERT_TRUE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games
));
3353 size_t matches_before
= provider_
->matches().size();
3354 provider_
->DeleteMatch(games
);
3355 EXPECT_EQ(matches_before
- 1, provider_
->matches().size());
3357 // Process history deletions.
3358 profile_
.BlockUntilHistoryProcessesPendingRequests();
3360 // Check that the match is gone.
3361 QueryForInput(ASCIIToUTF16("fla"), false, false);
3362 profile_
.BlockUntilHistoryProcessesPendingRequests();
3363 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3364 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games
));
3367 // Verifies that duplicates are preserved in AddMatchToMap().
3368 TEST_F(SearchProviderTest
, CheckDuplicateMatchesSaved
) {
3369 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("a"), 1);
3370 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("alpha"), 1);
3371 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("avid"), 1);
3373 profile_
.BlockUntilHistoryProcessesPendingRequests();
3374 QueryForInputAndWaitForFetcherResponses(
3375 ASCIIToUTF16("a"), false,
3376 "[\"a\",[\"a\", \"alpha\", \"avid\", \"apricot\"],[],[],"
3377 "{\"google:suggestrelevance\":[1450, 1200, 1150, 1100],"
3378 "\"google:verbatimrelevance\":1350}]",
3381 AutocompleteMatch verbatim
, match_alpha
, match_apricot
, match_avid
;
3382 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim
));
3383 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("alpha"), &match_alpha
));
3384 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("apricot"), &match_apricot
));
3385 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("avid"), &match_avid
));
3387 // Verbatim match duplicates are added such that each one has a higher
3388 // relevance than the previous one.
3389 EXPECT_EQ(2U, verbatim
.duplicate_matches
.size());
3391 // Other match duplicates are added in descending relevance order.
3392 EXPECT_EQ(1U, match_alpha
.duplicate_matches
.size());
3393 EXPECT_EQ(1U, match_avid
.duplicate_matches
.size());
3395 EXPECT_EQ(0U, match_apricot
.duplicate_matches
.size());
3398 TEST_F(SearchProviderTest
, SuggestQueryUsesToken
) {
3399 TemplateURLService
* turl_model
=
3400 TemplateURLServiceFactory::GetForProfile(&profile_
);
3402 TemplateURLData data
;
3403 data
.short_name
= ASCIIToUTF16("default");
3404 data
.SetKeyword(data
.short_name
);
3405 data
.SetURL("http://example/{searchTerms}{google:sessionToken}");
3406 data
.suggestions_url
=
3407 "http://suggest/?q={searchTerms}&{google:sessionToken}";
3408 default_t_url_
= new TemplateURL(data
);
3409 turl_model
->Add(default_t_url_
);
3410 turl_model
->SetUserSelectedDefaultSearchProvider(default_t_url_
);
3412 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
3413 QueryForInput(term
, false, false);
3415 // Make sure the default provider's suggest service was queried.
3416 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
3417 SearchProvider::kDefaultProviderURLFetcherID
);
3418 ASSERT_TRUE(fetcher
);
3420 // And the URL matches what we expected.
3421 TemplateURLRef::SearchTermsArgs
search_terms_args(term
);
3422 search_terms_args
.session_token
= provider_
->current_token_
;
3423 GURL
expected_url(default_t_url_
->suggestions_url_ref().ReplaceSearchTerms(
3424 search_terms_args
, turl_model
->search_terms_data()));
3425 EXPECT_EQ(fetcher
->GetOriginalURL().spec(), expected_url
.spec());
3427 // Complete running the fetcher to clean up.
3428 fetcher
->set_response_code(200);
3429 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3430 RunTillProviderDone();
3433 TEST_F(SearchProviderTest
, SessionToken
) {
3434 // Subsequent calls always get the same token.
3435 std::string token
= provider_
->GetSessionToken();
3436 std::string token2
= provider_
->GetSessionToken();
3437 EXPECT_EQ(token
, token2
);
3438 EXPECT_FALSE(token
.empty());
3440 // Calls do not regenerate a token.
3441 provider_
->current_token_
= "PRE-EXISTING TOKEN";
3442 token
= provider_
->GetSessionToken();
3443 EXPECT_EQ(token
, "PRE-EXISTING TOKEN");
3445 // ... unless the token has expired.
3446 provider_
->current_token_
.clear();
3447 const base::TimeDelta kSmallDelta
= base::TimeDelta::FromMilliseconds(1);
3448 provider_
->token_expiration_time_
= base::TimeTicks::Now() - kSmallDelta
;
3449 token
= provider_
->GetSessionToken();
3450 EXPECT_FALSE(token
.empty());
3451 EXPECT_EQ(token
, provider_
->current_token_
);
3453 // The expiration time is always updated.
3454 provider_
->GetSessionToken();
3455 base::TimeTicks expiration_time_1
= provider_
->token_expiration_time_
;
3456 base::PlatformThread::Sleep(kSmallDelta
);
3457 provider_
->GetSessionToken();
3458 base::TimeTicks expiration_time_2
= provider_
->token_expiration_time_
;
3459 EXPECT_GT(expiration_time_2
, expiration_time_1
);
3460 EXPECT_GE(expiration_time_2
, expiration_time_1
+ kSmallDelta
);
3463 TEST_F(SearchProviderTest
, AnswersCache
) {
3464 AutocompleteResult result
;
3466 AutocompleteMatch match1
;
3467 match1
.answer_contents
= base::ASCIIToUTF16("m1");
3468 match1
.answer_type
= base::ASCIIToUTF16("2334");
3469 match1
.fill_into_edit
= base::ASCIIToUTF16("weather los angeles");
3471 AutocompleteMatch non_answer_match1
;
3472 non_answer_match1
.fill_into_edit
= base::ASCIIToUTF16("weather laguna beach");
3474 // Test that an answer in the first slot populates the cache.
3475 matches
.push_back(match1
);
3476 matches
.push_back(non_answer_match1
);
3477 result
.AppendMatches(matches
);
3478 provider_
->RegisterDisplayedAnswers(result
);
3479 ASSERT_FALSE(provider_
->answers_cache_
.empty());
3481 // Without scored results, no answers will be retrieved.
3482 AnswersQueryData answer
= provider_
->FindAnswersPrefetchData();
3483 EXPECT_TRUE(answer
.full_query_text
.empty());
3484 EXPECT_TRUE(answer
.query_type
.empty());
3486 // Inject a scored result, which will trigger answer retrieval.
3487 base::string16 query
= base::ASCIIToUTF16("weather los angeles");
3488 SearchSuggestionParser::SuggestResult
suggest_result(
3489 query
, AutocompleteMatchType::SEARCH_HISTORY
, query
, base::string16(),
3490 base::string16(), base::string16(), base::string16(), nullptr,
3491 std::string(), std::string(), false, 1200, false, false, query
);
3492 QueryForInput(ASCIIToUTF16("weather l"), false, false);
3493 provider_
->transformed_default_history_results_
.push_back(suggest_result
);
3494 answer
= provider_
->FindAnswersPrefetchData();
3495 EXPECT_EQ(base::ASCIIToUTF16("weather los angeles"), answer
.full_query_text
);
3496 EXPECT_EQ(base::ASCIIToUTF16("2334"), answer
.query_type
);
3499 TEST_F(SearchProviderTest
, RemoveExtraAnswers
) {
3500 SuggestionAnswer answer1
;
3501 answer1
.set_type(42);
3502 SuggestionAnswer answer2
;
3503 answer2
.set_type(1983);
3504 SuggestionAnswer answer3
;
3505 answer3
.set_type(423);
3508 AutocompleteMatch match1
, match2
, match3
, match4
, match5
;
3509 match1
.answer
= SuggestionAnswer::copy(&answer1
);
3510 match1
.answer_contents
= base::ASCIIToUTF16("the answer");
3511 match1
.answer_type
= base::ASCIIToUTF16("42");
3512 match3
.answer
= SuggestionAnswer::copy(&answer2
);
3513 match3
.answer_contents
= base::ASCIIToUTF16("not to play");
3514 match3
.answer_type
= base::ASCIIToUTF16("1983");
3515 match5
.answer
= SuggestionAnswer::copy(&answer3
);
3516 match5
.answer_contents
= base::ASCIIToUTF16("a man");
3517 match5
.answer_type
= base::ASCIIToUTF16("423");
3519 matches
.push_back(match1
);
3520 matches
.push_back(match2
);
3521 matches
.push_back(match3
);
3522 matches
.push_back(match4
);
3523 matches
.push_back(match5
);
3525 SearchProvider::RemoveExtraAnswers(&matches
);
3526 EXPECT_EQ(base::ASCIIToUTF16("the answer"), matches
[0].answer_contents
);
3527 EXPECT_EQ(base::ASCIIToUTF16("42"), matches
[0].answer_type
);
3528 EXPECT_TRUE(answer1
.Equals(*matches
[0].answer
));
3529 EXPECT_TRUE(matches
[1].answer_contents
.empty());
3530 EXPECT_TRUE(matches
[1].answer_type
.empty());
3531 EXPECT_FALSE(matches
[1].answer
);
3532 EXPECT_TRUE(matches
[2].answer_contents
.empty());
3533 EXPECT_TRUE(matches
[2].answer_type
.empty());
3534 EXPECT_FALSE(matches
[2].answer
);
3535 EXPECT_TRUE(matches
[3].answer_contents
.empty());
3536 EXPECT_TRUE(matches
[3].answer_type
.empty());
3537 EXPECT_FALSE(matches
[3].answer
);
3538 EXPECT_TRUE(matches
[4].answer_contents
.empty());
3539 EXPECT_TRUE(matches
[4].answer_type
.empty());
3540 EXPECT_FALSE(matches
[4].answer
);
3543 TEST_F(SearchProviderTest
, DoesNotProvideOnFocus
) {
3544 AutocompleteInput
input(base::ASCIIToUTF16("f"), base::string16::npos
,
3545 std::string(), GURL(),
3546 metrics::OmniboxEventProto::INVALID_SPEC
, false,
3548 ChromeAutocompleteSchemeClassifier(&profile_
));
3549 provider_
->Start(input
, false, true);
3550 EXPECT_TRUE(provider_
->matches().empty());