1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/omnibox/search_provider.h"
9 #include "base/command_line.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/time/time.h"
18 #include "build/build_config.h"
19 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
20 #include "chrome/browser/autocomplete/autocomplete_controller.h"
21 #include "chrome/browser/autocomplete/chrome_autocomplete_provider_client.h"
22 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
23 #include "chrome/browser/autocomplete/history_url_provider.h"
24 #include "chrome/browser/history/history_service.h"
25 #include "chrome/browser/history/history_service_factory.h"
26 #include "chrome/browser/search_engines/template_url_service_factory.h"
27 #include "chrome/browser/signin/signin_manager_factory.h"
28 #include "chrome/browser/sync/profile_sync_service.h"
29 #include "chrome/browser/sync/profile_sync_service_factory.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/pref_names.h"
32 #include "chrome/test/base/testing_browser_process.h"
33 #include "chrome/test/base/testing_profile.h"
34 #include "components/google/core/browser/google_switches.h"
35 #include "components/metrics/proto/omnibox_event.pb.h"
36 #include "components/omnibox/autocomplete_input.h"
37 #include "components/omnibox/autocomplete_match.h"
38 #include "components/omnibox/autocomplete_provider.h"
39 #include "components/omnibox/autocomplete_provider_listener.h"
40 #include "components/omnibox/omnibox_field_trial.h"
41 #include "components/omnibox/omnibox_switches.h"
42 #include "components/omnibox/suggestion_answer.h"
43 #include "components/search_engines/search_engine_type.h"
44 #include "components/search_engines/search_engines_switches.h"
45 #include "components/search_engines/search_terms_data.h"
46 #include "components/search_engines/template_url.h"
47 #include "components/search_engines/template_url_service.h"
48 #include "components/signin/core/browser/signin_manager.h"
49 #include "components/sync_driver/pref_names.h"
50 #include "components/variations/entropy_provider.h"
51 #include "components/variations/variations_associated_data.h"
52 #include "content/public/test/test_browser_thread_bundle.h"
53 #include "net/url_request/test_url_fetcher_factory.h"
54 #include "net/url_request/url_request_status.h"
55 #include "testing/gtest/include/gtest/gtest.h"
57 using base::ASCIIToUTF16
;
61 // Returns the first match in |matches| with |allowed_to_be_default_match|
63 ACMatches::const_iterator
FindDefaultMatch(const ACMatches
& matches
) {
64 ACMatches::const_iterator it
= matches
.begin();
65 while ((it
!= matches
.end()) && !it
->allowed_to_be_default_match
)
70 class SuggestionDeletionHandler
;
71 class SearchProviderForTest
: public SearchProvider
{
73 SearchProviderForTest(AutocompleteProviderListener
* listener
,
74 TemplateURLService
* template_url_service
,
76 bool is_success() { return is_success_
; };
79 ~SearchProviderForTest() override
;
82 void RecordDeletionResult(bool success
) override
;
84 DISALLOW_COPY_AND_ASSIGN(SearchProviderForTest
);
87 SearchProviderForTest::SearchProviderForTest(
88 AutocompleteProviderListener
* listener
,
89 TemplateURLService
* template_url_service
,
91 : SearchProvider(listener
, template_url_service
,
92 scoped_ptr
<AutocompleteProviderClient
>(
93 new ChromeAutocompleteProviderClient(profile
))),
97 SearchProviderForTest::~SearchProviderForTest() {
100 void SearchProviderForTest::RecordDeletionResult(bool success
) {
101 is_success_
= success
;
106 // SearchProviderTest ---------------------------------------------------------
108 // The following environment is configured for these tests:
109 // . The TemplateURL default_t_url_ is set as the default provider.
110 // . The TemplateURL keyword_t_url_ is added to the TemplateURLService. This
111 // TemplateURL has a valid suggest and search URL.
112 // . The URL created by using the search term term1_ with default_t_url_ is
114 // . The URL created by using the search term keyword_term_ with keyword_t_url_
115 // is added to history.
116 // . test_factory_ is set as the URLFetcherFactory.
117 class SearchProviderTest
: public testing::Test
,
118 public AutocompleteProviderListener
{
121 ResultInfo() : result_type(AutocompleteMatchType::NUM_TYPES
),
122 allowed_to_be_default_match(false) {
124 ResultInfo(GURL gurl
,
125 AutocompleteMatch::Type result_type
,
126 bool allowed_to_be_default_match
,
127 base::string16 fill_into_edit
)
129 result_type(result_type
),
130 allowed_to_be_default_match(allowed_to_be_default_match
),
131 fill_into_edit(fill_into_edit
) {
135 const AutocompleteMatch::Type result_type
;
136 const bool allowed_to_be_default_match
;
137 const base::string16 fill_into_edit
;
141 const base::string16 input
;
142 const size_t num_results
;
143 const ResultInfo output
[3];
146 struct ExpectedMatch
{
147 std::string contents
;
148 bool allowed_to_be_default_match
;
152 : default_t_url_(NULL
),
153 term1_(ASCIIToUTF16("term1")),
154 keyword_t_url_(NULL
),
155 keyword_term_(ASCIIToUTF16("keyword")),
157 ResetFieldTrialList();
160 // See description above class for what this registers.
161 void SetUp() override
;
162 void TearDown() override
;
164 void RunTest(TestData
* cases
, int num_cases
, bool prefer_keyword
);
167 // Needed for AutocompleteFieldTrial::ActivateStaticTrials();
168 scoped_ptr
<base::FieldTrialList
> field_trial_list_
;
170 // Default values used for testing.
171 static const std::string kNotApplicable
;
172 static const ExpectedMatch kEmptyExpectedMatch
;
174 // Adds a search for |term|, using the engine |t_url| to the history, and
175 // returns the URL for that search.
176 GURL
AddSearchToHistory(TemplateURL
* t_url
, base::string16 term
, int visit_count
);
178 // Looks for a match in |provider_| with |contents| equal to |contents|.
179 // Sets |match| to it if found. Returns whether |match| was set.
180 bool FindMatchWithContents(const base::string16
& contents
,
181 AutocompleteMatch
* match
);
183 // Looks for a match in |provider_| with destination |url|. Sets |match| to
184 // it if found. Returns whether |match| was set.
185 bool FindMatchWithDestination(const GURL
& url
, AutocompleteMatch
* match
);
187 // AutocompleteProviderListener:
188 // If we're waiting for the provider to finish, this exits the message loop.
189 void OnProviderUpdate(bool updated_matches
) override
;
191 // Runs a nested message loop until provider_ is done. The message loop is
192 // exited by way of OnProviderUpdate.
193 void RunTillProviderDone();
195 // Invokes Start on provider_, then runs all pending tasks.
196 void QueryForInput(const base::string16
& text
,
197 bool prevent_inline_autocomplete
,
198 bool prefer_keyword
);
200 // Calls QueryForInput(), finishes any suggest query, then if |wyt_match| is
201 // non-NULL, sets it to the "what you typed" entry for |text|.
202 void QueryForInputAndSetWYTMatch(const base::string16
& text
,
203 AutocompleteMatch
* wyt_match
);
205 // Calls QueryForInput(), sets the JSON responses for the default and keyword
206 // fetchers, and waits until the responses have been returned and the matches
207 // returned. Use empty responses for each fetcher that shouldn't be set up /
209 void QueryForInputAndWaitForFetcherResponses(
210 const base::string16
& text
,
211 const bool prefer_keyword
,
212 const std::string
& default_fetcher_response
,
213 const std::string
& keyword_fetcher_response
);
215 // Notifies the URLFetcher for the suggest query corresponding to the default
216 // search provider that it's done.
217 // Be sure and wrap calls to this in ASSERT_NO_FATAL_FAILURE.
218 void FinishDefaultSuggestQuery();
220 // Runs SearchProvider on |input|, for which the suggest server replies
221 // with |json|, and expects that the resulting matches' contents equals
222 // that in |matches|. An empty entry in |matches| means no match should
223 // be returned in that position. Reports any errors with a message that
224 // includes |error_description|.
225 void ForcedQueryTestHelper(const std::string
& input
,
226 const std::string
& json
,
227 const std::string matches
[3],
228 const std::string
& error_description
);
230 // Verifies that |matches| and |expected_matches| agree on the first
231 // |num_expected_matches|, displaying an error message that includes
232 // |description| for any disagreement.
233 void CheckMatches(const std::string
& description
,
234 const size_t num_expected_matches
,
235 const ExpectedMatch expected_matches
[],
236 const ACMatches
& matches
);
238 void ResetFieldTrialList();
240 // Create a field trial, with ZeroSuggest activation based on |enabled|.
241 base::FieldTrial
* CreateZeroSuggestFieldTrial(bool enabled
);
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 // URLFetcherFactory implementation registered.
256 net::TestURLFetcherFactory test_factory_
;
259 TestingProfile profile_
;
262 scoped_refptr
<SearchProviderForTest
> provider_
;
264 // If non-NULL, OnProviderUpdate quits the current |run_loop_|.
265 base::RunLoop
* run_loop_
;
267 DISALLOW_COPY_AND_ASSIGN(SearchProviderTest
);
271 const std::string
SearchProviderTest::kNotApplicable
= "Not Applicable";
272 const SearchProviderTest::ExpectedMatch
273 SearchProviderTest::kEmptyExpectedMatch
= { kNotApplicable
, false };
275 void SearchProviderTest::SetUp() {
276 // Make sure that fetchers are automatically ungregistered upon destruction.
277 test_factory_
.set_remove_fetcher_on_delete(true);
279 // We need both the history service and template url model loaded.
280 ASSERT_TRUE(profile_
.CreateHistoryService(true, false));
281 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
282 &profile_
, &TemplateURLServiceFactory::BuildInstanceFor
);
284 TemplateURLService
* turl_model
=
285 TemplateURLServiceFactory::GetForProfile(&profile_
);
289 // Reset the default TemplateURL.
290 TemplateURLData data
;
291 data
.short_name
= ASCIIToUTF16("t");
292 data
.SetURL("http://defaultturl/{searchTerms}");
293 data
.suggestions_url
= "http://defaultturl2/{searchTerms}";
294 data
.instant_url
= "http://does/not/exist?strk=1";
295 data
.search_terms_replacement_key
= "strk";
296 default_t_url_
= new TemplateURL(data
);
297 turl_model
->Add(default_t_url_
);
298 turl_model
->SetUserSelectedDefaultSearchProvider(default_t_url_
);
299 TemplateURLID default_provider_id
= default_t_url_
->id();
300 ASSERT_NE(0, default_provider_id
);
302 // Add url1, with search term term1_.
303 term1_url_
= AddSearchToHistory(default_t_url_
, term1_
, 1);
305 // Create another TemplateURL.
306 data
.short_name
= ASCIIToUTF16("k");
307 data
.SetKeyword(ASCIIToUTF16("k"));
308 data
.SetURL("http://keyword/{searchTerms}");
309 data
.suggestions_url
= "http://suggest_keyword/{searchTerms}";
310 keyword_t_url_
= new TemplateURL(data
);
311 turl_model
->Add(keyword_t_url_
);
312 ASSERT_NE(0, keyword_t_url_
->id());
314 // Add a page and search term for keyword_t_url_.
315 keyword_url_
= AddSearchToHistory(keyword_t_url_
, keyword_term_
, 1);
317 // Keywords are updated by the InMemoryHistoryBackend only after the message
318 // has been processed on the history thread. Block until history processes all
319 // requests to ensure the InMemoryDatabase is the state we expect it.
320 profile_
.BlockUntilHistoryProcessesPendingRequests();
322 AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
323 &profile_
, &AutocompleteClassifierFactory::BuildInstanceFor
);
325 provider_
= new SearchProviderForTest(this, turl_model
, &profile_
);
326 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
= 0;
329 void SearchProviderTest::TearDown() {
330 base::RunLoop().RunUntilIdle();
332 // Shutdown the provider before the profile.
336 void SearchProviderTest::RunTest(TestData
* cases
,
338 bool prefer_keyword
) {
340 for (int i
= 0; i
< num_cases
; ++i
) {
341 AutocompleteInput
input(cases
[i
].input
, base::string16::npos
,
342 std::string(), GURL(),
343 metrics::OmniboxEventProto::INVALID_SPEC
, false,
344 prefer_keyword
, true, true,
345 ChromeAutocompleteSchemeClassifier(&profile_
));
346 provider_
->Start(input
, false);
347 matches
= provider_
->matches();
349 ASCIIToUTF16("Input was: ") +
351 ASCIIToUTF16("; prefer_keyword was: ") +
352 (prefer_keyword
? ASCIIToUTF16("true") : ASCIIToUTF16("false")));
353 EXPECT_EQ(cases
[i
].num_results
, matches
.size());
354 if (matches
.size() == cases
[i
].num_results
) {
355 for (size_t j
= 0; j
< cases
[i
].num_results
; ++j
) {
356 EXPECT_EQ(cases
[i
].output
[j
].gurl
, matches
[j
].destination_url
);
357 EXPECT_EQ(cases
[i
].output
[j
].result_type
, matches
[j
].type
);
358 EXPECT_EQ(cases
[i
].output
[j
].fill_into_edit
,
359 matches
[j
].fill_into_edit
);
360 EXPECT_EQ(cases
[i
].output
[j
].allowed_to_be_default_match
,
361 matches
[j
].allowed_to_be_default_match
);
367 void SearchProviderTest::OnProviderUpdate(bool updated_matches
) {
368 if (run_loop_
&& provider_
->done()) {
374 void SearchProviderTest::RunTillProviderDone() {
375 if (provider_
->done())
378 base::RunLoop run_loop
;
379 run_loop_
= &run_loop
;
383 void SearchProviderTest::QueryForInput(const base::string16
& text
,
384 bool prevent_inline_autocomplete
,
385 bool prefer_keyword
) {
387 AutocompleteInput
input(text
, base::string16::npos
, std::string(), GURL(),
388 metrics::OmniboxEventProto::INVALID_SPEC
,
389 prevent_inline_autocomplete
, prefer_keyword
, true,
390 true, ChromeAutocompleteSchemeClassifier(&profile_
));
391 provider_
->Start(input
, false);
393 // RunUntilIdle so that the task scheduled by SearchProvider to create the
395 base::RunLoop().RunUntilIdle();
398 void SearchProviderTest::QueryForInputAndSetWYTMatch(
399 const base::string16
& text
,
400 AutocompleteMatch
* wyt_match
) {
401 QueryForInput(text
, false, false);
402 profile_
.BlockUntilHistoryProcessesPendingRequests();
403 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
406 ASSERT_GE(provider_
->matches().size(), 1u);
407 EXPECT_TRUE(FindMatchWithDestination(
408 GURL(default_t_url_
->url_ref().ReplaceSearchTerms(
409 TemplateURLRef::SearchTermsArgs(base::CollapseWhitespace(
411 TemplateURLServiceFactory::GetForProfile(
412 &profile_
)->search_terms_data())),
416 void SearchProviderTest::QueryForInputAndWaitForFetcherResponses(
417 const base::string16
& text
,
418 const bool prefer_keyword
,
419 const std::string
& default_fetcher_response
,
420 const std::string
& keyword_fetcher_response
) {
421 QueryForInput(text
, false, prefer_keyword
);
422 if (!default_fetcher_response
.empty()) {
423 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
424 SearchProvider::kDefaultProviderURLFetcherID
);
425 ASSERT_TRUE(fetcher
);
426 fetcher
->set_response_code(200);
427 fetcher
->SetResponseString(default_fetcher_response
);
428 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
430 if (!keyword_fetcher_response
.empty()) {
431 net::TestURLFetcher
* keyword_fetcher
= test_factory_
.GetFetcherByID(
432 SearchProvider::kKeywordProviderURLFetcherID
);
433 ASSERT_TRUE(keyword_fetcher
);
434 keyword_fetcher
->set_response_code(200);
435 keyword_fetcher
->SetResponseString(keyword_fetcher_response
);
436 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
438 RunTillProviderDone();
441 GURL
SearchProviderTest::AddSearchToHistory(TemplateURL
* t_url
,
444 HistoryService
* history
=
445 HistoryServiceFactory::GetForProfile(&profile_
,
446 Profile::EXPLICIT_ACCESS
);
447 GURL
search(t_url
->url_ref().ReplaceSearchTerms(
448 TemplateURLRef::SearchTermsArgs(term
),
449 TemplateURLServiceFactory::GetForProfile(
450 &profile_
)->search_terms_data()));
451 static base::Time last_added_time
;
452 last_added_time
= std::max(base::Time::Now(),
453 last_added_time
+ base::TimeDelta::FromMicroseconds(1));
454 history
->AddPageWithDetails(search
, base::string16(), visit_count
, visit_count
,
455 last_added_time
, false, history::SOURCE_BROWSED
);
456 history
->SetKeywordSearchTermsForURL(search
, t_url
->id(), term
);
460 bool SearchProviderTest::FindMatchWithContents(const base::string16
& contents
,
461 AutocompleteMatch
* match
) {
462 for (ACMatches::const_iterator i
= provider_
->matches().begin();
463 i
!= provider_
->matches().end(); ++i
) {
464 if (i
->contents
== contents
) {
472 bool SearchProviderTest::FindMatchWithDestination(const GURL
& url
,
473 AutocompleteMatch
* match
) {
474 for (ACMatches::const_iterator i
= provider_
->matches().begin();
475 i
!= provider_
->matches().end(); ++i
) {
476 if (i
->destination_url
== url
) {
484 void SearchProviderTest::FinishDefaultSuggestQuery() {
485 net::TestURLFetcher
* default_fetcher
=
486 test_factory_
.GetFetcherByID(
487 SearchProvider::kDefaultProviderURLFetcherID
);
488 ASSERT_TRUE(default_fetcher
);
490 // Tell the SearchProvider the default suggest query is done.
491 default_fetcher
->set_response_code(200);
492 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
495 void SearchProviderTest::ForcedQueryTestHelper(
496 const std::string
& input
,
497 const std::string
& json
,
498 const std::string expected_matches
[3],
499 const std::string
& error_description
) {
500 // Send the query twice in order to have a synchronous pass after the first
501 // response is received. This is necessary because SearchProvider doesn't
502 // allow an asynchronous response to change the default match.
503 for (size_t i
= 0; i
< 2; ++i
) {
504 QueryForInputAndWaitForFetcherResponses(
505 ASCIIToUTF16(input
), false, json
, std::string());
508 const ACMatches
& matches
= provider_
->matches();
509 ASSERT_LE(matches
.size(), 3u);
511 // Ensure that the returned matches equal the expectations.
512 for (; i
< matches
.size(); ++i
) {
513 EXPECT_EQ(ASCIIToUTF16(expected_matches
[i
]), matches
[i
].contents
) <<
516 // Ensure that no expected matches are missing.
517 for (; i
< 3u; ++i
) {
518 EXPECT_EQ(std::string(), expected_matches
[i
]) <<
519 "Case #" << i
<< ": " << error_description
;
523 void SearchProviderTest::CheckMatches(const std::string
& description
,
524 const size_t num_expected_matches
,
525 const ExpectedMatch expected_matches
[],
526 const ACMatches
& matches
) {
527 ASSERT_FALSE(matches
.empty());
528 ASSERT_LE(matches
.size(), num_expected_matches
);
530 SCOPED_TRACE(description
);
531 // Ensure that the returned matches equal the expectations.
532 for (; i
< matches
.size(); ++i
) {
533 SCOPED_TRACE(" Case # " + base::IntToString(i
));
534 EXPECT_EQ(ASCIIToUTF16(expected_matches
[i
].contents
), matches
[i
].contents
);
535 EXPECT_EQ(expected_matches
[i
].allowed_to_be_default_match
,
536 matches
[i
].allowed_to_be_default_match
);
538 // Ensure that no expected matches are missing.
539 for (; i
< num_expected_matches
; ++i
) {
540 SCOPED_TRACE(" Case # " + base::IntToString(i
));
541 EXPECT_EQ(kNotApplicable
, expected_matches
[i
].contents
);
545 void SearchProviderTest::ResetFieldTrialList() {
546 // Destroy the existing FieldTrialList before creating a new one to avoid
548 field_trial_list_
.reset();
549 field_trial_list_
.reset(new base::FieldTrialList(
550 new metrics::SHA1EntropyProvider("foo")));
551 variations::testing::ClearAllVariationParams();
552 base::FieldTrial
* trial
= base::FieldTrialList::CreateFieldTrial(
553 "AutocompleteDynamicTrial_0", "DefaultGroup");
557 base::FieldTrial
* SearchProviderTest::CreateZeroSuggestFieldTrial(
559 std::map
<std::string
, std::string
> params
;
560 params
[std::string(OmniboxFieldTrial::kZeroSuggestRule
)] = enabled
?
562 variations::AssociateVariationParams(
563 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
);
564 return base::FieldTrialList::CreateFieldTrial(
565 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
568 void SearchProviderTest::ClearAllResults() {
569 provider_
->ClearAllResults();
572 // Actual Tests ---------------------------------------------------------------
574 // Make sure we query history for the default provider and a URLFetcher is
575 // created for the default provider suggest results.
576 TEST_F(SearchProviderTest
, QueryDefaultProvider
) {
577 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
578 QueryForInput(term
, false, false);
580 // Make sure the default providers suggest service was queried.
581 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
582 SearchProvider::kDefaultProviderURLFetcherID
);
583 ASSERT_TRUE(fetcher
);
585 // And the URL matches what we expected.
586 GURL
expected_url(default_t_url_
->suggestions_url_ref().ReplaceSearchTerms(
587 TemplateURLRef::SearchTermsArgs(term
),
588 TemplateURLServiceFactory::GetForProfile(
589 &profile_
)->search_terms_data()));
590 ASSERT_TRUE(fetcher
->GetOriginalURL() == expected_url
);
592 // Tell the SearchProvider the suggest query is done.
593 fetcher
->set_response_code(200);
594 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
597 // Run till the history results complete.
598 RunTillProviderDone();
600 // The SearchProvider is done. Make sure it has a result for the history
602 AutocompleteMatch term1_match
;
603 EXPECT_TRUE(FindMatchWithDestination(term1_url_
, &term1_match
));
604 // Term1 should not have a description, it's set later.
605 EXPECT_TRUE(term1_match
.description
.empty());
607 AutocompleteMatch wyt_match
;
608 EXPECT_TRUE(FindMatchWithDestination(
609 GURL(default_t_url_
->url_ref().ReplaceSearchTerms(
610 TemplateURLRef::SearchTermsArgs(term
),
611 TemplateURLServiceFactory::GetForProfile(
612 &profile_
)->search_terms_data())),
614 EXPECT_TRUE(wyt_match
.description
.empty());
616 // The match for term1 should be more relevant than the what you typed match.
617 EXPECT_GT(term1_match
.relevance
, wyt_match
.relevance
);
618 // This longer match should be inlineable.
619 EXPECT_TRUE(term1_match
.allowed_to_be_default_match
);
620 // The what you typed match should be too, of course.
621 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
624 TEST_F(SearchProviderTest
, HonorPreventInlineAutocomplete
) {
625 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
626 QueryForInput(term
, true, false);
628 ASSERT_FALSE(provider_
->matches().empty());
629 ASSERT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
630 provider_
->matches()[0].type
);
631 EXPECT_TRUE(provider_
->matches()[0].allowed_to_be_default_match
);
634 // Issues a query that matches the registered keyword and makes sure history
635 // is queried as well as URLFetchers getting created.
636 TEST_F(SearchProviderTest
, QueryKeywordProvider
) {
637 base::string16 term
= keyword_term_
.substr(0, keyword_term_
.length() - 1);
638 QueryForInput(keyword_t_url_
->keyword() + ASCIIToUTF16(" ") + term
,
642 // Make sure the default providers suggest service was queried.
643 net::TestURLFetcher
* default_fetcher
= test_factory_
.GetFetcherByID(
644 SearchProvider::kDefaultProviderURLFetcherID
);
645 ASSERT_TRUE(default_fetcher
);
647 // Tell the SearchProvider the default suggest query is done.
648 default_fetcher
->set_response_code(200);
649 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
650 default_fetcher
= NULL
;
652 // Make sure the keyword providers suggest service was queried.
653 net::TestURLFetcher
* keyword_fetcher
= test_factory_
.GetFetcherByID(
654 SearchProvider::kKeywordProviderURLFetcherID
);
655 ASSERT_TRUE(keyword_fetcher
);
657 // And the URL matches what we expected.
658 GURL
expected_url(keyword_t_url_
->suggestions_url_ref().ReplaceSearchTerms(
659 TemplateURLRef::SearchTermsArgs(term
),
660 TemplateURLServiceFactory::GetForProfile(
661 &profile_
)->search_terms_data()));
662 ASSERT_TRUE(keyword_fetcher
->GetOriginalURL() == expected_url
);
664 // Tell the SearchProvider the keyword suggest query is done.
665 keyword_fetcher
->set_response_code(200);
666 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
667 keyword_fetcher
= NULL
;
669 // Run till the history results complete.
670 RunTillProviderDone();
672 // The SearchProvider is done. Make sure it has a result for the history
674 AutocompleteMatch match
;
675 EXPECT_TRUE(FindMatchWithDestination(keyword_url_
, &match
));
677 // The match should have an associated keyword.
678 EXPECT_FALSE(match
.keyword
.empty());
680 // The fill into edit should contain the keyword.
681 EXPECT_EQ(keyword_t_url_
->keyword() + base::char16(' ') + keyword_term_
,
682 match
.fill_into_edit
);
685 TEST_F(SearchProviderTest
, DontSendPrivateDataToSuggest
) {
686 // None of the following input strings should be sent to the suggest server,
687 // because they may contain private data.
688 const char* inputs
[] = {
690 "http://username:password",
691 "https://username:password",
692 "username:password@hostname",
693 "http://username:password@hostname/",
696 "unknownscheme:anything",
697 "http://hostname/?query=q",
698 "http://hostname/path#ref",
699 "http://hostname/path #ref",
700 "https://hostname/path",
703 for (size_t i
= 0; i
< arraysize(inputs
); ++i
) {
704 QueryForInput(ASCIIToUTF16(inputs
[i
]), false, false);
705 // Make sure the default provider's suggest service was not queried.
706 ASSERT_TRUE(test_factory_
.GetFetcherByID(
707 SearchProvider::kDefaultProviderURLFetcherID
) == NULL
);
708 // Run till the history results complete.
709 RunTillProviderDone();
713 TEST_F(SearchProviderTest
, SendNonPrivateDataToSuggest
) {
714 // All of the following input strings should be sent to the suggest server,
715 // because they should not get caught by the private data checks.
716 const char* inputs
[] = {
720 "http://hostname/path",
721 "http://hostname #ref",
722 "www.hostname.com #ref",
725 "foo https://hostname/path"
728 profile_
.BlockUntilHistoryProcessesPendingRequests();
729 for (size_t i
= 0; i
< arraysize(inputs
); ++i
) {
730 QueryForInput(ASCIIToUTF16(inputs
[i
]), false, false);
731 // Make sure the default provider's suggest service was queried.
732 ASSERT_TRUE(test_factory_
.GetFetcherByID(
733 SearchProvider::kDefaultProviderURLFetcherID
) != NULL
);
737 TEST_F(SearchProviderTest
, DontAutocompleteURLLikeTerms
) {
738 GURL url
= AddSearchToHistory(default_t_url_
,
739 ASCIIToUTF16("docs.google.com"), 1);
741 // Add the term as a url.
742 HistoryServiceFactory::GetForProfile(&profile_
, Profile::EXPLICIT_ACCESS
)->
743 AddPageWithDetails(GURL("http://docs.google.com"), base::string16(), 1, 1,
744 base::Time::Now(), false, history::SOURCE_BROWSED
);
745 profile_
.BlockUntilHistoryProcessesPendingRequests();
747 AutocompleteMatch wyt_match
;
748 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("docs"),
751 // There should be two matches, one for what you typed, the other for
752 // 'docs.google.com'. The search term should have a lower priority than the
753 // what you typed match.
754 ASSERT_EQ(2u, provider_
->matches().size());
755 AutocompleteMatch term_match
;
756 EXPECT_TRUE(FindMatchWithDestination(url
, &term_match
));
757 EXPECT_GT(wyt_match
.relevance
, term_match
.relevance
);
758 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
759 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
762 TEST_F(SearchProviderTest
, DontGiveNavsuggestionsInForcedQueryMode
) {
763 const std::string kEmptyMatch
;
765 const std::string json
;
766 const std::string matches_in_default_mode
[3];
767 const std::string matches_in_forced_query_mode
[3];
769 // Without suggested relevance scores.
770 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
771 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]}]",
772 { "a", "a1.com", "a2" },
773 { "a", "a2", kEmptyMatch
} },
775 // With suggested relevance scores in a situation where navsuggest would
777 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
778 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
779 "\"google:suggestrelevance\":[1250, 1200]}]",
780 { "a", "a1.com", "a2" },
781 { "a", "a2", kEmptyMatch
} },
783 // With suggested relevance scores in a situation where navsuggest
785 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
786 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
787 "\"google:suggestrelevance\":[1350, 1250]}]",
788 { "a1.com", "a", "a2" },
789 { "a", "a2", kEmptyMatch
} },
791 // With suggested relevance scores in a situation where navsuggest
792 // would go first only because verbatim has been demoted.
793 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
794 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
795 "\"google:suggestrelevance\":[1450, 1400],"
796 "\"google:verbatimrelevance\":1350}]",
797 { "a1.com", "a2", "a" },
798 { "a2", "a", kEmptyMatch
} },
801 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
802 ForcedQueryTestHelper("a", cases
[i
].json
, cases
[i
].matches_in_default_mode
,
803 "regular input with json=" + cases
[i
].json
);
804 ForcedQueryTestHelper("?a", cases
[i
].json
,
805 cases
[i
].matches_in_forced_query_mode
,
806 "forced query input with json=" + cases
[i
].json
);
810 // A multiword search with one visit should not autocomplete until multiple
812 TEST_F(SearchProviderTest
, DontAutocompleteUntilMultipleWordsTyped
) {
813 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("one search"),
815 profile_
.BlockUntilHistoryProcessesPendingRequests();
817 AutocompleteMatch wyt_match
;
818 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("on"),
820 ASSERT_EQ(2u, provider_
->matches().size());
821 AutocompleteMatch term_match
;
822 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
823 EXPECT_GT(wyt_match
.relevance
, term_match
.relevance
);
824 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
825 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
827 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("one se"),
829 ASSERT_EQ(2u, provider_
->matches().size());
830 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
831 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
832 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
833 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
836 // A multiword search with more than one visit should autocomplete immediately.
837 TEST_F(SearchProviderTest
, AutocompleteMultipleVisitsImmediately
) {
838 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("two searches"),
840 profile_
.BlockUntilHistoryProcessesPendingRequests();
842 AutocompleteMatch wyt_match
;
843 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("tw"),
845 ASSERT_EQ(2u, provider_
->matches().size());
846 AutocompleteMatch term_match
;
847 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
848 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
849 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
850 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
853 // Autocompletion should work at a word boundary after a space, and should
854 // offer a suggestion for the trimmed search query.
855 TEST_F(SearchProviderTest
, AutocompleteAfterSpace
) {
856 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("two searches "), 2);
857 GURL
suggested_url(default_t_url_
->url_ref().ReplaceSearchTerms(
858 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("two searches")),
859 TemplateURLServiceFactory::GetForProfile(
860 &profile_
)->search_terms_data()));
861 profile_
.BlockUntilHistoryProcessesPendingRequests();
863 AutocompleteMatch wyt_match
;
864 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("two "),
866 ASSERT_EQ(2u, provider_
->matches().size());
867 AutocompleteMatch term_match
;
868 EXPECT_TRUE(FindMatchWithDestination(suggested_url
, &term_match
));
869 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
870 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
871 EXPECT_EQ(ASCIIToUTF16("searches"), term_match
.inline_autocompletion
);
872 EXPECT_EQ(ASCIIToUTF16("two searches"), term_match
.fill_into_edit
);
873 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
876 // Newer multiword searches should score more highly than older ones.
877 TEST_F(SearchProviderTest
, ScoreNewerSearchesHigher
) {
878 GURL
term_url_a(AddSearchToHistory(default_t_url_
,
879 ASCIIToUTF16("three searches aaa"), 1));
880 GURL
term_url_b(AddSearchToHistory(default_t_url_
,
881 ASCIIToUTF16("three searches bbb"), 1));
882 profile_
.BlockUntilHistoryProcessesPendingRequests();
884 AutocompleteMatch wyt_match
;
885 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("three se"),
887 ASSERT_EQ(3u, provider_
->matches().size());
888 AutocompleteMatch term_match_a
;
889 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
890 AutocompleteMatch term_match_b
;
891 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
892 EXPECT_GT(term_match_b
.relevance
, term_match_a
.relevance
);
893 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
894 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
895 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
896 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
899 // An autocompleted multiword search should not be replaced by a different
900 // autocompletion while the user is still typing a valid prefix unless the
901 // user has typed the prefix as a query before.
902 TEST_F(SearchProviderTest
, DontReplacePreviousAutocompletion
) {
903 GURL
term_url_a(AddSearchToHistory(default_t_url_
,
904 ASCIIToUTF16("four searches aaa"), 3));
905 GURL
term_url_b(AddSearchToHistory(default_t_url_
,
906 ASCIIToUTF16("four searches bbb"), 1));
907 GURL
term_url_c(AddSearchToHistory(default_t_url_
,
908 ASCIIToUTF16("four searches"), 1));
909 profile_
.BlockUntilHistoryProcessesPendingRequests();
911 AutocompleteMatch wyt_match
;
912 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fo"),
914 ASSERT_EQ(4u, provider_
->matches().size());
915 AutocompleteMatch term_match_a
;
916 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
917 AutocompleteMatch term_match_b
;
918 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
919 AutocompleteMatch term_match_c
;
920 EXPECT_TRUE(FindMatchWithDestination(term_url_c
, &term_match_c
));
921 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
922 // We don't care about the relative order of b and c.
923 EXPECT_GT(wyt_match
.relevance
, term_match_b
.relevance
);
924 EXPECT_GT(wyt_match
.relevance
, term_match_c
.relevance
);
925 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
926 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
927 EXPECT_TRUE(term_match_c
.allowed_to_be_default_match
);
928 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
930 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("four se"),
932 ASSERT_EQ(4u, provider_
->matches().size());
933 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
934 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
935 EXPECT_TRUE(FindMatchWithDestination(term_url_c
, &term_match_c
));
936 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
937 EXPECT_GT(wyt_match
.relevance
, term_match_b
.relevance
);
938 EXPECT_GT(wyt_match
.relevance
, term_match_c
.relevance
);
939 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
940 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
941 EXPECT_TRUE(term_match_c
.allowed_to_be_default_match
);
942 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
944 // For the exact previously-issued query, the what-you-typed match should win.
945 ASSERT_NO_FATAL_FAILURE(
946 QueryForInputAndSetWYTMatch(ASCIIToUTF16("four searches"), &wyt_match
));
947 ASSERT_EQ(3u, provider_
->matches().size());
948 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
949 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
950 EXPECT_GT(wyt_match
.relevance
, term_match_a
.relevance
);
951 EXPECT_GT(wyt_match
.relevance
, term_match_b
.relevance
);
952 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
953 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
954 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
957 // Non-completable multiword searches should not crowd out single-word searches.
958 TEST_F(SearchProviderTest
, DontCrowdOutSingleWords
) {
959 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five"), 1));
960 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches bbb"), 1);
961 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches ccc"), 1);
962 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches ddd"), 1);
963 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches eee"), 1);
964 profile_
.BlockUntilHistoryProcessesPendingRequests();
966 AutocompleteMatch wyt_match
;
967 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fi"),
969 ASSERT_EQ(AutocompleteProvider::kMaxMatches
+ 1, provider_
->matches().size());
970 AutocompleteMatch term_match
;
971 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
972 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
973 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
974 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
977 // Inline autocomplete matches regardless of case differences from the input.
978 TEST_F(SearchProviderTest
, InlineMixedCaseMatches
) {
979 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("FOO"), 1));
980 profile_
.BlockUntilHistoryProcessesPendingRequests();
982 AutocompleteMatch wyt_match
;
983 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
985 ASSERT_EQ(2u, provider_
->matches().size());
986 AutocompleteMatch term_match
;
987 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
988 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
989 EXPECT_EQ(ASCIIToUTF16("FOO"), term_match
.fill_into_edit
);
990 EXPECT_EQ(ASCIIToUTF16("OO"), term_match
.inline_autocompletion
);
991 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
994 // Verifies AutocompleteControllers return results (including keyword
995 // results) in the right order and set descriptions for them correctly.
996 TEST_F(SearchProviderTest
, KeywordOrderingAndDescriptions
) {
997 // Add an entry that corresponds to a keyword search with 'term2'.
998 AddSearchToHistory(keyword_t_url_
, ASCIIToUTF16("term2"), 1);
999 profile_
.BlockUntilHistoryProcessesPendingRequests();
1001 AutocompleteController
controller(&profile_
,
1002 TemplateURLServiceFactory::GetForProfile(&profile_
),
1003 NULL
, AutocompleteProvider::TYPE_SEARCH
);
1004 controller
.Start(AutocompleteInput(
1005 ASCIIToUTF16("k t"), base::string16::npos
, std::string(), GURL(),
1006 metrics::OmniboxEventProto::INVALID_SPEC
, false, false, true, true,
1007 ChromeAutocompleteSchemeClassifier(&profile_
)));
1008 const AutocompleteResult
& result
= controller
.result();
1010 // There should be three matches, one for the keyword history, one for
1011 // keyword provider's what-you-typed, and one for the default provider's
1012 // what you typed, in that order.
1013 ASSERT_EQ(3u, result
.size());
1014 EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY
, result
.match_at(0).type
);
1015 EXPECT_EQ(AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1016 result
.match_at(1).type
);
1017 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1018 result
.match_at(2).type
);
1019 EXPECT_GT(result
.match_at(0).relevance
, result
.match_at(1).relevance
);
1020 EXPECT_GT(result
.match_at(1).relevance
, result
.match_at(2).relevance
);
1021 EXPECT_TRUE(result
.match_at(0).allowed_to_be_default_match
);
1022 EXPECT_TRUE(result
.match_at(1).allowed_to_be_default_match
);
1023 EXPECT_FALSE(result
.match_at(2).allowed_to_be_default_match
);
1025 // The two keyword results should come with the keyword we expect.
1026 EXPECT_EQ(ASCIIToUTF16("k"), result
.match_at(0).keyword
);
1027 EXPECT_EQ(ASCIIToUTF16("k"), result
.match_at(1).keyword
);
1028 // The default provider has a different keyword. (We don't explicitly
1029 // set it during this test, so all we do is assert that it's different.)
1030 EXPECT_NE(result
.match_at(0).keyword
, result
.match_at(2).keyword
);
1032 // The top result will always have a description. The third result,
1033 // coming from a different provider than the first two, should also.
1034 // Whether the second result has one doesn't matter much. (If it was
1035 // missing, people would infer that it's the same search provider as
1036 // the one above it.)
1037 EXPECT_FALSE(result
.match_at(0).description
.empty());
1038 EXPECT_FALSE(result
.match_at(2).description
.empty());
1039 EXPECT_NE(result
.match_at(0).description
, result
.match_at(2).description
);
1042 TEST_F(SearchProviderTest
, KeywordVerbatim
) {
1043 TestData cases
[] = {
1044 // Test a simple keyword input.
1045 { ASCIIToUTF16("k foo"), 2,
1046 { ResultInfo(GURL("http://keyword/foo"),
1047 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1049 ASCIIToUTF16("k foo")),
1050 ResultInfo(GURL("http://defaultturl/k%20foo"),
1051 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1053 ASCIIToUTF16("k foo") ) } },
1055 // Make sure extra whitespace after the keyword doesn't change the
1056 // keyword verbatim query. Also verify that interior consecutive
1057 // whitespace gets trimmed.
1058 { ASCIIToUTF16("k foo"), 2,
1059 { ResultInfo(GURL("http://keyword/foo"),
1060 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1062 ASCIIToUTF16("k foo")),
1063 ResultInfo(GURL("http://defaultturl/k%20foo"),
1064 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1066 ASCIIToUTF16("k foo")) } },
1067 // Leading whitespace should be stripped before SearchProvider gets the
1068 // input; hence there are no tests here about how it handles those inputs.
1070 // Verify that interior consecutive whitespace gets trimmed in either case.
1071 { ASCIIToUTF16("k foo bar"), 2,
1072 { ResultInfo(GURL("http://keyword/foo%20bar"),
1073 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1075 ASCIIToUTF16("k foo bar")),
1076 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
1077 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1079 ASCIIToUTF16("k foo bar")) } },
1081 // Verify that trailing whitespace gets trimmed.
1082 { ASCIIToUTF16("k foo bar "), 2,
1083 { ResultInfo(GURL("http://keyword/foo%20bar"),
1084 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1086 ASCIIToUTF16("k foo bar")),
1087 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
1088 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1090 ASCIIToUTF16("k foo bar")) } },
1092 // Keywords can be prefixed by certain things that should get ignored
1093 // when constructing the keyword match.
1094 { ASCIIToUTF16("www.k foo"), 2,
1095 { ResultInfo(GURL("http://keyword/foo"),
1096 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1098 ASCIIToUTF16("k foo")),
1099 ResultInfo(GURL("http://defaultturl/www.k%20foo"),
1100 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1102 ASCIIToUTF16("www.k foo")) } },
1103 { ASCIIToUTF16("http://k foo"), 2,
1104 { ResultInfo(GURL("http://keyword/foo"),
1105 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1107 ASCIIToUTF16("k foo")),
1108 ResultInfo(GURL("http://defaultturl/http%3A//k%20foo"),
1109 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1111 ASCIIToUTF16("http://k foo")) } },
1112 { ASCIIToUTF16("http://www.k foo"), 2,
1113 { ResultInfo(GURL("http://keyword/foo"),
1114 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1116 ASCIIToUTF16("k foo")),
1117 ResultInfo(GURL("http://defaultturl/http%3A//www.k%20foo"),
1118 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1120 ASCIIToUTF16("http://www.k foo")) } },
1122 // A keyword with no remaining input shouldn't get a keyword
1124 { ASCIIToUTF16("k"), 1,
1125 { ResultInfo(GURL("http://defaultturl/k"),
1126 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1128 ASCIIToUTF16("k")) } },
1129 // Ditto. Trailing whitespace shouldn't make a difference.
1130 { ASCIIToUTF16("k "), 1,
1131 { ResultInfo(GURL("http://defaultturl/k"),
1132 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1134 ASCIIToUTF16("k")) } }
1136 // The fact that verbatim queries to keyword are handled by KeywordProvider
1137 // not SearchProvider is tested in
1138 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc.
1141 // Test not in keyword mode.
1142 RunTest(cases
, arraysize(cases
), false);
1144 // Test in keyword mode. (Both modes should give the same result.)
1145 RunTest(cases
, arraysize(cases
), true);
1148 // Ensures command-line flags are reflected in the URLs the search provider
1150 TEST_F(SearchProviderTest
, CommandLineOverrides
) {
1151 TemplateURLService
* turl_model
=
1152 TemplateURLServiceFactory::GetForProfile(&profile_
);
1154 TemplateURLData data
;
1155 data
.short_name
= ASCIIToUTF16("default");
1156 data
.SetKeyword(data
.short_name
);
1157 data
.SetURL("{google:baseURL}{searchTerms}");
1158 default_t_url_
= new TemplateURL(data
);
1159 turl_model
->Add(default_t_url_
);
1160 turl_model
->SetUserSelectedDefaultSearchProvider(default_t_url_
);
1162 CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL
,
1163 "http://www.bar.com/");
1164 CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1165 switches::kExtraSearchQueryParams
, "a=b");
1167 TestData cases
[] = {
1168 { ASCIIToUTF16("k a"), 2,
1169 { ResultInfo(GURL("http://keyword/a"),
1170 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1172 ASCIIToUTF16("k a")),
1173 ResultInfo(GURL("http://www.bar.com/k%20a?a=b"),
1174 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1176 ASCIIToUTF16("k a")) } },
1179 RunTest(cases
, arraysize(cases
), false);
1182 // Verifies Navsuggest results don't set a TemplateURL, which Instant relies on.
1183 // Also verifies that just the *first* navigational result is listed as a match
1184 // if suggested relevance scores were not sent.
1185 TEST_F(SearchProviderTest
, NavSuggestNoSuggestedRelevanceScores
) {
1186 QueryForInputAndWaitForFetcherResponses(
1187 ASCIIToUTF16("a.c"), false,
1188 "[\"a.c\",[\"a.com\", \"a.com/b\"],[\"a\", \"b\"],[],"
1189 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1192 // Make sure the only match is 'a.com' and it doesn't have a template_url.
1193 AutocompleteMatch nav_match
;
1194 EXPECT_TRUE(FindMatchWithDestination(GURL("http://a.com"), &nav_match
));
1195 EXPECT_TRUE(nav_match
.keyword
.empty());
1196 EXPECT_FALSE(nav_match
.allowed_to_be_default_match
);
1197 EXPECT_FALSE(FindMatchWithDestination(GURL("http://a.com/b"), &nav_match
));
1200 // Verifies that the most relevant suggest results are added properly.
1201 TEST_F(SearchProviderTest
, SuggestRelevance
) {
1202 QueryForInputAndWaitForFetcherResponses(
1203 ASCIIToUTF16("a"), false, "[\"a\",[\"a1\", \"a2\", \"a3\", \"a4\"]]",
1206 // Check the expected verbatim and (first 3) suggestions' relative relevances.
1207 AutocompleteMatch verbatim
, match_a1
, match_a2
, match_a3
, match_a4
;
1208 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim
));
1209 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a1"), &match_a1
));
1210 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a2"), &match_a2
));
1211 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a3"), &match_a3
));
1212 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("a4"), &match_a4
));
1213 EXPECT_GT(verbatim
.relevance
, match_a1
.relevance
);
1214 EXPECT_GT(match_a1
.relevance
, match_a2
.relevance
);
1215 EXPECT_GT(match_a2
.relevance
, match_a3
.relevance
);
1216 EXPECT_TRUE(verbatim
.allowed_to_be_default_match
);
1217 EXPECT_FALSE(match_a1
.allowed_to_be_default_match
);
1218 EXPECT_FALSE(match_a2
.allowed_to_be_default_match
);
1219 EXPECT_FALSE(match_a3
.allowed_to_be_default_match
);
1222 // Verifies that the default provider abandons suggested relevance scores
1223 // when in keyword mode. This should happen regardless of whether the
1224 // keyword provider returns suggested relevance scores.
1225 TEST_F(SearchProviderTest
, DefaultProviderNoSuggestRelevanceInKeywordMode
) {
1227 const std::string default_provider_json
;
1228 const std::string keyword_provider_json
;
1229 const std::string matches
[5];
1231 // First, try an input where the keyword provider does not deliver
1232 // suggested relevance scores.
1233 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1234 "{\"google:verbatimrelevance\":9700,"
1235 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1236 "\"google:suggestrelevance\":[9900, 9800]}]",
1237 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"]}]",
1238 { "a", "akeyword-query", "k a", "adefault.com", "k adefault-query" } },
1240 // Now try with keyword provider suggested relevance scores.
1241 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1242 "{\"google:verbatimrelevance\":9700,"
1243 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1244 "\"google:suggestrelevance\":[9900, 9800]}]",
1245 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"],"
1246 "\"google:verbatimrelevance\":9500,"
1247 "\"google:suggestrelevance\":[9600]}]",
1248 { "akeyword-query", "a", "k a", "adefault.com", "k adefault-query" } }
1251 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
1252 // Send the query twice in order to have a synchronous pass after the first
1253 // response is received. This is necessary because SearchProvider doesn't
1254 // allow an asynchronous response to change the default match.
1255 for (size_t j
= 0; j
< 2; ++j
) {
1256 QueryForInputAndWaitForFetcherResponses(
1257 ASCIIToUTF16("k a"), true, cases
[i
].default_provider_json
,
1258 cases
[i
].keyword_provider_json
);
1262 "for input with default_provider_json=" +
1263 cases
[i
].default_provider_json
+ " and keyword_provider_json=" +
1264 cases
[i
].keyword_provider_json
);
1265 const ACMatches
& matches
= provider_
->matches();
1266 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
1268 // Ensure that the returned matches equal the expectations.
1269 for (; j
< matches
.size(); ++j
)
1270 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
]), matches
[j
].contents
);
1271 // Ensure that no expected matches are missing.
1272 for (; j
< arraysize(cases
[i
].matches
); ++j
)
1273 EXPECT_EQ(std::string(), cases
[i
].matches
[j
]);
1277 // Verifies that suggest results with relevance scores are added
1278 // properly when using the default fetcher. When adding a new test
1279 // case to this test, please consider adding it to the tests in
1280 // KeywordFetcherSuggestRelevance below.
1281 TEST_F(SearchProviderTest
, DefaultFetcherSuggestRelevance
) {
1283 const std::string json
;
1284 const ExpectedMatch matches
[6];
1285 const std::string inline_autocompletion
;
1287 // Ensure that suggestrelevance scores reorder matches.
1288 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1289 { { "a", true }, { "c", false }, { "b", false }, kEmptyExpectedMatch
,
1290 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1292 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1293 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1294 "\"google:suggestrelevance\":[1, 2]}]",
1295 { { "a", true }, { "c.com", false }, { "b.com", false },
1296 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1299 // Without suggested relevance scores, we should only allow one
1300 // navsuggest result to be be displayed.
1301 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1302 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1303 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch
,
1304 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1307 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1308 // Negative values will have no effect; the calculated value will be used.
1309 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1310 "\"google:suggestrelevance\":[9998]}]",
1311 { { "a", true}, { "a1", false }, kEmptyExpectedMatch
,
1312 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1314 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1315 "\"google:suggestrelevance\":[9999]}]",
1316 { { "a1", true }, { "a", true }, kEmptyExpectedMatch
,
1317 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1319 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1320 "\"google:suggestrelevance\":[9999]}]",
1321 { { "a1", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1322 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1324 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1325 "\"google:suggestrelevance\":[9999]}]",
1326 { { "a1", true }, { "a", true }, kEmptyExpectedMatch
,
1327 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1329 { "[\"a\",[\"http://a.com\"],[],[],"
1330 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1331 "\"google:verbatimrelevance\":9999,"
1332 "\"google:suggestrelevance\":[9998]}]",
1333 { { "a", true }, { "a.com", false }, kEmptyExpectedMatch
,
1334 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1336 { "[\"a\",[\"http://a.com\"],[],[],"
1337 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1338 "\"google:verbatimrelevance\":9998,"
1339 "\"google:suggestrelevance\":[9999]}]",
1340 { { "a.com", true }, { "a", true }, kEmptyExpectedMatch
,
1341 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1343 { "[\"a\",[\"http://a.com\"],[],[],"
1344 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1345 "\"google:verbatimrelevance\":0,"
1346 "\"google:suggestrelevance\":[9999]}]",
1347 { { "a.com", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1348 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1350 { "[\"a\",[\"http://a.com\"],[],[],"
1351 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1352 "\"google:verbatimrelevance\":-1,"
1353 "\"google:suggestrelevance\":[9999]}]",
1354 { { "a.com", true }, { "a", true }, kEmptyExpectedMatch
,
1355 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1358 // Ensure that both types of relevance scores reorder matches together.
1359 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1360 "\"google:verbatimrelevance\":9998}]",
1361 { { "a1", true }, { "a", true }, { "a2", false }, kEmptyExpectedMatch
,
1362 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1365 // Check that an inlineable result appears first regardless of its score.
1366 // Also, if the result set lacks a single inlineable result, abandon the
1367 // request to suppress verbatim (verbatim_relevance=0), which will then
1368 // cause verbatim to appear (first).
1369 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1370 { { "a", true }, { "b", false }, kEmptyExpectedMatch
,
1371 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1373 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1374 "\"google:verbatimrelevance\":0}]",
1375 { { "a", true }, { "b", false }, kEmptyExpectedMatch
,
1376 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1378 { "[\"a\",[\"http://b.com\"],[],[],"
1379 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1380 "\"google:suggestrelevance\":[9999]}]",
1381 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch
,
1382 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1384 { "[\"a\",[\"http://b.com\"],[],[],"
1385 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1386 "\"google:suggestrelevance\":[9999],"
1387 "\"google:verbatimrelevance\":0}]",
1388 { { "a", true }, { "b.com", false }, kEmptyExpectedMatch
,
1389 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1392 // Allow low-scoring matches.
1393 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1394 { { "a1", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1395 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1397 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":10}]",
1398 { { "a1", true }, { "a", true }, kEmptyExpectedMatch
,
1399 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1401 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[10],"
1402 "\"google:verbatimrelevance\":0}]",
1403 { { "a1", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1404 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1406 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 20],"
1407 "\"google:verbatimrelevance\":0}]",
1408 { { "a2", true }, { "a1", false }, kEmptyExpectedMatch
,
1409 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1411 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 30],"
1412 "\"google:verbatimrelevance\":20}]",
1413 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1414 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1416 { "[\"a\",[\"http://a.com\"],[],[],"
1417 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1418 "\"google:suggestrelevance\":[10],"
1419 "\"google:verbatimrelevance\":0}]",
1420 { { "a.com", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1421 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1423 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1424 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1425 "\"google:suggestrelevance\":[10, 20],"
1426 "\"google:verbatimrelevance\":0}]",
1427 { { "a2.com", true }, { "a1.com", false }, kEmptyExpectedMatch
,
1428 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1431 // Ensure that all suggestions are considered, regardless of order.
1432 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1433 "{\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1434 { { "a", true }, { "h", false }, { "g", false }, { "f", false },
1435 { "e", false }, { "d", false } },
1437 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1438 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1439 "\"http://h.com\"],[],[],"
1440 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1441 "\"NAVIGATION\", \"NAVIGATION\","
1442 "\"NAVIGATION\", \"NAVIGATION\","
1444 "\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1445 { { "a", true }, { "h.com", false }, { "g.com", false },
1446 { "f.com", false }, { "e.com", false }, { "d.com", false } },
1449 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1450 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10]}]",
1451 { { "a", true }, { "a1", false }, { "a2", false }, kEmptyExpectedMatch
,
1452 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1454 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 10]}]",
1455 { { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1456 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1458 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1459 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1460 "\"google:suggestrelevance\":[10]}]",
1461 { { "a", true }, { "a1.com", false }, kEmptyExpectedMatch
,
1462 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1464 { "[\"a\",[\"http://a1.com\"],[],[],"
1465 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1466 "\"google:suggestrelevance\":[9999, 10]}]",
1467 { { "a", true }, { "a1.com", false }, kEmptyExpectedMatch
,
1468 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1471 // Ensure that all 'verbatim' results are merged with their maximum score.
1472 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1473 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1474 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1475 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1477 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1478 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1479 "\"google:verbatimrelevance\":0}]",
1480 { { "a2", true }, { "a", true }, { "a1", false }, kEmptyExpectedMatch
,
1481 kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1484 // Ensure that verbatim is always generated without other suggestions.
1485 // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
1486 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1487 { { "a", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1488 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1490 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1491 { { "a", true }, kEmptyExpectedMatch
, kEmptyExpectedMatch
,
1492 kEmptyExpectedMatch
, kEmptyExpectedMatch
, kEmptyExpectedMatch
},
1496 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
1497 // Send the query twice in order to have a synchronous pass after the first
1498 // response is received. This is necessary because SearchProvider doesn't
1499 // allow an asynchronous response to change the default match.
1500 for (size_t j
= 0; j
< 2; ++j
) {
1501 QueryForInputAndWaitForFetcherResponses(
1502 ASCIIToUTF16("a"), false, cases
[i
].json
, std::string());
1505 const std::string description
= "for input with json=" + cases
[i
].json
;
1506 CheckMatches(description
, arraysize(cases
[i
].matches
), cases
[i
].matches
,
1507 provider_
->matches());
1511 // Verifies that suggest results with relevance scores are added
1512 // properly when using the keyword fetcher. This is similar to the
1513 // test DefaultFetcherSuggestRelevance above but this uses inputs that
1514 // trigger keyword suggestions (i.e., "k a" rather than "a") and has
1515 // different expectations (because now the results are a mix of
1516 // keyword suggestions and default provider suggestions). When a new
1517 // test is added to this TEST_F, please consider if it would be
1518 // appropriate to add to DefaultFetcherSuggestRelevance as well.
1519 TEST_F(SearchProviderTest
, KeywordFetcherSuggestRelevance
) {
1520 struct KeywordFetcherMatch
{
1521 std::string contents
;
1523 bool allowed_to_be_default_match
;
1525 const KeywordFetcherMatch kEmptyMatch
= { kNotApplicable
, false, false };
1527 const std::string json
;
1528 const KeywordFetcherMatch matches
[6];
1529 const std::string inline_autocompletion
;
1531 // Ensure that suggest relevance scores reorder matches and that
1532 // the keyword verbatim (lacking a suggested verbatim score) beats
1533 // the default provider verbatim.
1534 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1535 { { "a", true, true },
1536 { "k a", false, false },
1537 { "c", true, false },
1538 { "b", true, false },
1539 kEmptyMatch
, kEmptyMatch
},
1541 // Again, check that relevance scores reorder matches, just this
1542 // time with navigation matches. This also checks that with
1543 // suggested relevance scores we allow multiple navsuggest results.
1544 // Note that navsuggest results that come from a keyword provider
1545 // are marked as not a keyword result. (They don't go to a
1546 // keyword search engine.)
1547 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
1548 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1549 "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
1550 { { "a", true, true },
1551 { "d", true, false },
1552 { "c.com", false, false },
1553 { "b.com", false, false },
1554 { "k a", false, false },
1558 // Without suggested relevance scores, we should only allow one
1559 // navsuggest result to be be displayed.
1560 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1561 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1562 { { "a", true, true },
1563 { "b.com", false, false },
1564 { "k a", false, false },
1565 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1568 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1569 // Negative values will have no effect; the calculated value will be used.
1570 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1571 "\"google:suggestrelevance\":[9998]}]",
1572 { { "a", true, true },
1573 { "a1", true, false },
1574 { "k a", false, false },
1575 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1577 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1578 "\"google:suggestrelevance\":[9999]}]",
1579 { { "a1", true, true },
1580 { "a", true, true },
1581 { "k a", false, false },
1582 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1584 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1585 "\"google:suggestrelevance\":[9999]}]",
1586 { { "a1", true, true },
1587 { "k a", false, false },
1588 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1590 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1591 "\"google:suggestrelevance\":[9999]}]",
1592 { { "a1", true, true },
1593 { "a", true, true },
1594 { "k a", false, false },
1595 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1597 { "[\"a\",[\"http://a.com\"],[],[],"
1598 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1599 "\"google:verbatimrelevance\":9999,"
1600 "\"google:suggestrelevance\":[9998]}]",
1601 { { "a", true, true },
1602 { "a.com", false, false },
1603 { "k a", false, false },
1604 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1607 // Ensure that both types of relevance scores reorder matches together.
1608 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1609 "\"google:verbatimrelevance\":9998}]",
1610 { { "a1", true, true },
1611 { "a", true, true },
1612 { "a2", true, false },
1613 { "k a", false, false },
1614 kEmptyMatch
, kEmptyMatch
},
1617 // Check that an inlineable match appears first regardless of its score.
1618 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1619 { { "a", true, true },
1620 { "b", true, false },
1621 { "k a", false, false },
1622 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1624 { "[\"a\",[\"http://b.com\"],[],[],"
1625 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1626 "\"google:suggestrelevance\":[9999]}]",
1627 { { "a", true, true },
1628 { "b.com", false, false },
1629 { "k a", false, false },
1630 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1632 // If there is no inlineable match, restore the keyword verbatim score.
1633 // The keyword verbatim match will then appear first.
1634 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1635 "\"google:verbatimrelevance\":0}]",
1636 { { "a", true, true },
1637 { "b", true, false },
1638 { "k a", false, false },
1639 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1641 { "[\"a\",[\"http://b.com\"],[],[],"
1642 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1643 "\"google:suggestrelevance\":[9999],"
1644 "\"google:verbatimrelevance\":0}]",
1645 { { "a", true, true },
1646 { "b.com", false, false },
1647 { "k a", false, false },
1648 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1651 // The top result does not have to score as highly as calculated
1652 // verbatim. i.e., there are no minimum score restrictions in
1654 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1655 { { "a1", true, true },
1656 { "k a", false, false },
1657 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1659 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":10}]",
1660 { { "a1", true, true },
1661 { "k a", false, false },
1662 { "a", true, true },
1663 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1665 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[10],"
1666 "\"google:verbatimrelevance\":0}]",
1667 { { "a1", true, true },
1668 { "k a", false, false },
1669 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1671 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 20],"
1672 "\"google:verbatimrelevance\":0}]",
1673 { { "a2", true, true },
1674 { "k a", false, false },
1675 { "a1", true, false },
1676 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1678 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 30],"
1679 "\"google:verbatimrelevance\":20}]",
1680 { { "a2", true, true },
1681 { "k a", false, false },
1682 { "a", true, true },
1683 { "a1", true, false },
1684 kEmptyMatch
, kEmptyMatch
},
1687 // Ensure that all suggestions are considered, regardless of order.
1688 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1689 "{\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1690 { { "a", true, true },
1691 { "k a", false, false },
1692 { "h", true, false },
1693 { "g", true, false },
1694 { "f", true, false },
1695 { "e", true, false } },
1697 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1698 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1699 "\"http://h.com\"],[],[],"
1700 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1701 "\"NAVIGATION\", \"NAVIGATION\","
1702 "\"NAVIGATION\", \"NAVIGATION\","
1704 "\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
1705 { { "a", true, true },
1706 { "k a", false, false },
1707 { "h.com", false, false },
1708 { "g.com", false, false },
1709 { "f.com", false, false },
1710 { "e.com", false, false } },
1713 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1714 // Note that keyword suggestions by default (not in suggested relevance
1715 // mode) score more highly than the default verbatim.
1716 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1717 { { "a", true, true },
1718 { "a1", true, false },
1719 { "a2", true, false },
1720 { "k a", false, false },
1721 kEmptyMatch
, kEmptyMatch
},
1723 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1724 { { "a", true, true },
1725 { "a1", true, false },
1726 { "k a", false, false },
1727 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1729 // In this case, ignoring the suggested relevance scores means we keep
1730 // only one navsuggest result.
1731 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1732 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1733 "\"google:suggestrelevance\":[1]}]",
1734 { { "a", true, true },
1735 { "a1.com", false, false },
1736 { "k a", false, false },
1737 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1739 { "[\"a\",[\"http://a1.com\"],[],[],"
1740 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1741 "\"google:suggestrelevance\":[9999, 1]}]",
1742 { { "a", true, true },
1743 { "a1.com", false, false },
1744 { "k a", false, false },
1745 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1748 // Ensure that all 'verbatim' results are merged with their maximum score.
1749 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1750 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1751 { { "a2", true, true },
1752 { "a", true, true },
1753 { "a1", true, false },
1754 { "k a", false, false },
1755 kEmptyMatch
, kEmptyMatch
},
1757 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1758 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1759 "\"google:verbatimrelevance\":0}]",
1760 { { "a2", true, true },
1761 { "a", true, true },
1762 { "a1", true, false },
1763 { "k a", false, false },
1764 kEmptyMatch
, kEmptyMatch
},
1767 // Ensure that verbatim is always generated without other suggestions.
1768 // TODO(mpearson): Ensure the value of verbatimrelevance is respected
1769 // (except when suggested relevances are ignored).
1770 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1771 { { "a", true, true },
1772 { "k a", false, false },
1773 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1775 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1776 { { "a", true, true },
1777 { "k a", false, false },
1778 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1781 // In reorder mode, navsuggestions will not need to be demoted (because
1782 // they are marked as not allowed to be default match and will be
1783 // reordered as necessary).
1784 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1785 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1786 "\"google:verbatimrelevance\":9990,"
1787 "\"google:suggestrelevance\":[9998, 9999]}]",
1788 { { "a", true, true },
1789 { "a2.com", false, false },
1790 { "a1.com", false, false },
1791 { "k a", false, false },
1792 kEmptyMatch
, kEmptyMatch
},
1794 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1795 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1796 "\"google:verbatimrelevance\":9990,"
1797 "\"google:suggestrelevance\":[9999, 9998]}]",
1798 { { "a", true, true },
1799 { "a1.com", false, false },
1800 { "a2.com", false, false },
1801 { "k a", false, false },
1802 kEmptyMatch
, kEmptyMatch
},
1804 { "[\"a\",[\"https://a/\"],[],[],"
1805 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1806 "\"google:suggestrelevance\":[9999]}]",
1807 { { "a", true, true },
1808 { "https://a", false, false },
1809 { "k a", false, false },
1810 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1812 // Check when navsuggest scores more than verbatim and there is query
1813 // suggestion but it scores lower.
1814 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1815 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1816 "\"google:verbatimrelevance\":9990,"
1817 "\"google:suggestrelevance\":[9998, 9999, 1300]}]",
1818 { { "a", true, true },
1819 { "a2.com", false, false },
1820 { "a1.com", false, false },
1821 { "a3", true, false },
1822 { "k a", false, false },
1825 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1826 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1827 "\"google:verbatimrelevance\":9990,"
1828 "\"google:suggestrelevance\":[9999, 9998, 1300]}]",
1829 { { "a", true, true },
1830 { "a1.com", false, false },
1831 { "a2.com", false, false },
1832 { "a3", true, false },
1833 { "k a", false, false },
1836 // Check when navsuggest scores more than a query suggestion. There is
1837 // a verbatim but it scores lower.
1838 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1839 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1840 "\"google:verbatimrelevance\":9990,"
1841 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1842 { { "a3", true, true },
1843 { "a2.com", false, false },
1844 { "a1.com", false, false },
1845 { "a", true, true },
1846 { "k a", false, false },
1849 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1850 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1851 "\"google:verbatimrelevance\":9990,"
1852 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1853 { { "a3", true, true },
1854 { "a1.com", false, false },
1855 { "a2.com", false, false },
1856 { "a", true, true },
1857 { "k a", false, false },
1860 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1861 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1862 "\"google:verbatimrelevance\":0,"
1863 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1864 { { "a3", true, true },
1865 { "a2.com", false, false },
1866 { "a1.com", false, false },
1867 { "k a", false, false },
1868 kEmptyMatch
, kEmptyMatch
},
1870 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1871 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1872 "\"google:verbatimrelevance\":0,"
1873 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1874 { { "a3", true, true },
1875 { "a1.com", false, false },
1876 { "a2.com", false, false },
1877 { "k a", false, false },
1878 kEmptyMatch
, kEmptyMatch
},
1880 // Check when there is neither verbatim nor a query suggestion that,
1881 // because we can't demote navsuggestions below a query suggestion,
1882 // we restore the keyword verbatim score.
1883 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1884 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1885 "\"google:verbatimrelevance\":0,"
1886 "\"google:suggestrelevance\":[9998, 9999]}]",
1887 { { "a", true, true },
1888 { "a2.com", false, false },
1889 { "a1.com", false, false },
1890 { "k a", false, false },
1891 kEmptyMatch
, kEmptyMatch
},
1893 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1894 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1895 "\"google:verbatimrelevance\":0,"
1896 "\"google:suggestrelevance\":[9999, 9998]}]",
1897 { { "a", true, true },
1898 { "a1.com", false, false },
1899 { "a2.com", false, false },
1900 { "k a", false, false },
1901 kEmptyMatch
, kEmptyMatch
},
1903 // More checks that everything works when it's not necessary to demote.
1904 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1905 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1906 "\"google:verbatimrelevance\":9990,"
1907 "\"google:suggestrelevance\":[9997, 9998, 9999]}]",
1908 { { "a3", true, true },
1909 { "a2.com", false, false },
1910 { "a1.com", false, false },
1911 { "a", true, true },
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\":[9998, 9997, 9999]}]",
1919 { { "a3", true, true },
1920 { "a1.com", false, false },
1921 { "a2.com", false, false },
1922 { "a", true, true },
1923 { "k a", false, false },
1928 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
1929 // Send the query twice in order to have a synchronous pass after the first
1930 // response is received. This is necessary because SearchProvider doesn't
1931 // allow an asynchronous response to change the default match.
1932 for (size_t j
= 0; j
< 2; ++j
) {
1933 QueryForInput(ASCIIToUTF16("k a"), false, true);
1935 // Set up a default fetcher with no results.
1936 net::TestURLFetcher
* default_fetcher
=
1937 test_factory_
.GetFetcherByID(
1938 SearchProvider::kDefaultProviderURLFetcherID
);
1939 ASSERT_TRUE(default_fetcher
);
1940 default_fetcher
->set_response_code(200);
1941 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
1942 default_fetcher
= NULL
;
1944 // Set up a keyword fetcher with provided results.
1945 net::TestURLFetcher
* keyword_fetcher
=
1946 test_factory_
.GetFetcherByID(
1947 SearchProvider::kKeywordProviderURLFetcherID
);
1948 ASSERT_TRUE(keyword_fetcher
);
1949 keyword_fetcher
->set_response_code(200);
1950 keyword_fetcher
->SetResponseString(cases
[i
].json
);
1951 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
1952 keyword_fetcher
= NULL
;
1953 RunTillProviderDone();
1956 SCOPED_TRACE("for input with json=" + cases
[i
].json
);
1957 const ACMatches
& matches
= provider_
->matches();
1958 ASSERT_FALSE(matches
.empty());
1959 // Find the first match that's allowed to be the default match and check
1960 // its inline_autocompletion.
1961 ACMatches::const_iterator it
= FindDefaultMatch(matches
);
1962 ASSERT_NE(matches
.end(), it
);
1963 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
1964 it
->inline_autocompletion
);
1966 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
1968 // Ensure that the returned matches equal the expectations.
1969 for (; j
< matches
.size(); ++j
) {
1970 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
].contents
),
1971 matches
[j
].contents
);
1972 EXPECT_EQ(cases
[i
].matches
[j
].from_keyword
,
1973 matches
[j
].keyword
== ASCIIToUTF16("k"));
1974 EXPECT_EQ(cases
[i
].matches
[j
].allowed_to_be_default_match
,
1975 matches
[j
].allowed_to_be_default_match
);
1977 // Ensure that no expected matches are missing.
1978 for (; j
< arraysize(cases
[i
].matches
); ++j
) {
1979 SCOPED_TRACE(" Case # " + base::IntToString(i
));
1980 EXPECT_EQ(kNotApplicable
, cases
[i
].matches
[j
].contents
);
1985 TEST_F(SearchProviderTest
, DontInlineAutocompleteAsynchronously
) {
1986 // This test sends two separate queries, each receiving different JSON
1987 // replies, and checks that at each stage of processing (receiving first
1988 // asynchronous response, handling new keystroke synchronously / sending the
1989 // second request, and receiving the second asynchronous response) we have the
1990 // expected matches. In particular, receiving the second response shouldn't
1991 // cause an unexpected inline autcompletion.
1993 const std::string first_json
;
1994 const ExpectedMatch first_async_matches
[4];
1995 const ExpectedMatch sync_matches
[4];
1996 const std::string second_json
;
1997 const ExpectedMatch second_async_matches
[4];
1999 // A simple test that verifies we don't inline autocomplete after the
2000 // first asynchronous response, but we do at the next keystroke if the
2001 // response's results were good enough. Furthermore, we should continue
2002 // inline autocompleting after the second asynchronous response if the new
2003 // top suggestion is the same as the old inline autocompleted suggestion.
2004 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2005 "{\"google:verbatimrelevance\":9000,"
2006 "\"google:suggestrelevance\":[9002, 9001]}]",
2007 { { "a", true }, { "ab1", false }, { "ab2", false },
2008 kEmptyExpectedMatch
},
2009 { { "ab1", true }, { "ab2", true }, { "ab", true },
2010 kEmptyExpectedMatch
},
2011 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2012 "{\"google:verbatimrelevance\":9000,"
2013 "\"google:suggestrelevance\":[9002, 9001]}]",
2014 { { "ab1", true }, { "ab2", false }, { "ab", true },
2015 kEmptyExpectedMatch
} },
2016 // Ditto, just for a navigation suggestion.
2017 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2018 "{\"google:verbatimrelevance\":9000,"
2019 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2020 "\"google:suggestrelevance\":[9002, 9001]}]",
2021 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2022 kEmptyExpectedMatch
},
2023 { { "ab1.com", true }, { "ab2.com", true }, { "ab", true },
2024 kEmptyExpectedMatch
},
2025 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2026 "{\"google:verbatimrelevance\":9000,"
2027 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2028 "\"google:suggestrelevance\":[9002, 9001]}]",
2029 { { "ab1.com", true }, { "ab2.com", false }, { "ab", true },
2030 kEmptyExpectedMatch
} },
2031 // A more realistic test of the same situation.
2032 { "[\"a\",[\"abcdef\", \"abcdef.com\", \"abc\"],[],[],"
2033 "{\"google:verbatimrelevance\":900,"
2034 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"QUERY\"],"
2035 "\"google:suggestrelevance\":[1250, 1200, 1000]}]",
2036 { { "a", true }, { "abcdef", false }, { "abcdef.com", false },
2038 { { "abcdef", true }, { "abcdef.com", true }, { "abc", true },
2040 "[\"ab\",[\"abcdef\", \"abcdef.com\", \"abc\"],[],[],"
2041 "{\"google:verbatimrelevance\":900,"
2042 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"QUERY\"],"
2043 "\"google:suggestrelevance\":[1250, 1200, 1000]}]",
2044 { { "abcdef", true }, { "abcdef.com", false }, { "abc", false },
2047 // Without an original inline autcompletion, a new inline autcompletion
2048 // should be rejected.
2049 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2050 "{\"google:verbatimrelevance\":9000,"
2051 "\"google:suggestrelevance\":[8000, 7000]}]",
2052 { { "a", true }, { "ab1", false }, { "ab2", false },
2053 kEmptyExpectedMatch
},
2054 { { "ab", true }, { "ab1", true }, { "ab2", true },
2055 kEmptyExpectedMatch
},
2056 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2057 "{\"google:verbatimrelevance\":9000,"
2058 "\"google:suggestrelevance\":[9002, 9001]}]",
2059 { { "ab", true }, { "ab1", false }, { "ab2", false },
2060 kEmptyExpectedMatch
} },
2061 // For the same test except with the queries scored in the opposite order
2062 // on the second JSON response, the queries should be ordered by the second
2063 // response's scores, not the first.
2064 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2065 "{\"google:verbatimrelevance\":9000,"
2066 "\"google:suggestrelevance\":[8000, 7000]}]",
2067 { { "a", true }, { "ab1", false }, { "ab2", false },
2068 kEmptyExpectedMatch
},
2069 { { "ab", true }, { "ab1", true }, { "ab2", true },
2070 kEmptyExpectedMatch
},
2071 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2072 "{\"google:verbatimrelevance\":9000,"
2073 "\"google:suggestrelevance\":[9001, 9002]}]",
2074 { { "ab", true }, { "ab2", false }, { "ab1", false },
2075 kEmptyExpectedMatch
} },
2076 // Now, the same verifications but with the new inline autocompletion as a
2077 // navsuggestion. The new autocompletion should still be rejected.
2078 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2079 "{\"google:verbatimrelevance\":9000,"
2080 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2081 "\"google:suggestrelevance\":[8000, 7000]}]",
2082 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2083 kEmptyExpectedMatch
},
2084 { { "ab", true }, { "ab1.com", true }, { "ab2.com", true },
2085 kEmptyExpectedMatch
},
2086 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2087 "{\"google:verbatimrelevance\":9000,"
2088 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2089 "\"google:suggestrelevance\":[9002, 9001]}]",
2090 { { "ab", true }, { "ab1.com", false }, { "ab2.com", false },
2091 kEmptyExpectedMatch
} },
2092 { "[\"a\",[\"ab1.com\", \"ab2.com\"],[],[],"
2093 "{\"google:verbatimrelevance\":9000,"
2094 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2095 "\"google:suggestrelevance\":[8000, 7000]}]",
2096 { { "a", true }, { "ab1.com", false }, { "ab2.com", false },
2097 kEmptyExpectedMatch
},
2098 { { "ab", true }, { "ab1.com", true }, { "ab2.com", true },
2099 kEmptyExpectedMatch
},
2100 "[\"ab\",[\"ab1.com\", \"ab2.com\"],[],[],"
2101 "{\"google:verbatimrelevance\":9000,"
2102 "\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2103 "\"google:suggestrelevance\":[9001, 9002]}]",
2104 { { "ab", true }, { "ab2.com", false }, { "ab1.com", false },
2105 kEmptyExpectedMatch
} },
2107 // It's okay to abandon an inline autocompletion asynchronously.
2108 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2109 "{\"google:verbatimrelevance\":9000,"
2110 "\"google:suggestrelevance\":[9002, 9001]}]",
2111 { { "a", true }, { "ab1", false }, { "ab2", false },
2112 kEmptyExpectedMatch
},
2113 { { "ab1", true }, { "ab2", true }, { "ab", true },
2114 kEmptyExpectedMatch
},
2115 "[\"ab\",[\"ab1\", \"ab2\"],[],[],"
2116 "{\"google:verbatimrelevance\":9000,"
2117 "\"google:suggestrelevance\":[8000, 7000]}]",
2118 { { "ab", true }, { "ab1", true }, { "ab2", false },
2119 kEmptyExpectedMatch
} },
2121 // Note: it's possible that the suggest server returns a suggestion with
2122 // an inline autocompletion (that as usual we delay in allowing it to
2123 // be displayed as an inline autocompletion until the next keystroke),
2124 // then, in response to the next keystroke, the server returns a different
2125 // suggestion as an inline autocompletion. This is not likely to happen.
2126 // Regardless, if it does, one could imagine three different behaviors:
2127 // - keep the original inline autocompletion until the next keystroke
2128 // (i.e., don't abandon an inline autocompletion asynchronously), then
2129 // use the new suggestion
2130 // - abandon all inline autocompletions upon the server response, then use
2131 // the new suggestion on the next keystroke
2132 // - ignore the new inline autocompletion provided by the server, yet
2133 // possibly keep the original if it scores well in the most recent
2134 // response, then use the new suggestion on the next keystroke
2135 // All of these behaviors are reasonable. The main thing we want to
2136 // ensure is that the second asynchronous response shouldn't cause *a new*
2137 // inline autocompletion to be displayed. We test that here.
2138 // The current implementation does the third bullet, but all of these
2139 // behaviors seem reasonable.
2140 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2141 "{\"google:verbatimrelevance\":9000,"
2142 "\"google:suggestrelevance\":[9002, 9001]}]",
2143 { { "a", true }, { "ab1", false }, { "ab2", false },
2144 kEmptyExpectedMatch
},
2145 { { "ab1", true }, { "ab2", true }, { "ab", true },
2146 kEmptyExpectedMatch
},
2147 "[\"ab\",[\"ab1\", \"ab3\"],[],[],"
2148 "{\"google:verbatimrelevance\":9000,"
2149 "\"google:suggestrelevance\":[9002, 9900]}]",
2150 { { "ab1", true }, { "ab3", false }, { "ab", true },
2151 kEmptyExpectedMatch
} },
2152 { "[\"a\",[\"ab1\", \"ab2\"],[],[],"
2153 "{\"google:verbatimrelevance\":9000,"
2154 "\"google:suggestrelevance\":[9002, 9001]}]",
2155 { { "a", true }, { "ab1", false }, { "ab2", false },
2156 kEmptyExpectedMatch
},
2157 { { "ab1", true }, { "ab2", true }, { "ab", true },
2158 kEmptyExpectedMatch
},
2159 "[\"ab\",[\"ab1\", \"ab3\"],[],[],"
2160 "{\"google:verbatimrelevance\":9000,"
2161 "\"google:suggestrelevance\":[8000, 9500]}]",
2162 { { "ab", true }, { "ab3", false }, { "ab1", true },
2163 kEmptyExpectedMatch
} },
2166 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2167 // First, send the query "a" and receive the JSON response |first_json|.
2169 QueryForInputAndWaitForFetcherResponses(
2170 ASCIIToUTF16("a"), false, cases
[i
].first_json
, std::string());
2172 // Verify that the matches after the asynchronous results are as expected.
2173 std::string description
= "first asynchronous response for input with "
2174 "first_json=" + cases
[i
].first_json
;
2175 CheckMatches(description
, arraysize(cases
[i
].first_async_matches
),
2176 cases
[i
].first_async_matches
, provider_
->matches());
2178 // Then, send the query "ab" and check the synchronous matches.
2179 description
= "synchronous response after the first keystroke after input "
2180 "with first_json=" + cases
[i
].first_json
;
2181 QueryForInput(ASCIIToUTF16("ab"), false, false);
2182 CheckMatches(description
, arraysize(cases
[i
].sync_matches
),
2183 cases
[i
].sync_matches
, provider_
->matches());
2185 // Finally, get the provided JSON response, |second_json|, and verify the
2186 // matches after the second asynchronous response are as expected.
2187 description
= "second asynchronous response after input with first_json=" +
2188 cases
[i
].first_json
+ " and second_json=" + cases
[i
].second_json
;
2189 net::TestURLFetcher
* second_fetcher
=
2190 test_factory_
.GetFetcherByID(
2191 SearchProvider::kDefaultProviderURLFetcherID
);
2192 ASSERT_TRUE(second_fetcher
);
2193 second_fetcher
->set_response_code(200);
2194 second_fetcher
->SetResponseString(cases
[i
].second_json
);
2195 second_fetcher
->delegate()->OnURLFetchComplete(second_fetcher
);
2196 RunTillProviderDone();
2197 CheckMatches(description
, arraysize(cases
[i
].second_async_matches
),
2198 cases
[i
].second_async_matches
, provider_
->matches());
2202 TEST_F(SearchProviderTest
, LocalAndRemoteRelevances
) {
2203 // We hardcode the string "term1" below, so ensure that the search term that
2204 // got added to history already is that string.
2205 ASSERT_EQ(ASCIIToUTF16("term1"), term1_
);
2206 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
2208 AddSearchToHistory(default_t_url_
, term
+ ASCIIToUTF16("2"), 2);
2209 profile_
.BlockUntilHistoryProcessesPendingRequests();
2212 const base::string16 input
;
2213 const std::string json
;
2214 const std::string matches
[6];
2216 // The history results outscore the default verbatim score. term2 has more
2217 // visits so it outscores term1. The suggestions are still returned since
2218 // they're server-scored.
2220 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
2221 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
2222 "\"google:suggestrelevance\":[1, 2, 3]}]",
2223 { "term2", "term1", "term", "a3", "a2", "a1" } },
2224 // Because we already have three suggestions by the time we see the history
2225 // results, they don't get returned.
2227 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
2228 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
2229 "\"google:verbatimrelevance\":1450,"
2230 "\"google:suggestrelevance\":[1440, 1430, 1420]}]",
2231 { "term", "a1", "a2", "a3", kNotApplicable
, kNotApplicable
} },
2232 // If we only have two suggestions, we have room for a history result.
2234 "[\"term\",[\"a1\", \"a2\"],[],[],"
2235 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2236 "\"google:verbatimrelevance\":1450,"
2237 "\"google:suggestrelevance\":[1430, 1410]}]",
2238 { "term", "a1", "a2", "term2", kNotApplicable
, kNotApplicable
} },
2239 // If we have more than three suggestions, they should all be returned as
2240 // long as we have enough total space for them.
2242 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
2243 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
2244 "\"google:verbatimrelevance\":1450,"
2245 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410]}]",
2246 { "term", "a1", "a2", "a3", "a4", kNotApplicable
} },
2248 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\", \"a5\", \"a6\"],[],[],"
2249 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\","
2250 "\"QUERY\", \"QUERY\"],"
2251 "\"google:verbatimrelevance\":1450,"
2252 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410, 1400, 1390]}]",
2253 { "term", "a1", "a2", "a3", "a4", "a5" } },
2255 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
2256 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
2257 "\"google:verbatimrelevance\":1450,"
2258 "\"google:suggestrelevance\":[1430, 1410, 1390, 1370]}]",
2259 { "term", "a1", "a2", "term2", "a3", "a4" } }
2262 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2263 QueryForInputAndWaitForFetcherResponses(
2264 cases
[i
].input
, false, cases
[i
].json
, std::string());
2266 const std::string description
= "for input with json=" + cases
[i
].json
;
2267 const ACMatches
& matches
= provider_
->matches();
2269 // Ensure no extra matches are present.
2270 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2273 // Ensure that the returned matches equal the expectations.
2274 for (; j
< matches
.size(); ++j
)
2275 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
]),
2276 matches
[j
].contents
) << description
;
2277 // Ensure that no expected matches are missing.
2278 for (; j
< arraysize(cases
[i
].matches
); ++j
)
2279 EXPECT_EQ(kNotApplicable
, cases
[i
].matches
[j
]) <<
2280 "Case # " << i
<< " " << description
;
2284 // Verifies suggest relevance behavior for URL input.
2285 TEST_F(SearchProviderTest
, DefaultProviderSuggestRelevanceScoringUrlInput
) {
2286 struct DefaultFetcherUrlInputMatch
{
2287 const std::string match_contents
;
2288 AutocompleteMatch::Type match_type
;
2289 bool allowed_to_be_default_match
;
2291 const DefaultFetcherUrlInputMatch kEmptyMatch
=
2292 { kNotApplicable
, AutocompleteMatchType::NUM_TYPES
, false };
2294 const std::string input
;
2295 const std::string json
;
2296 const DefaultFetcherUrlInputMatch output
[4];
2298 // Ensure NAVIGATION matches are allowed to be listed first for URL input.
2299 // Non-inlineable matches should not be allowed to be the default match.
2300 // Note that the top-scoring inlineable match is moved to the top
2301 // regardless of its score.
2302 { "a.com", "[\"a.com\",[\"http://b.com/\"],[],[],"
2303 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2304 "\"google:suggestrelevance\":[9999]}]",
2305 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2306 { "b.com", AutocompleteMatchType::NAVSUGGEST
, false },
2307 kEmptyMatch
, kEmptyMatch
} },
2308 { "a.com", "[\"a.com\",[\"https://b.com\"],[],[],"
2309 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2310 "\"google:suggestrelevance\":[9999]}]",
2311 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2312 { "https://b.com", AutocompleteMatchType::NAVSUGGEST
, false },
2313 kEmptyMatch
, kEmptyMatch
} },
2314 { "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[],"
2315 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2316 "\"google:suggestrelevance\":[9999]}]",
2317 { { "a.com/a", AutocompleteMatchType::NAVSUGGEST
, true },
2318 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2319 kEmptyMatch
, kEmptyMatch
} },
2320 { "a.com", "[\"a.com\",[\"https://a.com\"],[],[],"
2321 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2322 "\"google:suggestrelevance\":[9999]}]",
2323 { { "https://a.com", AutocompleteMatchType::NAVSUGGEST
, true },
2324 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2325 kEmptyMatch
, kEmptyMatch
} },
2327 // Ensure topmost inlineable SUGGEST matches are NOT allowed for URL
2328 // input. SearchProvider disregards search and verbatim suggested
2330 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2331 "{\"google:suggestrelevance\":[9999]}]",
2332 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2333 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2334 kEmptyMatch
, kEmptyMatch
} },
2335 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2336 "{\"google:suggestrelevance\":[9999]}]",
2337 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2338 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2339 kEmptyMatch
, kEmptyMatch
} },
2341 // Ensure the fallback mechanism allows inlineable NAVIGATION matches.
2342 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2343 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2344 "\"google:suggestrelevance\":[9999, 9998]}]",
2345 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST
, true },
2346 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2347 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2349 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2350 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2351 "\"google:suggestrelevance\":[9998, 9997],"
2352 "\"google:verbatimrelevance\":9999}]",
2353 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST
, true },
2354 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2355 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2358 // Ensure non-inlineable SUGGEST matches are allowed for URL input
2359 // assuming the best inlineable match is not a query (i.e., is a
2360 // NAVSUGGEST). The best inlineable match will be at the top of the
2361 // list regardless of its score.
2362 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2363 "{\"google:suggestrelevance\":[9999]}]",
2364 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2365 { "info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2366 kEmptyMatch
, kEmptyMatch
} },
2367 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2368 "{\"google:suggestrelevance\":[9999]}]",
2369 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2370 { "info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2371 kEmptyMatch
, kEmptyMatch
} },
2374 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2375 // Send the query twice in order to have a synchronous pass after the first
2376 // response is received. This is necessary because SearchProvider doesn't
2377 // allow an asynchronous response to change the default match.
2378 for (size_t j
= 0; j
< 2; ++j
) {
2379 QueryForInputAndWaitForFetcherResponses(
2380 ASCIIToUTF16(cases
[i
].input
), false, cases
[i
].json
, std::string());
2383 SCOPED_TRACE("input=" + cases
[i
].input
+ " json=" + cases
[i
].json
);
2385 const ACMatches
& matches
= provider_
->matches();
2386 ASSERT_LE(matches
.size(), arraysize(cases
[i
].output
));
2387 // Ensure that the returned matches equal the expectations.
2388 for (; j
< matches
.size(); ++j
) {
2389 EXPECT_EQ(ASCIIToUTF16(cases
[i
].output
[j
].match_contents
),
2390 matches
[j
].contents
);
2391 EXPECT_EQ(cases
[i
].output
[j
].match_type
, matches
[j
].type
);
2392 EXPECT_EQ(cases
[i
].output
[j
].allowed_to_be_default_match
,
2393 matches
[j
].allowed_to_be_default_match
);
2395 // Ensure that no expected matches are missing.
2396 for (; j
< arraysize(cases
[i
].output
); ++j
) {
2397 EXPECT_EQ(kNotApplicable
, cases
[i
].output
[j
].match_contents
);
2398 EXPECT_EQ(AutocompleteMatchType::NUM_TYPES
,
2399 cases
[i
].output
[j
].match_type
);
2400 EXPECT_FALSE(cases
[i
].output
[j
].allowed_to_be_default_match
);
2405 // A basic test that verifies the field trial triggered parsing logic.
2406 TEST_F(SearchProviderTest
, FieldTrialTriggeredParsing
) {
2407 QueryForInputAndWaitForFetcherResponses(
2408 ASCIIToUTF16("foo"), false,
2409 "[\"foo\",[\"foo bar\"],[\"\"],[],"
2410 "{\"google:suggesttype\":[\"QUERY\"],"
2411 "\"google:fieldtrialtriggered\":true}]",
2415 // Check for the match and field trial triggered bits.
2416 AutocompleteMatch match
;
2417 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("foo bar"), &match
));
2418 ProvidersInfo providers_info
;
2419 provider_
->AddProviderInfo(&providers_info
);
2420 ASSERT_EQ(1U, providers_info
.size());
2421 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_size());
2422 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_in_session_size());
2425 // Reset the session and check that bits are reset.
2426 provider_
->ResetSession();
2427 ProvidersInfo providers_info
;
2428 provider_
->AddProviderInfo(&providers_info
);
2429 ASSERT_EQ(1U, providers_info
.size());
2430 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_size());
2431 EXPECT_EQ(0, providers_info
[0].field_trial_triggered_in_session_size());
2435 // Verifies inline autocompletion of navigational results.
2436 TEST_F(SearchProviderTest
, NavigationInline
) {
2438 const std::string input
;
2439 const std::string url
;
2440 // Test the expected fill_into_edit, which may drop "http://".
2441 // Some cases do not trim "http://" to match from the start of the scheme.
2442 const std::string fill_into_edit
;
2443 const std::string inline_autocompletion
;
2444 const bool allowed_to_be_default_match_in_regular_mode
;
2445 const bool allowed_to_be_default_match_in_prevent_inline_mode
;
2447 // Do not inline matches that do not contain the input; trim http as needed.
2448 { "x", "http://www.abc.com",
2449 "www.abc.com", std::string(), false, false },
2450 { "https:", "http://www.abc.com",
2451 "www.abc.com", std::string(), false, false },
2452 { "http://www.abc.com/a", "http://www.abc.com",
2453 "http://www.abc.com", std::string(), false,
2456 // Do not inline matches with invalid input prefixes; trim http as needed.
2457 { "ttp", "http://www.abc.com",
2458 "www.abc.com", std::string(), false, false },
2459 { "://w", "http://www.abc.com",
2460 "www.abc.com", std::string(), false, false },
2461 { "ww.", "http://www.abc.com",
2462 "www.abc.com", std::string(), false, false },
2463 { ".ab", "http://www.abc.com",
2464 "www.abc.com", std::string(), false, false },
2465 { "bc", "http://www.abc.com",
2466 "www.abc.com", std::string(), false, false },
2467 { ".com", "http://www.abc.com",
2468 "www.abc.com", std::string(), false, false },
2470 // Do not inline matches that omit input domain labels; trim http as needed.
2471 { "www.a", "http://a.com",
2472 "a.com", std::string(), false, false },
2473 { "http://www.a", "http://a.com",
2474 "http://a.com", std::string(), false, false },
2475 { "www.a", "ftp://a.com",
2476 "ftp://a.com", std::string(), false, false },
2477 { "ftp://www.a", "ftp://a.com",
2478 "ftp://a.com", std::string(), false, false },
2480 // Input matching but with nothing to inline will not yield an offset, but
2481 // will be allowed to be default.
2482 { "abc.com", "http://www.abc.com",
2483 "www.abc.com", std::string(), true, true },
2484 { "abc.com/", "http://www.abc.com",
2485 "www.abc.com", std::string(), true, true },
2486 { "http://www.abc.com", "http://www.abc.com",
2487 "http://www.abc.com", std::string(), true, true },
2488 { "http://www.abc.com/", "http://www.abc.com",
2489 "http://www.abc.com", std::string(), true, true },
2491 // Inputs with trailing whitespace should inline when possible.
2492 { "abc.com ", "http://www.abc.com",
2493 "www.abc.com", std::string(), true, true },
2494 { "abc.com/ ", "http://www.abc.com",
2495 "www.abc.com", std::string(), true, true },
2496 { "abc.com ", "http://www.abc.com/bar",
2497 "www.abc.com/bar", "/bar", false, false },
2499 // A suggestion that's equivalent to what the input gets fixed up to
2500 // should be inlined.
2501 { "abc.com:", "http://abc.com/",
2502 "abc.com", std::string(), true, true },
2503 { "abc.com:", "http://www.abc.com",
2504 "www.abc.com", std::string(), true, true },
2506 // Inline matches when the input is a leading substring of the scheme.
2507 { "h", "http://www.abc.com",
2508 "http://www.abc.com", "ttp://www.abc.com", true, false },
2509 { "http", "http://www.abc.com",
2510 "http://www.abc.com", "://www.abc.com", true, false },
2512 // Inline matches when the input is a leading substring of the full URL.
2513 { "http:", "http://www.abc.com",
2514 "http://www.abc.com", "//www.abc.com", true, false },
2515 { "http://w", "http://www.abc.com",
2516 "http://www.abc.com", "ww.abc.com", true, false },
2517 { "http://www.", "http://www.abc.com",
2518 "http://www.abc.com", "abc.com", true, false },
2519 { "http://www.ab", "http://www.abc.com",
2520 "http://www.abc.com", "c.com", true, false },
2521 { "http://www.abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2522 "http://www.abc.com/path/file.htm?q=x#foo",
2523 "ath/file.htm?q=x#foo",
2525 { "http://abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2526 "http://abc.com/path/file.htm?q=x#foo",
2527 "ath/file.htm?q=x#foo",
2530 // Inline matches with valid URLPrefixes; only trim "http://".
2531 { "w", "http://www.abc.com",
2532 "www.abc.com", "ww.abc.com", true, false },
2533 { "www.a", "http://www.abc.com",
2534 "www.abc.com", "bc.com", true, false },
2535 { "abc", "http://www.abc.com",
2536 "www.abc.com", ".com", true, false },
2537 { "abc.c", "http://www.abc.com",
2538 "www.abc.com", "om", true, false },
2539 { "abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2540 "www.abc.com/path/file.htm?q=x#foo",
2541 "ath/file.htm?q=x#foo",
2543 { "abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2544 "abc.com/path/file.htm?q=x#foo",
2545 "ath/file.htm?q=x#foo",
2548 // Inline matches using the maximal URLPrefix components.
2549 { "h", "http://help.com",
2550 "help.com", "elp.com", true, false },
2551 { "http", "http://http.com",
2552 "http.com", ".com", true, false },
2553 { "h", "http://www.help.com",
2554 "www.help.com", "elp.com", true, false },
2555 { "http", "http://www.http.com",
2556 "www.http.com", ".com", true, false },
2557 { "w", "http://www.www.com",
2558 "www.www.com", "ww.com", true, false },
2560 // Test similar behavior for the ftp and https schemes.
2561 { "ftp://www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2562 "ftp://www.abc.com/path/file.htm?q=x#foo",
2563 "c.com/path/file.htm?q=x#foo", true, false },
2564 { "www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2565 "ftp://www.abc.com/path/file.htm?q=x#foo",
2566 "c.com/path/file.htm?q=x#foo", true, false },
2567 { "ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2568 "ftp://www.abc.com/path/file.htm?q=x#foo",
2569 "c.com/path/file.htm?q=x#foo", true, false },
2570 { "ab", "ftp://abc.com/path/file.htm?q=x#foo",
2571 "ftp://abc.com/path/file.htm?q=x#foo",
2572 "c.com/path/file.htm?q=x#foo", true, false },
2573 { "https://www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2574 "https://www.abc.com/path/file.htm?q=x#foo",
2575 "c.com/path/file.htm?q=x#foo",
2577 { "www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2578 "https://www.abc.com/path/file.htm?q=x#foo",
2579 "c.com/path/file.htm?q=x#foo", true, false },
2580 { "ab", "https://www.abc.com/path/file.htm?q=x#foo",
2581 "https://www.abc.com/path/file.htm?q=x#foo",
2582 "c.com/path/file.htm?q=x#foo", true, false },
2583 { "ab", "https://abc.com/path/file.htm?q=x#foo",
2584 "https://abc.com/path/file.htm?q=x#foo",
2585 "c.com/path/file.htm?q=x#foo", true, false },
2587 // Forced query input should inline and retain the "?" prefix.
2588 { "?http://www.ab", "http://www.abc.com",
2589 "?http://www.abc.com", "c.com", true, false },
2590 { "?www.ab", "http://www.abc.com",
2591 "?www.abc.com", "c.com", true, false },
2592 { "?ab", "http://www.abc.com",
2593 "?www.abc.com", "c.com", true, false },
2594 { "?abc.com", "http://www.abc.com",
2595 "?www.abc.com", std::string(), true, true },
2598 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2599 // First test regular mode.
2600 QueryForInput(ASCIIToUTF16(cases
[i
].input
), false, false);
2601 SearchSuggestionParser::NavigationResult
result(
2602 ChromeAutocompleteSchemeClassifier(&profile_
), GURL(cases
[i
].url
),
2603 AutocompleteMatchType::NAVSUGGEST
, base::string16(), std::string(),
2604 false, 0, false, ASCIIToUTF16(cases
[i
].input
), std::string());
2605 result
.set_received_after_last_keystroke(false);
2606 AutocompleteMatch
match(provider_
->NavigationToMatch(result
));
2607 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
2608 match
.inline_autocompletion
);
2609 EXPECT_EQ(ASCIIToUTF16(cases
[i
].fill_into_edit
), match
.fill_into_edit
);
2610 EXPECT_EQ(cases
[i
].allowed_to_be_default_match_in_regular_mode
,
2611 match
.allowed_to_be_default_match
);
2613 // Then test prevent-inline-autocomplete mode.
2614 QueryForInput(ASCIIToUTF16(cases
[i
].input
), true, false);
2615 SearchSuggestionParser::NavigationResult
result_prevent_inline(
2616 ChromeAutocompleteSchemeClassifier(&profile_
), GURL(cases
[i
].url
),
2617 AutocompleteMatchType::NAVSUGGEST
, base::string16(), std::string(),
2618 false, 0, false, ASCIIToUTF16(cases
[i
].input
), std::string());
2619 result_prevent_inline
.set_received_after_last_keystroke(false);
2620 AutocompleteMatch
match_prevent_inline(
2621 provider_
->NavigationToMatch(result_prevent_inline
));
2622 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
2623 match_prevent_inline
.inline_autocompletion
);
2624 EXPECT_EQ(ASCIIToUTF16(cases
[i
].fill_into_edit
),
2625 match_prevent_inline
.fill_into_edit
);
2626 EXPECT_EQ(cases
[i
].allowed_to_be_default_match_in_prevent_inline_mode
,
2627 match_prevent_inline
.allowed_to_be_default_match
);
2631 // Verifies that "http://" is not trimmed for input that is a leading substring.
2632 TEST_F(SearchProviderTest
, NavigationInlineSchemeSubstring
) {
2633 const base::string16
input(ASCIIToUTF16("ht"));
2634 const base::string16
url(ASCIIToUTF16("http://a.com"));
2635 SearchSuggestionParser::NavigationResult
result(
2636 ChromeAutocompleteSchemeClassifier(&profile_
), GURL(url
),
2637 AutocompleteMatchType::NAVSUGGEST
,
2638 base::string16(), std::string(), false, 0, false, input
, std::string());
2639 result
.set_received_after_last_keystroke(false);
2641 // Check the offset and strings when inline autocompletion is allowed.
2642 QueryForInput(input
, false, false);
2643 AutocompleteMatch
match_inline(provider_
->NavigationToMatch(result
));
2644 EXPECT_EQ(url
, match_inline
.fill_into_edit
);
2645 EXPECT_EQ(url
.substr(2), match_inline
.inline_autocompletion
);
2646 EXPECT_TRUE(match_inline
.allowed_to_be_default_match
);
2647 EXPECT_EQ(url
, match_inline
.contents
);
2649 // Check the same strings when inline autocompletion is prevented.
2650 QueryForInput(input
, true, false);
2651 AutocompleteMatch
match_prevent(provider_
->NavigationToMatch(result
));
2652 EXPECT_EQ(url
, match_prevent
.fill_into_edit
);
2653 EXPECT_FALSE(match_prevent
.allowed_to_be_default_match
);
2654 EXPECT_EQ(url
, match_prevent
.contents
);
2657 // Verifies that input "w" marks a more significant domain label than "www.".
2658 TEST_F(SearchProviderTest
, NavigationInlineDomainClassify
) {
2659 QueryForInput(ASCIIToUTF16("w"), false, false);
2660 SearchSuggestionParser::NavigationResult
result(
2661 ChromeAutocompleteSchemeClassifier(&profile_
),
2662 GURL("http://www.wow.com"), AutocompleteMatchType::NAVSUGGEST
,
2663 base::string16(), std::string(), false, 0, false, ASCIIToUTF16("w"),
2665 result
.set_received_after_last_keystroke(false);
2666 AutocompleteMatch
match(provider_
->NavigationToMatch(result
));
2667 EXPECT_EQ(ASCIIToUTF16("ow.com"), match
.inline_autocompletion
);
2668 EXPECT_TRUE(match
.allowed_to_be_default_match
);
2669 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match
.fill_into_edit
);
2670 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match
.contents
);
2672 // Ensure that the match for input "w" is marked on "wow" and not "www".
2673 ASSERT_EQ(3U, match
.contents_class
.size());
2674 EXPECT_EQ(0U, match
.contents_class
[0].offset
);
2675 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
,
2676 match
.contents_class
[0].style
);
2677 EXPECT_EQ(4U, match
.contents_class
[1].offset
);
2678 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
|
2679 AutocompleteMatch::ACMatchClassification::MATCH
,
2680 match
.contents_class
[1].style
);
2681 EXPECT_EQ(5U, match
.contents_class
[2].offset
);
2682 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
,
2683 match
.contents_class
[2].style
);
2686 #if !defined(OS_WIN)
2687 // Verify entity suggestion parsing.
2688 TEST_F(SearchProviderTest
, ParseEntitySuggestion
) {
2690 std::string contents
;
2691 std::string description
;
2692 std::string query_params
;
2693 std::string fill_into_edit
;
2694 AutocompleteMatchType::Type type
;
2696 const Match kEmptyMatch
= {
2697 kNotApplicable
, kNotApplicable
, kNotApplicable
, kNotApplicable
,
2698 AutocompleteMatchType::NUM_TYPES
};
2701 const std::string input_text
;
2702 const std::string response_json
;
2703 const Match matches
[5];
2705 // A query and an entity suggestion with different search terms.
2707 "[\"x\",[\"xy\", \"yy\"],[\"\",\"\"],[],"
2708 " {\"google:suggestdetail\":[{},"
2709 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2710 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2711 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
2712 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST
},
2713 { "xy", "A", "p=v", "yy",
2714 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY
},
2719 // A query and an entity suggestion with same search terms.
2721 "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
2722 " {\"google:suggestdetail\":[{},"
2723 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2724 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2725 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
2726 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST
},
2727 { "xy", "A", "p=v", "xy",
2728 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY
},
2734 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2735 QueryForInputAndWaitForFetcherResponses(
2736 ASCIIToUTF16(cases
[i
].input_text
), false, cases
[i
].response_json
,
2739 const ACMatches
& matches
= provider_
->matches();
2740 ASSERT_FALSE(matches
.empty());
2742 SCOPED_TRACE("for input with json = " + cases
[i
].response_json
);
2744 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2746 // Ensure that the returned matches equal the expectations.
2747 for (; j
< matches
.size(); ++j
) {
2748 const Match
& match
= cases
[i
].matches
[j
];
2749 SCOPED_TRACE(" and match index: " + base::IntToString(j
));
2750 EXPECT_EQ(match
.contents
,
2751 base::UTF16ToUTF8(matches
[j
].contents
));
2752 EXPECT_EQ(match
.description
,
2753 base::UTF16ToUTF8(matches
[j
].description
));
2754 EXPECT_EQ(match
.query_params
,
2755 matches
[j
].search_terms_args
->suggest_query_params
);
2756 EXPECT_EQ(match
.fill_into_edit
,
2757 base::UTF16ToUTF8(matches
[j
].fill_into_edit
));
2758 EXPECT_EQ(match
.type
, matches
[j
].type
);
2760 // Ensure that no expected matches are missing.
2761 for (; j
< arraysize(cases
[i
].matches
); ++j
) {
2762 SCOPED_TRACE(" and match index: " + base::IntToString(j
));
2763 EXPECT_EQ(cases
[i
].matches
[j
].contents
, kNotApplicable
);
2764 EXPECT_EQ(cases
[i
].matches
[j
].description
, kNotApplicable
);
2765 EXPECT_EQ(cases
[i
].matches
[j
].query_params
, kNotApplicable
);
2766 EXPECT_EQ(cases
[i
].matches
[j
].fill_into_edit
, kNotApplicable
);
2767 EXPECT_EQ(cases
[i
].matches
[j
].type
, AutocompleteMatchType::NUM_TYPES
);
2771 #endif // !defined(OS_WIN)
2774 // A basic test that verifies the prefetch metadata parsing logic.
2775 TEST_F(SearchProviderTest
, PrefetchMetadataParsing
) {
2777 std::string contents
;
2778 bool allowed_to_be_prefetched
;
2779 AutocompleteMatchType::Type type
;
2782 const Match kEmptyMatch
= { kNotApplicable
,
2784 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
2788 const std::string input_text
;
2789 bool prefer_keyword_provider_results
;
2790 const std::string default_provider_response_json
;
2791 const std::string keyword_provider_response_json
;
2792 const Match matches
[5];
2794 // Default provider response does not have prefetch details. Ensure that the
2795 // suggestions are not marked as prefetch query.
2798 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2800 { { "a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2801 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2802 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2807 // Ensure that default provider suggest response prefetch details are
2808 // parsed and recorded in AutocompleteMatch.
2811 "[\"ab\",[\"abc\", \"http://b.com\", \"http://c.com\"],[],[],"
2812 "{\"google:clientdata\":{\"phi\": 0},"
2813 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"NAVIGATION\"],"
2814 "\"google:suggestrelevance\":[999, 12, 1]}]",
2816 { { "ab", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2817 { "abc", true, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2818 { "b.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
2819 { "c.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
2823 // Default provider suggest response has prefetch details.
2824 // SEARCH_WHAT_YOU_TYPE suggestion outranks SEARCH_SUGGEST suggestion for
2825 // the same query string. Ensure that the prefetch details from
2826 // SEARCH_SUGGEST match are set onto SEARCH_WHAT_YOU_TYPE match.
2829 "[\"ab\",[\"ab\", \"http://ab.com\"],[],[],"
2830 "{\"google:clientdata\":{\"phi\": 0},"
2831 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2832 "\"google:suggestrelevance\":[99, 98]}]",
2834 { {"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2835 {"ab.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
2841 // Default provider response has prefetch details. We prefer keyword
2842 // provider results. Ensure that prefetch bit for a suggestion from the
2843 // default search provider does not get copied onto a higher-scoring match
2844 // for the same query string from the keyword provider.
2847 "[\"k a\",[\"a\", \"ab\"],[],[], {\"google:clientdata\":{\"phi\": 0},"
2848 "\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2849 "\"google:suggestrelevance\":[9, 12]}]",
2850 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2851 { { "a", false, AutocompleteMatchType::SEARCH_OTHER_ENGINE
, true},
2852 { "k a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
2853 { "ab", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
2854 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST
, true },
2855 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST
, true }
2860 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2861 QueryForInputAndWaitForFetcherResponses(
2862 ASCIIToUTF16(cases
[i
].input_text
),
2863 cases
[i
].prefer_keyword_provider_results
,
2864 cases
[i
].default_provider_response_json
,
2865 cases
[i
].prefer_keyword_provider_results
?
2866 cases
[i
].keyword_provider_response_json
: std::string());
2868 const std::string description
=
2869 "for input with json =" + cases
[i
].default_provider_response_json
;
2870 const ACMatches
& matches
= provider_
->matches();
2871 // The top match must inline and score as highly as calculated verbatim.
2872 ASSERT_FALSE(matches
.empty());
2873 EXPECT_GE(matches
[0].relevance
, 1300);
2875 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2876 // Ensure that the returned matches equal the expectations.
2877 for (size_t j
= 0; j
< matches
.size(); ++j
) {
2878 SCOPED_TRACE(description
);
2879 EXPECT_EQ(cases
[i
].matches
[j
].contents
,
2880 base::UTF16ToUTF8(matches
[j
].contents
));
2881 EXPECT_EQ(cases
[i
].matches
[j
].allowed_to_be_prefetched
,
2882 SearchProvider::ShouldPrefetch(matches
[j
]));
2883 EXPECT_EQ(cases
[i
].matches
[j
].type
, matches
[j
].type
);
2884 EXPECT_EQ(cases
[i
].matches
[j
].from_keyword
,
2885 matches
[j
].keyword
== ASCIIToUTF16("k"));
2890 TEST_F(SearchProviderTest
, XSSIGuardedJSONParsing_InvalidResponse
) {
2893 std::string
input_str("abc");
2894 QueryForInputAndWaitForFetcherResponses(
2895 ASCIIToUTF16(input_str
), false, "this is a bad non-json response",
2898 const ACMatches
& matches
= provider_
->matches();
2900 // Should have exactly one "search what you typed" match
2901 ASSERT_TRUE(matches
.size() == 1);
2902 EXPECT_EQ(input_str
, base::UTF16ToUTF8(matches
[0].contents
));
2903 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
2907 // A basic test that verifies that the XSSI guarded JSON response is parsed
2909 TEST_F(SearchProviderTest
, XSSIGuardedJSONParsing_ValidResponses
) {
2911 std::string contents
;
2912 AutocompleteMatchType::Type type
;
2914 const Match kEmptyMatch
= {
2915 kNotApplicable
, AutocompleteMatchType::NUM_TYPES
2919 const std::string input_text
;
2920 const std::string default_provider_response_json
;
2921 const Match matches
[4];
2925 "[\"a\",[\"b\", \"c\"],[],[],"
2926 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2927 "\"google:suggestrelevance\":[1, 2]}]",
2928 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
2929 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
2930 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
2934 // Standard XSSI guard - )]}'\n.
2936 ")]}'\n[\"a\",[\"b\", \"c\"],[],[],"
2937 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2938 "\"google:suggestrelevance\":[1, 2]}]",
2939 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
2940 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
2941 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
2945 // Modified XSSI guard - contains "[".
2947 ")]}'\n[)\"[\"a\",[\"b\", \"c\"],[],[],"
2948 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2949 "\"google:suggestrelevance\":[1, 2]}]",
2950 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
2951 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
2952 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
2958 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
2960 QueryForInputAndWaitForFetcherResponses(
2961 ASCIIToUTF16(cases
[i
].input_text
), false,
2962 cases
[i
].default_provider_response_json
, std::string());
2964 const ACMatches
& matches
= provider_
->matches();
2965 // The top match must inline and score as highly as calculated verbatim.
2966 ASSERT_FALSE(matches
.empty());
2967 EXPECT_GE(matches
[0].relevance
, 1300);
2969 SCOPED_TRACE("for case: " + base::IntToString(i
));
2970 ASSERT_LE(matches
.size(), arraysize(cases
[i
].matches
));
2972 // Ensure that the returned matches equal the expectations.
2973 for (; j
< matches
.size(); ++j
) {
2974 SCOPED_TRACE("and match: " + base::IntToString(j
));
2975 EXPECT_EQ(cases
[i
].matches
[j
].contents
,
2976 base::UTF16ToUTF8(matches
[j
].contents
));
2977 EXPECT_EQ(cases
[i
].matches
[j
].type
, matches
[j
].type
);
2979 for (; j
< arraysize(cases
[i
].matches
); ++j
) {
2980 SCOPED_TRACE("and match: " + base::IntToString(j
));
2981 EXPECT_EQ(cases
[i
].matches
[j
].contents
, kNotApplicable
);
2982 EXPECT_EQ(cases
[i
].matches
[j
].type
, AutocompleteMatchType::NUM_TYPES
);
2987 // Test that deletion url gets set on an AutocompleteMatch when available for a
2988 // personalized query or a personalized URL.
2989 TEST_F(SearchProviderTest
, ParseDeletionUrl
) {
2991 std::string contents
;
2992 std::string deletion_url
;
2993 AutocompleteMatchType::Type type
;
2996 const Match kEmptyMatch
= {
2997 kNotApplicable
, std::string(), AutocompleteMatchType::NUM_TYPES
3000 const char* url
[] = {
3001 "http://defaultturl/complete/deleteitems"
3002 "?delq=ab&client=chrome&deltok=xsrf124",
3003 "http://defaultturl/complete/deleteitems"
3004 "?delq=www.amazon.com&client=chrome&deltok=xsrf123",
3008 const std::string input_text
;
3009 const std::string response_json
;
3010 const Match matches
[5];
3012 // A deletion URL on a personalized query should be reflected in the
3013 // resulting AutocompleteMatch.
3015 "[\"a\",[\"ab\", \"ac\",\"www.amazon.com\"],[],[],"
3016 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3017 "\"PERSONALIZED_NAVIGATION\"],"
3018 "\"google:suggestrelevance\":[3, 2, 1],"
3019 "\"google:suggestdetail\":[{\"du\":"
3020 "\"/complete/deleteitems?delq=ab&client=chrome"
3021 "&deltok=xsrf124\"}, {}, {\"du\":"
3022 "\"/complete/deleteitems?delq=www.amazon.com&"
3023 "client=chrome&deltok=xsrf123\"}]}]",
3024 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3025 { "ab", url
[0], AutocompleteMatchType::SEARCH_SUGGEST
},
3026 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3027 { "www.amazon.com", url
[1],
3028 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED
},
3032 // Personalized queries or a personalized URL without deletion URLs
3033 // shouldn't cause errors.
3035 "[\"a\",[\"ab\", \"ac\"],[],[],"
3036 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3037 "\"PERSONALIZED_NAVIGATION\"],"
3038 "\"google:suggestrelevance\":[1, 2],"
3039 "\"google:suggestdetail\":[{}, {}]}]",
3040 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3041 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3042 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3043 { "www.amazon.com", "",
3044 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED
},
3048 // Personalized queries or a personalized URL without
3049 // google:suggestdetail shouldn't cause errors.
3051 "[\"a\",[\"ab\", \"ac\"],[],[],"
3052 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
3053 "\"PERSONALIZED_NAVIGATION\"],"
3054 "\"google:suggestrelevance\":[1, 2]}]",
3055 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3056 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3057 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3058 { "www.amazon.com", "",
3059 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED
},
3065 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
3066 QueryForInputAndWaitForFetcherResponses(
3067 ASCIIToUTF16(cases
[i
].input_text
), false, cases
[i
].response_json
,
3070 const ACMatches
& matches
= provider_
->matches();
3071 ASSERT_FALSE(matches
.empty());
3073 SCOPED_TRACE("for input with json = " + cases
[i
].response_json
);
3075 for (size_t j
= 0; j
< matches
.size(); ++j
) {
3076 const Match
& match
= cases
[i
].matches
[j
];
3077 SCOPED_TRACE(" and match index: " + base::IntToString(j
));
3078 EXPECT_EQ(match
.contents
, base::UTF16ToUTF8(matches
[j
].contents
));
3079 EXPECT_EQ(match
.deletion_url
, matches
[j
].GetAdditionalInfo(
3085 TEST_F(SearchProviderTest
, ReflectsBookmarkBarState
) {
3086 profile_
.GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar
, false);
3087 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
3088 QueryForInput(term
, true, false);
3089 ASSERT_FALSE(provider_
->matches().empty());
3090 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
3091 provider_
->matches()[0].type
);
3092 ASSERT_TRUE(provider_
->matches()[0].search_terms_args
!= NULL
);
3093 EXPECT_FALSE(provider_
->matches()[0].search_terms_args
->bookmark_bar_pinned
);
3095 profile_
.GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar
, true);
3096 term
= term1_
.substr(0, term1_
.length() - 1);
3097 QueryForInput(term
, true, false);
3098 ASSERT_FALSE(provider_
->matches().empty());
3099 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
3100 provider_
->matches()[0].type
);
3101 ASSERT_TRUE(provider_
->matches()[0].search_terms_args
!= NULL
);
3102 EXPECT_TRUE(provider_
->matches()[0].search_terms_args
->bookmark_bar_pinned
);
3105 TEST_F(SearchProviderTest
, CanSendURL
) {
3106 TemplateURLData template_url_data
;
3107 template_url_data
.short_name
= ASCIIToUTF16("t");
3108 template_url_data
.SetURL("http://www.google.com/{searchTerms}");
3109 template_url_data
.suggestions_url
= "http://www.google.com/{searchTerms}";
3110 template_url_data
.instant_url
= "http://does/not/exist?strk=1";
3111 template_url_data
.search_terms_replacement_key
= "strk";
3112 template_url_data
.id
= SEARCH_ENGINE_GOOGLE
;
3113 TemplateURL
google_template_url(template_url_data
);
3115 // Create field trial.
3116 CreateZeroSuggestFieldTrial(true);
3118 ChromeAutocompleteProviderClient
client(&profile_
);
3121 EXPECT_FALSE(SearchProvider::CanSendURL(
3122 GURL("http://www.google.com/search"),
3123 GURL("https://www.google.com/complete/search"), &google_template_url
,
3124 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3125 SigninManagerBase
* signin
= SigninManagerFactory::GetForProfile(&profile_
);
3126 signin
->SetAuthenticatedUsername("test");
3128 // All conditions should be met.
3129 EXPECT_TRUE(SearchProvider::CanSendURL(
3130 GURL("http://www.google.com/search"),
3131 GURL("https://www.google.com/complete/search"), &google_template_url
,
3132 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3134 // Not in field trial.
3135 ResetFieldTrialList();
3136 CreateZeroSuggestFieldTrial(false);
3137 EXPECT_FALSE(SearchProvider::CanSendURL(
3138 GURL("http://www.google.com/search"),
3139 GURL("https://www.google.com/complete/search"), &google_template_url
,
3140 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3141 ResetFieldTrialList();
3142 CreateZeroSuggestFieldTrial(true);
3144 // Invalid page URL.
3145 EXPECT_FALSE(SearchProvider::CanSendURL(
3147 GURL("https://www.google.com/complete/search"), &google_template_url
,
3148 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3150 // Invalid page classification.
3151 EXPECT_FALSE(SearchProvider::CanSendURL(
3152 GURL("http://www.google.com/search"),
3153 GURL("https://www.google.com/complete/search"), &google_template_url
,
3154 metrics::OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS
,
3155 SearchTermsData(), &client
));
3157 // Invalid page classification.
3158 EXPECT_FALSE(SearchProvider::CanSendURL(
3159 GURL("http://www.google.com/search"),
3160 GURL("https://www.google.com/complete/search"), &google_template_url
,
3161 metrics::OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS
,
3162 SearchTermsData(), &client
));
3164 // HTTPS page URL on same domain as provider.
3165 EXPECT_TRUE(SearchProvider::CanSendURL(
3166 GURL("https://www.google.com/search"),
3167 GURL("https://www.google.com/complete/search"),
3168 &google_template_url
, metrics::OmniboxEventProto::OTHER
,
3169 SearchTermsData(), &client
));
3171 // Non-HTTP[S] page URL on same domain as provider.
3172 EXPECT_FALSE(SearchProvider::CanSendURL(
3173 GURL("ftp://www.google.com/search"),
3174 GURL("https://www.google.com/complete/search"), &google_template_url
,
3175 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3177 // Non-HTTP page URL on different domain.
3178 EXPECT_FALSE(SearchProvider::CanSendURL(
3179 GURL("https://www.notgoogle.com/search"),
3180 GURL("https://www.google.com/complete/search"), &google_template_url
,
3181 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3183 // Non-HTTPS provider.
3184 EXPECT_FALSE(SearchProvider::CanSendURL(
3185 GURL("http://www.google.com/search"),
3186 GURL("http://www.google.com/complete/search"), &google_template_url
,
3187 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3189 // Suggest disabled.
3190 profile_
.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled
, false);
3191 EXPECT_FALSE(SearchProvider::CanSendURL(
3192 GURL("http://www.google.com/search"),
3193 GURL("https://www.google.com/complete/search"), &google_template_url
,
3194 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3195 profile_
.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled
, true);
3198 ChromeAutocompleteProviderClient
client_incognito(
3199 profile_
.GetOffTheRecordProfile());
3200 EXPECT_FALSE(SearchProvider::CanSendURL(
3201 GURL("http://www.google.com/search"),
3202 GURL("https://www.google.com/complete/search"), &google_template_url
,
3203 metrics::OmniboxEventProto::OTHER
, SearchTermsData(),
3204 &client_incognito
));
3206 // Tab sync not enabled.
3207 profile_
.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncKeepEverythingSynced
,
3209 profile_
.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs
, false);
3210 EXPECT_FALSE(SearchProvider::CanSendURL(
3211 GURL("http://www.google.com/search"),
3212 GURL("https://www.google.com/complete/search"), &google_template_url
,
3213 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3214 profile_
.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs
, true);
3216 // Tab sync is encrypted.
3217 ProfileSyncService
* service
=
3218 ProfileSyncServiceFactory::GetInstance()->GetForProfile(&profile_
);
3219 syncer::ModelTypeSet encrypted_types
= service
->GetEncryptedDataTypes();
3220 encrypted_types
.Put(syncer::SESSIONS
);
3221 service
->OnEncryptedTypesChanged(encrypted_types
, false);
3222 EXPECT_FALSE(SearchProvider::CanSendURL(
3223 GURL("http://www.google.com/search"),
3224 GURL("https://www.google.com/complete/search"), &google_template_url
,
3225 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3226 encrypted_types
.Remove(syncer::SESSIONS
);
3227 service
->OnEncryptedTypesChanged(encrypted_types
, false);
3229 // Check that there were no side effects from previous tests.
3230 EXPECT_TRUE(SearchProvider::CanSendURL(
3231 GURL("http://www.google.com/search"),
3232 GURL("https://www.google.com/complete/search"), &google_template_url
,
3233 metrics::OmniboxEventProto::OTHER
, SearchTermsData(), &client
));
3236 TEST_F(SearchProviderTest
, TestDeleteMatch
) {
3237 AutocompleteMatch
match(
3238 provider_
.get(), 0, true, AutocompleteMatchType::SEARCH_SUGGEST
);
3239 match
.RecordAdditionalInfo(
3240 SearchProvider::kDeletionUrlKey
,
3241 "https://www.google.com/complete/deleteitem?q=foo");
3243 // Test a successful deletion request.
3244 provider_
->matches_
.push_back(match
);
3245 provider_
->DeleteMatch(match
);
3246 EXPECT_FALSE(provider_
->deletion_handlers_
.empty());
3247 EXPECT_TRUE(provider_
->matches_
.empty());
3248 // Set up a default fetcher with provided results.
3249 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
3250 SearchProvider::kDeletionURLFetcherID
);
3251 ASSERT_TRUE(fetcher
);
3252 fetcher
->set_response_code(200);
3253 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3254 EXPECT_TRUE(provider_
->deletion_handlers_
.empty());
3255 EXPECT_TRUE(provider_
->is_success());
3257 // Test a failing deletion request.
3258 provider_
->matches_
.push_back(match
);
3259 provider_
->DeleteMatch(match
);
3260 EXPECT_FALSE(provider_
->deletion_handlers_
.empty());
3261 // Set up a default fetcher with provided results.
3262 fetcher
= test_factory_
.GetFetcherByID(
3263 SearchProvider::kDeletionURLFetcherID
);
3264 ASSERT_TRUE(fetcher
);
3265 fetcher
->set_response_code(500);
3266 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3267 EXPECT_TRUE(provider_
->deletion_handlers_
.empty());
3268 EXPECT_FALSE(provider_
->is_success());
3271 TEST_F(SearchProviderTest
, TestDeleteHistoryQueryMatch
) {
3273 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("flash games"), 1));
3274 profile_
.BlockUntilHistoryProcessesPendingRequests();
3276 AutocompleteMatch games
;
3277 QueryForInput(ASCIIToUTF16("fla"), false, false);
3278 profile_
.BlockUntilHistoryProcessesPendingRequests();
3279 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3280 ASSERT_TRUE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games
));
3282 size_t matches_before
= provider_
->matches().size();
3283 provider_
->DeleteMatch(games
);
3284 EXPECT_EQ(matches_before
- 1, provider_
->matches().size());
3286 // Process history deletions.
3287 profile_
.BlockUntilHistoryProcessesPendingRequests();
3289 // Check that the match is gone.
3290 QueryForInput(ASCIIToUTF16("fla"), false, false);
3291 profile_
.BlockUntilHistoryProcessesPendingRequests();
3292 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3293 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games
));
3296 // Verifies that duplicates are preserved in AddMatchToMap().
3297 TEST_F(SearchProviderTest
, CheckDuplicateMatchesSaved
) {
3298 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("a"), 1);
3299 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("alpha"), 1);
3300 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("avid"), 1);
3302 profile_
.BlockUntilHistoryProcessesPendingRequests();
3303 QueryForInputAndWaitForFetcherResponses(
3304 ASCIIToUTF16("a"), false,
3305 "[\"a\",[\"a\", \"alpha\", \"avid\", \"apricot\"],[],[],"
3306 "{\"google:suggestrelevance\":[1450, 1200, 1150, 1100],"
3307 "\"google:verbatimrelevance\":1350}]",
3310 AutocompleteMatch verbatim
, match_alpha
, match_apricot
, match_avid
;
3311 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim
));
3312 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("alpha"), &match_alpha
));
3313 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("apricot"), &match_apricot
));
3314 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("avid"), &match_avid
));
3316 // Verbatim match duplicates are added such that each one has a higher
3317 // relevance than the previous one.
3318 EXPECT_EQ(2U, verbatim
.duplicate_matches
.size());
3320 // Other match duplicates are added in descending relevance order.
3321 EXPECT_EQ(1U, match_alpha
.duplicate_matches
.size());
3322 EXPECT_EQ(1U, match_avid
.duplicate_matches
.size());
3324 EXPECT_EQ(0U, match_apricot
.duplicate_matches
.size());
3327 TEST_F(SearchProviderTest
, SuggestQueryUsesToken
) {
3328 CommandLine::ForCurrentProcess()->AppendSwitch(
3329 switches::kEnableAnswersInSuggest
);
3331 TemplateURLService
* turl_model
=
3332 TemplateURLServiceFactory::GetForProfile(&profile_
);
3334 TemplateURLData data
;
3335 data
.short_name
= ASCIIToUTF16("default");
3336 data
.SetKeyword(data
.short_name
);
3337 data
.SetURL("http://example/{searchTerms}{google:sessionToken}");
3338 data
.suggestions_url
=
3339 "http://suggest/?q={searchTerms}&{google:sessionToken}";
3340 default_t_url_
= new TemplateURL(data
);
3341 turl_model
->Add(default_t_url_
);
3342 turl_model
->SetUserSelectedDefaultSearchProvider(default_t_url_
);
3344 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
3345 QueryForInput(term
, false, false);
3347 // Make sure the default provider's suggest service was queried.
3348 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
3349 SearchProvider::kDefaultProviderURLFetcherID
);
3350 ASSERT_TRUE(fetcher
);
3352 // And the URL matches what we expected.
3353 TemplateURLRef::SearchTermsArgs
search_terms_args(term
);
3354 search_terms_args
.session_token
= provider_
->current_token_
;
3355 GURL
expected_url(default_t_url_
->suggestions_url_ref().ReplaceSearchTerms(
3356 search_terms_args
, turl_model
->search_terms_data()));
3357 EXPECT_EQ(fetcher
->GetOriginalURL().spec(), expected_url
.spec());
3359 // Complete running the fetcher to clean up.
3360 fetcher
->set_response_code(200);
3361 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3362 RunTillProviderDone();
3365 TEST_F(SearchProviderTest
, SessionToken
) {
3366 // Subsequent calls always get the same token.
3367 std::string token
= provider_
->GetSessionToken();
3368 std::string token2
= provider_
->GetSessionToken();
3369 EXPECT_EQ(token
, token2
);
3370 EXPECT_FALSE(token
.empty());
3372 // Calls do not regenerate a token.
3373 provider_
->current_token_
= "PRE-EXISTING TOKEN";
3374 token
= provider_
->GetSessionToken();
3375 EXPECT_EQ(token
, "PRE-EXISTING TOKEN");
3377 // ... unless the token has expired.
3378 provider_
->current_token_
.clear();
3379 const base::TimeDelta kSmallDelta
= base::TimeDelta::FromMilliseconds(1);
3380 provider_
->token_expiration_time_
= base::TimeTicks::Now() - kSmallDelta
;
3381 token
= provider_
->GetSessionToken();
3382 EXPECT_FALSE(token
.empty());
3383 EXPECT_EQ(token
, provider_
->current_token_
);
3385 // The expiration time is always updated.
3386 provider_
->GetSessionToken();
3387 base::TimeTicks expiration_time_1
= provider_
->token_expiration_time_
;
3388 base::PlatformThread::Sleep(kSmallDelta
);
3389 provider_
->GetSessionToken();
3390 base::TimeTicks expiration_time_2
= provider_
->token_expiration_time_
;
3391 EXPECT_GT(expiration_time_2
, expiration_time_1
);
3392 EXPECT_GE(expiration_time_2
, expiration_time_1
+ kSmallDelta
);
3395 TEST_F(SearchProviderTest
, AnswersCache
) {
3396 AutocompleteResult result
;
3398 AutocompleteMatch match1
;
3399 match1
.answer_contents
= base::ASCIIToUTF16("m1");
3400 match1
.answer_type
= base::ASCIIToUTF16("2334");
3401 match1
.fill_into_edit
= base::ASCIIToUTF16("weather los angeles");
3403 AutocompleteMatch non_answer_match1
;
3404 non_answer_match1
.fill_into_edit
= base::ASCIIToUTF16("weather laguna beach");
3406 // Test that an answer in the first slot populates the cache.
3407 matches
.push_back(match1
);
3408 matches
.push_back(non_answer_match1
);
3409 result
.AppendMatches(matches
);
3410 provider_
->RegisterDisplayedAnswers(result
);
3411 ASSERT_FALSE(provider_
->answers_cache_
.empty());
3413 // Without scored results, no answers will be retrieved.
3414 AnswersQueryData answer
= provider_
->FindAnswersPrefetchData();
3415 EXPECT_TRUE(answer
.full_query_text
.empty());
3416 EXPECT_TRUE(answer
.query_type
.empty());
3418 // Inject a scored result, which will trigger answer retrieval.
3419 base::string16 query
= base::ASCIIToUTF16("weather los angeles");
3420 SearchSuggestionParser::SuggestResult
suggest_result(
3421 query
, AutocompleteMatchType::SEARCH_HISTORY
, query
, base::string16(),
3422 base::string16(), base::string16(), base::string16(), nullptr,
3423 std::string(), std::string(), false, 1200, false, false, query
);
3424 QueryForInput(ASCIIToUTF16("weather l"), false, false);
3425 provider_
->transformed_default_history_results_
.push_back(suggest_result
);
3426 answer
= provider_
->FindAnswersPrefetchData();
3427 EXPECT_EQ(base::ASCIIToUTF16("weather los angeles"), answer
.full_query_text
);
3428 EXPECT_EQ(base::ASCIIToUTF16("2334"), answer
.query_type
);
3431 TEST_F(SearchProviderTest
, RemoveExtraAnswers
) {
3432 SuggestionAnswer answer1
;
3433 answer1
.set_type(42);
3434 SuggestionAnswer answer2
;
3435 answer2
.set_type(1983);
3436 SuggestionAnswer answer3
;
3437 answer3
.set_type(423);
3440 AutocompleteMatch match1
, match2
, match3
, match4
, match5
;
3441 match1
.answer
= SuggestionAnswer::copy(&answer1
);
3442 match1
.answer_contents
= base::ASCIIToUTF16("the answer");
3443 match1
.answer_type
= base::ASCIIToUTF16("42");
3444 match3
.answer
= SuggestionAnswer::copy(&answer2
);
3445 match3
.answer_contents
= base::ASCIIToUTF16("not to play");
3446 match3
.answer_type
= base::ASCIIToUTF16("1983");
3447 match5
.answer
= SuggestionAnswer::copy(&answer3
);
3448 match5
.answer_contents
= base::ASCIIToUTF16("a man");
3449 match5
.answer_type
= base::ASCIIToUTF16("423");
3451 matches
.push_back(match1
);
3452 matches
.push_back(match2
);
3453 matches
.push_back(match3
);
3454 matches
.push_back(match4
);
3455 matches
.push_back(match5
);
3457 SearchProvider::RemoveExtraAnswers(&matches
);
3458 EXPECT_EQ(base::ASCIIToUTF16("the answer"), matches
[0].answer_contents
);
3459 EXPECT_EQ(base::ASCIIToUTF16("42"), matches
[0].answer_type
);
3460 EXPECT_TRUE(answer1
.Equals(*matches
[0].answer
));
3461 EXPECT_TRUE(matches
[1].answer_contents
.empty());
3462 EXPECT_TRUE(matches
[1].answer_type
.empty());
3463 EXPECT_FALSE(matches
[1].answer
);
3464 EXPECT_TRUE(matches
[2].answer_contents
.empty());
3465 EXPECT_TRUE(matches
[2].answer_type
.empty());
3466 EXPECT_FALSE(matches
[2].answer
);
3467 EXPECT_TRUE(matches
[3].answer_contents
.empty());
3468 EXPECT_TRUE(matches
[3].answer_type
.empty());
3469 EXPECT_FALSE(matches
[3].answer
);
3470 EXPECT_TRUE(matches
[4].answer_contents
.empty());
3471 EXPECT_TRUE(matches
[4].answer_type
.empty());
3472 EXPECT_FALSE(matches
[4].answer
);