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/browser/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/chrome_autocomplete_provider_client.h"
21 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
22 #include "chrome/browser/history/history_service_factory.h"
23 #include "chrome/browser/search_engines/template_url_service_factory.h"
24 #include "chrome/browser/signin/account_tracker_service_factory.h"
25 #include "chrome/browser/signin/signin_manager_factory.h"
26 #include "chrome/browser/sync/profile_sync_service.h"
27 #include "chrome/browser/sync/profile_sync_service_factory.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/pref_names.h"
30 #include "chrome/test/base/testing_browser_process.h"
31 #include "chrome/test/base/testing_profile.h"
32 #include "components/google/core/browser/google_switches.h"
33 #include "components/history/core/browser/history_service.h"
34 #include "components/metrics/proto/omnibox_event.pb.h"
35 #include "components/omnibox/browser/autocomplete_controller.h"
36 #include "components/omnibox/browser/autocomplete_input.h"
37 #include "components/omnibox/browser/autocomplete_match.h"
38 #include "components/omnibox/browser/autocomplete_provider.h"
39 #include "components/omnibox/browser/autocomplete_provider_listener.h"
40 #include "components/omnibox/browser/history_url_provider.h"
41 #include "components/omnibox/browser/omnibox_field_trial.h"
42 #include "components/omnibox/browser/omnibox_switches.h"
43 #include "components/omnibox/browser/suggestion_answer.h"
44 #include "components/search_engines/search_engine_type.h"
45 #include "components/search_engines/search_engines_switches.h"
46 #include "components/search_engines/search_terms_data.h"
47 #include "components/search_engines/template_url.h"
48 #include "components/search_engines/template_url_service.h"
49 #include "components/signin/core/browser/account_tracker_service.h"
50 #include "components/signin/core/browser/signin_manager.h"
51 #include "components/sync_driver/pref_names.h"
52 #include "components/variations/entropy_provider.h"
53 #include "components/variations/variations_associated_data.h"
54 #include "content/public/test/test_browser_thread_bundle.h"
55 #include "net/url_request/test_url_fetcher_factory.h"
56 #include "net/url_request/url_request_status.h"
57 #include "testing/gtest/include/gtest/gtest.h"
59 using base::ASCIIToUTF16
;
63 // Returns the first match in |matches| with |allowed_to_be_default_match|
65 ACMatches::const_iterator
FindDefaultMatch(const ACMatches
& matches
) {
66 ACMatches::const_iterator it
= matches
.begin();
67 while ((it
!= matches
.end()) && !it
->allowed_to_be_default_match
)
72 class SuggestionDeletionHandler
;
73 class SearchProviderForTest
: public SearchProvider
{
75 SearchProviderForTest(ChromeAutocompleteProviderClient
* client
,
76 AutocompleteProviderListener
* listener
,
78 bool is_success() { return is_success_
; }
81 ~SearchProviderForTest() override
;
84 void RecordDeletionResult(bool success
) override
;
86 DISALLOW_COPY_AND_ASSIGN(SearchProviderForTest
);
89 SearchProviderForTest::SearchProviderForTest(
90 ChromeAutocompleteProviderClient
* client
,
91 AutocompleteProviderListener
* listener
,
93 : SearchProvider(client
, listener
), is_success_(false) {
96 SearchProviderForTest::~SearchProviderForTest() {
99 void SearchProviderForTest::RecordDeletionResult(bool success
) {
100 is_success_
= success
;
105 // SearchProviderTest ---------------------------------------------------------
107 // The following environment is configured for these tests:
108 // . The TemplateURL default_t_url_ is set as the default provider.
109 // . The TemplateURL keyword_t_url_ is added to the TemplateURLService. This
110 // TemplateURL has a valid suggest and search URL.
111 // . The URL created by using the search term term1_ with default_t_url_ is
113 // . The URL created by using the search term keyword_term_ with keyword_t_url_
114 // is added to history.
115 // . test_factory_ is set as the URLFetcherFactory.
116 class SearchProviderTest
: public testing::Test
,
117 public AutocompleteProviderListener
{
120 ResultInfo() : result_type(AutocompleteMatchType::NUM_TYPES
),
121 allowed_to_be_default_match(false) {
123 ResultInfo(GURL gurl
,
124 AutocompleteMatch::Type result_type
,
125 bool allowed_to_be_default_match
,
126 base::string16 fill_into_edit
)
128 result_type(result_type
),
129 allowed_to_be_default_match(allowed_to_be_default_match
),
130 fill_into_edit(fill_into_edit
) {
134 const AutocompleteMatch::Type result_type
;
135 const bool allowed_to_be_default_match
;
136 const base::string16 fill_into_edit
;
140 const base::string16 input
;
141 const size_t num_results
;
142 const ResultInfo output
[3];
145 struct ExpectedMatch
{
146 std::string contents
;
147 bool allowed_to_be_default_match
;
151 : default_t_url_(NULL
),
152 term1_(ASCIIToUTF16("term1")),
153 keyword_t_url_(NULL
),
154 keyword_term_(ASCIIToUTF16("keyword")),
156 ResetFieldTrialList();
159 // See description above class for what this registers.
160 void SetUp() override
;
161 void TearDown() override
;
163 void RunTest(TestData
* cases
, int num_cases
, bool prefer_keyword
);
166 // Needed for AutocompleteFieldTrial::ActivateStaticTrials();
167 scoped_ptr
<base::FieldTrialList
> field_trial_list_
;
169 // Default values used for testing.
170 static const std::string kNotApplicable
;
171 static const ExpectedMatch kEmptyExpectedMatch
;
173 // Adds a search for |term|, using the engine |t_url| to the history, and
174 // returns the URL for that search.
175 GURL
AddSearchToHistory(TemplateURL
* t_url
, base::string16 term
, int visit_count
);
177 // Looks for a match in |provider_| with |contents| equal to |contents|.
178 // Sets |match| to it if found. Returns whether |match| was set.
179 bool FindMatchWithContents(const base::string16
& contents
,
180 AutocompleteMatch
* match
);
182 // Looks for a match in |provider_| with destination |url|. Sets |match| to
183 // it if found. Returns whether |match| was set.
184 bool FindMatchWithDestination(const GURL
& url
, AutocompleteMatch
* match
);
186 // AutocompleteProviderListener:
187 // If we're waiting for the provider to finish, this exits the message loop.
188 void OnProviderUpdate(bool updated_matches
) override
;
190 // Runs a nested message loop until provider_ is done. The message loop is
191 // exited by way of OnProviderUpdate.
192 void RunTillProviderDone();
194 // Invokes Start on provider_, then runs all pending tasks.
195 void QueryForInput(const base::string16
& text
,
196 bool prevent_inline_autocomplete
,
197 bool prefer_keyword
);
199 // Calls QueryForInput(), finishes any suggest query, then if |wyt_match| is
200 // non-NULL, sets it to the "what you typed" entry for |text|.
201 void QueryForInputAndSetWYTMatch(const base::string16
& text
,
202 AutocompleteMatch
* wyt_match
);
204 // Calls QueryForInput(), sets the JSON responses for the default and keyword
205 // fetchers, and waits until the responses have been returned and the matches
206 // returned. Use empty responses for each fetcher that shouldn't be set up /
208 void QueryForInputAndWaitForFetcherResponses(
209 const base::string16
& text
,
210 const bool prefer_keyword
,
211 const std::string
& default_fetcher_response
,
212 const std::string
& keyword_fetcher_response
);
214 // Notifies the URLFetcher for the suggest query corresponding to the default
215 // search provider that it's done.
216 // Be sure and wrap calls to this in ASSERT_NO_FATAL_FAILURE.
217 void FinishDefaultSuggestQuery();
219 // Runs SearchProvider on |input|, for which the suggest server replies
220 // with |json|, and expects that the resulting matches' contents equals
221 // that in |matches|. An empty entry in |matches| means no match should
222 // be returned in that position. Reports any errors with a message that
223 // includes |error_description|.
224 void ForcedQueryTestHelper(const std::string
& input
,
225 const std::string
& json
,
226 const std::string matches
[3],
227 const std::string
& error_description
);
229 // Verifies that |matches| and |expected_matches| agree on the first
230 // |num_expected_matches|, displaying an error message that includes
231 // |description| for any disagreement.
232 void CheckMatches(const std::string
& description
,
233 const size_t num_expected_matches
,
234 const ExpectedMatch expected_matches
[],
235 const ACMatches
& matches
);
237 void ResetFieldTrialList();
239 // Enable or disable the specified Omnibox field trial rule.
240 base::FieldTrial
* CreateFieldTrial(const char* field_trial_rule
,
243 void ClearAllResults();
245 // See description above class for details of these fields.
246 TemplateURL
* default_t_url_
;
247 const base::string16 term1_
;
249 TemplateURL
* keyword_t_url_
;
250 const base::string16 keyword_term_
;
253 content::TestBrowserThreadBundle thread_bundle_
;
255 net::TestURLFetcherFactory test_factory_
;
256 TestingProfile profile_
;
257 scoped_ptr
<ChromeAutocompleteProviderClient
> client_
;
258 scoped_refptr
<SearchProviderForTest
> provider_
;
260 // If non-NULL, OnProviderUpdate quits the current |run_loop_|.
261 base::RunLoop
* run_loop_
;
263 DISALLOW_COPY_AND_ASSIGN(SearchProviderTest
);
267 const std::string
SearchProviderTest::kNotApplicable
= "Not Applicable";
268 const SearchProviderTest::ExpectedMatch
269 SearchProviderTest::kEmptyExpectedMatch
= { kNotApplicable
, false };
271 void SearchProviderTest::SetUp() {
272 // Make sure that fetchers are automatically ungregistered upon destruction.
273 test_factory_
.set_remove_fetcher_on_delete(true);
275 // We need both the history service and template url model loaded.
276 ASSERT_TRUE(profile_
.CreateHistoryService(true, false));
277 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
278 &profile_
, &TemplateURLServiceFactory::BuildInstanceFor
);
280 client_
.reset(new ChromeAutocompleteProviderClient(&profile_
));
282 TemplateURLService
* turl_model
=
283 TemplateURLServiceFactory::GetForProfile(&profile_
);
287 // Reset the default TemplateURL.
288 TemplateURLData data
;
289 data
.SetShortName(ASCIIToUTF16("t"));
290 data
.SetURL("http://defaultturl/{searchTerms}");
291 data
.suggestions_url
= "http://defaultturl2/{searchTerms}";
292 data
.instant_url
= "http://does/not/exist?strk=1";
293 data
.search_terms_replacement_key
= "strk";
294 default_t_url_
= new TemplateURL(data
);
295 turl_model
->Add(default_t_url_
);
296 turl_model
->SetUserSelectedDefaultSearchProvider(default_t_url_
);
297 TemplateURLID default_provider_id
= default_t_url_
->id();
298 ASSERT_NE(0, default_provider_id
);
300 // Add url1, with search term term1_.
301 term1_url_
= AddSearchToHistory(default_t_url_
, term1_
, 1);
303 // Create another TemplateURL.
304 data
.SetShortName(ASCIIToUTF16("k"));
305 data
.SetKeyword(ASCIIToUTF16("k"));
306 data
.SetURL("http://keyword/{searchTerms}");
307 data
.suggestions_url
= "http://suggest_keyword/{searchTerms}";
308 keyword_t_url_
= new TemplateURL(data
);
309 turl_model
->Add(keyword_t_url_
);
310 ASSERT_NE(0, keyword_t_url_
->id());
312 // Add a page and search term for keyword_t_url_.
313 keyword_url_
= AddSearchToHistory(keyword_t_url_
, keyword_term_
, 1);
315 // Keywords are updated by the InMemoryHistoryBackend only after the message
316 // has been processed on the history thread. Block until history processes all
317 // requests to ensure the InMemoryDatabase is the state we expect it.
318 profile_
.BlockUntilHistoryProcessesPendingRequests();
320 AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
321 &profile_
, &AutocompleteClassifierFactory::BuildInstanceFor
);
323 provider_
= new SearchProviderForTest(client_
.get(), this, &profile_
);
324 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
= 0;
327 void SearchProviderTest::TearDown() {
328 base::RunLoop().RunUntilIdle();
330 // Shutdown the provider before the profile.
334 void SearchProviderTest::RunTest(TestData
* cases
,
336 bool prefer_keyword
) {
338 for (int i
= 0; i
< num_cases
; ++i
) {
339 AutocompleteInput
input(cases
[i
].input
, base::string16::npos
, std::string(),
340 GURL(), metrics::OmniboxEventProto::INVALID_SPEC
,
341 false, prefer_keyword
, true, true, false,
342 ChromeAutocompleteSchemeClassifier(&profile_
));
343 provider_
->Start(input
, false);
344 matches
= provider_
->matches();
346 ASCIIToUTF16("Input was: ") +
348 ASCIIToUTF16("; prefer_keyword was: ") +
349 (prefer_keyword
? ASCIIToUTF16("true") : ASCIIToUTF16("false")));
350 EXPECT_EQ(cases
[i
].num_results
, matches
.size());
351 if (matches
.size() == cases
[i
].num_results
) {
352 for (size_t j
= 0; j
< cases
[i
].num_results
; ++j
) {
353 EXPECT_EQ(cases
[i
].output
[j
].gurl
, matches
[j
].destination_url
);
354 EXPECT_EQ(cases
[i
].output
[j
].result_type
, matches
[j
].type
);
355 EXPECT_EQ(cases
[i
].output
[j
].fill_into_edit
,
356 matches
[j
].fill_into_edit
);
357 EXPECT_EQ(cases
[i
].output
[j
].allowed_to_be_default_match
,
358 matches
[j
].allowed_to_be_default_match
);
364 void SearchProviderTest::OnProviderUpdate(bool updated_matches
) {
365 if (run_loop_
&& provider_
->done()) {
371 void SearchProviderTest::RunTillProviderDone() {
372 if (provider_
->done())
375 base::RunLoop run_loop
;
376 run_loop_
= &run_loop
;
380 void SearchProviderTest::QueryForInput(const base::string16
& text
,
381 bool prevent_inline_autocomplete
,
382 bool prefer_keyword
) {
384 AutocompleteInput
input(text
, base::string16::npos
, std::string(), GURL(),
385 metrics::OmniboxEventProto::INVALID_SPEC
,
386 prevent_inline_autocomplete
, prefer_keyword
, true,
388 ChromeAutocompleteSchemeClassifier(&profile_
));
389 provider_
->Start(input
, false);
391 // RunUntilIdle so that the task scheduled by SearchProvider to create the
393 base::RunLoop().RunUntilIdle();
396 void SearchProviderTest::QueryForInputAndSetWYTMatch(
397 const base::string16
& text
,
398 AutocompleteMatch
* wyt_match
) {
399 QueryForInput(text
, false, false);
400 profile_
.BlockUntilHistoryProcessesPendingRequests();
401 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
404 ASSERT_GE(provider_
->matches().size(), 1u);
405 EXPECT_TRUE(FindMatchWithDestination(
406 GURL(default_t_url_
->url_ref().ReplaceSearchTerms(
407 TemplateURLRef::SearchTermsArgs(base::CollapseWhitespace(
409 TemplateURLServiceFactory::GetForProfile(
410 &profile_
)->search_terms_data())),
414 void SearchProviderTest::QueryForInputAndWaitForFetcherResponses(
415 const base::string16
& text
,
416 const bool prefer_keyword
,
417 const std::string
& default_fetcher_response
,
418 const std::string
& keyword_fetcher_response
) {
419 QueryForInput(text
, false, prefer_keyword
);
420 if (!default_fetcher_response
.empty()) {
421 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
422 SearchProvider::kDefaultProviderURLFetcherID
);
423 ASSERT_TRUE(fetcher
);
424 fetcher
->set_response_code(200);
425 fetcher
->SetResponseString(default_fetcher_response
);
426 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
428 if (!keyword_fetcher_response
.empty()) {
429 net::TestURLFetcher
* keyword_fetcher
= test_factory_
.GetFetcherByID(
430 SearchProvider::kKeywordProviderURLFetcherID
);
431 ASSERT_TRUE(keyword_fetcher
);
432 keyword_fetcher
->set_response_code(200);
433 keyword_fetcher
->SetResponseString(keyword_fetcher_response
);
434 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
436 RunTillProviderDone();
439 GURL
SearchProviderTest::AddSearchToHistory(TemplateURL
* t_url
,
442 history::HistoryService
* history
= HistoryServiceFactory::GetForProfile(
443 &profile_
, ServiceAccessType::EXPLICIT_ACCESS
);
444 GURL
search(t_url
->url_ref().ReplaceSearchTerms(
445 TemplateURLRef::SearchTermsArgs(term
),
446 TemplateURLServiceFactory::GetForProfile(
447 &profile_
)->search_terms_data()));
448 static base::Time last_added_time
;
449 last_added_time
= std::max(base::Time::Now(),
450 last_added_time
+ base::TimeDelta::FromMicroseconds(1));
451 history
->AddPageWithDetails(search
, base::string16(), visit_count
, visit_count
,
452 last_added_time
, false, history::SOURCE_BROWSED
);
453 history
->SetKeywordSearchTermsForURL(search
, t_url
->id(), term
);
457 bool SearchProviderTest::FindMatchWithContents(const base::string16
& contents
,
458 AutocompleteMatch
* match
) {
459 for (ACMatches::const_iterator i
= provider_
->matches().begin();
460 i
!= provider_
->matches().end(); ++i
) {
461 if (i
->contents
== contents
) {
469 bool SearchProviderTest::FindMatchWithDestination(const GURL
& url
,
470 AutocompleteMatch
* match
) {
471 for (ACMatches::const_iterator i
= provider_
->matches().begin();
472 i
!= provider_
->matches().end(); ++i
) {
473 if (i
->destination_url
== url
) {
481 void SearchProviderTest::FinishDefaultSuggestQuery() {
482 net::TestURLFetcher
* default_fetcher
=
483 test_factory_
.GetFetcherByID(
484 SearchProvider::kDefaultProviderURLFetcherID
);
485 ASSERT_TRUE(default_fetcher
);
487 // Tell the SearchProvider the default suggest query is done.
488 default_fetcher
->set_response_code(200);
489 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
492 void SearchProviderTest::ForcedQueryTestHelper(
493 const std::string
& input
,
494 const std::string
& json
,
495 const std::string expected_matches
[3],
496 const std::string
& error_description
) {
497 // Send the query twice in order to have a synchronous pass after the first
498 // response is received. This is necessary because SearchProvider doesn't
499 // allow an asynchronous response to change the default match.
500 for (size_t i
= 0; i
< 2; ++i
) {
501 QueryForInputAndWaitForFetcherResponses(
502 ASCIIToUTF16(input
), false, json
, std::string());
505 const ACMatches
& matches
= provider_
->matches();
506 ASSERT_LE(matches
.size(), 3u);
508 // Ensure that the returned matches equal the expectations.
509 for (; i
< matches
.size(); ++i
) {
510 EXPECT_EQ(ASCIIToUTF16(expected_matches
[i
]), matches
[i
].contents
) <<
513 // Ensure that no expected matches are missing.
514 for (; i
< 3u; ++i
) {
515 EXPECT_EQ(std::string(), expected_matches
[i
]) <<
516 "Case #" << i
<< ": " << error_description
;
520 void SearchProviderTest::CheckMatches(const std::string
& description
,
521 const size_t num_expected_matches
,
522 const ExpectedMatch expected_matches
[],
523 const ACMatches
& matches
) {
524 ASSERT_FALSE(matches
.empty());
525 ASSERT_LE(matches
.size(), num_expected_matches
);
527 SCOPED_TRACE(description
);
528 // Ensure that the returned matches equal the expectations.
529 for (; i
< matches
.size(); ++i
) {
530 SCOPED_TRACE(" Case # " + base::SizeTToString(i
));
531 EXPECT_EQ(ASCIIToUTF16(expected_matches
[i
].contents
), matches
[i
].contents
);
532 EXPECT_EQ(expected_matches
[i
].allowed_to_be_default_match
,
533 matches
[i
].allowed_to_be_default_match
);
535 // Ensure that no expected matches are missing.
536 for (; i
< num_expected_matches
; ++i
) {
537 SCOPED_TRACE(" Case # " + base::SizeTToString(i
));
538 EXPECT_EQ(kNotApplicable
, expected_matches
[i
].contents
);
542 void SearchProviderTest::ResetFieldTrialList() {
543 // Destroy the existing FieldTrialList before creating a new one to avoid
545 field_trial_list_
.reset();
546 field_trial_list_
.reset(new base::FieldTrialList(
547 new metrics::SHA1EntropyProvider("foo")));
548 variations::testing::ClearAllVariationParams();
549 base::FieldTrial
* trial
= base::FieldTrialList::CreateFieldTrial(
550 "AutocompleteDynamicTrial_0", "DefaultGroup");
553 base::FieldTrial
* SearchProviderTest::CreateFieldTrial(
554 const char* field_trial_rule
,
556 std::map
<std::string
, std::string
> params
;
557 params
[std::string(field_trial_rule
)] = enabled
?
559 variations::AssociateVariationParams(
560 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
);
561 return base::FieldTrialList::CreateFieldTrial(
562 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
565 void SearchProviderTest::ClearAllResults() {
566 provider_
->ClearAllResults();
569 // Actual Tests ---------------------------------------------------------------
571 // Make sure we query history for the default provider and a URLFetcher is
572 // created for the default provider suggest results.
573 TEST_F(SearchProviderTest
, QueryDefaultProvider
) {
574 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
575 QueryForInput(term
, false, false);
577 // Make sure the default providers suggest service was queried.
578 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
579 SearchProvider::kDefaultProviderURLFetcherID
);
580 ASSERT_TRUE(fetcher
);
582 // And the URL matches what we expected.
583 GURL
expected_url(default_t_url_
->suggestions_url_ref().ReplaceSearchTerms(
584 TemplateURLRef::SearchTermsArgs(term
),
585 TemplateURLServiceFactory::GetForProfile(
586 &profile_
)->search_terms_data()));
587 ASSERT_TRUE(fetcher
->GetOriginalURL() == expected_url
);
589 // Tell the SearchProvider the suggest query is done.
590 fetcher
->set_response_code(200);
591 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
594 // Run till the history results complete.
595 RunTillProviderDone();
597 // The SearchProvider is done. Make sure it has a result for the history
599 AutocompleteMatch term1_match
;
600 EXPECT_TRUE(FindMatchWithDestination(term1_url_
, &term1_match
));
601 // Term1 should not have a description, it's set later.
602 EXPECT_TRUE(term1_match
.description
.empty());
604 AutocompleteMatch wyt_match
;
605 EXPECT_TRUE(FindMatchWithDestination(
606 GURL(default_t_url_
->url_ref().ReplaceSearchTerms(
607 TemplateURLRef::SearchTermsArgs(term
),
608 TemplateURLServiceFactory::GetForProfile(
609 &profile_
)->search_terms_data())),
611 EXPECT_TRUE(wyt_match
.description
.empty());
613 // The match for term1 should be more relevant than the what you typed match.
614 EXPECT_GT(term1_match
.relevance
, wyt_match
.relevance
);
615 // This longer match should be inlineable.
616 EXPECT_TRUE(term1_match
.allowed_to_be_default_match
);
617 // The what you typed match should be too, of course.
618 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
621 // Make sure we get a query-what-you-typed result from the default search
622 // provider even if the default search provider's keyword is renamed in the
623 // middle of processing the query.
624 TEST_F(SearchProviderTest
, HasQueryWhatYouTypedIfDefaultKeywordChanges
) {
625 base::string16 query
= ASCIIToUTF16("query");
626 QueryForInput(query
, false, false);
628 // Make sure the default provider's suggest service was queried.
629 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
630 SearchProvider::kDefaultProviderURLFetcherID
);
631 ASSERT_TRUE(fetcher
);
633 // Look up the TemplateURL for the keyword and modify its keyword.
634 TemplateURLService
* template_url_service
=
635 TemplateURLServiceFactory::GetForProfile(&profile_
);
636 TemplateURL
* template_url
=
637 template_url_service
->GetTemplateURLForKeyword(default_t_url_
->keyword());
638 EXPECT_TRUE(template_url
);
639 template_url_service
->ResetTemplateURL(
640 template_url
, template_url
->short_name(),
641 ASCIIToUTF16("new_keyword_asdf"), template_url
->url());
643 // In resetting the default provider, the fetcher should've been canceled.
644 fetcher
= test_factory_
.GetFetcherByID(
645 SearchProvider::kDefaultProviderURLFetcherID
);
646 EXPECT_TRUE(!fetcher
);
647 RunTillProviderDone();
649 // Makes sure the query-what-you-typed match is there.
650 AutocompleteMatch wyt_match
;
651 EXPECT_TRUE(FindMatchWithDestination(
652 GURL(default_t_url_
->url_ref().ReplaceSearchTerms(
653 TemplateURLRef::SearchTermsArgs(query
),
654 TemplateURLServiceFactory::GetForProfile(
655 &profile_
)->search_terms_data())),
657 EXPECT_TRUE(wyt_match
.description
.empty());
658 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
661 TEST_F(SearchProviderTest
, HonorPreventInlineAutocomplete
) {
662 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
663 QueryForInput(term
, true, false);
665 ASSERT_FALSE(provider_
->matches().empty());
666 ASSERT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
667 provider_
->matches()[0].type
);
668 EXPECT_TRUE(provider_
->matches()[0].allowed_to_be_default_match
);
671 // Issues a query that matches the registered keyword and makes sure history
672 // is queried as well as URLFetchers getting created.
673 TEST_F(SearchProviderTest
, QueryKeywordProvider
) {
674 base::string16 term
= keyword_term_
.substr(0, keyword_term_
.length() - 1);
675 QueryForInput(keyword_t_url_
->keyword() + ASCIIToUTF16(" ") + term
,
679 // Make sure the default providers suggest service was queried.
680 net::TestURLFetcher
* default_fetcher
= test_factory_
.GetFetcherByID(
681 SearchProvider::kDefaultProviderURLFetcherID
);
682 ASSERT_TRUE(default_fetcher
);
684 // Tell the SearchProvider the default suggest query is done.
685 default_fetcher
->set_response_code(200);
686 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
687 default_fetcher
= NULL
;
689 // Make sure the keyword providers suggest service was queried.
690 net::TestURLFetcher
* keyword_fetcher
= test_factory_
.GetFetcherByID(
691 SearchProvider::kKeywordProviderURLFetcherID
);
692 ASSERT_TRUE(keyword_fetcher
);
694 // And the URL matches what we expected.
695 GURL
expected_url(keyword_t_url_
->suggestions_url_ref().ReplaceSearchTerms(
696 TemplateURLRef::SearchTermsArgs(term
),
697 TemplateURLServiceFactory::GetForProfile(
698 &profile_
)->search_terms_data()));
699 ASSERT_TRUE(keyword_fetcher
->GetOriginalURL() == expected_url
);
701 // Tell the SearchProvider the keyword suggest query is done.
702 keyword_fetcher
->set_response_code(200);
703 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
704 keyword_fetcher
= NULL
;
706 // Run till the history results complete.
707 RunTillProviderDone();
709 // The SearchProvider is done. Make sure it has a result for the history
711 AutocompleteMatch match
;
712 EXPECT_TRUE(FindMatchWithDestination(keyword_url_
, &match
));
714 // The match should have an associated keyword.
715 EXPECT_FALSE(match
.keyword
.empty());
717 // The fill into edit should contain the keyword.
718 EXPECT_EQ(keyword_t_url_
->keyword() + base::char16(' ') + keyword_term_
,
719 match
.fill_into_edit
);
722 TEST_F(SearchProviderTest
, SendDataToSuggestAtAppropriateTimes
) {
725 const bool expect_to_send_to_default_provider
;
727 // None of the following input strings should be sent to the default
728 // suggest server because they may contain potentially private data.
729 { "username:password", false },
731 { "http://username:password", false },
732 { "https://username:password", false },
733 { "username:password@hostname", false },
734 { "http://username:password@hostname/", false },
735 { "file://filename", false },
736 { "data://data", false },
737 { "unknownscheme:anything", false },
738 { "http://hostname/?query=q", false },
739 { "http://hostname/path#ref", false },
740 { "http://hostname/path #ref", false },
741 { "https://hostname/path", false },
742 // For all of the following input strings, it doesn't make much difference
743 // if we allow them to be sent to the default provider or not. The strings
744 // need to be in this list of test cases however so that they are tested
745 // against the keyword provider and verified that they are allowed to be
750 // All of the following input strings should be sent to the default suggest
751 // server because they should not get caught by the private data checks.
754 { "query with spaces", true },
755 { "http://hostname", true },
756 { "http://hostname/path", true },
757 { "http://hostname #ref", true },
758 { "www.hostname.com #ref", true },
759 { "https://hostname", true },
760 { "#hashtag", true },
761 { "foo https://hostname/path", true },
764 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
765 SCOPED_TRACE("for input=" + cases
[i
].input
);
766 QueryForInput(ASCIIToUTF16(cases
[i
].input
), false, false);
767 // Make sure the default provider's suggest service was or was not queried
770 cases
[i
].expect_to_send_to_default_provider
,
771 test_factory_
.GetFetcherByID(
772 SearchProvider::kDefaultProviderURLFetcherID
) != NULL
);
773 // Send the same input with an explicitly invoked keyword. In all cases,
774 // it's okay to send the request to the keyword suggest server.
775 QueryForInput(ASCIIToUTF16("k ") + ASCIIToUTF16(cases
[i
].input
), false,
777 EXPECT_TRUE(test_factory_
.GetFetcherByID(
778 SearchProvider::kKeywordProviderURLFetcherID
) != NULL
);
782 TEST_F(SearchProviderTest
, DontAutocompleteURLLikeTerms
) {
783 GURL url
= AddSearchToHistory(default_t_url_
,
784 ASCIIToUTF16("docs.google.com"), 1);
786 // Add the term as a url.
787 HistoryServiceFactory::GetForProfile(&profile_
,
788 ServiceAccessType::EXPLICIT_ACCESS
)
789 ->AddPageWithDetails(GURL("http://docs.google.com"), base::string16(), 1,
790 1, base::Time::Now(), false,
791 history::SOURCE_BROWSED
);
792 profile_
.BlockUntilHistoryProcessesPendingRequests();
794 AutocompleteMatch wyt_match
;
795 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("docs"),
798 // There should be two matches, one for what you typed, the other for
799 // 'docs.google.com'. The search term should have a lower priority than the
800 // what you typed match.
801 ASSERT_EQ(2u, provider_
->matches().size());
802 AutocompleteMatch term_match
;
803 EXPECT_TRUE(FindMatchWithDestination(url
, &term_match
));
804 EXPECT_GT(wyt_match
.relevance
, term_match
.relevance
);
805 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
806 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
809 TEST_F(SearchProviderTest
, DontGiveNavsuggestionsInForcedQueryMode
) {
810 const std::string kEmptyMatch
;
812 const std::string json
;
813 const std::string matches_in_default_mode
[3];
814 const std::string matches_in_forced_query_mode
[3];
816 // Without suggested relevance scores.
817 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
818 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]}]",
819 { "a", "a1.com", "a2" },
820 { "a", "a2", kEmptyMatch
} },
822 // With suggested relevance scores in a situation where navsuggest would
824 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
825 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
826 "\"google:suggestrelevance\":[1250, 1200]}]",
827 { "a", "a1.com", "a2" },
828 { "a", "a2", kEmptyMatch
} },
830 // With suggested relevance scores in a situation where navsuggest
832 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
833 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
834 "\"google:suggestrelevance\":[1350, 1250]}]",
835 { "a1.com", "a", "a2" },
836 { "a", "a2", kEmptyMatch
} },
838 // With suggested relevance scores in a situation where navsuggest
839 // would go first only because verbatim has been demoted.
840 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
841 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
842 "\"google:suggestrelevance\":[1450, 1400],"
843 "\"google:verbatimrelevance\":1350}]",
844 { "a1.com", "a2", "a" },
845 { "a2", "a", kEmptyMatch
} },
848 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
849 ForcedQueryTestHelper("a", cases
[i
].json
, cases
[i
].matches_in_default_mode
,
850 "regular input with json=" + cases
[i
].json
);
851 ForcedQueryTestHelper("?a", cases
[i
].json
,
852 cases
[i
].matches_in_forced_query_mode
,
853 "forced query input with json=" + cases
[i
].json
);
857 // A multiword search with one visit should not autocomplete until multiple
859 TEST_F(SearchProviderTest
, DontAutocompleteUntilMultipleWordsTyped
) {
860 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("one search"),
862 profile_
.BlockUntilHistoryProcessesPendingRequests();
864 AutocompleteMatch wyt_match
;
865 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("on"),
867 ASSERT_EQ(2u, provider_
->matches().size());
868 AutocompleteMatch term_match
;
869 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
870 EXPECT_GT(wyt_match
.relevance
, term_match
.relevance
);
871 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
872 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
874 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("one se"),
876 ASSERT_EQ(2u, provider_
->matches().size());
877 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
878 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
879 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
880 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
883 // A multiword search with more than one visit should autocomplete immediately.
884 TEST_F(SearchProviderTest
, AutocompleteMultipleVisitsImmediately
) {
885 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("two searches"),
887 profile_
.BlockUntilHistoryProcessesPendingRequests();
889 AutocompleteMatch wyt_match
;
890 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("tw"),
892 ASSERT_EQ(2u, provider_
->matches().size());
893 AutocompleteMatch term_match
;
894 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
895 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
896 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
897 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
900 // Autocompletion should work at a word boundary after a space, and should
901 // offer a suggestion for the trimmed search query.
902 TEST_F(SearchProviderTest
, AutocompleteAfterSpace
) {
903 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("two searches "), 2);
904 GURL
suggested_url(default_t_url_
->url_ref().ReplaceSearchTerms(
905 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("two searches")),
906 TemplateURLServiceFactory::GetForProfile(
907 &profile_
)->search_terms_data()));
908 profile_
.BlockUntilHistoryProcessesPendingRequests();
910 AutocompleteMatch wyt_match
;
911 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("two "),
913 ASSERT_EQ(2u, provider_
->matches().size());
914 AutocompleteMatch term_match
;
915 EXPECT_TRUE(FindMatchWithDestination(suggested_url
, &term_match
));
916 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
917 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
918 EXPECT_EQ(ASCIIToUTF16("searches"), term_match
.inline_autocompletion
);
919 EXPECT_EQ(ASCIIToUTF16("two searches"), term_match
.fill_into_edit
);
920 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
923 // Newer multiword searches should score more highly than older ones.
924 TEST_F(SearchProviderTest
, ScoreNewerSearchesHigher
) {
925 GURL
term_url_a(AddSearchToHistory(default_t_url_
,
926 ASCIIToUTF16("three searches aaa"), 1));
927 GURL
term_url_b(AddSearchToHistory(default_t_url_
,
928 ASCIIToUTF16("three searches bbb"), 1));
929 profile_
.BlockUntilHistoryProcessesPendingRequests();
931 AutocompleteMatch wyt_match
;
932 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("three se"),
934 ASSERT_EQ(3u, provider_
->matches().size());
935 AutocompleteMatch term_match_a
;
936 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
937 AutocompleteMatch term_match_b
;
938 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
939 EXPECT_GT(term_match_b
.relevance
, term_match_a
.relevance
);
940 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
941 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
942 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
943 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
946 // If ScoreHistoryResults doesn't properly clear its output vector it can skip
947 // scoring the actual results and just return results from a previous run.
948 TEST_F(SearchProviderTest
, ResetResultsBetweenRuns
) {
949 GURL
term_url_a(AddSearchToHistory(default_t_url_
,
950 ASCIIToUTF16("games"), 1));
951 GURL
term_url_b(AddSearchToHistory(default_t_url_
,
952 ASCIIToUTF16("gangnam style"), 1));
953 GURL
term_url_c(AddSearchToHistory(default_t_url_
,
954 ASCIIToUTF16("gundam"), 1));
955 profile_
.BlockUntilHistoryProcessesPendingRequests();
957 AutocompleteMatch wyt_match
;
958 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
960 ASSERT_EQ(1u, provider_
->matches().size());
962 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("g"),
964 ASSERT_EQ(4u, provider_
->matches().size());
966 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("ga"),
968 ASSERT_EQ(3u, provider_
->matches().size());
970 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("gan"),
972 ASSERT_EQ(2u, provider_
->matches().size());
974 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("gans"),
976 ASSERT_EQ(1u, provider_
->matches().size());
979 // An autocompleted multiword search should not be replaced by a different
980 // autocompletion while the user is still typing a valid prefix unless the
981 // user has typed the prefix as a query before.
982 TEST_F(SearchProviderTest
, DontReplacePreviousAutocompletion
) {
983 GURL
term_url_a(AddSearchToHistory(default_t_url_
,
984 ASCIIToUTF16("four searches aaa"), 3));
985 GURL
term_url_b(AddSearchToHistory(default_t_url_
,
986 ASCIIToUTF16("four searches bbb"), 1));
987 GURL
term_url_c(AddSearchToHistory(default_t_url_
,
988 ASCIIToUTF16("four searches"), 1));
989 profile_
.BlockUntilHistoryProcessesPendingRequests();
991 AutocompleteMatch wyt_match
;
992 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fo"),
994 ASSERT_EQ(4u, provider_
->matches().size());
995 AutocompleteMatch term_match_a
;
996 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
997 AutocompleteMatch term_match_b
;
998 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
999 AutocompleteMatch term_match_c
;
1000 EXPECT_TRUE(FindMatchWithDestination(term_url_c
, &term_match_c
));
1001 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
1002 // We don't care about the relative order of b and c.
1003 EXPECT_GT(wyt_match
.relevance
, term_match_b
.relevance
);
1004 EXPECT_GT(wyt_match
.relevance
, term_match_c
.relevance
);
1005 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
1006 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
1007 EXPECT_TRUE(term_match_c
.allowed_to_be_default_match
);
1008 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
1010 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("four se"),
1012 ASSERT_EQ(4u, provider_
->matches().size());
1013 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
1014 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
1015 EXPECT_TRUE(FindMatchWithDestination(term_url_c
, &term_match_c
));
1016 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
1017 EXPECT_GT(wyt_match
.relevance
, term_match_b
.relevance
);
1018 EXPECT_GT(wyt_match
.relevance
, term_match_c
.relevance
);
1019 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
1020 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
1021 EXPECT_TRUE(term_match_c
.allowed_to_be_default_match
);
1022 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
1024 // For the exact previously-issued query, the what-you-typed match should win.
1025 ASSERT_NO_FATAL_FAILURE(
1026 QueryForInputAndSetWYTMatch(ASCIIToUTF16("four searches"), &wyt_match
));
1027 ASSERT_EQ(3u, provider_
->matches().size());
1028 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
1029 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
1030 EXPECT_GT(wyt_match
.relevance
, term_match_a
.relevance
);
1031 EXPECT_GT(wyt_match
.relevance
, term_match_b
.relevance
);
1032 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
1033 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
1034 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
1037 // Non-completable multiword searches should not crowd out single-word searches.
1038 TEST_F(SearchProviderTest
, DontCrowdOutSingleWords
) {
1039 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five"), 1));
1040 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches bbb"), 1);
1041 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches ccc"), 1);
1042 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches ddd"), 1);
1043 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches eee"), 1);
1044 profile_
.BlockUntilHistoryProcessesPendingRequests();
1046 AutocompleteMatch wyt_match
;
1047 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fi"),
1049 ASSERT_EQ(AutocompleteProvider::kMaxMatches
+ 1, provider_
->matches().size());
1050 AutocompleteMatch term_match
;
1051 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
1052 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
1053 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
1054 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
1057 // Inline autocomplete matches regardless of case differences from the input.
1058 TEST_F(SearchProviderTest
, InlineMixedCaseMatches
) {
1059 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("FOO"), 1));
1060 profile_
.BlockUntilHistoryProcessesPendingRequests();
1062 AutocompleteMatch wyt_match
;
1063 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
1065 ASSERT_EQ(2u, provider_
->matches().size());
1066 AutocompleteMatch term_match
;
1067 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
1068 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
1069 EXPECT_EQ(ASCIIToUTF16("FOO"), term_match
.fill_into_edit
);
1070 EXPECT_EQ(ASCIIToUTF16("OO"), term_match
.inline_autocompletion
);
1071 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
1072 // Make sure the case doesn't affect the highlighting.
1073 // (SearchProvider intentionally marks the new text as MATCH; that's why
1074 // the tests below look backwards.)
1075 ASSERT_EQ(2U, term_match
.contents_class
.size());
1076 EXPECT_EQ(0U, term_match
.contents_class
[0].offset
);
1077 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::NONE
,
1078 term_match
.contents_class
[0].style
);
1079 EXPECT_EQ(1U, term_match
.contents_class
[1].offset
);
1080 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::MATCH
,
1081 term_match
.contents_class
[1].style
);
1084 // Verifies AutocompleteControllers return results (including keyword
1085 // results) in the right order and set descriptions for them correctly.
1086 TEST_F(SearchProviderTest
, KeywordOrderingAndDescriptions
) {
1087 // Add an entry that corresponds to a keyword search with 'term2'.
1088 AddSearchToHistory(keyword_t_url_
, ASCIIToUTF16("term2"), 1);
1089 profile_
.BlockUntilHistoryProcessesPendingRequests();
1091 AutocompleteController
controller(
1092 make_scoped_ptr(new ChromeAutocompleteProviderClient(&profile_
)), nullptr,
1093 AutocompleteProvider::TYPE_SEARCH
);
1094 controller
.Start(AutocompleteInput(
1095 ASCIIToUTF16("k t"), base::string16::npos
, std::string(), GURL(),
1096 metrics::OmniboxEventProto::INVALID_SPEC
, false, false, true, true, false,
1097 ChromeAutocompleteSchemeClassifier(&profile_
)));
1098 const AutocompleteResult
& result
= controller
.result();
1100 // There should be three matches, one for the keyword history, one for
1101 // keyword provider's what-you-typed, and one for the default provider's
1102 // what you typed, in that order.
1103 ASSERT_EQ(3u, result
.size());
1104 EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY
, result
.match_at(0).type
);
1105 EXPECT_EQ(AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1106 result
.match_at(1).type
);
1107 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1108 result
.match_at(2).type
);
1109 EXPECT_GT(result
.match_at(0).relevance
, result
.match_at(1).relevance
);
1110 EXPECT_GT(result
.match_at(1).relevance
, result
.match_at(2).relevance
);
1111 EXPECT_TRUE(result
.match_at(0).allowed_to_be_default_match
);
1112 EXPECT_TRUE(result
.match_at(1).allowed_to_be_default_match
);
1113 EXPECT_FALSE(result
.match_at(2).allowed_to_be_default_match
);
1115 // The two keyword results should come with the keyword we expect.
1116 EXPECT_EQ(ASCIIToUTF16("k"), result
.match_at(0).keyword
);
1117 EXPECT_EQ(ASCIIToUTF16("k"), result
.match_at(1).keyword
);
1118 // The default provider has a different keyword. (We don't explicitly
1119 // set it during this test, so all we do is assert that it's different.)
1120 EXPECT_NE(result
.match_at(0).keyword
, result
.match_at(2).keyword
);
1122 // The top result will always have a description. The third result,
1123 // coming from a different provider than the first two, should also.
1124 // Whether the second result has one doesn't matter much. (If it was
1125 // missing, people would infer that it's the same search provider as
1126 // the one above it.)
1127 EXPECT_FALSE(result
.match_at(0).description
.empty());
1128 EXPECT_FALSE(result
.match_at(2).description
.empty());
1129 EXPECT_NE(result
.match_at(0).description
, result
.match_at(2).description
);
1132 TEST_F(SearchProviderTest
, KeywordVerbatim
) {
1133 TestData cases
[] = {
1134 // Test a simple keyword input.
1135 { ASCIIToUTF16("k foo"), 2,
1136 { ResultInfo(GURL("http://keyword/foo"),
1137 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1139 ASCIIToUTF16("k foo")),
1140 ResultInfo(GURL("http://defaultturl/k%20foo"),
1141 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1143 ASCIIToUTF16("k foo") ) } },
1145 // Make sure extra whitespace after the keyword doesn't change the
1146 // keyword verbatim query. Also verify that interior consecutive
1147 // whitespace gets trimmed.
1148 { ASCIIToUTF16("k foo"), 2,
1149 { ResultInfo(GURL("http://keyword/foo"),
1150 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1152 ASCIIToUTF16("k foo")),
1153 ResultInfo(GURL("http://defaultturl/k%20foo"),
1154 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1156 ASCIIToUTF16("k foo")) } },
1157 // Leading whitespace should be stripped before SearchProvider gets the
1158 // input; hence there are no tests here about how it handles those inputs.
1160 // Verify that interior consecutive whitespace gets trimmed in either case.
1161 { ASCIIToUTF16("k foo bar"), 2,
1162 { ResultInfo(GURL("http://keyword/foo%20bar"),
1163 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1165 ASCIIToUTF16("k foo bar")),
1166 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
1167 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1169 ASCIIToUTF16("k foo bar")) } },
1171 // Verify that trailing whitespace gets trimmed.
1172 { ASCIIToUTF16("k foo bar "), 2,
1173 { ResultInfo(GURL("http://keyword/foo%20bar"),
1174 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1176 ASCIIToUTF16("k foo bar")),
1177 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
1178 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1180 ASCIIToUTF16("k foo bar")) } },
1182 // Keywords can be prefixed by certain things that should get ignored
1183 // when constructing the keyword match.
1184 { ASCIIToUTF16("www.k foo"), 2,
1185 { ResultInfo(GURL("http://keyword/foo"),
1186 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1188 ASCIIToUTF16("k foo")),
1189 ResultInfo(GURL("http://defaultturl/www.k%20foo"),
1190 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1192 ASCIIToUTF16("www.k foo")) } },
1193 { ASCIIToUTF16("http://k foo"), 2,
1194 { ResultInfo(GURL("http://keyword/foo"),
1195 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1197 ASCIIToUTF16("k foo")),
1198 ResultInfo(GURL("http://defaultturl/http%3A//k%20foo"),
1199 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1201 ASCIIToUTF16("http://k foo")) } },
1202 { ASCIIToUTF16("http://www.k foo"), 2,
1203 { ResultInfo(GURL("http://keyword/foo"),
1204 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1206 ASCIIToUTF16("k foo")),
1207 ResultInfo(GURL("http://defaultturl/http%3A//www.k%20foo"),
1208 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1210 ASCIIToUTF16("http://www.k foo")) } },
1212 // A keyword with no remaining input shouldn't get a keyword
1214 { ASCIIToUTF16("k"), 1,
1215 { ResultInfo(GURL("http://defaultturl/k"),
1216 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1218 ASCIIToUTF16("k")) } },
1219 // Ditto. Trailing whitespace shouldn't make a difference.
1220 { ASCIIToUTF16("k "), 1,
1221 { ResultInfo(GURL("http://defaultturl/k"),
1222 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1224 ASCIIToUTF16("k")) } }
1226 // The fact that verbatim queries to keyword are handled by KeywordProvider
1227 // not SearchProvider is tested in
1228 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc.
1231 // Test not in keyword mode.
1232 RunTest(cases
, arraysize(cases
), false);
1234 // Test in keyword mode. (Both modes should give the same result.)
1235 RunTest(cases
, arraysize(cases
), true);
1238 // Ensures command-line flags are reflected in the URLs the search provider
1240 TEST_F(SearchProviderTest
, CommandLineOverrides
) {
1241 TemplateURLService
* turl_model
=
1242 TemplateURLServiceFactory::GetForProfile(&profile_
);
1244 TemplateURLData data
;
1245 data
.SetShortName(ASCIIToUTF16("default"));
1246 data
.SetKeyword(data
.short_name());
1247 data
.SetURL("{google:baseURL}{searchTerms}");
1248 default_t_url_
= new TemplateURL(data
);
1249 turl_model
->Add(default_t_url_
);
1250 turl_model
->SetUserSelectedDefaultSearchProvider(default_t_url_
);
1252 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1253 switches::kGoogleBaseURL
, "http://www.bar.com/");
1254 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1255 switches::kExtraSearchQueryParams
, "a=b");
1257 TestData cases
[] = {
1258 { ASCIIToUTF16("k a"), 2,
1259 { ResultInfo(GURL("http://keyword/a"),
1260 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1262 ASCIIToUTF16("k a")),
1263 ResultInfo(GURL("http://www.bar.com/k%20a?a=b"),
1264 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1266 ASCIIToUTF16("k a")) } },
1269 RunTest(cases
, arraysize(cases
), false);
1272 // Verifies Navsuggest results don't set a TemplateURL, which Instant relies on.
1273 // Also verifies that just the *first* navigational result is listed as a match
1274 // if suggested relevance scores were not sent.
1275 TEST_F(SearchProviderTest
, NavSuggestNoSuggestedRelevanceScores
) {
1276 QueryForInputAndWaitForFetcherResponses(
1277 ASCIIToUTF16("a.c"), false,
1278 "[\"a.c\",[\"a.com\", \"a.com/b\"],[\"a\", \"b\"],[],"
1279 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1282 // Make sure the only match is 'a.com' and it doesn't have a template_url.
1283 AutocompleteMatch nav_match
;
1284 EXPECT_TRUE(FindMatchWithDestination(GURL("http://a.com"), &nav_match
));
1285 EXPECT_TRUE(nav_match
.keyword
.empty());
1286 EXPECT_FALSE(nav_match
.allowed_to_be_default_match
);
1287 EXPECT_FALSE(FindMatchWithDestination(GURL("http://a.com/b"), &nav_match
));
1290 // Verifies that the most relevant suggest results are added properly.
1291 TEST_F(SearchProviderTest
, SuggestRelevance
) {
1292 QueryForInputAndWaitForFetcherResponses(
1293 ASCIIToUTF16("a"), false, "[\"a\",[\"a1\", \"a2\", \"a3\", \"a4\"]]",
1296 // Check the expected verbatim and (first 3) suggestions' relative relevances.
1297 AutocompleteMatch verbatim
, match_a1
, match_a2
, match_a3
, match_a4
;
1298 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim
));
1299 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a1"), &match_a1
));
1300 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a2"), &match_a2
));
1301 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a3"), &match_a3
));
1302 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("a4"), &match_a4
));
1303 EXPECT_GT(verbatim
.relevance
, match_a1
.relevance
);
1304 EXPECT_GT(match_a1
.relevance
, match_a2
.relevance
);
1305 EXPECT_GT(match_a2
.relevance
, match_a3
.relevance
);
1306 EXPECT_TRUE(verbatim
.allowed_to_be_default_match
);
1307 EXPECT_FALSE(match_a1
.allowed_to_be_default_match
);
1308 EXPECT_FALSE(match_a2
.allowed_to_be_default_match
);
1309 EXPECT_FALSE(match_a3
.allowed_to_be_default_match
);
1312 // Verifies that the default provider abandons suggested relevance scores
1313 // when in keyword mode. This should happen regardless of whether the
1314 // keyword provider returns suggested relevance scores.
1315 TEST_F(SearchProviderTest
, DefaultProviderNoSuggestRelevanceInKeywordMode
) {
1317 const std::string default_provider_json
;
1318 const std::string keyword_provider_json
;
1319 const std::string matches
[5];
1321 // First, try an input where the keyword provider does not deliver
1322 // suggested relevance scores.
1323 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1324 "{\"google:verbatimrelevance\":9700,"
1325 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1326 "\"google:suggestrelevance\":[9900, 9800]}]",
1327 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"]}]",
1328 { "a", "akeyword-query", "k a", "adefault.com", "k adefault-query" } },
1330 // Now try with keyword provider suggested relevance scores.
1331 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1332 "{\"google:verbatimrelevance\":9700,"
1333 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1334 "\"google:suggestrelevance\":[9900, 9800]}]",
1335 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"],"
1336 "\"google:verbatimrelevance\":9500,"
1337 "\"google:suggestrelevance\":[9600]}]",
1338 { "akeyword-query", "a", "k a", "adefault.com", "k adefault-query" } }
1341 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
1342 // Send the query twice in order to have a synchronous pass after the first
1343 // response is received. This is necessary because SearchProvider doesn't
1344 // allow an asynchronous response to change the default match.
1345 for (size_t j
= 0; j
< 2; ++j
) {
1346 QueryForInputAndWaitForFetcherResponses(
1347 ASCIIToUTF16("k a"), true, cases
[i
].default_provider_json
,
1348 cases
[i
].keyword_provider_json
);
1352 "for input with default_provider_json=" +
1353 cases
[i
].default_provider_json
+ " and keyword_provider_json=" +
1354 cases
[i
].keyword_provider_json
);
1355 const ACMatches
& matches
= provider_
->matches();
1356 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
1358 // Ensure that the returned matches equal the expectations.
1359 for (; j
< matches
.size(); ++j
)
1360 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
]), matches
[j
].contents
);
1361 // Ensure that no expected matches are missing.
1362 for (; j
< arraysize(cases
[i
].matches
); ++j
)
1363 EXPECT_EQ(std::string(), cases
[i
].matches
[j
]);
1367 // Verifies that suggest results with relevance scores are added
1368 // properly when using the default fetcher. When adding a new test
1369 // case to this test, please consider adding it to the tests in
1370 // KeywordFetcherSuggestRelevance below.
1371 TEST_F(SearchProviderTest
, DefaultFetcherSuggestRelevance
) {
1373 const std::string json
;
1374 const ExpectedMatch matches
[6];
1375 const std::string inline_autocompletion
;
1377 // Ensure that suggestrelevance scores reorder matches.
1378 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1379 { { "a", true }, { "c", false }, { "b", false }, kEmptyExpectedMatch
,
1380 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1382 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1383 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1384 "\"google:suggestrelevance\":[1, 2]}]",
1385 { { "a", true }, { "c.com", false }, { "b.com", false },
1386 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1389 // Without suggested relevance scores, we should only allow one
1390 // navsuggest result to be be displayed.
1391 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1392 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1393 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch
,
1394 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1397 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1398 // Negative values will have no effect; the calculated value will be used.
1399 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1400 "\"google:suggestrelevance\":[9998]}]",
1401 { { "a", true}, { "a1", false }, kEmptyExpectedMatch
,
1402 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1404 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1405 "\"google:suggestrelevance\":[9999]}]",
1406 { { "a1", true }, { "a", true }, kEmptyExpectedMatch
,
1407 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1409 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1410 "\"google:suggestrelevance\":[9999]}]",
1411 { { "a1", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1412 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1414 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1415 "\"google:suggestrelevance\":[9999]}]",
1416 { { "a1", true }, { "a", true }, kEmptyExpectedMatch
,
1417 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1419 { "[\"a\",[\"http://a.com\"],[],[],"
1420 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1421 "\"google:verbatimrelevance\":9999,"
1422 "\"google:suggestrelevance\":[9998]}]",
1423 { { "a", true }, { "a.com", false }, kEmptyExpectedMatch
,
1424 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1426 { "[\"a\",[\"http://a.com\"],[],[],"
1427 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1428 "\"google:verbatimrelevance\":9998,"
1429 "\"google:suggestrelevance\":[9999]}]",
1430 { { "a.com", true }, { "a", true }, kEmptyExpectedMatch
,
1431 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1433 { "[\"a\",[\"http://a.com\"],[],[],"
1434 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1435 "\"google:verbatimrelevance\":0,"
1436 "\"google:suggestrelevance\":[9999]}]",
1437 { { "a.com", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1438 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1440 { "[\"a\",[\"http://a.com\"],[],[],"
1441 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1442 "\"google:verbatimrelevance\":-1,"
1443 "\"google:suggestrelevance\":[9999]}]",
1444 { { "a.com", true }, { "a", true }, kEmptyExpectedMatch
,
1445 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1448 // Ensure that both types of relevance scores reorder matches together.
1449 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1450 "\"google:verbatimrelevance\":9998}]",
1451 { { "a1", true }, { "a", true }, { "a2", false }, kEmptyExpectedMatch
,
1452 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1455 // Check that an inlineable result appears first regardless of its score.
1456 // Also, if the result set lacks a single inlineable result, abandon the
1457 // request to suppress verbatim (verbatim_relevance=0), which will then
1458 // cause verbatim to appear (first).
1459 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1460 { { "a", true }, { "b", false }, kEmptyExpectedMatch
,
1461 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1463 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1464 "\"google:verbatimrelevance\":0}]",
1465 { { "a", true }, { "b", false }, kEmptyExpectedMatch
,
1466 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1468 { "[\"a\",[\"http://b.com\"],[],[],"
1469 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1470 "\"google:suggestrelevance\":[9999]}]",
1471 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch
,
1472 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1474 { "[\"a\",[\"http://b.com\"],[],[],"
1475 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1476 "\"google:suggestrelevance\":[9999],"
1477 "\"google:verbatimrelevance\":0}]",
1478 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch
,
1479 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1482 // Allow low-scoring matches.
1483 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1484 { { "a1", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1485 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1487 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":10}]",
1488 { { "a1", true }, { "a", true }, kEmptyExpectedMatch
,
1489 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1491 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[10],"
1492 "\"google:verbatimrelevance\":0}]",
1493 { { "a1", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1494 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1496 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 20],"
1497 "\"google:verbatimrelevance\":0}]",
1498 { { "a2", true }, { "a1", false }, kEmptyExpectedMatch
,
1499 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1501 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 30],"
1502 "\"google:verbatimrelevance\":20}]",
1503 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1504 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1506 { "[\"a\",[\"http://a.com\"],[],[],"
1507 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1508 "\"google:suggestrelevance\":[10],"
1509 "\"google:verbatimrelevance\":0}]",
1510 { { "a.com", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1511 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1513 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1514 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1515 "\"google:suggestrelevance\":[10, 20],"
1516 "\"google:verbatimrelevance\":0}]",
1517 { { "a2.com", true }, { "a1.com", false }, kEmptyExpectedMatch
,
1518 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1521 // Ensure that all suggestions are considered, regardless of order.
1522 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1523 "{\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1524 { { "a", true }, { "h", false }, { "g", false }, { "f", false },
1525 { "e", false }, { "d", false } },
1527 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1528 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1529 "\"http://h.com\"],[],[],"
1530 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1531 "\"NAVIGATION\", \"NAVIGATION\","
1532 "\"NAVIGATION\", \"NAVIGATION\","
1534 "\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1535 { { "a", true }, { "h.com", false }, { "g.com", false },
1536 { "f.com", false }, { "e.com", false }, { "d.com", false } },
1539 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1540 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10]}]",
1541 { { "a", true }, { "a1", false }, { "a2", false }, kEmptyExpectedMatch
,
1542 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1544 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 10]}]",
1545 { { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1546 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1548 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1549 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1550 "\"google:suggestrelevance\":[10]}]",
1551 { { "a", true }, { "a1.com", false }, kEmptyExpectedMatch
,
1552 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1554 { "[\"a\",[\"http://a1.com\"],[],[],"
1555 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1556 "\"google:suggestrelevance\":[9999, 10]}]",
1557 { { "a", true }, { "a1.com", false }, kEmptyExpectedMatch
,
1558 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1561 // Ensure that all 'verbatim' results are merged with their maximum score.
1562 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1563 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1564 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1565 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1567 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1568 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1569 "\"google:verbatimrelevance\":0}]",
1570 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1571 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1574 // Ensure that verbatim is always generated without other suggestions.
1575 // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
1576 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1577 { { "a", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1578 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1580 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1581 { { "a", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1582 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1586 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
1587 // Send the query twice in order to have a synchronous pass after the first
1588 // response is received. This is necessary because SearchProvider doesn't
1589 // allow an asynchronous response to change the default match.
1590 for (size_t j
= 0; j
< 2; ++j
) {
1591 QueryForInputAndWaitForFetcherResponses(
1592 ASCIIToUTF16("a"), false, cases
[i
].json
, std::string());
1595 const std::string description
= "for input with json=" + cases
[i
].json
;
1596 CheckMatches(description
, arraysize(cases
[i
].matches
), cases
[i
].matches
,
1597 provider_
->matches());
1601 // Verifies that suggest results with relevance scores are added
1602 // properly when using the keyword fetcher. This is similar to the
1603 // test DefaultFetcherSuggestRelevance above but this uses inputs that
1604 // trigger keyword suggestions (i.e., "k a" rather than "a") and has
1605 // different expectations (because now the results are a mix of
1606 // keyword suggestions and default provider suggestions). When a new
1607 // test is added to this TEST_F, please consider if it would be
1608 // appropriate to add to DefaultFetcherSuggestRelevance as well.
1609 TEST_F(SearchProviderTest
, KeywordFetcherSuggestRelevance
) {
1610 struct KeywordFetcherMatch
{
1611 std::string contents
;
1613 bool allowed_to_be_default_match
;
1615 const KeywordFetcherMatch kEmptyMatch
= { kNotApplicable
, false, false };
1617 const std::string json
;
1618 const KeywordFetcherMatch matches
[6];
1619 const std::string inline_autocompletion
;
1621 // Ensure that suggest relevance scores reorder matches and that
1622 // the keyword verbatim (lacking a suggested verbatim score) beats
1623 // the default provider verbatim.
1624 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1625 { { "a", true, true },
1626 { "k a", false, false },
1627 { "c", true, false },
1628 { "b", true, false },
1629 kEmptyMatch
, kEmptyMatch
},
1631 // Again, check that relevance scores reorder matches, just this
1632 // time with navigation matches. This also checks that with
1633 // suggested relevance scores we allow multiple navsuggest results.
1634 // Note that navsuggest results that come from a keyword provider
1635 // are marked as not a keyword result. (They don't go to a
1636 // keyword search engine.)
1637 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
1638 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1639 "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
1640 { { "a", true, true },
1641 { "d", true, false },
1642 { "c.com", false, false },
1643 { "b.com", false, false },
1644 { "k a", false, false },
1648 // Without suggested relevance scores, we should only allow one
1649 // navsuggest result to be be displayed.
1650 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1651 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1652 { { "a", true, true },
1653 { "b.com", false, false },
1654 { "k a", false, false },
1655 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1658 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1659 // Negative values will have no effect; the calculated value will be used.
1660 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1661 "\"google:suggestrelevance\":[9998]}]",
1662 { { "a", true, true },
1663 { "a1", true, false },
1664 { "k a", false, false },
1665 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1667 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1668 "\"google:suggestrelevance\":[9999]}]",
1669 { { "a1", true, true },
1670 { "a", true, true },
1671 { "k a", false, false },
1672 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1674 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1675 "\"google:suggestrelevance\":[9999]}]",
1676 { { "a1", true, true },
1677 { "k a", false, false },
1678 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1680 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1681 "\"google:suggestrelevance\":[9999]}]",
1682 { { "a1", true, true },
1683 { "a", true, true },
1684 { "k a", false, false },
1685 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1687 { "[\"a\",[\"http://a.com\"],[],[],"
1688 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1689 "\"google:verbatimrelevance\":9999,"
1690 "\"google:suggestrelevance\":[9998]}]",
1691 { { "a", true, true },
1692 { "a.com", false, false },
1693 { "k a", false, false },
1694 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1697 // Ensure that both types of relevance scores reorder matches together.
1698 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1699 "\"google:verbatimrelevance\":9998}]",
1700 { { "a1", true, true },
1701 { "a", true, true },
1702 { "a2", true, false },
1703 { "k a", false, false },
1704 kEmptyMatch
, kEmptyMatch
},
1707 // Check that an inlineable match appears first regardless of its score.
1708 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1709 { { "a", true, true },
1710 { "b", true, false },
1711 { "k a", false, false },
1712 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1714 { "[\"a\",[\"http://b.com\"],[],[],"
1715 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1716 "\"google:suggestrelevance\":[9999]}]",
1717 { { "a", true, true },
1718 { "b.com", false, false },
1719 { "k a", false, false },
1720 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1722 // If there is no inlineable match, restore the keyword verbatim score.
1723 // The keyword verbatim match will then appear first.
1724 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1725 "\"google:verbatimrelevance\":0}]",
1726 { { "a", true, true },
1727 { "b", true, false },
1728 { "k a", false, false },
1729 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1731 { "[\"a\",[\"http://b.com\"],[],[],"
1732 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1733 "\"google:suggestrelevance\":[9999],"
1734 "\"google:verbatimrelevance\":0}]",
1735 { { "a", true, true },
1736 { "b.com", false, false },
1737 { "k a", false, false },
1738 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1741 // The top result does not have to score as highly as calculated
1742 // verbatim. i.e., there are no minimum score restrictions in
1744 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1745 { { "a1", true, true },
1746 { "k a", false, false },
1747 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1749 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":10}]",
1750 { { "a1", true, true },
1751 { "k a", false, false },
1752 { "a", true, true },
1753 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1755 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[10],"
1756 "\"google:verbatimrelevance\":0}]",
1757 { { "a1", true, true },
1758 { "k a", false, false },
1759 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1761 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 20],"
1762 "\"google:verbatimrelevance\":0}]",
1763 { { "a2", true, true },
1764 { "k a", false, false },
1765 { "a1", true, false },
1766 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1768 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 30],"
1769 "\"google:verbatimrelevance\":20}]",
1770 { { "a2", true, true },
1771 { "k a", false, false },
1772 { "a", true, true },
1773 { "a1", true, false },
1774 kEmptyMatch
, kEmptyMatch
},
1777 // Ensure that all suggestions are considered, regardless of order.
1778 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1779 "{\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1780 { { "a", true, true },
1781 { "k a", false, false },
1782 { "h", true, false },
1783 { "g", true, false },
1784 { "f", true, false },
1785 { "e", true, false } },
1787 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1788 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1789 "\"http://h.com\"],[],[],"
1790 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1791 "\"NAVIGATION\", \"NAVIGATION\","
1792 "\"NAVIGATION\", \"NAVIGATION\","
1794 "\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1795 { { "a", true, true },
1796 { "k a", false, false },
1797 { "h.com", false, false },
1798 { "g.com", false, false },
1799 { "f.com", false, false },
1800 { "e.com", false, false } },
1803 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1804 // Note that keyword suggestions by default (not in suggested relevance
1805 // mode) score more highly than the default verbatim.
1806 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1807 { { "a", true, true },
1808 { "a1", true, false },
1809 { "a2", true, false },
1810 { "k a", false, false },
1811 kEmptyMatch
, kEmptyMatch
},
1813 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1814 { { "a", true, true },
1815 { "a1", true, false },
1816 { "k a", false, false },
1817 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1819 // In this case, ignoring the suggested relevance scores means we keep
1820 // only one navsuggest result.
1821 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1822 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1823 "\"google:suggestrelevance\":[1]}]",
1824 { { "a", true, true },
1825 { "a1.com", false, false },
1826 { "k a", false, false },
1827 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1829 { "[\"a\",[\"http://a1.com\"],[],[],"
1830 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1831 "\"google:suggestrelevance\":[9999, 1]}]",
1832 { { "a", true, true },
1833 { "a1.com", false, false },
1834 { "k a", false, false },
1835 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1838 // Ensure that all 'verbatim' results are merged with their maximum score.
1839 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1840 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1841 { { "a2", true, true },
1842 { "a", true, true },
1843 { "a1", true, false },
1844 { "k a", false, false },
1845 kEmptyMatch
, kEmptyMatch
},
1847 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1848 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1849 "\"google:verbatimrelevance\":0}]",
1850 { { "a2", true, true },
1851 { "a", true, true },
1852 { "a1", true, false },
1853 { "k a", false, false },
1854 kEmptyMatch
, kEmptyMatch
},
1857 // Ensure that verbatim is always generated without other suggestions.
1858 // TODO(mpearson): Ensure the value of verbatimrelevance is respected
1859 // (except when suggested relevances are ignored).
1860 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1861 { { "a", true, true },
1862 { "k a", false, false },
1863 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1865 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1866 { { "a", true, true },
1867 { "k a", false, false },
1868 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1871 // In reorder mode, navsuggestions will not need to be demoted (because
1872 // they are marked as not allowed to be default match and will be
1873 // reordered as necessary).
1874 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1875 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1876 "\"google:verbatimrelevance\":9990,"
1877 "\"google:suggestrelevance\":[9998, 9999]}]",
1878 { { "a", true, true },
1879 { "a2.com", false, false },
1880 { "a1.com", false, false },
1881 { "k a", false, false },
1882 kEmptyMatch
, kEmptyMatch
},
1884 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1885 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1886 "\"google:verbatimrelevance\":9990,"
1887 "\"google:suggestrelevance\":[9999, 9998]}]",
1888 { { "a", true, true },
1889 { "a1.com", false, false },
1890 { "a2.com", false, false },
1891 { "k a", false, false },
1892 kEmptyMatch
, kEmptyMatch
},
1894 { "[\"a\",[\"https://a/\"],[],[],"
1895 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1896 "\"google:suggestrelevance\":[9999]}]",
1897 { { "a", true, true },
1898 { "https://a", false, false },
1899 { "k a", false, false },
1900 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1902 // Check when navsuggest scores more than verbatim and there is query
1903 // suggestion but it scores lower.
1904 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1905 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1906 "\"google:verbatimrelevance\":9990,"
1907 "\"google:suggestrelevance\":[9998, 9999, 1300]}]",
1908 { { "a", true, true },
1909 { "a2.com", false, false },
1910 { "a1.com", false, false },
1911 { "a3", true, false },
1912 { "k a", false, false },
1915 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1916 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1917 "\"google:verbatimrelevance\":9990,"
1918 "\"google:suggestrelevance\":[9999, 9998, 1300]}]",
1919 { { "a", true, true },
1920 { "a1.com", false, false },
1921 { "a2.com", false, false },
1922 { "a3", true, false },
1923 { "k a", false, false },
1926 // Check when navsuggest scores more than a query suggestion. There is
1927 // a verbatim but it scores lower.
1928 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1929 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1930 "\"google:verbatimrelevance\":9990,"
1931 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1932 { { "a3", true, true },
1933 { "a2.com", false, false },
1934 { "a1.com", false, false },
1935 { "a", true, true },
1936 { "k a", false, false },
1939 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1940 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1941 "\"google:verbatimrelevance\":9990,"
1942 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1943 { { "a3", true, true },
1944 { "a1.com", false, false },
1945 { "a2.com", false, false },
1946 { "a", true, true },
1947 { "k a", false, false },
1950 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1951 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1952 "\"google:verbatimrelevance\":0,"
1953 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1954 { { "a3", true, true },
1955 { "a2.com", false, false },
1956 { "a1.com", false, false },
1957 { "k a", false, false },
1958 kEmptyMatch
, kEmptyMatch
},
1960 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1961 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1962 "\"google:verbatimrelevance\":0,"
1963 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1964 { { "a3", true, true },
1965 { "a1.com", false, false },
1966 { "a2.com", false, false },
1967 { "k a", false, false },
1968 kEmptyMatch
, kEmptyMatch
},
1970 // Check when there is neither verbatim nor a query suggestion that,
1971 // because we can't demote navsuggestions below a query suggestion,
1972 // we restore the keyword verbatim score.
1973 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1974 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1975 "\"google:verbatimrelevance\":0,"
1976 "\"google:suggestrelevance\":[9998, 9999]}]",
1977 { { "a", true, true },
1978 { "a2.com", false, false },
1979 { "a1.com", false, false },
1980 { "k a", false, false },
1981 kEmptyMatch
, kEmptyMatch
},
1983 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1984 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1985 "\"google:verbatimrelevance\":0,"
1986 "\"google:suggestrelevance\":[9999, 9998]}]",
1987 { { "a", true, true },
1988 { "a1.com", false, false },
1989 { "a2.com", false, false },
1990 { "k a", false, false },
1991 kEmptyMatch
, kEmptyMatch
},
1993 // More checks that everything works when it's not necessary to demote.
1994 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1995 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1996 "\"google:verbatimrelevance\":9990,"
1997 "\"google:suggestrelevance\":[9997, 9998, 9999]}]",
1998 { { "a3", true, true },
1999 { "a2.com", false, false },
2000 { "a1.com", false, false },
2001 { "a", true, true },
2002 { "k a", false, false },
2005 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2006 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2007 "\"google:verbatimrelevance\":9990,"
2008 "\"google:suggestrelevance\":[9998, 9997, 9999]}]",
2009 { { "a3", true, true },
2010 { "a1.com", false, false },
2011 { "a2.com", false, false },
2012 { "a", true, true },
2013 { "k a", false, false },
2018 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2019 // Send the query twice in order to have a synchronous pass after the first
2020 // response is received. This is necessary because SearchProvider doesn't
2021 // allow an asynchronous response to change the default match.
2022 for (size_t j
= 0; j
< 2; ++j
) {
2023 QueryForInput(ASCIIToUTF16("k a"), false, true);
2025 // Set up a default fetcher with no results.
2026 net::TestURLFetcher
* default_fetcher
=
2027 test_factory_
.GetFetcherByID(
2028 SearchProvider::kDefaultProviderURLFetcherID
);
2029 ASSERT_TRUE(default_fetcher
);
2030 default_fetcher
->set_response_code(200);
2031 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
2032 default_fetcher
= NULL
;
2034 // Set up a keyword fetcher with provided results.
2035 net::TestURLFetcher
* keyword_fetcher
=
2036 test_factory_
.GetFetcherByID(
2037 SearchProvider::kKeywordProviderURLFetcherID
);
2038 ASSERT_TRUE(keyword_fetcher
);
2039 keyword_fetcher
->set_response_code(200);
2040 keyword_fetcher
->SetResponseString(cases
[i
].json
);
2041 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
2042 keyword_fetcher
= NULL
;
2043 RunTillProviderDone();
2046 SCOPED_TRACE("for input with json=" + cases
[i
].json
);
2047 const ACMatches
& matches
= provider_
->matches();
2048 ASSERT_FALSE(matches
.empty());
2049 // Find the first match that's allowed to be the default match and check
2050 // its inline_autocompletion.
2051 ACMatches::const_iterator it
= FindDefaultMatch(matches
);
2052 ASSERT_NE(matches
.end(), it
);
2053 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
2054 it
->inline_autocompletion
);
2056 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2058 // Ensure that the returned matches equal the expectations.
2059 for (; j
< matches
.size(); ++j
) {
2060 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
].contents
),
2061 matches
[j
].contents
);
2062 EXPECT_EQ(cases
[i
].matches
[j
].from_keyword
,
2063 matches
[j
].keyword
== ASCIIToUTF16("k"));
2064 EXPECT_EQ(cases
[i
].matches
[j
].allowed_to_be_default_match
,
2065 matches
[j
].allowed_to_be_default_match
);
2067 // Ensure that no expected matches are missing.
2068 for (; j
< arraysize(cases
[i
].matches
); ++j
) {
2069 SCOPED_TRACE(" Case # " + base::SizeTToString(i
));
2070 EXPECT_EQ(kNotApplicable
, cases
[i
].matches
[j
].contents
);
2075 TEST_F(SearchProviderTest
, DontInlineAutocompleteAsynchronously
) {
2076 // This test sends two separate queries, each receiving different JSON
2077 // replies, and checks that at each stage of processing (receiving first
2078 // asynchronous response, handling new keystroke synchronously / sending the
2079 // second request, and receiving the second asynchronous response) we have the
2080 // expected matches. In particular, receiving the second response shouldn't
2081 // cause an unexpected inline autcompletion.
2083 const std::string first_json
;
2084 const ExpectedMatch first_async_matches
[4];
2085 const ExpectedMatch sync_matches
[4];
2086 const std::string second_json
;
2087 const ExpectedMatch second_async_matches
[4];
2089 // A simple test that verifies we don't inline autocomplete after the
2090 // first asynchronous response, but we do at the next keystroke if the
2091 // response's results were good enough. Furthermore, we should continue
2092 // inline autocompleting after the second asynchronous response if the new
2093 // top suggestion is the same as the old inline autocompleted suggestion.
2094 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2095 "{\"google:verbatimrelevance\":9000,"
2096 "\"google:suggestrelevance\":[9002, 9001]}]",
2097 { { "a", true }, { "ab1", false }, { "ab2", false },
2098 kEmptyExpectedMatch
},
2099 { { "ab1", true }, { "ab2", true }, { "ab", true },
2100 kEmptyExpectedMatch
},
2101 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2102 "{\"google:verbatimrelevance\":9000,"
2103 "\"google:suggestrelevance\":[9002, 9001]}]",
2104 { { "ab1", true }, { "ab2", false }, { "ab", true },
2105 kEmptyExpectedMatch
} },
2106 // Ditto, just for a navigation suggestion.
2107 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2108 "{\"google:verbatimrelevance\":9000,"
2109 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2110 "\"google:suggestrelevance\":[9002, 9001]}]",
2111 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2112 kEmptyExpectedMatch
},
2113 { { "ab1.com", true }, { "ab2.com", true }, { "ab", true },
2114 kEmptyExpectedMatch
},
2115 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2116 "{\"google:verbatimrelevance\":9000,"
2117 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2118 "\"google:suggestrelevance\":[9002, 9001]}]",
2119 { { "ab1.com", true }, { "ab2.com", false }, { "ab", true },
2120 kEmptyExpectedMatch
} },
2121 // A more realistic test of the same situation.
2122 { "[\"a\",[\"abcdef\", \"abcdef.com\", \"abc\"],[],[],"
2123 "{\"google:verbatimrelevance\":900,"
2124 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"QUERY\"],"
2125 "\"google:suggestrelevance\":[1250, 1200, 1000]}]",
2126 { { "a", true }, { "abcdef", false }, { "abcdef.com", false },
2128 { { "abcdef", true }, { "abcdef.com", true }, { "abc", true },
2130 "[\"ab\",[\"abcdef\", \"abcdef.com\", \"abc\"],[],[],"
2131 "{\"google:verbatimrelevance\":900,"
2132 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"QUERY\"],"
2133 "\"google:suggestrelevance\":[1250, 1200, 1000]}]",
2134 { { "abcdef", true }, { "abcdef.com", false }, { "abc", false },
2137 // Without an original inline autcompletion, a new inline autcompletion
2138 // should be rejected.
2139 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2140 "{\"google:verbatimrelevance\":9000,"
2141 "\"google:suggestrelevance\":[8000, 7000]}]",
2142 { { "a", true }, { "ab1", false }, { "ab2", false },
2143 kEmptyExpectedMatch
},
2144 { { "ab", true }, { "ab1", true }, { "ab2", true },
2145 kEmptyExpectedMatch
},
2146 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2147 "{\"google:verbatimrelevance\":9000,"
2148 "\"google:suggestrelevance\":[9002, 9001]}]",
2149 { { "ab", true }, { "ab1", false }, { "ab2", false },
2150 kEmptyExpectedMatch
} },
2151 // For the same test except with the queries scored in the opposite order
2152 // on the second JSON response, the queries should be ordered by the second
2153 // response's scores, not the first.
2154 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2155 "{\"google:verbatimrelevance\":9000,"
2156 "\"google:suggestrelevance\":[8000, 7000]}]",
2157 { { "a", true }, { "ab1", false }, { "ab2", false },
2158 kEmptyExpectedMatch
},
2159 { { "ab", true }, { "ab1", true }, { "ab2", true },
2160 kEmptyExpectedMatch
},
2161 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2162 "{\"google:verbatimrelevance\":9000,"
2163 "\"google:suggestrelevance\":[9001, 9002]}]",
2164 { { "ab", true }, { "ab2", false }, { "ab1", false },
2165 kEmptyExpectedMatch
} },
2166 // Now, the same verifications but with the new inline autocompletion as a
2167 // navsuggestion. The new autocompletion should still be rejected.
2168 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2169 "{\"google:verbatimrelevance\":9000,"
2170 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2171 "\"google:suggestrelevance\":[8000, 7000]}]",
2172 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2173 kEmptyExpectedMatch
},
2174 { { "ab", true }, { "ab1.com", true }, { "ab2.com", true },
2175 kEmptyExpectedMatch
},
2176 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2177 "{\"google:verbatimrelevance\":9000,"
2178 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2179 "\"google:suggestrelevance\":[9002, 9001]}]",
2180 { { "ab", true }, { "ab1.com", false }, { "ab2.com", false },
2181 kEmptyExpectedMatch
} },
2182 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2183 "{\"google:verbatimrelevance\":9000,"
2184 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2185 "\"google:suggestrelevance\":[8000, 7000]}]",
2186 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2187 kEmptyExpectedMatch
},
2188 { { "ab", true }, { "ab1.com", true }, { "ab2.com", true },
2189 kEmptyExpectedMatch
},
2190 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2191 "{\"google:verbatimrelevance\":9000,"
2192 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2193 "\"google:suggestrelevance\":[9001, 9002]}]",
2194 { { "ab", true }, { "ab2.com", false }, { "ab1.com", false },
2195 kEmptyExpectedMatch
} },
2197 // It's okay to abandon an inline autocompletion asynchronously.
2198 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2199 "{\"google:verbatimrelevance\":9000,"
2200 "\"google:suggestrelevance\":[9002, 9001]}]",
2201 { { "a", true }, { "ab1", false }, { "ab2", false },
2202 kEmptyExpectedMatch
},
2203 { { "ab1", true }, { "ab2", true }, { "ab", true },
2204 kEmptyExpectedMatch
},
2205 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2206 "{\"google:verbatimrelevance\":9000,"
2207 "\"google:suggestrelevance\":[8000, 7000]}]",
2208 { { "ab", true }, { "ab1", true }, { "ab2", false },
2209 kEmptyExpectedMatch
} },
2211 // Note: it's possible that the suggest server returns a suggestion with
2212 // an inline autocompletion (that as usual we delay in allowing it to
2213 // be displayed as an inline autocompletion until the next keystroke),
2214 // then, in response to the next keystroke, the server returns a different
2215 // suggestion as an inline autocompletion. This is not likely to happen.
2216 // Regardless, if it does, one could imagine three different behaviors:
2217 // - keep the original inline autocompletion until the next keystroke
2218 // (i.e., don't abandon an inline autocompletion asynchronously), then
2219 // use the new suggestion
2220 // - abandon all inline autocompletions upon the server response, then use
2221 // the new suggestion on the next keystroke
2222 // - ignore the new inline autocompletion provided by the server, yet
2223 // possibly keep the original if it scores well in the most recent
2224 // response, then use the new suggestion on the next keystroke
2225 // All of these behaviors are reasonable. The main thing we want to
2226 // ensure is that the second asynchronous response shouldn't cause *a new*
2227 // inline autocompletion to be displayed. We test that here.
2228 // The current implementation does the third bullet, but all of these
2229 // behaviors seem reasonable.
2230 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2231 "{\"google:verbatimrelevance\":9000,"
2232 "\"google:suggestrelevance\":[9002, 9001]}]",
2233 { { "a", true }, { "ab1", false }, { "ab2", false },
2234 kEmptyExpectedMatch
},
2235 { { "ab1", true }, { "ab2", true }, { "ab", true },
2236 kEmptyExpectedMatch
},
2237 "[\"ab\",[\"ab1\", \"ab3\"],[],[],"
2238 "{\"google:verbatimrelevance\":9000,"
2239 "\"google:suggestrelevance\":[9002, 9900]}]",
2240 { { "ab1", true }, { "ab3", false }, { "ab", true },
2241 kEmptyExpectedMatch
} },
2242 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2243 "{\"google:verbatimrelevance\":9000,"
2244 "\"google:suggestrelevance\":[9002, 9001]}]",
2245 { { "a", true }, { "ab1", false }, { "ab2", false },
2246 kEmptyExpectedMatch
},
2247 { { "ab1", true }, { "ab2", true }, { "ab", true },
2248 kEmptyExpectedMatch
},
2249 "[\"ab\",[\"ab1\", \"ab3\"],[],[],"
2250 "{\"google:verbatimrelevance\":9000,"
2251 "\"google:suggestrelevance\":[8000, 9500]}]",
2252 { { "ab", true }, { "ab3", false }, { "ab1", true },
2253 kEmptyExpectedMatch
} },
2256 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2257 // First, send the query "a" and receive the JSON response |first_json|.
2259 QueryForInputAndWaitForFetcherResponses(
2260 ASCIIToUTF16("a"), false, cases
[i
].first_json
, std::string());
2262 // Verify that the matches after the asynchronous results are as expected.
2263 std::string description
= "first asynchronous response for input with "
2264 "first_json=" + cases
[i
].first_json
;
2265 CheckMatches(description
, arraysize(cases
[i
].first_async_matches
),
2266 cases
[i
].first_async_matches
, provider_
->matches());
2268 // Then, send the query "ab" and check the synchronous matches.
2269 description
= "synchronous response after the first keystroke after input "
2270 "with first_json=" + cases
[i
].first_json
;
2271 QueryForInput(ASCIIToUTF16("ab"), false, false);
2272 CheckMatches(description
, arraysize(cases
[i
].sync_matches
),
2273 cases
[i
].sync_matches
, provider_
->matches());
2275 // Finally, get the provided JSON response, |second_json|, and verify the
2276 // matches after the second asynchronous response are as expected.
2277 description
= "second asynchronous response after input with first_json=" +
2278 cases
[i
].first_json
+ " and second_json=" + cases
[i
].second_json
;
2279 net::TestURLFetcher
* second_fetcher
=
2280 test_factory_
.GetFetcherByID(
2281 SearchProvider::kDefaultProviderURLFetcherID
);
2282 ASSERT_TRUE(second_fetcher
);
2283 second_fetcher
->set_response_code(200);
2284 second_fetcher
->SetResponseString(cases
[i
].second_json
);
2285 second_fetcher
->delegate()->OnURLFetchComplete(second_fetcher
);
2286 RunTillProviderDone();
2287 CheckMatches(description
, arraysize(cases
[i
].second_async_matches
),
2288 cases
[i
].second_async_matches
, provider_
->matches());
2292 TEST_F(SearchProviderTest
, LocalAndRemoteRelevances
) {
2293 // We hardcode the string "term1" below, so ensure that the search term that
2294 // got added to history already is that string.
2295 ASSERT_EQ(ASCIIToUTF16("term1"), term1_
);
2296 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
2298 AddSearchToHistory(default_t_url_
, term
+ ASCIIToUTF16("2"), 2);
2299 profile_
.BlockUntilHistoryProcessesPendingRequests();
2302 const base::string16 input
;
2303 const std::string json
;
2304 const std::string matches
[6];
2306 // The history results outscore the default verbatim score. term2 has more
2307 // visits so it outscores term1. The suggestions are still returned since
2308 // they're server-scored.
2310 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
2311 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
2312 "\"google:suggestrelevance\":[1, 2, 3]}]",
2313 { "term2", "term1", "term", "a3", "a2", "a1" } },
2314 // Because we already have three suggestions by the time we see the history
2315 // results, they don't get returned.
2317 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
2318 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
2319 "\"google:verbatimrelevance\":1450,"
2320 "\"google:suggestrelevance\":[1440, 1430, 1420]}]",
2321 { "term", "a1", "a2", "a3", kNotApplicable
, kNotApplicable
} },
2322 // If we only have two suggestions, we have room for a history result.
2324 "[\"term\",[\"a1\", \"a2\"],[],[],"
2325 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2326 "\"google:verbatimrelevance\":1450,"
2327 "\"google:suggestrelevance\":[1430, 1410]}]",
2328 { "term", "a1", "a2", "term2", kNotApplicable
, kNotApplicable
} },
2329 // If we have more than three suggestions, they should all be returned as
2330 // long as we have enough total space for them.
2332 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
2333 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
2334 "\"google:verbatimrelevance\":1450,"
2335 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410]}]",
2336 { "term", "a1", "a2", "a3", "a4", kNotApplicable
} },
2338 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\", \"a5\", \"a6\"],[],[],"
2339 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\","
2340 "\"QUERY\", \"QUERY\"],"
2341 "\"google:verbatimrelevance\":1450,"
2342 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410, 1400, 1390]}]",
2343 { "term", "a1", "a2", "a3", "a4", "a5" } },
2345 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
2346 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
2347 "\"google:verbatimrelevance\":1450,"
2348 "\"google:suggestrelevance\":[1430, 1410, 1390, 1370]}]",
2349 { "term", "a1", "a2", "term2", "a3", "a4" } }
2352 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2353 QueryForInputAndWaitForFetcherResponses(
2354 cases
[i
].input
, false, cases
[i
].json
, std::string());
2356 const std::string description
= "for input with json=" + cases
[i
].json
;
2357 const ACMatches
& matches
= provider_
->matches();
2359 // Ensure no extra matches are present.
2360 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2363 // Ensure that the returned matches equal the expectations.
2364 for (; j
< matches
.size(); ++j
)
2365 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
]),
2366 matches
[j
].contents
) << description
;
2367 // Ensure that no expected matches are missing.
2368 for (; j
< arraysize(cases
[i
].matches
); ++j
)
2369 EXPECT_EQ(kNotApplicable
, cases
[i
].matches
[j
]) <<
2370 "Case # " << i
<< " " << description
;
2374 // Verifies suggest relevance behavior for URL input.
2375 TEST_F(SearchProviderTest
, DefaultProviderSuggestRelevanceScoringUrlInput
) {
2376 struct DefaultFetcherUrlInputMatch
{
2377 const std::string match_contents
;
2378 AutocompleteMatch::Type match_type
;
2379 bool allowed_to_be_default_match
;
2381 const DefaultFetcherUrlInputMatch kEmptyMatch
=
2382 { kNotApplicable
, AutocompleteMatchType::NUM_TYPES
, false };
2384 const std::string input
;
2385 const std::string json
;
2386 const DefaultFetcherUrlInputMatch output
[4];
2388 // Ensure NAVIGATION matches are allowed to be listed first for URL input.
2389 // Non-inlineable matches should not be allowed to be the default match.
2390 // Note that the top-scoring inlineable match is moved to the top
2391 // regardless of its score.
2392 { "a.com", "[\"a.com\",[\"http://b.com/\"],[],[],"
2393 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2394 "\"google:suggestrelevance\":[9999]}]",
2395 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2396 { "b.com", AutocompleteMatchType::NAVSUGGEST
, false },
2397 kEmptyMatch
, kEmptyMatch
} },
2398 { "a.com", "[\"a.com\",[\"https://b.com\"],[],[],"
2399 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2400 "\"google:suggestrelevance\":[9999]}]",
2401 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2402 { "https://b.com", AutocompleteMatchType::NAVSUGGEST
, false },
2403 kEmptyMatch
, kEmptyMatch
} },
2404 { "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[],"
2405 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2406 "\"google:suggestrelevance\":[9999]}]",
2407 { { "a.com/a", AutocompleteMatchType::NAVSUGGEST
, true },
2408 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2409 kEmptyMatch
, kEmptyMatch
} },
2410 { "a.com", "[\"a.com\",[\"https://a.com\"],[],[],"
2411 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2412 "\"google:suggestrelevance\":[9999]}]",
2413 { { "https://a.com", AutocompleteMatchType::NAVSUGGEST
, true },
2414 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2415 kEmptyMatch
, kEmptyMatch
} },
2417 // Ensure topmost inlineable SUGGEST matches are NOT allowed for URL
2418 // input. SearchProvider disregards search and verbatim suggested
2420 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2421 "{\"google:suggestrelevance\":[9999]}]",
2422 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2423 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2424 kEmptyMatch
, kEmptyMatch
} },
2425 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2426 "{\"google:suggestrelevance\":[9999]}]",
2427 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2428 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2429 kEmptyMatch
, kEmptyMatch
} },
2431 // Ensure the fallback mechanism allows inlineable NAVIGATION matches.
2432 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2433 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2434 "\"google:suggestrelevance\":[9999, 9998]}]",
2435 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST
, true },
2436 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2437 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2439 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2440 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2441 "\"google:suggestrelevance\":[9998, 9997],"
2442 "\"google:verbatimrelevance\":9999}]",
2443 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST
, true },
2444 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2445 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2448 // Ensure non-inlineable SUGGEST matches are allowed for URL input
2449 // assuming the best inlineable match is not a query (i.e., is a
2450 // NAVSUGGEST). The best inlineable match will be at the top of the
2451 // list regardless of its score.
2452 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2453 "{\"google:suggestrelevance\":[9999]}]",
2454 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2455 { "info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2456 kEmptyMatch
, kEmptyMatch
} },
2457 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2458 "{\"google:suggestrelevance\":[9999]}]",
2459 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2460 { "info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2461 kEmptyMatch
, kEmptyMatch
} },
2463 // Ensure that if the user explicitly enters a scheme, a navsuggest
2464 // result for a URL with a different scheme is not inlineable.
2465 { "http://a.com", "[\"http://a.com\","
2466 "[\"http://a.com/1\", \"https://a.com/\"],[],[],"
2467 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2468 "\"google:suggestrelevance\":[9000, 8000]}]",
2469 { { "http://a.com/1", AutocompleteMatchType::NAVSUGGEST
, true },
2470 { "https://a.com", AutocompleteMatchType::NAVSUGGEST
, false },
2471 { "http://a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
2476 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2477 // Send the query twice in order to have a synchronous pass after the first
2478 // response is received. This is necessary because SearchProvider doesn't
2479 // allow an asynchronous response to change the default match.
2480 for (size_t j
= 0; j
< 2; ++j
) {
2481 QueryForInputAndWaitForFetcherResponses(
2482 ASCIIToUTF16(cases
[i
].input
), false, cases
[i
].json
, std::string());
2485 SCOPED_TRACE("input=" + cases
[i
].input
+ " json=" + cases
[i
].json
);
2487 const ACMatches
& matches
= provider_
->matches();
2488 ASSERT_LE(matches
.size(), arraysize(cases
[i
].output
));
2489 // Ensure that the returned matches equal the expectations.
2490 for (; j
< matches
.size(); ++j
) {
2491 EXPECT_EQ(ASCIIToUTF16(cases
[i
].output
[j
].match_contents
),
2492 matches
[j
].contents
);
2493 EXPECT_EQ(cases
[i
].output
[j
].match_type
, matches
[j
].type
);
2494 EXPECT_EQ(cases
[i
].output
[j
].allowed_to_be_default_match
,
2495 matches
[j
].allowed_to_be_default_match
);
2497 // Ensure that no expected matches are missing.
2498 for (; j
< arraysize(cases
[i
].output
); ++j
) {
2499 EXPECT_EQ(kNotApplicable
, cases
[i
].output
[j
].match_contents
);
2500 EXPECT_EQ(AutocompleteMatchType::NUM_TYPES
,
2501 cases
[i
].output
[j
].match_type
);
2502 EXPECT_FALSE(cases
[i
].output
[j
].allowed_to_be_default_match
);
2507 // A basic test that verifies the field trial triggered parsing logic.
2508 TEST_F(SearchProviderTest
, FieldTrialTriggeredParsing
) {
2509 QueryForInputAndWaitForFetcherResponses(
2510 ASCIIToUTF16("foo"), false,
2511 "[\"foo\",[\"foo bar\"],[\"\"],[],"
2512 "{\"google:suggesttype\":[\"QUERY\"],"
2513 "\"google:fieldtrialtriggered\":true}]",
2517 // Check for the match and field trial triggered bits.
2518 AutocompleteMatch match
;
2519 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("foo bar"), &match
));
2520 ProvidersInfo providers_info
;
2521 provider_
->AddProviderInfo(&providers_info
);
2522 ASSERT_EQ(1U, providers_info
.size());
2523 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_size());
2524 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_in_session_size());
2527 // Reset the session and check that bits are reset.
2528 provider_
->ResetSession();
2529 ProvidersInfo providers_info
;
2530 provider_
->AddProviderInfo(&providers_info
);
2531 ASSERT_EQ(1U, providers_info
.size());
2532 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_size());
2533 EXPECT_EQ(0, providers_info
[0].field_trial_triggered_in_session_size());
2537 // Verifies inline autocompletion of navigational results.
2538 TEST_F(SearchProviderTest
, NavigationInline
) {
2540 const std::string input
;
2541 const std::string url
;
2542 // Test the expected fill_into_edit, which may drop "http://".
2543 // Some cases do not trim "http://" to match from the start of the scheme.
2544 const std::string fill_into_edit
;
2545 const std::string inline_autocompletion
;
2546 const bool allowed_to_be_default_match_in_regular_mode
;
2547 const bool allowed_to_be_default_match_in_prevent_inline_mode
;
2549 // Do not inline matches that do not contain the input; trim http as needed.
2550 { "x", "http://www.abc.com",
2551 "www.abc.com", std::string(), false, false },
2552 { "https:", "http://www.abc.com",
2553 "www.abc.com", std::string(), false, false },
2554 { "http://www.abc.com/a", "http://www.abc.com",
2555 "http://www.abc.com", std::string(), false,
2558 // Do not inline matches with invalid input prefixes; trim http as needed.
2559 { "ttp", "http://www.abc.com",
2560 "www.abc.com", std::string(), false, false },
2561 { "://w", "http://www.abc.com",
2562 "www.abc.com", std::string(), false, false },
2563 { "ww.", "http://www.abc.com",
2564 "www.abc.com", std::string(), false, false },
2565 { ".ab", "http://www.abc.com",
2566 "www.abc.com", std::string(), false, false },
2567 { "bc", "http://www.abc.com",
2568 "www.abc.com", std::string(), false, false },
2569 { ".com", "http://www.abc.com",
2570 "www.abc.com", std::string(), false, false },
2572 // Do not inline matches that omit input domain labels; trim http as needed.
2573 { "www.a", "http://a.com",
2574 "a.com", std::string(), false, false },
2575 { "http://www.a", "http://a.com",
2576 "http://a.com", std::string(), false, false },
2577 { "www.a", "ftp://a.com",
2578 "ftp://a.com", std::string(), false, false },
2579 { "ftp://www.a", "ftp://a.com",
2580 "ftp://a.com", std::string(), false, false },
2582 // Input matching but with nothing to inline will not yield an offset, but
2583 // will be allowed to be default.
2584 { "abc.com", "http://www.abc.com",
2585 "www.abc.com", std::string(), true, true },
2586 { "abc.com/", "http://www.abc.com",
2587 "www.abc.com", std::string(), true, true },
2588 { "http://www.abc.com", "http://www.abc.com",
2589 "http://www.abc.com", std::string(), true, true },
2590 { "http://www.abc.com/", "http://www.abc.com",
2591 "http://www.abc.com", std::string(), true, true },
2593 // Inputs with trailing whitespace should inline when possible.
2594 { "abc.com ", "http://www.abc.com",
2595 "www.abc.com", std::string(), true, true },
2596 { "abc.com/ ", "http://www.abc.com",
2597 "www.abc.com", std::string(), true, true },
2598 { "abc.com ", "http://www.abc.com/bar",
2599 "www.abc.com/bar", "/bar", false, false },
2601 // A suggestion that's equivalent to what the input gets fixed up to
2602 // should be inlined.
2603 { "abc.com:", "http://abc.com/",
2604 "abc.com", std::string(), true, true },
2605 { "abc.com:", "http://www.abc.com",
2606 "www.abc.com", std::string(), true, true },
2608 // Inline matches when the input is a leading substring of the scheme.
2609 { "h", "http://www.abc.com",
2610 "http://www.abc.com", "ttp://www.abc.com", true, false },
2611 { "http", "http://www.abc.com",
2612 "http://www.abc.com", "://www.abc.com", true, false },
2614 // Inline matches when the input is a leading substring of the full URL.
2615 { "http:", "http://www.abc.com",
2616 "http://www.abc.com", "//www.abc.com", true, false },
2617 { "http://w", "http://www.abc.com",
2618 "http://www.abc.com", "ww.abc.com", true, false },
2619 { "http://www.", "http://www.abc.com",
2620 "http://www.abc.com", "abc.com", true, false },
2621 { "http://www.ab", "http://www.abc.com",
2622 "http://www.abc.com", "c.com", true, false },
2623 { "http://www.abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2624 "http://www.abc.com/path/file.htm?q=x#foo",
2625 "ath/file.htm?q=x#foo",
2627 { "http://abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2628 "http://abc.com/path/file.htm?q=x#foo",
2629 "ath/file.htm?q=x#foo",
2632 // Inline matches with valid URLPrefixes; only trim "http://".
2633 { "w", "http://www.abc.com",
2634 "www.abc.com", "ww.abc.com", true, false },
2635 { "www.a", "http://www.abc.com",
2636 "www.abc.com", "bc.com", true, false },
2637 { "abc", "http://www.abc.com",
2638 "www.abc.com", ".com", true, false },
2639 { "abc.c", "http://www.abc.com",
2640 "www.abc.com", "om", true, false },
2641 { "abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2642 "www.abc.com/path/file.htm?q=x#foo",
2643 "ath/file.htm?q=x#foo",
2645 { "abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2646 "abc.com/path/file.htm?q=x#foo",
2647 "ath/file.htm?q=x#foo",
2650 // Inline matches using the maximal URLPrefix components.
2651 { "h", "http://help.com",
2652 "help.com", "elp.com", true, false },
2653 { "http", "http://http.com",
2654 "http.com", ".com", true, false },
2655 { "h", "http://www.help.com",
2656 "www.help.com", "elp.com", true, false },
2657 { "http", "http://www.http.com",
2658 "www.http.com", ".com", true, false },
2659 { "w", "http://www.www.com",
2660 "www.www.com", "ww.com", true, false },
2662 // Test similar behavior for the ftp and https schemes.
2663 { "ftp://www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2664 "ftp://www.abc.com/path/file.htm?q=x#foo",
2665 "c.com/path/file.htm?q=x#foo", true, false },
2666 { "www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2667 "ftp://www.abc.com/path/file.htm?q=x#foo",
2668 "c.com/path/file.htm?q=x#foo", true, false },
2669 { "ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2670 "ftp://www.abc.com/path/file.htm?q=x#foo",
2671 "c.com/path/file.htm?q=x#foo", true, false },
2672 { "ab", "ftp://abc.com/path/file.htm?q=x#foo",
2673 "ftp://abc.com/path/file.htm?q=x#foo",
2674 "c.com/path/file.htm?q=x#foo", true, false },
2675 { "https://www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2676 "https://www.abc.com/path/file.htm?q=x#foo",
2677 "c.com/path/file.htm?q=x#foo",
2679 { "www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2680 "https://www.abc.com/path/file.htm?q=x#foo",
2681 "c.com/path/file.htm?q=x#foo", true, false },
2682 { "ab", "https://www.abc.com/path/file.htm?q=x#foo",
2683 "https://www.abc.com/path/file.htm?q=x#foo",
2684 "c.com/path/file.htm?q=x#foo", true, false },
2685 { "ab", "https://abc.com/path/file.htm?q=x#foo",
2686 "https://abc.com/path/file.htm?q=x#foo",
2687 "c.com/path/file.htm?q=x#foo", true, false },
2689 // Forced query input should inline and retain the "?" prefix.
2690 { "?http://www.ab", "http://www.abc.com",
2691 "?http://www.abc.com", "c.com", true, false },
2692 { "?www.ab", "http://www.abc.com",
2693 "?www.abc.com", "c.com", true, false },
2694 { "?ab", "http://www.abc.com",
2695 "?www.abc.com", "c.com", true, false },
2696 { "?abc.com", "http://www.abc.com",
2697 "?www.abc.com", std::string(), true, true },
2700 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2701 // First test regular mode.
2702 QueryForInput(ASCIIToUTF16(cases
[i
].input
), false, false);
2703 SearchSuggestionParser::NavigationResult
result(
2704 ChromeAutocompleteSchemeClassifier(&profile_
), GURL(cases
[i
].url
),
2705 AutocompleteMatchType::NAVSUGGEST
, base::string16(), std::string(),
2706 false, 0, false, ASCIIToUTF16(cases
[i
].input
), std::string());
2707 result
.set_received_after_last_keystroke(false);
2708 AutocompleteMatch
match(provider_
->NavigationToMatch(result
));
2709 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
2710 match
.inline_autocompletion
);
2711 EXPECT_EQ(ASCIIToUTF16(cases
[i
].fill_into_edit
), match
.fill_into_edit
);
2712 EXPECT_EQ(cases
[i
].allowed_to_be_default_match_in_regular_mode
,
2713 match
.allowed_to_be_default_match
);
2715 // Then test prevent-inline-autocomplete mode.
2716 QueryForInput(ASCIIToUTF16(cases
[i
].input
), true, false);
2717 SearchSuggestionParser::NavigationResult
result_prevent_inline(
2718 ChromeAutocompleteSchemeClassifier(&profile_
), GURL(cases
[i
].url
),
2719 AutocompleteMatchType::NAVSUGGEST
, base::string16(), std::string(),
2720 false, 0, false, ASCIIToUTF16(cases
[i
].input
), std::string());
2721 result_prevent_inline
.set_received_after_last_keystroke(false);
2722 AutocompleteMatch
match_prevent_inline(
2723 provider_
->NavigationToMatch(result_prevent_inline
));
2724 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
2725 match_prevent_inline
.inline_autocompletion
);
2726 EXPECT_EQ(ASCIIToUTF16(cases
[i
].fill_into_edit
),
2727 match_prevent_inline
.fill_into_edit
);
2728 EXPECT_EQ(cases
[i
].allowed_to_be_default_match_in_prevent_inline_mode
,
2729 match_prevent_inline
.allowed_to_be_default_match
);
2733 // Verifies that "http://" is not trimmed for input that is a leading substring.
2734 TEST_F(SearchProviderTest
, NavigationInlineSchemeSubstring
) {
2735 const base::string16
input(ASCIIToUTF16("ht"));
2736 const base::string16
url(ASCIIToUTF16("http://a.com"));
2737 SearchSuggestionParser::NavigationResult
result(
2738 ChromeAutocompleteSchemeClassifier(&profile_
), GURL(url
),
2739 AutocompleteMatchType::NAVSUGGEST
,
2740 base::string16(), std::string(), false, 0, false, input
, std::string());
2741 result
.set_received_after_last_keystroke(false);
2743 // Check the offset and strings when inline autocompletion is allowed.
2744 QueryForInput(input
, false, false);
2745 AutocompleteMatch
match_inline(provider_
->NavigationToMatch(result
));
2746 EXPECT_EQ(url
, match_inline
.fill_into_edit
);
2747 EXPECT_EQ(url
.substr(2), match_inline
.inline_autocompletion
);
2748 EXPECT_TRUE(match_inline
.allowed_to_be_default_match
);
2749 EXPECT_EQ(url
, match_inline
.contents
);
2751 // Check the same strings when inline autocompletion is prevented.
2752 QueryForInput(input
, true, false);
2753 AutocompleteMatch
match_prevent(provider_
->NavigationToMatch(result
));
2754 EXPECT_EQ(url
, match_prevent
.fill_into_edit
);
2755 EXPECT_FALSE(match_prevent
.allowed_to_be_default_match
);
2756 EXPECT_EQ(url
, match_prevent
.contents
);
2759 // Verifies that input "w" marks a more significant domain label than "www.".
2760 TEST_F(SearchProviderTest
, NavigationInlineDomainClassify
) {
2761 QueryForInput(ASCIIToUTF16("w"), false, false);
2762 SearchSuggestionParser::NavigationResult
result(
2763 ChromeAutocompleteSchemeClassifier(&profile_
),
2764 GURL("http://www.wow.com"), AutocompleteMatchType::NAVSUGGEST
,
2765 base::string16(), std::string(), false, 0, false, ASCIIToUTF16("w"),
2767 result
.set_received_after_last_keystroke(false);
2768 AutocompleteMatch
match(provider_
->NavigationToMatch(result
));
2769 EXPECT_EQ(ASCIIToUTF16("ow.com"), match
.inline_autocompletion
);
2770 EXPECT_TRUE(match
.allowed_to_be_default_match
);
2771 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match
.fill_into_edit
);
2772 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match
.contents
);
2774 // Ensure that the match for input "w" is marked on "wow" and not "www".
2775 ASSERT_EQ(3U, match
.contents_class
.size());
2776 EXPECT_EQ(0U, match
.contents_class
[0].offset
);
2777 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
,
2778 match
.contents_class
[0].style
);
2779 EXPECT_EQ(4U, match
.contents_class
[1].offset
);
2780 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
|
2781 AutocompleteMatch::ACMatchClassification::MATCH
,
2782 match
.contents_class
[1].style
);
2783 EXPECT_EQ(5U, match
.contents_class
[2].offset
);
2784 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
,
2785 match
.contents_class
[2].style
);
2788 #if !defined(OS_WIN)
2789 // Verify entity suggestion parsing.
2790 TEST_F(SearchProviderTest
, ParseEntitySuggestion
) {
2792 std::string contents
;
2793 std::string description
;
2794 std::string query_params
;
2795 std::string fill_into_edit
;
2796 AutocompleteMatchType::Type type
;
2798 const Match kEmptyMatch
= {
2799 kNotApplicable
, kNotApplicable
, kNotApplicable
, kNotApplicable
,
2800 AutocompleteMatchType::NUM_TYPES
};
2803 const std::string input_text
;
2804 const std::string response_json
;
2805 const Match matches
[5];
2807 // A query and an entity suggestion with different search terms.
2809 "[\"x\",[\"xy\", \"yy\"],[\"\",\"\"],[],"
2810 " {\"google:suggestdetail\":[{},"
2811 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2812 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2813 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
2814 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST
},
2815 { "xy", "A", "p=v", "yy",
2816 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY
},
2821 // A query and an entity suggestion with same search terms.
2823 "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
2824 " {\"google:suggestdetail\":[{},"
2825 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2826 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2827 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
2828 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST
},
2829 { "xy", "A", "p=v", "xy",
2830 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY
},
2836 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2837 QueryForInputAndWaitForFetcherResponses(
2838 ASCIIToUTF16(cases
[i
].input_text
), false, cases
[i
].response_json
,
2841 const ACMatches
& matches
= provider_
->matches();
2842 ASSERT_FALSE(matches
.empty());
2844 SCOPED_TRACE("for input with json = " + cases
[i
].response_json
);
2846 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2848 // Ensure that the returned matches equal the expectations.
2849 for (; j
< matches
.size(); ++j
) {
2850 const Match
& match
= cases
[i
].matches
[j
];
2851 SCOPED_TRACE(" and match index: " + base::SizeTToString(j
));
2852 EXPECT_EQ(match
.contents
,
2853 base::UTF16ToUTF8(matches
[j
].contents
));
2854 EXPECT_EQ(match
.description
,
2855 base::UTF16ToUTF8(matches
[j
].description
));
2856 EXPECT_EQ(match
.query_params
,
2857 matches
[j
].search_terms_args
->suggest_query_params
);
2858 EXPECT_EQ(match
.fill_into_edit
,
2859 base::UTF16ToUTF8(matches
[j
].fill_into_edit
));
2860 EXPECT_EQ(match
.type
, matches
[j
].type
);
2862 // Ensure that no expected matches are missing.
2863 for (; j
< arraysize(cases
[i
].matches
); ++j
) {
2864 SCOPED_TRACE(" and match index: " + base::SizeTToString(j
));
2865 EXPECT_EQ(cases
[i
].matches
[j
].contents
, kNotApplicable
);
2866 EXPECT_EQ(cases
[i
].matches
[j
].description
, kNotApplicable
);
2867 EXPECT_EQ(cases
[i
].matches
[j
].query_params
, kNotApplicable
);
2868 EXPECT_EQ(cases
[i
].matches
[j
].fill_into_edit
, kNotApplicable
);
2869 EXPECT_EQ(cases
[i
].matches
[j
].type
, AutocompleteMatchType::NUM_TYPES
);
2873 #endif // !defined(OS_WIN)
2876 // A basic test that verifies the prefetch metadata parsing logic.
2877 TEST_F(SearchProviderTest
, PrefetchMetadataParsing
) {
2879 std::string contents
;
2880 bool allowed_to_be_prefetched
;
2881 AutocompleteMatchType::Type type
;
2884 const Match kEmptyMatch
= { kNotApplicable
,
2886 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
2890 const std::string input_text
;
2891 bool prefer_keyword_provider_results
;
2892 const std::string default_provider_response_json
;
2893 const std::string keyword_provider_response_json
;
2894 const Match matches
[5];
2896 // Default provider response does not have prefetch details. Ensure that the
2897 // suggestions are not marked as prefetch query.
2900 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2902 { { "a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2903 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2904 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2909 // Ensure that default provider suggest response prefetch details are
2910 // parsed and recorded in AutocompleteMatch.
2913 "[\"ab\",[\"abc\", \"http://b.com\", \"http://c.com\"],[],[],"
2914 "{\"google:clientdata\":{\"phi\": 0},"
2915 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"NAVIGATION\"],"
2916 "\"google:suggestrelevance\":[999, 12, 1]}]",
2918 { { "ab", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2919 { "abc", true, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2920 { "b.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
2921 { "c.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
2925 // Default provider suggest response has prefetch details.
2926 // SEARCH_WHAT_YOU_TYPE suggestion outranks SEARCH_SUGGEST suggestion for
2927 // the same query string. Ensure that the prefetch details from
2928 // SEARCH_SUGGEST match are set onto SEARCH_WHAT_YOU_TYPE match.
2931 "[\"ab\",[\"ab\", \"http://ab.com\"],[],[],"
2932 "{\"google:clientdata\":{\"phi\": 0},"
2933 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2934 "\"google:suggestrelevance\":[99, 98]}]",
2936 { {"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2937 {"ab.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
2943 // Default provider response has prefetch details. We prefer keyword
2944 // provider results. Ensure that prefetch bit for a suggestion from the
2945 // default search provider does not get copied onto a higher-scoring match
2946 // for the same query string from the keyword provider.
2949 "[\"k a\",[\"a\", \"ab\"],[],[], {\"google:clientdata\":{\"phi\": 0},"
2950 "\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2951 "\"google:suggestrelevance\":[9, 12]}]",
2952 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2953 { { "a", false, AutocompleteMatchType::SEARCH_OTHER_ENGINE
, true},
2954 { "k a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2955 { "ab", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2956 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST
, true },
2957 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST
, true }
2962 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2963 QueryForInputAndWaitForFetcherResponses(
2964 ASCIIToUTF16(cases
[i
].input_text
),
2965 cases
[i
].prefer_keyword_provider_results
,
2966 cases
[i
].default_provider_response_json
,
2967 cases
[i
].prefer_keyword_provider_results
?
2968 cases
[i
].keyword_provider_response_json
: std::string());
2970 const std::string description
=
2971 "for input with json =" + cases
[i
].default_provider_response_json
;
2972 const ACMatches
& matches
= provider_
->matches();
2973 // The top match must inline and score as highly as calculated verbatim.
2974 ASSERT_FALSE(matches
.empty());
2975 EXPECT_GE(matches
[0].relevance
, 1300);
2977 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2978 // Ensure that the returned matches equal the expectations.
2979 for (size_t j
= 0; j
< matches
.size(); ++j
) {
2980 SCOPED_TRACE(description
);
2981 EXPECT_EQ(cases
[i
].matches
[j
].contents
,
2982 base::UTF16ToUTF8(matches
[j
].contents
));
2983 EXPECT_EQ(cases
[i
].matches
[j
].allowed_to_be_prefetched
,
2984 SearchProvider::ShouldPrefetch(matches
[j
]));
2985 EXPECT_EQ(cases
[i
].matches
[j
].type
, matches
[j
].type
);
2986 EXPECT_EQ(cases
[i
].matches
[j
].from_keyword
,
2987 matches
[j
].keyword
== ASCIIToUTF16("k"));
2992 TEST_F(SearchProviderTest
, XSSIGuardedJSONParsing_InvalidResponse
) {
2995 std::string
input_str("abc");
2996 QueryForInputAndWaitForFetcherResponses(
2997 ASCIIToUTF16(input_str
), false, "this is a bad non-json response",
3000 const ACMatches
& matches
= provider_
->matches();
3002 // Should have exactly one "search what you typed" match
3003 ASSERT_TRUE(matches
.size() == 1);
3004 EXPECT_EQ(input_str
, base::UTF16ToUTF8(matches
[0].contents
));
3005 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
3009 // A basic test that verifies that the XSSI guarded JSON response is parsed
3011 TEST_F(SearchProviderTest
, XSSIGuardedJSONParsing_ValidResponses
) {
3013 std::string contents
;
3014 AutocompleteMatchType::Type type
;
3016 const Match kEmptyMatch
= {
3017 kNotApplicable
, AutocompleteMatchType::NUM_TYPES
3021 const std::string input_text
;
3022 const std::string default_provider_response_json
;
3023 const Match matches
[4];
3027 "[\"a\",[\"b\", \"c\"],[],[],"
3028 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
3029 "\"google:suggestrelevance\":[1, 2]}]",
3030 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3031 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
3032 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
3036 // Standard XSSI guard - )]}'\n.
3038 ")]}'\n[\"a\",[\"b\", \"c\"],[],[],"
3039 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
3040 "\"google:suggestrelevance\":[1, 2]}]",
3041 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3042 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
3043 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
3047 // Modified XSSI guard - contains "[".
3049 ")]}'\n[)\"[\"a\",[\"b\", \"c\"],[],[],"
3050 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
3051 "\"google:suggestrelevance\":[1, 2]}]",
3052 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3053 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
3054 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
3060 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
3062 QueryForInputAndWaitForFetcherResponses(
3063 ASCIIToUTF16(cases
[i
].input_text
), false,
3064 cases
[i
].default_provider_response_json
, std::string());
3066 const ACMatches
& matches
= provider_
->matches();
3067 // The top match must inline and score as highly as calculated verbatim.
3068 ASSERT_FALSE(matches
.empty());
3069 EXPECT_GE(matches
[0].relevance
, 1300);
3071 SCOPED_TRACE("for case: " + base::SizeTToString(i
));
3072 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
3074 // Ensure that the returned matches equal the expectations.
3075 for (; j
< matches
.size(); ++j
) {
3076 SCOPED_TRACE("and match: " + base::SizeTToString(j
));
3077 EXPECT_EQ(cases
[i
].matches
[j
].contents
,
3078 base::UTF16ToUTF8(matches
[j
].contents
));
3079 EXPECT_EQ(cases
[i
].matches
[j
].type
, matches
[j
].type
);
3081 for (; j
< arraysize(cases
[i
].matches
); ++j
) {
3082 SCOPED_TRACE("and match: " + base::SizeTToString(j
));
3083 EXPECT_EQ(cases
[i
].matches
[j
].contents
, kNotApplicable
);
3084 EXPECT_EQ(cases
[i
].matches
[j
].type
, AutocompleteMatchType::NUM_TYPES
);
3089 // Test that deletion url gets set on an AutocompleteMatch when available for a
3090 // personalized query or a personalized URL.
3091 TEST_F(SearchProviderTest
, ParseDeletionUrl
) {
3093 std::string contents
;
3094 std::string deletion_url
;
3095 AutocompleteMatchType::Type type
;
3098 const Match kEmptyMatch
= {
3099 kNotApplicable
, std::string(), AutocompleteMatchType::NUM_TYPES
3102 const char* url
[] = {
3103 "http://defaultturl/complete/deleteitems"
3104 "?delq=ab&client=chrome&deltok=xsrf124",
3105 "http://defaultturl/complete/deleteitems"
3106 "?delq=www.amazon.com&client=chrome&deltok=xsrf123",
3110 const std::string input_text
;
3111 const std::string response_json
;
3112 const Match matches
[5];
3114 // A deletion URL on a personalized query should be reflected in the
3115 // resulting AutocompleteMatch.
3117 "[\"a\",[\"ab\", \"ac\",\"www.amazon.com\"],[],[],"
3118 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3119 "\"PERSONALIZED_NAVIGATION\"],"
3120 "\"google:suggestrelevance\":[3, 2, 1],"
3121 "\"google:suggestdetail\":[{\"du\":"
3122 "\"/complete/deleteitems?delq=ab&client=chrome"
3123 "&deltok=xsrf124\"}, {}, {\"du\":"
3124 "\"/complete/deleteitems?delq=www.amazon.com&"
3125 "client=chrome&deltok=xsrf123\"}]}]",
3126 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3127 { "ab", url
[0], AutocompleteMatchType::SEARCH_SUGGEST
},
3128 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3129 { "www.amazon.com", url
[1],
3130 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED
},
3134 // Personalized queries or a personalized URL without deletion URLs
3135 // shouldn't cause errors.
3137 "[\"a\",[\"ab\", \"ac\"],[],[],"
3138 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3139 "\"PERSONALIZED_NAVIGATION\"],"
3140 "\"google:suggestrelevance\":[1, 2],"
3141 "\"google:suggestdetail\":[{}, {}]}]",
3142 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3143 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3144 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3145 { "www.amazon.com", "",
3146 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED
},
3150 // Personalized queries or a personalized URL without
3151 // google:suggestdetail shouldn't cause errors.
3153 "[\"a\",[\"ab\", \"ac\"],[],[],"
3154 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3155 "\"PERSONALIZED_NAVIGATION\"],"
3156 "\"google:suggestrelevance\":[1, 2]}]",
3157 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3158 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3159 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3160 { "www.amazon.com", "",
3161 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED
},
3167 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
3168 QueryForInputAndWaitForFetcherResponses(
3169 ASCIIToUTF16(cases
[i
].input_text
), false, cases
[i
].response_json
,
3172 const ACMatches
& matches
= provider_
->matches();
3173 ASSERT_FALSE(matches
.empty());
3175 SCOPED_TRACE("for input with json = " + cases
[i
].response_json
);
3177 for (size_t j
= 0; j
< matches
.size(); ++j
) {
3178 const Match
& match
= cases
[i
].matches
[j
];
3179 SCOPED_TRACE(" and match index: " + base::SizeTToString(j
));
3180 EXPECT_EQ(match
.contents
, base::UTF16ToUTF8(matches
[j
].contents
));
3181 EXPECT_EQ(match
.deletion_url
, matches
[j
].GetAdditionalInfo(
3187 TEST_F(SearchProviderTest
, ReflectsBookmarkBarState
) {
3188 profile_
.GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar
, false);
3189 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
3190 QueryForInput(term
, true, false);
3191 ASSERT_FALSE(provider_
->matches().empty());
3192 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
3193 provider_
->matches()[0].type
);
3194 ASSERT_TRUE(provider_
->matches()[0].search_terms_args
!= NULL
);
3195 EXPECT_FALSE(provider_
->matches()[0].search_terms_args
->bookmark_bar_pinned
);
3197 profile_
.GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar
, true);
3198 term
= term1_
.substr(0, term1_
.length() - 1);
3199 QueryForInput(term
, true, false);
3200 ASSERT_FALSE(provider_
->matches().empty());
3201 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
3202 provider_
->matches()[0].type
);
3203 ASSERT_TRUE(provider_
->matches()[0].search_terms_args
!= NULL
);
3204 EXPECT_TRUE(provider_
->matches()[0].search_terms_args
->bookmark_bar_pinned
);
3207 TEST_F(SearchProviderTest
, CanSendURL
) {
3208 TemplateURLData template_url_data
;
3209 template_url_data
.SetShortName(ASCIIToUTF16("t"));
3210 template_url_data
.SetURL("http://www.google.com/{searchTerms}");
3211 template_url_data
.suggestions_url
= "http://www.google.com/{searchTerms}";
3212 template_url_data
.instant_url
= "http://does/not/exist?strk=1";
3213 template_url_data
.search_terms_replacement_key
= "strk";
3214 template_url_data
.id
= SEARCH_ENGINE_GOOGLE
;
3215 TemplateURL
google_template_url(template_url_data
);
3217 // Create field trial.
3218 CreateFieldTrial(OmniboxFieldTrial::kZeroSuggestRule
, true);
3220 ChromeAutocompleteProviderClient
client(&profile_
);
3223 EXPECT_FALSE(SearchProvider::CanSendURL(
3224 GURL("http://www.google.com/search"),
3225 GURL("https://www.google.com/complete/search"), &google_template_url
,
3226 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3227 SigninManagerBase
* signin
= SigninManagerFactory::GetForProfile(&profile_
);
3228 signin
->SetAuthenticatedAccountInfo("gaia_id", "test");
3230 // All conditions should be met.
3231 EXPECT_TRUE(SearchProvider::CanSendURL(
3232 GURL("http://www.google.com/search"),
3233 GURL("https://www.google.com/complete/search"), &google_template_url
,
3234 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3236 // Not in field trial.
3237 ResetFieldTrialList();
3238 CreateFieldTrial(OmniboxFieldTrial::kZeroSuggestRule
, false);
3239 EXPECT_FALSE(SearchProvider::CanSendURL(
3240 GURL("http://www.google.com/search"),
3241 GURL("https://www.google.com/complete/search"), &google_template_url
,
3242 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3243 ResetFieldTrialList();
3244 CreateFieldTrial(OmniboxFieldTrial::kZeroSuggestRule
, true);
3246 // Invalid page URL.
3247 EXPECT_FALSE(SearchProvider::CanSendURL(
3249 GURL("https://www.google.com/complete/search"), &google_template_url
,
3250 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3252 // Invalid page classification.
3253 EXPECT_FALSE(SearchProvider::CanSendURL(
3254 GURL("http://www.google.com/search"),
3255 GURL("https://www.google.com/complete/search"), &google_template_url
,
3256 metrics::OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS
,
3257 SearchTermsData(), &client
));
3259 // Invalid page classification.
3260 EXPECT_FALSE(SearchProvider::CanSendURL(
3261 GURL("http://www.google.com/search"),
3262 GURL("https://www.google.com/complete/search"), &google_template_url
,
3263 metrics::OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS
,
3264 SearchTermsData(), &client
));
3266 // HTTPS page URL on same domain as provider.
3267 EXPECT_TRUE(SearchProvider::CanSendURL(
3268 GURL("https://www.google.com/search"),
3269 GURL("https://www.google.com/complete/search"),
3270 &google_template_url
, metrics::OmniboxEventProto::OTHER
,
3271 SearchTermsData(), &client
));
3273 // Non-HTTP[S] page URL on same domain as provider.
3274 EXPECT_FALSE(SearchProvider::CanSendURL(
3275 GURL("ftp://www.google.com/search"),
3276 GURL("https://www.google.com/complete/search"), &google_template_url
,
3277 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3279 // Non-HTTP page URL on different domain.
3280 EXPECT_FALSE(SearchProvider::CanSendURL(
3281 GURL("https://www.notgoogle.com/search"),
3282 GURL("https://www.google.com/complete/search"), &google_template_url
,
3283 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3285 // Non-HTTPS provider.
3286 EXPECT_FALSE(SearchProvider::CanSendURL(
3287 GURL("http://www.google.com/search"),
3288 GURL("http://www.google.com/complete/search"), &google_template_url
,
3289 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3291 // Suggest disabled.
3292 profile_
.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled
, 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 profile_
.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled
, true);
3300 ChromeAutocompleteProviderClient
client_incognito(
3301 profile_
.GetOffTheRecordProfile());
3302 EXPECT_FALSE(SearchProvider::CanSendURL(
3303 GURL("http://www.google.com/search"),
3304 GURL("https://www.google.com/complete/search"), &google_template_url
,
3305 metrics::OmniboxEventProto::OTHER
, SearchTermsData(),
3306 &client_incognito
));
3308 // Tab sync not enabled.
3309 profile_
.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncKeepEverythingSynced
,
3311 profile_
.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs
, false);
3312 EXPECT_FALSE(SearchProvider::CanSendURL(
3313 GURL("http://www.google.com/search"),
3314 GURL("https://www.google.com/complete/search"), &google_template_url
,
3315 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3316 profile_
.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs
, true);
3318 // Tab sync is encrypted.
3319 ProfileSyncService
* service
=
3320 ProfileSyncServiceFactory::GetInstance()->GetForProfile(&profile_
);
3321 syncer::ModelTypeSet encrypted_types
= service
->GetEncryptedDataTypes();
3322 encrypted_types
.Put(syncer::SESSIONS
);
3323 service
->OnEncryptedTypesChanged(encrypted_types
, false);
3324 EXPECT_FALSE(SearchProvider::CanSendURL(
3325 GURL("http://www.google.com/search"),
3326 GURL("https://www.google.com/complete/search"), &google_template_url
,
3327 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3328 encrypted_types
.Remove(syncer::SESSIONS
);
3329 service
->OnEncryptedTypesChanged(encrypted_types
, false);
3331 // Check that there were no side effects from previous tests.
3332 EXPECT_TRUE(SearchProvider::CanSendURL(
3333 GURL("http://www.google.com/search"),
3334 GURL("https://www.google.com/complete/search"), &google_template_url
,
3335 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3338 TEST_F(SearchProviderTest
, TestDeleteMatch
) {
3339 AutocompleteMatch
match(
3340 provider_
.get(), 0, true, AutocompleteMatchType::SEARCH_SUGGEST
);
3341 match
.RecordAdditionalInfo(
3342 SearchProvider::kDeletionUrlKey
,
3343 "https://www.google.com/complete/deleteitem?q=foo");
3345 // Test a successful deletion request.
3346 provider_
->matches_
.push_back(match
);
3347 provider_
->DeleteMatch(match
);
3348 EXPECT_FALSE(provider_
->deletion_handlers_
.empty());
3349 EXPECT_TRUE(provider_
->matches_
.empty());
3350 // Set up a default fetcher with provided results.
3351 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
3352 SearchProvider::kDeletionURLFetcherID
);
3353 ASSERT_TRUE(fetcher
);
3354 fetcher
->set_response_code(200);
3355 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3356 EXPECT_TRUE(provider_
->deletion_handlers_
.empty());
3357 EXPECT_TRUE(provider_
->is_success());
3359 // Test a failing deletion request.
3360 provider_
->matches_
.push_back(match
);
3361 provider_
->DeleteMatch(match
);
3362 EXPECT_FALSE(provider_
->deletion_handlers_
.empty());
3363 // Set up a default fetcher with provided results.
3364 fetcher
= test_factory_
.GetFetcherByID(
3365 SearchProvider::kDeletionURLFetcherID
);
3366 ASSERT_TRUE(fetcher
);
3367 fetcher
->set_response_code(500);
3368 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3369 EXPECT_TRUE(provider_
->deletion_handlers_
.empty());
3370 EXPECT_FALSE(provider_
->is_success());
3373 TEST_F(SearchProviderTest
, TestDeleteHistoryQueryMatch
) {
3375 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("flash games"), 1));
3376 profile_
.BlockUntilHistoryProcessesPendingRequests();
3378 AutocompleteMatch games
;
3379 QueryForInput(ASCIIToUTF16("fla"), false, false);
3380 profile_
.BlockUntilHistoryProcessesPendingRequests();
3381 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3382 ASSERT_TRUE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games
));
3384 size_t matches_before
= provider_
->matches().size();
3385 provider_
->DeleteMatch(games
);
3386 EXPECT_EQ(matches_before
- 1, provider_
->matches().size());
3388 // Process history deletions.
3389 profile_
.BlockUntilHistoryProcessesPendingRequests();
3391 // Check that the match is gone.
3392 QueryForInput(ASCIIToUTF16("fla"), false, false);
3393 profile_
.BlockUntilHistoryProcessesPendingRequests();
3394 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3395 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games
));
3398 // Verifies that duplicates are preserved in AddMatchToMap().
3399 TEST_F(SearchProviderTest
, CheckDuplicateMatchesSaved
) {
3400 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("a"), 1);
3401 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("alpha"), 1);
3402 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("avid"), 1);
3404 profile_
.BlockUntilHistoryProcessesPendingRequests();
3405 QueryForInputAndWaitForFetcherResponses(
3406 ASCIIToUTF16("a"), false,
3407 "[\"a\",[\"a\", \"alpha\", \"avid\", \"apricot\"],[],[],"
3408 "{\"google:suggestrelevance\":[1450, 1200, 1150, 1100],"
3409 "\"google:verbatimrelevance\":1350}]",
3412 AutocompleteMatch verbatim
, match_alpha
, match_apricot
, match_avid
;
3413 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim
));
3414 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("alpha"), &match_alpha
));
3415 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("apricot"), &match_apricot
));
3416 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("avid"), &match_avid
));
3418 // Verbatim match duplicates are added such that each one has a higher
3419 // relevance than the previous one.
3420 EXPECT_EQ(2U, verbatim
.duplicate_matches
.size());
3422 // Other match duplicates are added in descending relevance order.
3423 EXPECT_EQ(1U, match_alpha
.duplicate_matches
.size());
3424 EXPECT_EQ(1U, match_avid
.duplicate_matches
.size());
3426 EXPECT_EQ(0U, match_apricot
.duplicate_matches
.size());
3429 TEST_F(SearchProviderTest
, SuggestQueryUsesToken
) {
3430 TemplateURLService
* turl_model
=
3431 TemplateURLServiceFactory::GetForProfile(&profile_
);
3433 TemplateURLData data
;
3434 data
.SetShortName(ASCIIToUTF16("default"));
3435 data
.SetKeyword(data
.short_name());
3436 data
.SetURL("http://example/{searchTerms}{google:sessionToken}");
3437 data
.suggestions_url
=
3438 "http://suggest/?q={searchTerms}&{google:sessionToken}";
3439 default_t_url_
= new TemplateURL(data
);
3440 turl_model
->Add(default_t_url_
);
3441 turl_model
->SetUserSelectedDefaultSearchProvider(default_t_url_
);
3443 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
3444 QueryForInput(term
, false, false);
3446 // Make sure the default provider's suggest service was queried.
3447 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
3448 SearchProvider::kDefaultProviderURLFetcherID
);
3449 ASSERT_TRUE(fetcher
);
3451 // And the URL matches what we expected.
3452 TemplateURLRef::SearchTermsArgs
search_terms_args(term
);
3453 search_terms_args
.session_token
= provider_
->current_token_
;
3454 GURL
expected_url(default_t_url_
->suggestions_url_ref().ReplaceSearchTerms(
3455 search_terms_args
, turl_model
->search_terms_data()));
3456 EXPECT_EQ(fetcher
->GetOriginalURL().spec(), expected_url
.spec());
3458 // Complete running the fetcher to clean up.
3459 fetcher
->set_response_code(200);
3460 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3461 RunTillProviderDone();
3464 TEST_F(SearchProviderTest
, SessionToken
) {
3465 // Subsequent calls always get the same token.
3466 std::string token
= provider_
->GetSessionToken();
3467 std::string token2
= provider_
->GetSessionToken();
3468 EXPECT_EQ(token
, token2
);
3469 EXPECT_FALSE(token
.empty());
3471 // Calls do not regenerate a token.
3472 provider_
->current_token_
= "PRE-EXISTING TOKEN";
3473 token
= provider_
->GetSessionToken();
3474 EXPECT_EQ(token
, "PRE-EXISTING TOKEN");
3476 // ... unless the token has expired.
3477 provider_
->current_token_
.clear();
3478 const base::TimeDelta kSmallDelta
= base::TimeDelta::FromMilliseconds(1);
3479 provider_
->token_expiration_time_
= base::TimeTicks::Now() - kSmallDelta
;
3480 token
= provider_
->GetSessionToken();
3481 EXPECT_FALSE(token
.empty());
3482 EXPECT_EQ(token
, provider_
->current_token_
);
3484 // The expiration time is always updated.
3485 provider_
->GetSessionToken();
3486 base::TimeTicks expiration_time_1
= provider_
->token_expiration_time_
;
3487 base::PlatformThread::Sleep(kSmallDelta
);
3488 provider_
->GetSessionToken();
3489 base::TimeTicks expiration_time_2
= provider_
->token_expiration_time_
;
3490 EXPECT_GT(expiration_time_2
, expiration_time_1
);
3491 EXPECT_GE(expiration_time_2
, expiration_time_1
+ kSmallDelta
);
3494 TEST_F(SearchProviderTest
, AnswersCache
) {
3495 AutocompleteResult result
;
3497 AutocompleteMatch match1
;
3498 match1
.answer_contents
= base::ASCIIToUTF16("m1");
3499 match1
.answer_type
= base::ASCIIToUTF16("2334");
3500 match1
.fill_into_edit
= base::ASCIIToUTF16("weather los angeles");
3502 AutocompleteMatch non_answer_match1
;
3503 non_answer_match1
.fill_into_edit
= base::ASCIIToUTF16("weather laguna beach");
3505 // Test that an answer in the first slot populates the cache.
3506 matches
.push_back(match1
);
3507 matches
.push_back(non_answer_match1
);
3508 result
.AppendMatches(AutocompleteInput(), matches
);
3509 provider_
->RegisterDisplayedAnswers(result
);
3510 ASSERT_FALSE(provider_
->answers_cache_
.empty());
3512 // Without scored results, no answers will be retrieved.
3513 AnswersQueryData answer
= provider_
->FindAnswersPrefetchData();
3514 EXPECT_TRUE(answer
.full_query_text
.empty());
3515 EXPECT_TRUE(answer
.query_type
.empty());
3517 // Inject a scored result, which will trigger answer retrieval.
3518 base::string16 query
= base::ASCIIToUTF16("weather los angeles");
3519 SearchSuggestionParser::SuggestResult
suggest_result(
3520 query
, AutocompleteMatchType::SEARCH_HISTORY
, query
, base::string16(),
3521 base::string16(), base::string16(), base::string16(), nullptr,
3522 std::string(), std::string(), false, 1200, false, false, query
);
3523 QueryForInput(ASCIIToUTF16("weather l"), false, false);
3524 provider_
->transformed_default_history_results_
.push_back(suggest_result
);
3525 answer
= provider_
->FindAnswersPrefetchData();
3526 EXPECT_EQ(base::ASCIIToUTF16("weather los angeles"), answer
.full_query_text
);
3527 EXPECT_EQ(base::ASCIIToUTF16("2334"), answer
.query_type
);
3530 TEST_F(SearchProviderTest
, RemoveExtraAnswers
) {
3531 SuggestionAnswer answer1
;
3532 answer1
.set_type(42);
3533 SuggestionAnswer answer2
;
3534 answer2
.set_type(1983);
3535 SuggestionAnswer answer3
;
3536 answer3
.set_type(423);
3539 AutocompleteMatch match1
, match2
, match3
, match4
, match5
;
3540 match1
.answer
= SuggestionAnswer::copy(&answer1
);
3541 match1
.answer_contents
= base::ASCIIToUTF16("the answer");
3542 match1
.answer_type
= base::ASCIIToUTF16("42");
3543 match3
.answer
= SuggestionAnswer::copy(&answer2
);
3544 match3
.answer_contents
= base::ASCIIToUTF16("not to play");
3545 match3
.answer_type
= base::ASCIIToUTF16("1983");
3546 match5
.answer
= SuggestionAnswer::copy(&answer3
);
3547 match5
.answer_contents
= base::ASCIIToUTF16("a man");
3548 match5
.answer_type
= base::ASCIIToUTF16("423");
3550 matches
.push_back(match1
);
3551 matches
.push_back(match2
);
3552 matches
.push_back(match3
);
3553 matches
.push_back(match4
);
3554 matches
.push_back(match5
);
3556 SearchProvider::RemoveExtraAnswers(&matches
);
3557 EXPECT_EQ(base::ASCIIToUTF16("the answer"), matches
[0].answer_contents
);
3558 EXPECT_EQ(base::ASCIIToUTF16("42"), matches
[0].answer_type
);
3559 EXPECT_TRUE(answer1
.Equals(*matches
[0].answer
));
3560 EXPECT_TRUE(matches
[1].answer_contents
.empty());
3561 EXPECT_TRUE(matches
[1].answer_type
.empty());
3562 EXPECT_FALSE(matches
[1].answer
);
3563 EXPECT_TRUE(matches
[2].answer_contents
.empty());
3564 EXPECT_TRUE(matches
[2].answer_type
.empty());
3565 EXPECT_FALSE(matches
[2].answer
);
3566 EXPECT_TRUE(matches
[3].answer_contents
.empty());
3567 EXPECT_TRUE(matches
[3].answer_type
.empty());
3568 EXPECT_FALSE(matches
[3].answer
);
3569 EXPECT_TRUE(matches
[4].answer_contents
.empty());
3570 EXPECT_TRUE(matches
[4].answer_type
.empty());
3571 EXPECT_FALSE(matches
[4].answer
);
3574 TEST_F(SearchProviderTest
, DoesNotProvideOnFocus
) {
3575 AutocompleteInput
input(
3576 base::ASCIIToUTF16("f"), base::string16::npos
, std::string(), GURL(),
3577 metrics::OmniboxEventProto::INVALID_SPEC
, false, true, true, true, true,
3578 ChromeAutocompleteSchemeClassifier(&profile_
));
3579 provider_
->Start(input
, false);
3580 EXPECT_TRUE(provider_
->matches().empty());