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 "chrome/browser/autocomplete/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/autocomplete_input.h"
22 #include "chrome/browser/autocomplete/autocomplete_match.h"
23 #include "chrome/browser/autocomplete/autocomplete_provider.h"
24 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
25 #include "chrome/browser/autocomplete/history_url_provider.h"
26 #include "chrome/browser/history/history_service.h"
27 #include "chrome/browser/history/history_service_factory.h"
28 #include "chrome/browser/omnibox/omnibox_field_trial.h"
29 #include "chrome/browser/search_engines/search_engine_type.h"
30 #include "chrome/browser/search_engines/template_url.h"
31 #include "chrome/browser/search_engines/template_url_service.h"
32 #include "chrome/browser/search_engines/template_url_service_factory.h"
33 #include "chrome/browser/signin/signin_manager.h"
34 #include "chrome/browser/signin/signin_manager_factory.h"
35 #include "chrome/browser/sync/profile_sync_service.h"
36 #include "chrome/browser/sync/profile_sync_service_factory.h"
37 #include "chrome/common/chrome_switches.h"
38 #include "chrome/common/metrics/variations/variations_util.h"
39 #include "chrome/common/pref_names.h"
40 #include "chrome/test/base/testing_browser_process.h"
41 #include "chrome/test/base/testing_profile.h"
42 #include "components/variations/entropy_provider.h"
43 #include "content/public/test/test_browser_thread_bundle.h"
44 #include "net/url_request/test_url_fetcher_factory.h"
45 #include "net/url_request/url_request_status.h"
46 #include "testing/gtest/include/gtest/gtest.h"
48 using base::ASCIIToUTF16
;
52 // Returns the first match in |matches| with |allowed_to_be_default_match|
54 ACMatches::const_iterator
FindDefaultMatch(const ACMatches
& matches
) {
55 ACMatches::const_iterator it
= matches
.begin();
56 while ((it
!= matches
.end()) && !it
->allowed_to_be_default_match
)
61 class SuggestionDeletionHandler
;
62 class SearchProviderForTest
: public SearchProvider
{
64 SearchProviderForTest(
65 AutocompleteProviderListener
* listener
,
67 bool is_success() { return is_success_
; };
70 virtual ~SearchProviderForTest();
73 virtual void RecordDeletionResult(bool success
) OVERRIDE
;
75 DISALLOW_COPY_AND_ASSIGN(SearchProviderForTest
);
78 SearchProviderForTest::SearchProviderForTest(
79 AutocompleteProviderListener
* listener
,
81 : SearchProvider(listener
, profile
), is_success_(false) {
84 SearchProviderForTest::~SearchProviderForTest() {
87 void SearchProviderForTest::RecordDeletionResult(bool success
) {
88 is_success_
= success
;
93 // SearchProviderTest ---------------------------------------------------------
95 // The following environment is configured for these tests:
96 // . The TemplateURL default_t_url_ is set as the default provider.
97 // . The TemplateURL keyword_t_url_ is added to the TemplateURLService. This
98 // TemplateURL has a valid suggest and search URL.
99 // . The URL created by using the search term term1_ with default_t_url_ is
101 // . The URL created by using the search term keyword_term_ with keyword_t_url_
102 // is added to history.
103 // . test_factory_ is set as the URLFetcherFactory.
104 class SearchProviderTest
: public testing::Test
,
105 public AutocompleteProviderListener
{
108 ResultInfo() : result_type(AutocompleteMatchType::NUM_TYPES
),
109 allowed_to_be_default_match(false) {
111 ResultInfo(GURL gurl
,
112 AutocompleteMatch::Type result_type
,
113 bool allowed_to_be_default_match
,
114 base::string16 fill_into_edit
)
116 result_type(result_type
),
117 allowed_to_be_default_match(allowed_to_be_default_match
),
118 fill_into_edit(fill_into_edit
) {
122 const AutocompleteMatch::Type result_type
;
123 const bool allowed_to_be_default_match
;
124 const base::string16 fill_into_edit
;
128 const base::string16 input
;
129 const size_t num_results
;
130 const ResultInfo output
[3];
134 : default_t_url_(NULL
),
135 term1_(ASCIIToUTF16("term1")),
136 keyword_t_url_(NULL
),
137 keyword_term_(ASCIIToUTF16("keyword")),
139 ResetFieldTrialList();
142 // See description above class for what this registers.
143 virtual void SetUp() OVERRIDE
;
144 virtual void TearDown() OVERRIDE
;
146 void RunTest(TestData
* cases
, int num_cases
, bool prefer_keyword
);
149 // Needed for AutocompleteFieldTrial::ActivateStaticTrials();
150 scoped_ptr
<base::FieldTrialList
> field_trial_list_
;
152 // Default value used for testing.
153 static const std::string kNotApplicable
;
155 // Adds a search for |term|, using the engine |t_url| to the history, and
156 // returns the URL for that search.
157 GURL
AddSearchToHistory(TemplateURL
* t_url
, base::string16 term
, int visit_count
);
159 // Looks for a match in |provider_| with |contents| equal to |contents|.
160 // Sets |match| to it if found. Returns whether |match| was set.
161 bool FindMatchWithContents(const base::string16
& contents
,
162 AutocompleteMatch
* match
);
164 // Looks for a match in |provider_| with destination |url|. Sets |match| to
165 // it if found. Returns whether |match| was set.
166 bool FindMatchWithDestination(const GURL
& url
, AutocompleteMatch
* match
);
168 // AutocompleteProviderListener:
169 // If we're waiting for the provider to finish, this exits the message loop.
170 virtual void OnProviderUpdate(bool updated_matches
) OVERRIDE
;
172 // Runs a nested message loop until provider_ is done. The message loop is
173 // exited by way of OnProviderUpdate.
174 void RunTillProviderDone();
176 // Invokes Start on provider_, then runs all pending tasks.
177 void QueryForInput(const base::string16
& text
,
178 bool prevent_inline_autocomplete
,
179 bool prefer_keyword
);
181 // Calls QueryForInput(), finishes any suggest query, then if |wyt_match| is
182 // non-NULL, sets it to the "what you typed" entry for |text|.
183 void QueryForInputAndSetWYTMatch(const base::string16
& text
,
184 AutocompleteMatch
* wyt_match
);
186 // Notifies the URLFetcher for the suggest query corresponding to the default
187 // search provider that it's done.
188 // Be sure and wrap calls to this in ASSERT_NO_FATAL_FAILURE.
189 void FinishDefaultSuggestQuery();
191 // Runs SearchProvider on |input|, for which the suggest server replies
192 // with |json|, and expects that the resulting matches' contents equals
193 // that in |matches|. An empty entry in |matches| means no match should
194 // be returned in that position. Reports any errors with a message that
195 // includes |error_description|.
196 void ForcedQueryTestHelper(const std::string
& input
,
197 const std::string
& json
,
198 const std::string matches
[3],
199 const std::string
& error_description
);
201 void ResetFieldTrialList();
203 void ClearAllResults();
205 // See description above class for details of these fields.
206 TemplateURL
* default_t_url_
;
207 const base::string16 term1_
;
209 TemplateURL
* keyword_t_url_
;
210 const base::string16 keyword_term_
;
213 content::TestBrowserThreadBundle thread_bundle_
;
215 // URLFetcherFactory implementation registered.
216 net::TestURLFetcherFactory test_factory_
;
219 TestingProfile profile_
;
222 scoped_refptr
<SearchProviderForTest
> provider_
;
224 // If non-NULL, OnProviderUpdate quits the current |run_loop_|.
225 base::RunLoop
* run_loop_
;
227 DISALLOW_COPY_AND_ASSIGN(SearchProviderTest
);
231 const std::string
SearchProviderTest::kNotApplicable
= "Not Applicable";
233 void SearchProviderTest::SetUp() {
234 // Make sure that fetchers are automatically ungregistered upon destruction.
235 test_factory_
.set_remove_fetcher_on_delete(true);
237 // We need both the history service and template url model loaded.
238 ASSERT_TRUE(profile_
.CreateHistoryService(true, false));
239 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
240 &profile_
, &TemplateURLServiceFactory::BuildInstanceFor
);
242 TemplateURLService
* turl_model
=
243 TemplateURLServiceFactory::GetForProfile(&profile_
);
247 // Reset the default TemplateURL.
248 TemplateURLData data
;
249 data
.short_name
= ASCIIToUTF16("t");
250 data
.SetURL("http://defaultturl/{searchTerms}");
251 data
.suggestions_url
= "http://defaultturl2/{searchTerms}";
252 data
.instant_url
= "http://does/not/exist?strk=1";
253 data
.search_terms_replacement_key
= "strk";
254 default_t_url_
= new TemplateURL(&profile_
, data
);
255 turl_model
->Add(default_t_url_
);
256 turl_model
->SetDefaultSearchProvider(default_t_url_
);
257 TemplateURLID default_provider_id
= default_t_url_
->id();
258 ASSERT_NE(0, default_provider_id
);
260 // Add url1, with search term term1_.
261 term1_url_
= AddSearchToHistory(default_t_url_
, term1_
, 1);
263 // Create another TemplateURL.
264 data
.short_name
= ASCIIToUTF16("k");
265 data
.SetKeyword(ASCIIToUTF16("k"));
266 data
.SetURL("http://keyword/{searchTerms}");
267 data
.suggestions_url
= "http://suggest_keyword/{searchTerms}";
268 keyword_t_url_
= new TemplateURL(&profile_
, data
);
269 turl_model
->Add(keyword_t_url_
);
270 ASSERT_NE(0, keyword_t_url_
->id());
272 // Add a page and search term for keyword_t_url_.
273 keyword_url_
= AddSearchToHistory(keyword_t_url_
, keyword_term_
, 1);
275 // Keywords are updated by the InMemoryHistoryBackend only after the message
276 // has been processed on the history thread. Block until history processes all
277 // requests to ensure the InMemoryDatabase is the state we expect it.
278 profile_
.BlockUntilHistoryProcessesPendingRequests();
280 provider_
= new SearchProviderForTest(this, &profile_
);
281 provider_
->kMinimumTimeBetweenSuggestQueriesMs
= 0;
284 void SearchProviderTest::TearDown() {
285 base::RunLoop().RunUntilIdle();
287 // Shutdown the provider before the profile.
291 void SearchProviderTest::RunTest(TestData
* cases
,
293 bool prefer_keyword
) {
295 for (int i
= 0; i
< num_cases
; ++i
) {
296 AutocompleteInput
input(cases
[i
].input
, base::string16::npos
,
297 base::string16(), GURL(),
298 AutocompleteInput::INVALID_SPEC
, false,
299 prefer_keyword
, true,
300 AutocompleteInput::ALL_MATCHES
);
301 provider_
->Start(input
, false);
302 matches
= provider_
->matches();
303 base::string16 diagnostic_details
=
304 ASCIIToUTF16("Input was: ") +
306 ASCIIToUTF16("; prefer_keyword was: ") +
307 (prefer_keyword
? ASCIIToUTF16("true") : ASCIIToUTF16("false"));
308 EXPECT_EQ(cases
[i
].num_results
, matches
.size()) << diagnostic_details
;
309 if (matches
.size() == cases
[i
].num_results
) {
310 for (size_t j
= 0; j
< cases
[i
].num_results
; ++j
) {
311 EXPECT_EQ(cases
[i
].output
[j
].gurl
, matches
[j
].destination_url
) <<
313 EXPECT_EQ(cases
[i
].output
[j
].result_type
, matches
[j
].type
) <<
315 EXPECT_EQ(cases
[i
].output
[j
].fill_into_edit
,
316 matches
[j
].fill_into_edit
) << diagnostic_details
;
317 EXPECT_EQ(cases
[i
].output
[j
].allowed_to_be_default_match
,
318 matches
[j
].allowed_to_be_default_match
) << diagnostic_details
;
324 void SearchProviderTest::OnProviderUpdate(bool updated_matches
) {
325 if (run_loop_
&& provider_
->done()) {
331 void SearchProviderTest::RunTillProviderDone() {
332 if (provider_
->done())
335 base::RunLoop run_loop
;
336 run_loop_
= &run_loop
;
340 void SearchProviderTest::QueryForInput(const base::string16
& text
,
341 bool prevent_inline_autocomplete
,
342 bool prefer_keyword
) {
344 AutocompleteInput
input(text
, base::string16::npos
, base::string16(), GURL(),
345 AutocompleteInput::INVALID_SPEC
,
346 prevent_inline_autocomplete
, prefer_keyword
, true,
347 AutocompleteInput::ALL_MATCHES
);
348 provider_
->Start(input
, false);
350 // RunUntilIdle so that the task scheduled by SearchProvider to create the
352 base::RunLoop().RunUntilIdle();
355 void SearchProviderTest::QueryForInputAndSetWYTMatch(
356 const base::string16
& text
,
357 AutocompleteMatch
* wyt_match
) {
358 QueryForInput(text
, false, false);
359 profile_
.BlockUntilHistoryProcessesPendingRequests();
360 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
363 ASSERT_GE(provider_
->matches().size(), 1u);
364 EXPECT_TRUE(FindMatchWithDestination(GURL(
365 default_t_url_
->url_ref().ReplaceSearchTerms(
366 TemplateURLRef::SearchTermsArgs(text
))),
370 GURL
SearchProviderTest::AddSearchToHistory(TemplateURL
* t_url
,
373 HistoryService
* history
=
374 HistoryServiceFactory::GetForProfile(&profile_
,
375 Profile::EXPLICIT_ACCESS
);
376 GURL
search(t_url
->url_ref().ReplaceSearchTerms(
377 TemplateURLRef::SearchTermsArgs(term
)));
378 static base::Time last_added_time
;
379 last_added_time
= std::max(base::Time::Now(),
380 last_added_time
+ base::TimeDelta::FromMicroseconds(1));
381 history
->AddPageWithDetails(search
, base::string16(), visit_count
, visit_count
,
382 last_added_time
, false, history::SOURCE_BROWSED
);
383 history
->SetKeywordSearchTermsForURL(search
, t_url
->id(), term
);
387 bool SearchProviderTest::FindMatchWithContents(const base::string16
& contents
,
388 AutocompleteMatch
* match
) {
389 for (ACMatches::const_iterator i
= provider_
->matches().begin();
390 i
!= provider_
->matches().end(); ++i
) {
391 if (i
->contents
== contents
) {
399 bool SearchProviderTest::FindMatchWithDestination(const GURL
& url
,
400 AutocompleteMatch
* match
) {
401 for (ACMatches::const_iterator i
= provider_
->matches().begin();
402 i
!= provider_
->matches().end(); ++i
) {
403 if (i
->destination_url
== url
) {
411 void SearchProviderTest::FinishDefaultSuggestQuery() {
412 net::TestURLFetcher
* default_fetcher
=
413 test_factory_
.GetFetcherByID(
414 SearchProvider::kDefaultProviderURLFetcherID
);
415 ASSERT_TRUE(default_fetcher
);
417 // Tell the SearchProvider the default suggest query is done.
418 default_fetcher
->set_response_code(200);
419 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
422 void SearchProviderTest::ForcedQueryTestHelper(
423 const std::string
& input
,
424 const std::string
& json
,
425 const std::string expected_matches
[3],
426 const std::string
& error_description
) {
427 QueryForInput(ASCIIToUTF16(input
), false, false);
428 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
429 SearchProvider::kDefaultProviderURLFetcherID
);
430 ASSERT_TRUE(fetcher
);
431 fetcher
->set_response_code(200);
432 fetcher
->SetResponseString(json
);
433 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
434 RunTillProviderDone();
436 const ACMatches
& matches
= provider_
->matches();
437 ASSERT_LE(matches
.size(), 3u);
439 // Ensure that the returned matches equal the expectations.
440 for (; i
< matches
.size(); ++i
) {
441 EXPECT_EQ(ASCIIToUTF16(expected_matches
[i
]), matches
[i
].contents
) <<
444 // Ensure that no expected matches are missing.
445 for (; i
< 3u; ++i
) {
446 EXPECT_EQ(std::string(), expected_matches
[i
]) <<
447 "Case #" << i
<< ": " << error_description
;
451 void SearchProviderTest::ResetFieldTrialList() {
452 // Destroy the existing FieldTrialList before creating a new one to avoid
454 field_trial_list_
.reset();
455 field_trial_list_
.reset(new base::FieldTrialList(
456 new metrics::SHA1EntropyProvider("foo")));
457 chrome_variations::testing::ClearAllVariationParams();
458 base::FieldTrial
* trial
= base::FieldTrialList::CreateFieldTrial(
459 "AutocompleteDynamicTrial_0", "DefaultGroup");
463 void SearchProviderTest::ClearAllResults() {
464 provider_
->ClearAllResults();
467 // Actual Tests ---------------------------------------------------------------
469 // Make sure we query history for the default provider and a URLFetcher is
470 // created for the default provider suggest results.
471 TEST_F(SearchProviderTest
, QueryDefaultProvider
) {
472 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
473 QueryForInput(term
, false, false);
475 // Make sure the default providers suggest service was queried.
476 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
477 SearchProvider::kDefaultProviderURLFetcherID
);
478 ASSERT_TRUE(fetcher
);
480 // And the URL matches what we expected.
481 GURL
expected_url(default_t_url_
->suggestions_url_ref().ReplaceSearchTerms(
482 TemplateURLRef::SearchTermsArgs(term
)));
483 ASSERT_TRUE(fetcher
->GetOriginalURL() == expected_url
);
485 // Tell the SearchProvider the suggest query is done.
486 fetcher
->set_response_code(200);
487 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
490 // Run till the history results complete.
491 RunTillProviderDone();
493 // The SearchProvider is done. Make sure it has a result for the history
495 AutocompleteMatch term1_match
;
496 EXPECT_TRUE(FindMatchWithDestination(term1_url_
, &term1_match
));
497 // Term1 should not have a description, it's set later.
498 EXPECT_TRUE(term1_match
.description
.empty());
500 AutocompleteMatch wyt_match
;
501 EXPECT_TRUE(FindMatchWithDestination(
502 GURL(default_t_url_
->url_ref().ReplaceSearchTerms(
503 TemplateURLRef::SearchTermsArgs(term
))), &wyt_match
));
504 EXPECT_TRUE(wyt_match
.description
.empty());
506 // The match for term1 should be more relevant than the what you typed match.
507 EXPECT_GT(term1_match
.relevance
, wyt_match
.relevance
);
508 // This longer match should be inlineable.
509 EXPECT_TRUE(term1_match
.allowed_to_be_default_match
);
510 // The what you typed match should be too, of course.
511 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
514 TEST_F(SearchProviderTest
, HonorPreventInlineAutocomplete
) {
515 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
516 QueryForInput(term
, true, false);
518 ASSERT_FALSE(provider_
->matches().empty());
519 ASSERT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
520 provider_
->matches()[0].type
);
521 EXPECT_TRUE(provider_
->matches()[0].allowed_to_be_default_match
);
524 // Issues a query that matches the registered keyword and makes sure history
525 // is queried as well as URLFetchers getting created.
526 TEST_F(SearchProviderTest
, QueryKeywordProvider
) {
527 base::string16 term
= keyword_term_
.substr(0, keyword_term_
.length() - 1);
528 QueryForInput(keyword_t_url_
->keyword() + ASCIIToUTF16(" ") + term
,
532 // Make sure the default providers suggest service was queried.
533 net::TestURLFetcher
* default_fetcher
= test_factory_
.GetFetcherByID(
534 SearchProvider::kDefaultProviderURLFetcherID
);
535 ASSERT_TRUE(default_fetcher
);
537 // Tell the SearchProvider the default suggest query is done.
538 default_fetcher
->set_response_code(200);
539 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
540 default_fetcher
= NULL
;
542 // Make sure the keyword providers suggest service was queried.
543 net::TestURLFetcher
* keyword_fetcher
= test_factory_
.GetFetcherByID(
544 SearchProvider::kKeywordProviderURLFetcherID
);
545 ASSERT_TRUE(keyword_fetcher
);
547 // And the URL matches what we expected.
548 GURL
expected_url(keyword_t_url_
->suggestions_url_ref().ReplaceSearchTerms(
549 TemplateURLRef::SearchTermsArgs(term
)));
550 ASSERT_TRUE(keyword_fetcher
->GetOriginalURL() == expected_url
);
552 // Tell the SearchProvider the keyword suggest query is done.
553 keyword_fetcher
->set_response_code(200);
554 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
555 keyword_fetcher
= NULL
;
557 // Run till the history results complete.
558 RunTillProviderDone();
560 // The SearchProvider is done. Make sure it has a result for the history
562 AutocompleteMatch match
;
563 EXPECT_TRUE(FindMatchWithDestination(keyword_url_
, &match
));
565 // The match should have an associated keyword.
566 EXPECT_FALSE(match
.keyword
.empty());
568 // The fill into edit should contain the keyword.
569 EXPECT_EQ(keyword_t_url_
->keyword() + base::char16(' ') + keyword_term_
,
570 match
.fill_into_edit
);
573 TEST_F(SearchProviderTest
, DontSendPrivateDataToSuggest
) {
574 // None of the following input strings should be sent to the suggest server,
575 // because they may contain private data.
576 const char* inputs
[] = {
578 "http://username:password",
579 "https://username:password",
580 "username:password@hostname",
581 "http://username:password@hostname/",
584 "unknownscheme:anything",
585 "http://hostname/?query=q",
586 "http://hostname/path#ref",
587 "http://hostname/path #ref",
588 "https://hostname/path",
591 for (size_t i
= 0; i
< arraysize(inputs
); ++i
) {
592 QueryForInput(ASCIIToUTF16(inputs
[i
]), false, false);
593 // Make sure the default provider's suggest service was not queried.
594 ASSERT_TRUE(test_factory_
.GetFetcherByID(
595 SearchProvider::kDefaultProviderURLFetcherID
) == NULL
);
596 // Run till the history results complete.
597 RunTillProviderDone();
601 TEST_F(SearchProviderTest
, SendNonPrivateDataToSuggest
) {
602 // All of the following input strings should be sent to the suggest server,
603 // because they should not get caught by the private data checks.
604 const char* inputs
[] = {
608 "http://hostname/path",
609 "http://hostname #ref",
610 "www.hostname.com #ref",
613 "foo https://hostname/path"
616 profile_
.BlockUntilHistoryProcessesPendingRequests();
617 for (size_t i
= 0; i
< arraysize(inputs
); ++i
) {
618 QueryForInput(ASCIIToUTF16(inputs
[i
]), false, false);
619 // Make sure the default provider's suggest service was queried.
620 ASSERT_TRUE(test_factory_
.GetFetcherByID(
621 SearchProvider::kDefaultProviderURLFetcherID
) != NULL
);
625 TEST_F(SearchProviderTest
, DontAutocompleteURLLikeTerms
) {
626 AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
627 &profile_
, &AutocompleteClassifierFactory::BuildInstanceFor
);
628 GURL url
= AddSearchToHistory(default_t_url_
,
629 ASCIIToUTF16("docs.google.com"), 1);
631 // Add the term as a url.
632 HistoryServiceFactory::GetForProfile(&profile_
, Profile::EXPLICIT_ACCESS
)->
633 AddPageWithDetails(GURL("http://docs.google.com"), base::string16(), 1, 1,
634 base::Time::Now(), false, history::SOURCE_BROWSED
);
635 profile_
.BlockUntilHistoryProcessesPendingRequests();
637 AutocompleteMatch wyt_match
;
638 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("docs"),
641 // There should be two matches, one for what you typed, the other for
642 // 'docs.google.com'. The search term should have a lower priority than the
643 // what you typed match.
644 ASSERT_EQ(2u, provider_
->matches().size());
645 AutocompleteMatch term_match
;
646 EXPECT_TRUE(FindMatchWithDestination(url
, &term_match
));
647 EXPECT_GT(wyt_match
.relevance
, term_match
.relevance
);
648 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
649 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
652 TEST_F(SearchProviderTest
, DontGiveNavsuggestionsInForcedQueryMode
) {
653 const std::string kEmptyMatch
;
655 const std::string json
;
656 const std::string matches_in_default_mode
[3];
657 const std::string matches_in_forced_query_mode
[3];
659 // Without suggested relevance scores.
660 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
661 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]}]",
662 { "a", "a1.com", "a2" },
663 { "a", "a2", kEmptyMatch
} },
665 // With suggested relevance scores in a situation where navsuggest would
667 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
668 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
669 "\"google:suggestrelevance\":[1250, 1200]}]",
670 { "a", "a1.com", "a2" },
671 { "a", "a2", kEmptyMatch
} },
673 // With suggested relevance scores in a situation where navsuggest
675 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
676 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
677 "\"google:suggestrelevance\":[1350, 1250]}]",
678 { "a1.com", "a", "a2" },
679 { "a", "a2", kEmptyMatch
} },
681 // With suggested relevance scores in a situation where navsuggest
682 // would go first only because verbatim has been demoted.
683 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
684 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
685 "\"google:suggestrelevance\":[1450, 1400],"
686 "\"google:verbatimrelevance\":1350}]",
687 { "a1.com", "a2", "a" },
688 { "a2", "a", kEmptyMatch
} },
691 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); ++i
) {
692 ForcedQueryTestHelper("a", cases
[i
].json
, cases
[i
].matches_in_default_mode
,
693 "regular input with json=" + cases
[i
].json
);
694 ForcedQueryTestHelper("?a", cases
[i
].json
,
695 cases
[i
].matches_in_forced_query_mode
,
696 "forced query input with json=" + cases
[i
].json
);
700 // A multiword search with one visit should not autocomplete until multiple
702 TEST_F(SearchProviderTest
, DontAutocompleteUntilMultipleWordsTyped
) {
703 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("one search"),
705 profile_
.BlockUntilHistoryProcessesPendingRequests();
707 AutocompleteMatch wyt_match
;
708 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("on"),
710 ASSERT_EQ(2u, provider_
->matches().size());
711 AutocompleteMatch term_match
;
712 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
713 EXPECT_GT(wyt_match
.relevance
, term_match
.relevance
);
714 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
715 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
717 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("one se"),
719 ASSERT_EQ(2u, provider_
->matches().size());
720 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
721 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
722 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
723 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
726 // A multiword search with more than one visit should autocomplete immediately.
727 TEST_F(SearchProviderTest
, AutocompleteMultipleVisitsImmediately
) {
728 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("two searches"),
730 profile_
.BlockUntilHistoryProcessesPendingRequests();
732 AutocompleteMatch wyt_match
;
733 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("tw"),
735 ASSERT_EQ(2u, provider_
->matches().size());
736 AutocompleteMatch term_match
;
737 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
738 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
739 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
740 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
743 // Autocompletion should work at a word boundary after a space.
744 TEST_F(SearchProviderTest
, AutocompleteAfterSpace
) {
745 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("two searches"),
747 profile_
.BlockUntilHistoryProcessesPendingRequests();
749 AutocompleteMatch wyt_match
;
750 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("two "),
752 ASSERT_EQ(2u, provider_
->matches().size());
753 AutocompleteMatch term_match
;
754 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
755 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
756 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
757 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
760 // Newer multiword searches should score more highly than older ones.
761 TEST_F(SearchProviderTest
, ScoreNewerSearchesHigher
) {
762 GURL
term_url_a(AddSearchToHistory(default_t_url_
,
763 ASCIIToUTF16("three searches aaa"), 1));
764 GURL
term_url_b(AddSearchToHistory(default_t_url_
,
765 ASCIIToUTF16("three searches bbb"), 1));
766 profile_
.BlockUntilHistoryProcessesPendingRequests();
768 AutocompleteMatch wyt_match
;
769 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("three se"),
771 ASSERT_EQ(3u, provider_
->matches().size());
772 AutocompleteMatch term_match_a
;
773 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
774 AutocompleteMatch term_match_b
;
775 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
776 EXPECT_GT(term_match_b
.relevance
, term_match_a
.relevance
);
777 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
778 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
779 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
780 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
783 // An autocompleted multiword search should not be replaced by a different
784 // autocompletion while the user is still typing a valid prefix.
785 TEST_F(SearchProviderTest
, DontReplacePreviousAutocompletion
) {
786 GURL
term_url_a(AddSearchToHistory(default_t_url_
,
787 ASCIIToUTF16("four searches aaa"), 2));
788 GURL
term_url_b(AddSearchToHistory(default_t_url_
,
789 ASCIIToUTF16("four searches bbb"), 1));
790 profile_
.BlockUntilHistoryProcessesPendingRequests();
792 AutocompleteMatch wyt_match
;
793 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fo"),
795 ASSERT_EQ(3u, provider_
->matches().size());
796 AutocompleteMatch term_match_a
;
797 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
798 AutocompleteMatch term_match_b
;
799 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
800 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
801 EXPECT_GT(wyt_match
.relevance
, term_match_b
.relevance
);
802 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
803 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
804 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
806 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("four se"),
808 ASSERT_EQ(3u, provider_
->matches().size());
809 EXPECT_TRUE(FindMatchWithDestination(term_url_a
, &term_match_a
));
810 EXPECT_TRUE(FindMatchWithDestination(term_url_b
, &term_match_b
));
811 EXPECT_GT(term_match_a
.relevance
, wyt_match
.relevance
);
812 EXPECT_GT(wyt_match
.relevance
, term_match_b
.relevance
);
813 EXPECT_TRUE(term_match_a
.allowed_to_be_default_match
);
814 EXPECT_TRUE(term_match_b
.allowed_to_be_default_match
);
815 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
818 // Non-completable multiword searches should not crowd out single-word searches.
819 TEST_F(SearchProviderTest
, DontCrowdOutSingleWords
) {
820 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five"), 1));
821 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches bbb"), 1);
822 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches ccc"), 1);
823 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches ddd"), 1);
824 AddSearchToHistory(default_t_url_
, ASCIIToUTF16("five searches eee"), 1);
825 profile_
.BlockUntilHistoryProcessesPendingRequests();
827 AutocompleteMatch wyt_match
;
828 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fi"),
830 ASSERT_EQ(AutocompleteProvider::kMaxMatches
+ 1, provider_
->matches().size());
831 AutocompleteMatch term_match
;
832 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
833 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
834 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
835 EXPECT_TRUE(wyt_match
.allowed_to_be_default_match
);
838 // Inline autocomplete matches regardless of case differences from the input.
839 TEST_F(SearchProviderTest
, InlineMixedCaseMatches
) {
840 GURL
term_url(AddSearchToHistory(default_t_url_
, ASCIIToUTF16("FOO"), 1));
841 profile_
.BlockUntilHistoryProcessesPendingRequests();
843 AutocompleteMatch wyt_match
;
844 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
846 ASSERT_EQ(2u, provider_
->matches().size());
847 AutocompleteMatch term_match
;
848 EXPECT_TRUE(FindMatchWithDestination(term_url
, &term_match
));
849 EXPECT_GT(term_match
.relevance
, wyt_match
.relevance
);
850 EXPECT_EQ(ASCIIToUTF16("FOO"), term_match
.fill_into_edit
);
851 EXPECT_EQ(ASCIIToUTF16("OO"), term_match
.inline_autocompletion
);
852 EXPECT_TRUE(term_match
.allowed_to_be_default_match
);
855 // Verifies AutocompleteControllers return results (including keyword
856 // results) in the right order and set descriptions for them correctly.
857 TEST_F(SearchProviderTest
, KeywordOrderingAndDescriptions
) {
858 // Add an entry that corresponds to a keyword search with 'term2'.
859 AddSearchToHistory(keyword_t_url_
, ASCIIToUTF16("term2"), 1);
860 profile_
.BlockUntilHistoryProcessesPendingRequests();
862 AutocompleteController
controller(&profile_
, NULL
,
863 AutocompleteProvider::TYPE_SEARCH
);
864 controller
.Start(AutocompleteInput(
865 ASCIIToUTF16("k t"), base::string16::npos
, base::string16(), GURL(),
866 AutocompleteInput::INVALID_SPEC
, false, false, true,
867 AutocompleteInput::ALL_MATCHES
));
868 const AutocompleteResult
& result
= controller
.result();
870 // There should be three matches, one for the keyword history, one for
871 // keyword provider's what-you-typed, and one for the default provider's
872 // what you typed, in that order.
873 ASSERT_EQ(3u, result
.size());
874 EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY
, result
.match_at(0).type
);
875 EXPECT_EQ(AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
876 result
.match_at(1).type
);
877 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
878 result
.match_at(2).type
);
879 EXPECT_GT(result
.match_at(0).relevance
, result
.match_at(1).relevance
);
880 EXPECT_GT(result
.match_at(1).relevance
, result
.match_at(2).relevance
);
881 EXPECT_TRUE(result
.match_at(0).allowed_to_be_default_match
);
882 EXPECT_TRUE(result
.match_at(1).allowed_to_be_default_match
);
883 EXPECT_FALSE(result
.match_at(2).allowed_to_be_default_match
);
885 // The two keyword results should come with the keyword we expect.
886 EXPECT_EQ(ASCIIToUTF16("k"), result
.match_at(0).keyword
);
887 EXPECT_EQ(ASCIIToUTF16("k"), result
.match_at(1).keyword
);
888 // The default provider has a different keyword. (We don't explicitly
889 // set it during this test, so all we do is assert that it's different.)
890 EXPECT_NE(result
.match_at(0).keyword
, result
.match_at(2).keyword
);
892 // The top result will always have a description. The third result,
893 // coming from a different provider than the first two, should also.
894 // Whether the second result has one doesn't matter much. (If it was
895 // missing, people would infer that it's the same search provider as
896 // the one above it.)
897 EXPECT_FALSE(result
.match_at(0).description
.empty());
898 EXPECT_FALSE(result
.match_at(2).description
.empty());
899 EXPECT_NE(result
.match_at(0).description
, result
.match_at(2).description
);
902 TEST_F(SearchProviderTest
, KeywordVerbatim
) {
904 // Test a simple keyword input.
905 { ASCIIToUTF16("k foo"), 2,
906 { ResultInfo(GURL("http://keyword/foo"),
907 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
909 ASCIIToUTF16("k foo")),
910 ResultInfo(GURL("http://defaultturl/k%20foo"),
911 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
913 ASCIIToUTF16("k foo") ) } },
915 // Make sure extra whitespace after the keyword doesn't change the
916 // keyword verbatim query.
917 { ASCIIToUTF16("k foo"), 2,
918 { ResultInfo(GURL("http://keyword/foo"),
919 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
921 ASCIIToUTF16("k foo")),
922 ResultInfo(GURL("http://defaultturl/k%20%20%20foo"),
923 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
925 ASCIIToUTF16("k foo")) } },
926 // Leading whitespace should be stripped before SearchProvider gets the
927 // input; hence there are no tests here about how it handles those inputs.
929 // But whitespace elsewhere in the query string should matter to both
931 { ASCIIToUTF16("k foo bar"), 2,
932 { ResultInfo(GURL("http://keyword/foo%20%20bar"),
933 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
935 ASCIIToUTF16("k foo bar")),
936 ResultInfo(GURL("http://defaultturl/k%20%20foo%20%20bar"),
937 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
939 ASCIIToUTF16("k foo bar")) } },
940 // Note in the above test case we don't test trailing whitespace because
941 // SearchProvider still doesn't handle this well. See related bugs:
942 // 102690, 99239, 164635.
944 // Keywords can be prefixed by certain things that should get ignored
945 // when constructing the keyword match.
946 { ASCIIToUTF16("www.k foo"), 2,
947 { ResultInfo(GURL("http://keyword/foo"),
948 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
950 ASCIIToUTF16("k foo")),
951 ResultInfo(GURL("http://defaultturl/www.k%20foo"),
952 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
954 ASCIIToUTF16("www.k foo")) } },
955 { ASCIIToUTF16("http://k foo"), 2,
956 { ResultInfo(GURL("http://keyword/foo"),
957 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
959 ASCIIToUTF16("k foo")),
960 ResultInfo(GURL("http://defaultturl/http%3A//k%20foo"),
961 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
963 ASCIIToUTF16("http://k foo")) } },
964 { ASCIIToUTF16("http://www.k foo"), 2,
965 { ResultInfo(GURL("http://keyword/foo"),
966 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
968 ASCIIToUTF16("k foo")),
969 ResultInfo(GURL("http://defaultturl/http%3A//www.k%20foo"),
970 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
972 ASCIIToUTF16("http://www.k foo")) } },
974 // A keyword with no remaining input shouldn't get a keyword
976 { ASCIIToUTF16("k"), 1,
977 { ResultInfo(GURL("http://defaultturl/k"),
978 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
980 ASCIIToUTF16("k")) } },
981 { ASCIIToUTF16("k "), 1,
982 { ResultInfo(GURL("http://defaultturl/k%20"),
983 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
985 ASCIIToUTF16("k ")) } }
987 // The fact that verbatim queries to keyword are handled by KeywordProvider
988 // not SearchProvider is tested in
989 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc.
992 // Test not in keyword mode.
993 RunTest(cases
, arraysize(cases
), false);
995 // Test in keyword mode. (Both modes should give the same result.)
996 RunTest(cases
, arraysize(cases
), true);
999 // Ensures command-line flags are reflected in the URLs the search provider
1001 TEST_F(SearchProviderTest
, CommandLineOverrides
) {
1002 TemplateURLService
* turl_model
=
1003 TemplateURLServiceFactory::GetForProfile(&profile_
);
1005 TemplateURLData data
;
1006 data
.short_name
= ASCIIToUTF16("default");
1007 data
.SetKeyword(data
.short_name
);
1008 data
.SetURL("{google:baseURL}{searchTerms}");
1009 default_t_url_
= new TemplateURL(&profile_
, data
);
1010 turl_model
->Add(default_t_url_
);
1011 turl_model
->SetDefaultSearchProvider(default_t_url_
);
1013 CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL
,
1014 "http://www.bar.com/");
1015 CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1016 switches::kExtraSearchQueryParams
, "a=b");
1018 TestData cases
[] = {
1019 { ASCIIToUTF16("k a"), 2,
1020 { ResultInfo(GURL("http://keyword/a"),
1021 AutocompleteMatchType::SEARCH_OTHER_ENGINE
,
1023 ASCIIToUTF16("k a")),
1024 ResultInfo(GURL("http://www.bar.com/k%20a?a=b"),
1025 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
1027 ASCIIToUTF16("k a")) } },
1030 RunTest(cases
, arraysize(cases
), false);
1033 // Verifies Navsuggest results don't set a TemplateURL, which Instant relies on.
1034 // Also verifies that just the *first* navigational result is listed as a match
1035 // if suggested relevance scores were not sent.
1036 TEST_F(SearchProviderTest
, NavSuggestNoSuggestedRelevanceScores
) {
1037 QueryForInput(ASCIIToUTF16("a.c"), false, false);
1039 // Make sure the default providers suggest service was queried.
1040 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
1041 SearchProvider::kDefaultProviderURLFetcherID
);
1042 ASSERT_TRUE(fetcher
);
1044 // Tell the SearchProvider the suggest query is done.
1045 fetcher
->set_response_code(200);
1046 fetcher
->SetResponseString(
1047 "[\"a.c\",[\"a.com\", \"a.com/b\"],[\"a\", \"b\"],[],"
1048 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]");
1049 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
1052 // Run till the history results complete.
1053 RunTillProviderDone();
1055 // Make sure the only match is 'a.com' and it doesn't have a template_url.
1056 AutocompleteMatch nav_match
;
1057 EXPECT_TRUE(FindMatchWithDestination(GURL("http://a.com"), &nav_match
));
1058 EXPECT_TRUE(nav_match
.keyword
.empty());
1059 EXPECT_TRUE(nav_match
.allowed_to_be_default_match
);
1060 EXPECT_FALSE(FindMatchWithDestination(GURL("http://a.com/b"), &nav_match
));
1063 // Verifies that the most relevant suggest results are added properly.
1064 TEST_F(SearchProviderTest
, SuggestRelevance
) {
1065 QueryForInput(ASCIIToUTF16("a"), false, false);
1067 // Make sure the default provider's suggest service was queried.
1068 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
1069 SearchProvider::kDefaultProviderURLFetcherID
);
1070 ASSERT_TRUE(fetcher
);
1072 // Tell the SearchProvider the suggest query is done.
1073 fetcher
->set_response_code(200);
1074 fetcher
->SetResponseString("[\"a\",[\"a1\", \"a2\", \"a3\", \"a4\"]]");
1075 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
1078 // Run till the history results complete.
1079 RunTillProviderDone();
1081 // Check the expected verbatim and (first 3) suggestions' relative relevances.
1082 AutocompleteMatch verbatim
, match_a1
, match_a2
, match_a3
, match_a4
;
1083 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim
));
1084 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a1"), &match_a1
));
1085 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a2"), &match_a2
));
1086 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a3"), &match_a3
));
1087 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("a4"), &match_a4
));
1088 EXPECT_GT(verbatim
.relevance
, match_a1
.relevance
);
1089 EXPECT_GT(match_a1
.relevance
, match_a2
.relevance
);
1090 EXPECT_GT(match_a2
.relevance
, match_a3
.relevance
);
1091 EXPECT_TRUE(verbatim
.allowed_to_be_default_match
);
1092 EXPECT_TRUE(match_a1
.allowed_to_be_default_match
);
1093 EXPECT_TRUE(match_a2
.allowed_to_be_default_match
);
1094 EXPECT_TRUE(match_a3
.allowed_to_be_default_match
);
1097 // Verifies that the default provider abandons suggested relevance scores
1098 // when in keyword mode. This should happen regardless of whether the
1099 // keyword provider returns suggested relevance scores.
1100 TEST_F(SearchProviderTest
, DefaultProviderNoSuggestRelevanceInKeywordMode
) {
1102 const std::string default_provider_json
;
1103 const std::string keyword_provider_json
;
1104 const std::string matches
[5];
1106 // First, try an input where the keyword provider does not deliver
1107 // suggested relevance scores.
1108 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1109 "{\"google:verbatimrelevance\":9700,"
1110 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1111 "\"google:suggestrelevance\":[9900, 9800]}]",
1112 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"]}]",
1113 { "a", "akeyword-query", "k a", "adefault.com", "k adefault-query" } },
1115 // Now try with keyword provider suggested relevance scores.
1116 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1117 "{\"google:verbatimrelevance\":9700,"
1118 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1119 "\"google:suggestrelevance\":[9900, 9800]}]",
1120 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"],"
1121 "\"google:verbatimrelevance\":9500,"
1122 "\"google:suggestrelevance\":[9600]}]",
1123 { "akeyword-query", "a", "k a", "adefault.com", "k adefault-query" } }
1126 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
1127 QueryForInput(ASCIIToUTF16("k a"), false, true);
1128 net::TestURLFetcher
* default_fetcher
=
1129 test_factory_
.GetFetcherByID(
1130 SearchProvider::kDefaultProviderURLFetcherID
);
1131 ASSERT_TRUE(default_fetcher
);
1132 default_fetcher
->set_response_code(200);
1133 default_fetcher
->SetResponseString(cases
[i
].default_provider_json
);
1134 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
1135 net::TestURLFetcher
* keyword_fetcher
=
1136 test_factory_
.GetFetcherByID(
1137 SearchProvider::kKeywordProviderURLFetcherID
);
1138 ASSERT_TRUE(keyword_fetcher
);
1139 keyword_fetcher
->set_response_code(200);
1140 keyword_fetcher
->SetResponseString(cases
[i
].keyword_provider_json
);
1141 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
1142 RunTillProviderDone();
1144 const std::string description
= "for input with default_provider_json=" +
1145 cases
[i
].default_provider_json
+ " and keyword_provider_json=" +
1146 cases
[i
].keyword_provider_json
;
1147 const ACMatches
& matches
= provider_
->matches();
1148 ASSERT_LE(matches
.size(), ARRAYSIZE_UNSAFE(cases
[i
].matches
));
1150 // Ensure that the returned matches equal the expectations.
1151 for (; j
< matches
.size(); ++j
) {
1152 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
]), matches
[j
].contents
) <<
1155 // Ensure that no expected matches are missing.
1156 for (; j
< ARRAYSIZE_UNSAFE(cases
[i
].matches
); ++j
)
1157 EXPECT_EQ(std::string(), cases
[i
].matches
[j
]) << description
;
1161 // Verifies that suggest results with relevance scores are added
1162 // properly when using the default fetcher. When adding a new test
1163 // case to this test, please consider adding it to the tests in
1164 // KeywordFetcherSuggestRelevance below.
1165 TEST_F(SearchProviderTest
, DefaultFetcherSuggestRelevance
) {
1166 struct DefaultFetcherMatch
{
1167 std::string contents
;
1168 bool allowed_to_be_default_match
;
1170 const DefaultFetcherMatch kEmptyMatch
= { kNotApplicable
, false };
1172 const std::string json
;
1173 const DefaultFetcherMatch matches
[6];
1174 const std::string inline_autocompletion
;
1176 // Ensure that suggestrelevance scores reorder matches.
1177 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1178 { { "a", true }, { "c", false }, { "b", false }, kEmptyMatch
,
1179 kEmptyMatch
, kEmptyMatch
},
1181 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1182 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1183 "\"google:suggestrelevance\":[1, 2]}]",
1184 { { "a", true }, { "c.com", false }, { "b.com", false }, kEmptyMatch
,
1185 kEmptyMatch
, kEmptyMatch
},
1188 // Without suggested relevance scores, we should only allow one
1189 // navsuggest result to be be displayed.
1190 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1191 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1192 { { "a", true }, { "b.com", false }, kEmptyMatch
, kEmptyMatch
,
1193 kEmptyMatch
, kEmptyMatch
},
1196 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1197 // Negative values will have no effect; the calculated value will be used.
1198 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1199 "\"google:suggestrelevance\":[9998]}]",
1200 { { "a", true}, { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1203 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1204 "\"google:suggestrelevance\":[9999]}]",
1205 { { "a1", true }, { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1208 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1209 "\"google:suggestrelevance\":[9999]}]",
1210 { { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1213 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1214 "\"google:suggestrelevance\":[9999]}]",
1215 { { "a1", true }, { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1218 { "[\"a\",[\"http://a.com\"],[],[],"
1219 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1220 "\"google:verbatimrelevance\":9999,"
1221 "\"google:suggestrelevance\":[9998]}]",
1222 { { "a", true }, { "a.com", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1225 { "[\"a\",[\"http://a.com\"],[],[],"
1226 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1227 "\"google:verbatimrelevance\":9998,"
1228 "\"google:suggestrelevance\":[9999]}]",
1229 { { "a.com", true }, { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1232 { "[\"a\",[\"http://a.com\"],[],[],"
1233 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1234 "\"google:verbatimrelevance\":0,"
1235 "\"google:suggestrelevance\":[9999]}]",
1236 { { "a.com", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1239 { "[\"a\",[\"http://a.com\"],[],[],"
1240 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1241 "\"google:verbatimrelevance\":-1,"
1242 "\"google:suggestrelevance\":[9999]}]",
1243 { { "a.com", true }, { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1247 // Ensure that both types of relevance scores reorder matches together.
1248 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1249 "\"google:verbatimrelevance\":9998}]",
1250 { { "a1", true }, { "a", true }, { "a2", true }, kEmptyMatch
, kEmptyMatch
,
1254 // Ensure that only inlinable matches may be ranked as the highest result.
1255 // Ignore all suggested relevance scores if this constraint is violated.
1256 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1257 { { "a", true }, { "b", false }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1260 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1261 "\"google:verbatimrelevance\":0}]",
1262 { { "a", true }, { "b", false }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1265 { "[\"a\",[\"http://b.com\"],[],[],"
1266 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1267 "\"google:suggestrelevance\":[9999]}]",
1268 { { "a", true }, { "b.com", false }, kEmptyMatch
, kEmptyMatch
,
1269 kEmptyMatch
, kEmptyMatch
},
1271 { "[\"a\",[\"http://b.com\"],[],[],"
1272 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1273 "\"google:suggestrelevance\":[9999],"
1274 "\"google:verbatimrelevance\":0}]",
1275 { { "a", true }, { "b.com", false }, kEmptyMatch
, kEmptyMatch
,
1276 kEmptyMatch
, kEmptyMatch
},
1278 { "[\"a\",[\"https://a/\"],[],[],"
1279 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1280 "\"google:suggestrelevance\":[9999]}]",
1281 { { "https://a", true }, { "a", true }, kEmptyMatch
, kEmptyMatch
,
1282 kEmptyMatch
, kEmptyMatch
},
1285 // Ensure that the top result is ranked as highly as calculated verbatim.
1286 // Ignore the suggested verbatim relevance if this constraint is violated.
1287 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1288 { { "a", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1291 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1292 { { "a", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1295 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1296 "\"google:verbatimrelevance\":0}]",
1297 { { "a", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1300 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1301 "\"google:verbatimrelevance\":0}]",
1302 { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
,
1305 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1306 "\"google:verbatimrelevance\":2}]",
1307 { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
,
1310 { "[\"a\",[\"http://a.com\"],[],[],"
1311 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1312 "\"google:suggestrelevance\":[1],"
1313 "\"google:verbatimrelevance\":0}]",
1314 { { "a", true }, { "a.com", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1317 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1318 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1319 "\"google:suggestrelevance\":[1, 2],"
1320 "\"google:verbatimrelevance\":0}]",
1321 { { "a", true }, { "a2.com", true }, { "a1.com", true }, kEmptyMatch
,
1322 kEmptyMatch
, kEmptyMatch
},
1325 // Ensure that all suggestions are considered, regardless of order.
1326 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1327 "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1328 { { "a", true }, { "h", false }, { "g", false }, { "f", false },
1329 {"e", false }, {"d", false } },
1331 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1332 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1333 "\"http://h.com\"],[],[],"
1334 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1335 "\"NAVIGATION\", \"NAVIGATION\","
1336 "\"NAVIGATION\", \"NAVIGATION\","
1338 "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1339 { { "a", true }, { "h.com", false }, { "g.com", false },
1340 { "f.com", false }, {"e.com", false }, {"d.com", false } },
1343 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1344 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1345 { { "a", true }, { "a1", true }, { "a2", true }, kEmptyMatch
, kEmptyMatch
,
1348 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1349 { { "a", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1352 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1353 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1354 "\"google:suggestrelevance\":[1]}]",
1355 { { "a", true }, { "a1.com", true }, kEmptyMatch
, kEmptyMatch
,
1356 kEmptyMatch
, kEmptyMatch
},
1358 { "[\"a\",[\"http://a1.com\"],[],[],"
1359 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1360 "\"google:suggestrelevance\":[9999, 1]}]",
1361 { { "a", true }, { "a1.com", true }, kEmptyMatch
, kEmptyMatch
,
1362 kEmptyMatch
, kEmptyMatch
},
1365 // Ensure that all 'verbatim' results are merged with their maximum score.
1366 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1367 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1368 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
,
1371 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1372 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1373 "\"google:verbatimrelevance\":0}]",
1374 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
,
1378 // Ensure that verbatim is always generated without other suggestions.
1379 // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
1380 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1381 { { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1384 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1385 { { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1390 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
1391 QueryForInput(ASCIIToUTF16("a"), false, false);
1392 net::TestURLFetcher
* fetcher
=
1393 test_factory_
.GetFetcherByID(
1394 SearchProvider::kDefaultProviderURLFetcherID
);
1395 ASSERT_TRUE(fetcher
);
1396 fetcher
->set_response_code(200);
1397 fetcher
->SetResponseString(cases
[i
].json
);
1398 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
1399 RunTillProviderDone();
1401 const std::string description
= "for input with json=" + cases
[i
].json
;
1402 const ACMatches
& matches
= provider_
->matches();
1403 // The top match must inline and score as highly as calculated verbatim.
1404 ASSERT_FALSE(matches
.empty());
1405 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
1406 matches
[0].inline_autocompletion
) << description
;
1407 EXPECT_GE(matches
[0].relevance
, 1300) << description
;
1409 ASSERT_LE(matches
.size(), ARRAYSIZE_UNSAFE(cases
[i
].matches
));
1411 // Ensure that the returned matches equal the expectations.
1412 for (; j
< matches
.size(); ++j
) {
1413 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
].contents
),
1414 matches
[j
].contents
) << description
;
1415 EXPECT_EQ(cases
[i
].matches
[j
].allowed_to_be_default_match
,
1416 matches
[j
].allowed_to_be_default_match
) << description
;
1418 // Ensure that no expected matches are missing.
1419 for (; j
< ARRAYSIZE_UNSAFE(cases
[i
].matches
); ++j
)
1420 EXPECT_EQ(kNotApplicable
, cases
[i
].matches
[j
].contents
) <<
1421 "Case # " << i
<< " " << description
;
1425 // This test is like DefaultFetcherSuggestRelevance above except it enables
1426 // the field trial that causes the omnibox to be willing to reorder matches
1427 // to guarantee the top result is a legal default match. This field trial
1428 // causes SearchProvider to allow some constraints to be violated that it
1429 // wouldn't normally because the omnibox will fix the problems later.
1430 TEST_F(SearchProviderTest
, DefaultFetcherSuggestRelevanceWithReorder
) {
1431 struct DefaultFetcherMatch
{
1432 std::string contents
;
1433 bool allowed_to_be_default_match
;
1435 const DefaultFetcherMatch kEmptyMatch
= { kNotApplicable
, false };
1437 const std::string json
;
1438 const DefaultFetcherMatch matches
[6];
1439 const std::string inline_autocompletion
;
1441 // Ensure that suggestrelevance scores reorder matches.
1442 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1443 { { "a", true }, { "c", false }, { "b", false }, kEmptyMatch
, kEmptyMatch
,
1446 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1447 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1448 "\"google:suggestrelevance\":[1, 2]}]",
1449 { { "a", true }, { "c.com", false }, { "b.com", false }, kEmptyMatch
,
1450 kEmptyMatch
, kEmptyMatch
},
1453 // Without suggested relevance scores, we should only allow one
1454 // navsuggest result to be be displayed.
1455 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1456 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1457 { { "a", true }, { "b.com", false }, kEmptyMatch
, kEmptyMatch
,
1458 kEmptyMatch
, kEmptyMatch
},
1461 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1462 // Negative values will have no effect; the calculated value will be used.
1463 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1464 "\"google:suggestrelevance\":[9998]}]",
1465 { { "a", true}, { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1468 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1469 "\"google:suggestrelevance\":[9999]}]",
1470 { { "a1", true }, { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1473 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1474 "\"google:suggestrelevance\":[9999]}]",
1475 { { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1478 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1479 "\"google:suggestrelevance\":[9999]}]",
1480 { { "a1", true }, { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1483 { "[\"a\",[\"http://a.com\"],[],[],"
1484 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1485 "\"google:verbatimrelevance\":9999,"
1486 "\"google:suggestrelevance\":[9998]}]",
1487 { { "a", true }, { "a.com", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1490 { "[\"a\",[\"http://a.com\"],[],[],"
1491 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1492 "\"google:verbatimrelevance\":9998,"
1493 "\"google:suggestrelevance\":[9999]}]",
1494 { { "a.com", true }, { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1497 { "[\"a\",[\"http://a.com\"],[],[],"
1498 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1499 "\"google:verbatimrelevance\":0,"
1500 "\"google:suggestrelevance\":[9999]}]",
1501 { { "a.com", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1504 { "[\"a\",[\"http://a.com\"],[],[],"
1505 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1506 "\"google:verbatimrelevance\":-1,"
1507 "\"google:suggestrelevance\":[9999]}]",
1508 { { "a.com", true }, { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1512 // Ensure that both types of relevance scores reorder matches together.
1513 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1514 "\"google:verbatimrelevance\":9998}]",
1515 { { "a1", true }, { "a", true }, { "a2", true }, kEmptyMatch
, kEmptyMatch
,
1519 // Allow non-inlineable matches to be the highest-scoring match but,
1520 // if the result set lacks a single inlineable result, abandon suggested
1521 // relevance scores entirely.
1522 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1523 { { "b", false }, { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1526 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1527 "\"google:verbatimrelevance\":0}]",
1528 { { "a", true }, { "b", false }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1531 { "[\"a\",[\"http://b.com\"],[],[],"
1532 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1533 "\"google:suggestrelevance\":[9999]}]",
1534 { { "b.com", false }, { "a", true }, kEmptyMatch
, kEmptyMatch
,
1535 kEmptyMatch
, kEmptyMatch
},
1537 { "[\"a\",[\"http://b.com\"],[],[],"
1538 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1539 "\"google:suggestrelevance\":[9999],"
1540 "\"google:verbatimrelevance\":0}]",
1541 { { "a", true }, { "b.com", false }, kEmptyMatch
, kEmptyMatch
,
1542 kEmptyMatch
, kEmptyMatch
},
1545 // Allow low-scoring matches.
1546 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1547 { { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1550 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1551 { { "a1", true }, { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1554 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1555 "\"google:verbatimrelevance\":0}]",
1556 { { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1559 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1560 "\"google:verbatimrelevance\":0}]",
1561 { { "a2", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1564 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1565 "\"google:verbatimrelevance\":2}]",
1566 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
,
1569 { "[\"a\",[\"http://a.com\"],[],[],"
1570 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1571 "\"google:suggestrelevance\":[1],"
1572 "\"google:verbatimrelevance\":0}]",
1573 { { "a.com", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1576 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1577 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1578 "\"google:suggestrelevance\":[1, 2],"
1579 "\"google:verbatimrelevance\":0}]",
1580 { { "a2.com", true }, { "a1.com", true }, kEmptyMatch
, kEmptyMatch
,
1581 kEmptyMatch
, kEmptyMatch
},
1584 // Ensure that all suggestions are considered, regardless of order.
1585 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1586 "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1587 { { "a", true }, { "h", false }, { "g", false }, { "f", false },
1588 { "e", false }, { "d", false } },
1590 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1591 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1592 "\"http://h.com\"],[],[],"
1593 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1594 "\"NAVIGATION\", \"NAVIGATION\","
1595 "\"NAVIGATION\", \"NAVIGATION\","
1597 "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1598 { { "a", true }, { "h.com", false }, { "g.com", false },
1599 { "f.com", false }, { "e.com", false }, { "d.com", false } },
1602 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1603 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1604 { { "a", true }, { "a1", true }, { "a2", true }, kEmptyMatch
, kEmptyMatch
,
1607 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1608 { { "a", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1611 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1612 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1613 "\"google:suggestrelevance\":[1]}]",
1614 { { "a", true }, { "a1.com", true }, kEmptyMatch
, kEmptyMatch
,
1615 kEmptyMatch
, kEmptyMatch
},
1617 { "[\"a\",[\"http://a1.com\"],[],[],"
1618 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1619 "\"google:suggestrelevance\":[9999, 1]}]",
1620 { { "a", true }, { "a1.com", true }, kEmptyMatch
, kEmptyMatch
,
1621 kEmptyMatch
, kEmptyMatch
},
1624 // Ensure that all 'verbatim' results are merged with their maximum score.
1625 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1626 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1627 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
,
1630 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1631 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1632 "\"google:verbatimrelevance\":0}]",
1633 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch
, kEmptyMatch
,
1637 // Ensure that verbatim is always generated without other suggestions.
1638 // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
1639 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1640 { { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1643 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1644 { { "a", true }, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
,
1649 std::map
<std::string
, std::string
> params
;
1650 params
[std::string(OmniboxFieldTrial::kReorderForLegalDefaultMatchRule
) +
1651 ":*:*"] = OmniboxFieldTrial::kReorderForLegalDefaultMatchRuleEnabled
;
1652 ASSERT_TRUE(chrome_variations::AssociateVariationParams(
1653 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
1654 base::FieldTrialList::CreateFieldTrial(
1655 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
1657 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
1658 QueryForInput(ASCIIToUTF16("a"), false, false);
1659 net::TestURLFetcher
* fetcher
=
1660 test_factory_
.GetFetcherByID(
1661 SearchProvider::kDefaultProviderURLFetcherID
);
1662 ASSERT_TRUE(fetcher
);
1663 fetcher
->set_response_code(200);
1664 fetcher
->SetResponseString(cases
[i
].json
);
1665 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
1666 RunTillProviderDone();
1668 const std::string description
= "for input with json=" + cases
[i
].json
;
1669 const ACMatches
& matches
= provider_
->matches();
1670 ASSERT_FALSE(matches
.empty());
1671 // Find the first match that's allowed to be the default match and check
1672 // its inline_autocompletion.
1673 ACMatches::const_iterator it
= FindDefaultMatch(matches
);
1674 ASSERT_NE(matches
.end(), it
);
1675 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
1676 it
->inline_autocompletion
) << description
;
1678 ASSERT_LE(matches
.size(), ARRAYSIZE_UNSAFE(cases
[i
].matches
));
1680 // Ensure that the returned matches equal the expectations.
1681 for (; j
< matches
.size(); ++j
) {
1682 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
].contents
),
1683 matches
[j
].contents
) << description
;
1684 EXPECT_EQ(cases
[i
].matches
[j
].allowed_to_be_default_match
,
1685 matches
[j
].allowed_to_be_default_match
) << description
;
1687 // Ensure that no expected matches are missing.
1688 for (; j
< ARRAYSIZE_UNSAFE(cases
[i
].matches
); ++j
)
1689 EXPECT_EQ(kNotApplicable
, cases
[i
].matches
[j
].contents
) <<
1690 "Case # " << i
<< " " << description
;
1694 // Verifies that suggest results with relevance scores are added
1695 // properly when using the keyword fetcher. This is similar to the
1696 // test DefaultFetcherSuggestRelevance above but this uses inputs that
1697 // trigger keyword suggestions (i.e., "k a" rather than "a") and has
1698 // different expectations (because now the results are a mix of
1699 // keyword suggestions and default provider suggestions). When a new
1700 // test is added to this TEST_F, please consider if it would be
1701 // appropriate to add to DefaultFetcherSuggestRelevance as well.
1702 TEST_F(SearchProviderTest
, KeywordFetcherSuggestRelevance
) {
1703 struct KeywordFetcherMatch
{
1704 std::string contents
;
1706 bool allowed_to_be_default_match
;
1708 const KeywordFetcherMatch kEmptyMatch
= { kNotApplicable
, false, false };
1710 const std::string json
;
1711 const KeywordFetcherMatch matches
[6];
1712 const std::string inline_autocompletion
;
1714 // Ensure that suggest relevance scores reorder matches and that
1715 // the keyword verbatim (lacking a suggested verbatim score) beats
1716 // the default provider verbatim.
1717 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1718 { { "a", true, true },
1719 { "k a", false, false },
1720 { "c", true, false },
1721 { "b", true, false },
1722 kEmptyMatch
, kEmptyMatch
},
1724 // Again, check that relevance scores reorder matches, just this
1725 // time with navigation matches. This also checks that with
1726 // suggested relevance scores we allow multiple navsuggest results.
1727 // Note that navsuggest results that come from a keyword provider
1728 // are marked as not a keyword result. (They don't go to a
1729 // keyword search engine.)
1730 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
1731 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1732 "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
1733 { { "a", true, true },
1734 { "d", true, false },
1735 { "c.com", false, false },
1736 { "b.com", false, false },
1737 { "k a", false, false },
1741 // Without suggested relevance scores, we should only allow one
1742 // navsuggest result to be be displayed.
1743 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1744 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1745 { { "a", true, true },
1746 { "b.com", false, false },
1747 { "k a", false, false },
1748 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1751 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1752 // Negative values will have no effect; the calculated value will be used.
1753 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1754 "\"google:suggestrelevance\":[9998]}]",
1755 { { "a", true, true },
1756 { "a1", true, true },
1757 { "k a", false, false },
1758 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1760 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1761 "\"google:suggestrelevance\":[9999]}]",
1762 { { "a1", true, true },
1763 { "a", true, true },
1764 { "k a", false, false },
1765 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1767 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1768 "\"google:suggestrelevance\":[9999]}]",
1769 { { "a1", true, true },
1770 { "k a", false, false },
1771 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1773 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1774 "\"google:suggestrelevance\":[9999]}]",
1775 { { "a1", true, true },
1776 { "a", true, true },
1777 { "k a", false, false },
1778 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1780 { "[\"a\",[\"http://a.com\"],[],[],"
1781 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1782 "\"google:verbatimrelevance\":9999,"
1783 "\"google:suggestrelevance\":[9998]}]",
1784 { { "a", true, true },
1785 { "a.com", false, false },
1786 { "k a", false, false },
1787 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1790 // Ensure that both types of relevance scores reorder matches together.
1791 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1792 "\"google:verbatimrelevance\":9998}]",
1793 { { "a1", true, true },
1794 { "a", true, true },
1795 { "a2", true, true },
1796 { "k a", false, false },
1797 kEmptyMatch
, kEmptyMatch
},
1800 // Ensure that only inlinable matches may be ranked as the highest result.
1801 // Ignore all suggested relevance scores if this constraint is violated.
1802 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1803 { { "a", true, true },
1804 { "b", true, false },
1805 { "k a", false, false },
1806 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1808 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1809 "\"google:verbatimrelevance\":0}]",
1810 { { "a", true, true },
1811 { "b", true, false },
1812 { "k a", false, false },
1813 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1815 { "[\"a\",[\"http://b.com\"],[],[],"
1816 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1817 "\"google:suggestrelevance\":[9999]}]",
1818 { { "a", true, true },
1819 { "b.com", false, false },
1820 { "k a", false, false },
1821 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1823 { "[\"a\",[\"http://b.com\"],[],[],"
1824 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1825 "\"google:suggestrelevance\":[9999],"
1826 "\"google:verbatimrelevance\":0}]",
1827 { { "a", true, true },
1828 { "b.com", false, false },
1829 { "k a", false, false },
1830 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1833 // Ensure that the top result is ranked as highly as calculated verbatim.
1834 // Ignore the suggested verbatim relevance if this constraint is violated.
1835 // Note that keyword suggestions by default (not in suggested relevance
1836 // mode) score more highly than the default verbatim.
1837 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1838 { { "a", true, true },
1839 { "a1", true, true },
1840 { "k a", false, false },
1841 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1843 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1844 { { "a", true, true },
1845 { "a1", true, true },
1846 { "k a", false, false },
1847 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1849 // Continuing the same category of tests, but make sure we keep the
1850 // suggested relevance scores even as we discard the verbatim relevance
1852 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1853 "\"google:verbatimrelevance\":0}]",
1854 { { "a", true, true },
1855 { "k a", false, false },
1856 { "a1", true, true },
1857 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1859 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1860 "\"google:verbatimrelevance\":0}]",
1861 { { "a", true, true },
1862 { "k a", false, false },
1863 { "a2", true, true },
1864 { "a1", true, true },
1865 kEmptyMatch
, kEmptyMatch
},
1867 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1868 "\"google:verbatimrelevance\":2}]",
1869 { { "a", true, true },
1870 { "k a", false, false },
1871 { "a2", true, true },
1872 { "a1", true, true },
1873 kEmptyMatch
, kEmptyMatch
},
1876 // Ensure that all suggestions are considered, regardless of order.
1877 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1878 "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1879 { { "a", true, true },
1880 { "k a", false, false },
1881 { "h", true, false },
1882 { "g", true, false },
1883 { "f", true, false },
1884 { "e", true, false } },
1886 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1887 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1888 "\"http://h.com\"],[],[],"
1889 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1890 "\"NAVIGATION\", \"NAVIGATION\","
1891 "\"NAVIGATION\", \"NAVIGATION\","
1893 "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1894 { { "a", true, true },
1895 { "k a", false, false },
1896 { "h.com", false, false },
1897 { "g.com", false, false },
1898 { "f.com", false, false },
1899 { "e.com", false, false } },
1902 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1903 // Note that keyword suggestions by default (not in suggested relevance
1904 // mode) score more highly than the default verbatim.
1905 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1906 { { "a", true, true },
1907 { "a1", true, true },
1908 { "a2", true, true },
1909 { "k a", false, false },
1910 kEmptyMatch
, kEmptyMatch
},
1912 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1913 { { "a", true, true },
1914 { "a1", true, true },
1915 { "k a", false, false },
1916 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1918 // In this case, ignoring the suggested relevance scores means we keep
1919 // only one navsuggest result.
1920 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1921 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1922 "\"google:suggestrelevance\":[1]}]",
1923 { { "a", true, true },
1924 { "a1.com", false, false },
1925 { "k a", false, false },
1926 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1928 { "[\"a\",[\"http://a1.com\"],[],[],"
1929 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1930 "\"google:suggestrelevance\":[9999, 1]}]",
1931 { { "a", true, true },
1932 { "a1.com", false, false },
1933 { "k a", false, false },
1934 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1937 // Ensure that all 'verbatim' results are merged with their maximum score.
1938 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1939 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1940 { { "a2", true, true },
1941 { "a", true, true },
1942 { "a1", true, true },
1943 { "k a", false, false },
1944 kEmptyMatch
, kEmptyMatch
},
1946 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1947 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1948 "\"google:verbatimrelevance\":0}]",
1949 { { "a2", true, true },
1950 { "a", true, true },
1951 { "a1", true, true },
1952 { "k a", false, false },
1953 kEmptyMatch
, kEmptyMatch
},
1956 // Ensure that verbatim is always generated without other suggestions.
1957 // TODO(mpearson): Ensure the value of verbatimrelevance is respected
1958 // (except when suggested relevances are ignored).
1959 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1960 { { "a", true, true },
1961 { "k a", false, false },
1962 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1964 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1965 { { "a", true, true },
1966 { "k a", false, false },
1967 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
1970 // Check that navsuggestions will be demoted below queries.
1971 // (Navsuggestions are not allowed to appear first.) In the process,
1972 // make sure the navsuggestions still remain in the same order.
1973 // First, check the situation where navsuggest scores more than verbatim
1974 // and there are no query suggestions.
1975 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1976 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1977 "\"google:verbatimrelevance\":9990,"
1978 "\"google:suggestrelevance\":[9998, 9999]}]",
1979 { { "a", true, true },
1980 { "a2.com", false, false },
1981 { "a1.com", false, false },
1982 { "k a", false, false },
1983 kEmptyMatch
, kEmptyMatch
},
1985 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1986 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1987 "\"google:verbatimrelevance\":9990,"
1988 "\"google:suggestrelevance\":[9999, 9998]}]",
1989 { { "a", true, true },
1990 { "a1.com", false, false },
1991 { "a2.com", false, false },
1992 { "k a", false, false },
1993 kEmptyMatch
, kEmptyMatch
},
1995 { "[\"a\",[\"https://a/\"],[],[],"
1996 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1997 "\"google:suggestrelevance\":[9999]}]",
1998 { { "a", true, true },
1999 { "https://a", false, false },
2000 { "k a", false, false },
2001 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2003 // Check when navsuggest scores more than verbatim and there is query
2004 // suggestion but it scores lower.
2005 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2006 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2007 "\"google:verbatimrelevance\":9990,"
2008 "\"google:suggestrelevance\":[9998, 9999, 1300]}]",
2009 { { "a", true, true },
2010 { "a2.com", false, false },
2011 { "a1.com", false, false },
2012 { "a3", true, true },
2013 { "k a", false, false },
2016 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2017 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2018 "\"google:verbatimrelevance\":9990,"
2019 "\"google:suggestrelevance\":[9999, 9998, 1300]}]",
2020 { { "a", true, true },
2021 { "a1.com", false, false },
2022 { "a2.com", false, false },
2023 { "a3", true, true },
2024 { "k a", false, false },
2027 // Check when navsuggest scores more than a query suggestion. There is
2028 // a verbatim but it scores lower.
2029 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2030 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2031 "\"google:verbatimrelevance\":9990,"
2032 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
2033 { { "a3", true, true },
2034 { "a2.com", false, false },
2035 { "a1.com", false, false },
2036 { "a", true, true },
2037 { "k a", false, false },
2040 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2041 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2042 "\"google:verbatimrelevance\":9990,"
2043 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
2044 { { "a3", true, true },
2045 { "a1.com", false, false },
2046 { "a2.com", false, false },
2047 { "a", true, true },
2048 { "k a", false, false },
2051 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2052 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2053 "\"google:verbatimrelevance\":0,"
2054 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
2055 { { "a3", true, true },
2056 { "a2.com", false, false },
2057 { "a1.com", false, false },
2058 { "k a", false, false },
2059 kEmptyMatch
, kEmptyMatch
},
2061 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2062 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2063 "\"google:verbatimrelevance\":0,"
2064 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
2065 { { "a3", true, true },
2066 { "a1.com", false, false },
2067 { "a2.com", false, false },
2068 { "k a", false, false },
2069 kEmptyMatch
, kEmptyMatch
},
2071 // Check when there is neither verbatim nor a query suggestion that,
2072 // because we can't demote navsuggestions below a query suggestion,
2073 // we abandon suggested relevance scores entirely. One consequence is
2074 // that this means we restore the keyword verbatim match. Note
2075 // that in this case of abandoning suggested relevance scores, we still
2076 // keep the navsuggestions in the same order, but we revert to only allowing
2077 // one navigation to appear because the scores are completely local.
2078 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
2079 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2080 "\"google:verbatimrelevance\":0,"
2081 "\"google:suggestrelevance\":[9998, 9999]}]",
2082 { { "a", true, true },
2083 { "a2.com", false, false },
2084 { "k a", false, false },
2085 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2087 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
2088 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2089 "\"google:verbatimrelevance\":0,"
2090 "\"google:suggestrelevance\":[9999, 9998]}]",
2091 { { "a", true, true },
2092 { "a1.com", false, false },
2093 { "k a", false, false },
2094 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2096 // More checks that everything works when it's not necessary to demote.
2097 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2098 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2099 "\"google:verbatimrelevance\":9990,"
2100 "\"google:suggestrelevance\":[9997, 9998, 9999]}]",
2101 { { "a3", true, true },
2102 { "a2.com", false, false },
2103 { "a1.com", false, false },
2104 { "a", true, true },
2105 { "k a", false, false },
2108 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2109 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2110 "\"google:verbatimrelevance\":9990,"
2111 "\"google:suggestrelevance\":[9998, 9997, 9999]}]",
2112 { { "a3", true, true },
2113 { "a1.com", false, false },
2114 { "a2.com", false, false },
2115 { "a", true, true },
2116 { "k a", false, false },
2121 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
2122 QueryForInput(ASCIIToUTF16("k a"), false, true);
2124 // Set up a default fetcher with no results.
2125 net::TestURLFetcher
* default_fetcher
=
2126 test_factory_
.GetFetcherByID(
2127 SearchProvider::kDefaultProviderURLFetcherID
);
2128 ASSERT_TRUE(default_fetcher
);
2129 default_fetcher
->set_response_code(200);
2130 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
2131 default_fetcher
= NULL
;
2133 // Set up a keyword fetcher with provided results.
2134 net::TestURLFetcher
* keyword_fetcher
=
2135 test_factory_
.GetFetcherByID(
2136 SearchProvider::kKeywordProviderURLFetcherID
);
2137 ASSERT_TRUE(keyword_fetcher
);
2138 keyword_fetcher
->set_response_code(200);
2139 keyword_fetcher
->SetResponseString(cases
[i
].json
);
2140 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
2141 keyword_fetcher
= NULL
;
2142 RunTillProviderDone();
2144 const std::string description
= "for input with json=" + cases
[i
].json
;
2145 const ACMatches
& matches
= provider_
->matches();
2146 // The top match must inline and score as highly as calculated verbatim.
2147 ASSERT_FALSE(matches
.empty());
2148 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
2149 matches
[0].inline_autocompletion
) << description
;
2150 EXPECT_GE(matches
[0].relevance
, 1300) << description
;
2152 ASSERT_LE(matches
.size(), ARRAYSIZE_UNSAFE(cases
[i
].matches
));
2154 // Ensure that the returned matches equal the expectations.
2155 for (; j
< matches
.size(); ++j
) {
2156 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
].contents
),
2157 matches
[j
].contents
) << description
;
2158 EXPECT_EQ(cases
[i
].matches
[j
].from_keyword
,
2159 matches
[j
].keyword
== ASCIIToUTF16("k")) << description
;
2160 EXPECT_EQ(cases
[i
].matches
[j
].allowed_to_be_default_match
,
2161 matches
[j
].allowed_to_be_default_match
) << description
;
2163 // Ensure that no expected matches are missing.
2164 for (; j
< ARRAYSIZE_UNSAFE(cases
[i
].matches
); ++j
)
2165 EXPECT_EQ(kNotApplicable
, cases
[i
].matches
[j
].contents
) <<
2166 "Case # " << i
<< " " << description
;
2170 // This test is like KeywordFetcherSuggestRelevance above except it
2171 // enables the field trial that causes the omnibox to be willing to
2172 // reorder matches to guarantee the top result is a legal default
2173 // match. This field trial causes SearchProvider to allow some
2174 // constraints to be violated that it wouldn't normally because the
2175 // omnibox will fix the problems later.
2176 TEST_F(SearchProviderTest
, KeywordFetcherSuggestRelevanceWithReorder
) {
2177 struct KeywordFetcherMatch
{
2178 std::string contents
;
2180 bool allowed_to_be_default_match
;
2182 const KeywordFetcherMatch kEmptyMatch
= { kNotApplicable
, false, false };
2184 const std::string json
;
2185 const KeywordFetcherMatch matches
[6];
2186 const std::string inline_autocompletion
;
2188 // Ensure that suggest relevance scores reorder matches and that
2189 // the keyword verbatim (lacking a suggested verbatim score) beats
2190 // the default provider verbatim.
2191 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2192 { { "a", true, true },
2193 { "k a", false, false },
2194 { "c", true, false },
2195 { "b", true, false },
2196 kEmptyMatch
, kEmptyMatch
},
2198 // Again, check that relevance scores reorder matches, just this
2199 // time with navigation matches. This also checks that with
2200 // suggested relevance scores we allow multiple navsuggest results.
2201 // Note that navsuggest results that come from a keyword provider
2202 // are marked as not a keyword result. (They don't go to a
2203 // keyword search engine.)
2204 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
2205 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2206 "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
2207 { { "a", true, true },
2208 { "d", true, false },
2209 { "c.com", false, false },
2210 { "b.com", false, false },
2211 { "k a", false, false },
2215 // Without suggested relevance scores, we should only allow one
2216 // navsuggest result to be be displayed.
2217 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
2218 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
2219 { { "a", true, true },
2220 { "b.com", false, false },
2221 { "k a", false, false },
2222 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2225 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
2226 // Negative values will have no effect; the calculated value will be used.
2227 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
2228 "\"google:suggestrelevance\":[9998]}]",
2229 { { "a", true, true },
2230 { "a1", true, true },
2231 { "k a", false, false },
2232 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2234 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
2235 "\"google:suggestrelevance\":[9999]}]",
2236 { { "a1", true, true },
2237 { "a", true, true },
2238 { "k a", false, false },
2239 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2241 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
2242 "\"google:suggestrelevance\":[9999]}]",
2243 { { "a1", true, true },
2244 { "k a", false, false },
2245 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2247 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
2248 "\"google:suggestrelevance\":[9999]}]",
2249 { { "a1", true, true },
2250 { "a", true, true },
2251 { "k a", false, false },
2252 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2254 { "[\"a\",[\"http://a.com\"],[],[],"
2255 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2256 "\"google:verbatimrelevance\":9999,"
2257 "\"google:suggestrelevance\":[9998]}]",
2258 { { "a", true, true },
2259 { "a.com", false, false },
2260 { "k a", false, false },
2261 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2264 // Ensure that both types of relevance scores reorder matches together.
2265 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
2266 "\"google:verbatimrelevance\":9998}]",
2267 { { "a1", true, true },
2268 { "a", true, true },
2269 { "a2", true, true },
2270 { "k a", false, false },
2271 kEmptyMatch
, kEmptyMatch
},
2274 // Check that non-inlinable matches may be ranked as the highest result
2275 // if there is at least one inlineable match.
2276 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
2277 { { "b", true, false },
2278 { "a", true, true },
2279 { "k a", false, false },
2280 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2282 { "[\"a\",[\"http://b.com\"],[],[],"
2283 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2284 "\"google:suggestrelevance\":[9999]}]",
2285 { { "b.com", false, false },
2286 { "a", true, true },
2287 { "k a", false, false },
2288 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2290 // On the other hand, if there is no inlineable match, restore
2291 // the keyword verbatim score.
2292 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
2293 "\"google:verbatimrelevance\":0}]",
2294 { { "b", true, false },
2295 { "a", true, true },
2296 { "k a", false, false },
2297 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2299 { "[\"a\",[\"http://b.com\"],[],[],"
2300 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2301 "\"google:suggestrelevance\":[9999],"
2302 "\"google:verbatimrelevance\":0}]",
2303 { { "b.com", false, false },
2304 { "a", true, true },
2305 { "k a", false, false },
2306 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2309 // The top result does not have to score as highly as calculated
2310 // verbatim. i.e., there are no minimum score restrictions in
2312 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
2313 { { "a1", true, true },
2314 { "k a", false, false },
2315 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2317 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
2318 { { "a1", true, true },
2319 { "k a", false, false },
2320 { "a", true, true },
2321 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2323 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
2324 "\"google:verbatimrelevance\":0}]",
2325 { { "k a", false, false },
2326 { "a1", true, true },
2327 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2329 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
2330 "\"google:verbatimrelevance\":0}]",
2332 { "k a", false, false },
2333 { "a2", true, true },
2334 { "a1", true, true },
2335 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2337 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
2338 "\"google:verbatimrelevance\":2}]",
2339 { { "k a", false, false },
2340 { "a2", true, true },
2341 { "a", true, true },
2342 { "a1", true, true },
2343 kEmptyMatch
, kEmptyMatch
},
2346 // Ensure that all suggestions are considered, regardless of order.
2347 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
2348 "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
2349 { { "a", true, true },
2350 { "k a", false, false },
2351 { "h", true, false },
2352 { "g", true, false },
2353 { "f", true, false },
2354 { "e", true, false } },
2356 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
2357 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
2358 "\"http://h.com\"],[],[],"
2359 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
2360 "\"NAVIGATION\", \"NAVIGATION\","
2361 "\"NAVIGATION\", \"NAVIGATION\","
2363 "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
2364 { { "a", true, true },
2365 { "k a", false, false },
2366 { "h.com", false, false },
2367 { "g.com", false, false },
2368 { "f.com", false, false },
2369 { "e.com", false, false } },
2372 // Ensure that incorrectly sized suggestion relevance lists are ignored.
2373 // Note that keyword suggestions by default (not in suggested relevance
2374 // mode) score more highly than the default verbatim.
2375 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
2376 { { "a", true, true },
2377 { "a1", true, true },
2378 { "a2", true, true },
2379 { "k a", false, false },
2380 kEmptyMatch
, kEmptyMatch
},
2382 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
2383 { { "a", true, true },
2384 { "a1", true, true },
2385 { "k a", false, false },
2386 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2388 // In this case, ignoring the suggested relevance scores means we keep
2389 // only one navsuggest result.
2390 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
2391 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2392 "\"google:suggestrelevance\":[1]}]",
2393 { { "a", true, true },
2394 { "a1.com", false, false },
2395 { "k a", false, false },
2396 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2398 { "[\"a\",[\"http://a1.com\"],[],[],"
2399 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2400 "\"google:suggestrelevance\":[9999, 1]}]",
2401 { { "a", true, true },
2402 { "a1.com", false, false },
2403 { "k a", false, false },
2404 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2407 // Ensure that all 'verbatim' results are merged with their maximum score.
2408 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
2409 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
2410 { { "a2", true, true },
2411 { "a", true, true },
2412 { "a1", true, true },
2413 { "k a", false, false },
2414 kEmptyMatch
, kEmptyMatch
},
2416 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
2417 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
2418 "\"google:verbatimrelevance\":0}]",
2419 { { "a2", true, true },
2420 { "a", true, true },
2421 { "a1", true, true },
2422 { "k a", false, false },
2423 kEmptyMatch
, kEmptyMatch
},
2426 // Ensure that verbatim is always generated without other suggestions.
2427 // TODO(mpearson): Ensure the value of verbatimrelevance is respected
2428 // (except when suggested relevances are ignored).
2429 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
2430 { { "k a", false, false },
2431 { "a", true, true },
2432 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2434 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
2435 { { "a", true, true },
2436 { "k a", false, false },
2437 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2440 // In reorder mode, navsuggestions will not need to be demoted (because
2441 // they are marked as not allowed to be default match and will be
2442 // reordered as necessary).
2443 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
2444 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2445 "\"google:verbatimrelevance\":9990,"
2446 "\"google:suggestrelevance\":[9998, 9999]}]",
2447 { { "a2.com", false, false },
2448 { "a1.com", false, false },
2449 { "a", true, true },
2450 { "k a", false, false },
2451 kEmptyMatch
, kEmptyMatch
},
2453 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
2454 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2455 "\"google:verbatimrelevance\":9990,"
2456 "\"google:suggestrelevance\":[9999, 9998]}]",
2457 { { "a1.com", false, false },
2458 { "a2.com", false, false },
2459 { "a", true, true },
2460 { "k a", false, false },
2461 kEmptyMatch
, kEmptyMatch
},
2463 { "[\"a\",[\"https://a/\"],[],[],"
2464 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2465 "\"google:suggestrelevance\":[9999]}]",
2466 { { "https://a", false, false },
2467 { "a", true, true },
2468 { "k a", false, false },
2469 kEmptyMatch
, kEmptyMatch
, kEmptyMatch
},
2471 // Check when navsuggest scores more than verbatim and there is query
2472 // suggestion but it scores lower.
2473 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2474 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2475 "\"google:verbatimrelevance\":9990,"
2476 "\"google:suggestrelevance\":[9998, 9999, 1300]}]",
2477 { { "a2.com", false, false },
2478 { "a1.com", false, false },
2479 { "a", true, true },
2480 { "a3", true, true },
2481 { "k a", false, false },
2484 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2485 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2486 "\"google:verbatimrelevance\":9990,"
2487 "\"google:suggestrelevance\":[9999, 9998, 1300]}]",
2488 { { "a1.com", false, false },
2489 { "a2.com", false, false },
2490 { "a", true, true },
2491 { "a3", true, true },
2492 { "k a", false, false },
2495 // Check when navsuggest scores more than a query suggestion. There is
2496 // a verbatim but it scores lower.
2497 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2498 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2499 "\"google:verbatimrelevance\":9990,"
2500 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
2501 { { "a2.com", false, false },
2502 { "a1.com", false, false },
2503 { "a3", true, true },
2504 { "a", true, true },
2505 { "k a", false, false },
2508 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2509 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2510 "\"google:verbatimrelevance\":9990,"
2511 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
2512 { { "a1.com", false, false },
2513 { "a2.com", false, false },
2514 { "a3", true, true },
2515 { "a", true, true },
2516 { "k a", false, false },
2519 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2520 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2521 "\"google:verbatimrelevance\":0,"
2522 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
2523 { { "a2.com", false, false },
2524 { "a1.com", false, false },
2525 { "a3", true, true },
2526 { "k a", false, false },
2527 kEmptyMatch
, kEmptyMatch
},
2529 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2530 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2531 "\"google:verbatimrelevance\":0,"
2532 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
2533 { { "a1.com", false, false },
2534 { "a2.com", false, false },
2535 { "a3", true, true },
2536 { "k a", false, false },
2537 kEmptyMatch
, kEmptyMatch
},
2539 // Check when there is neither verbatim nor a query suggestion that,
2540 // because we can't demote navsuggestions below a query suggestion,
2541 // we restore the keyword verbatim score.
2542 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
2543 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2544 "\"google:verbatimrelevance\":0,"
2545 "\"google:suggestrelevance\":[9998, 9999]}]",
2546 { { "a2.com", false, false },
2547 { "a1.com", false, false },
2548 { "a", true, true },
2549 { "k a", false, false },
2550 kEmptyMatch
, kEmptyMatch
},
2552 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
2553 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
2554 "\"google:verbatimrelevance\":0,"
2555 "\"google:suggestrelevance\":[9999, 9998]}]",
2556 { { "a1.com", false, false },
2557 { "a2.com", false, false },
2558 { "a", true, true },
2559 { "k a", false, false },
2560 kEmptyMatch
, kEmptyMatch
},
2562 // More checks that everything works when it's not necessary to demote.
2563 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2564 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2565 "\"google:verbatimrelevance\":9990,"
2566 "\"google:suggestrelevance\":[9997, 9998, 9999]}]",
2567 { { "a3", true, true },
2568 { "a2.com", false, false },
2569 { "a1.com", false, false },
2570 { "a", true, true },
2571 { "k a", false, false },
2574 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
2575 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
2576 "\"google:verbatimrelevance\":9990,"
2577 "\"google:suggestrelevance\":[9998, 9997, 9999]}]",
2578 { { "a3", true, true },
2579 { "a1.com", false, false },
2580 { "a2.com", false, false },
2581 { "a", true, true },
2582 { "k a", false, false },
2587 std::map
<std::string
, std::string
> params
;
2588 params
[std::string(OmniboxFieldTrial::kReorderForLegalDefaultMatchRule
) +
2589 ":*:*"] = OmniboxFieldTrial::kReorderForLegalDefaultMatchRuleEnabled
;
2590 ASSERT_TRUE(chrome_variations::AssociateVariationParams(
2591 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
2592 base::FieldTrialList::CreateFieldTrial(
2593 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
2595 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
2596 QueryForInput(ASCIIToUTF16("k a"), false, true);
2598 // Set up a default fetcher with no results.
2599 net::TestURLFetcher
* default_fetcher
=
2600 test_factory_
.GetFetcherByID(
2601 SearchProvider::kDefaultProviderURLFetcherID
);
2602 ASSERT_TRUE(default_fetcher
);
2603 default_fetcher
->set_response_code(200);
2604 default_fetcher
->delegate()->OnURLFetchComplete(default_fetcher
);
2605 default_fetcher
= NULL
;
2607 // Set up a keyword fetcher with provided results.
2608 net::TestURLFetcher
* keyword_fetcher
=
2609 test_factory_
.GetFetcherByID(
2610 SearchProvider::kKeywordProviderURLFetcherID
);
2611 ASSERT_TRUE(keyword_fetcher
);
2612 keyword_fetcher
->set_response_code(200);
2613 keyword_fetcher
->SetResponseString(cases
[i
].json
);
2614 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
2615 keyword_fetcher
= NULL
;
2616 RunTillProviderDone();
2618 const std::string description
= "for input with json=" + cases
[i
].json
;
2619 const ACMatches
& matches
= provider_
->matches();
2620 ASSERT_FALSE(matches
.empty());
2621 // Find the first match that's allowed to be the default match and check
2622 // its inline_autocompletion.
2623 ACMatches::const_iterator it
= FindDefaultMatch(matches
);
2624 ASSERT_NE(matches
.end(), it
);
2625 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
2626 it
->inline_autocompletion
) << description
;
2628 ASSERT_LE(matches
.size(), ARRAYSIZE_UNSAFE(cases
[i
].matches
));
2630 // Ensure that the returned matches equal the expectations.
2631 for (; j
< matches
.size(); ++j
) {
2632 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
].contents
),
2633 matches
[j
].contents
) << description
;
2634 EXPECT_EQ(cases
[i
].matches
[j
].from_keyword
,
2635 matches
[j
].keyword
== ASCIIToUTF16("k")) << description
;
2636 EXPECT_EQ(cases
[i
].matches
[j
].allowed_to_be_default_match
,
2637 matches
[j
].allowed_to_be_default_match
) << description
;
2639 // Ensure that no expected matches are missing.
2640 for (; j
< ARRAYSIZE_UNSAFE(cases
[i
].matches
); ++j
)
2641 EXPECT_EQ(kNotApplicable
, cases
[i
].matches
[j
].contents
) <<
2642 "Case # " << i
<< " " << description
;
2646 TEST_F(SearchProviderTest
, LocalAndRemoteRelevances
) {
2647 // We hardcode the string "term1" below, so ensure that the search term that
2648 // got added to history already is that string.
2649 ASSERT_EQ(ASCIIToUTF16("term1"), term1_
);
2650 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
2652 AddSearchToHistory(default_t_url_
, term
+ ASCIIToUTF16("2"), 2);
2653 profile_
.BlockUntilHistoryProcessesPendingRequests();
2656 const base::string16 input
;
2657 const std::string json
;
2658 const std::string matches
[6];
2660 // The history results outscore the default verbatim score. term2 has more
2661 // visits so it outscores term1. The suggestions are still returned since
2662 // they're server-scored.
2664 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
2665 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
2666 "\"google:suggestrelevance\":[1, 2, 3]}]",
2667 { "term2", "term1", "term", "a3", "a2", "a1" } },
2668 // Because we already have three suggestions by the time we see the history
2669 // results, they don't get returned.
2671 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
2672 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
2673 "\"google:verbatimrelevance\":1450,"
2674 "\"google:suggestrelevance\":[1440, 1430, 1420]}]",
2675 { "term", "a1", "a2", "a3", kNotApplicable
, kNotApplicable
} },
2676 // If we only have two suggestions, we have room for a history result.
2678 "[\"term\",[\"a1\", \"a2\"],[],[],"
2679 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2680 "\"google:verbatimrelevance\":1450,"
2681 "\"google:suggestrelevance\":[1430, 1410]}]",
2682 { "term", "a1", "a2", "term2", kNotApplicable
, kNotApplicable
} },
2683 // If we have more than three suggestions, they should all be returned as
2684 // long as we have enough total space for them.
2686 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
2687 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
2688 "\"google:verbatimrelevance\":1450,"
2689 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410]}]",
2690 { "term", "a1", "a2", "a3", "a4", kNotApplicable
} },
2692 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\", \"a5\", \"a6\"],[],[],"
2693 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\","
2694 "\"QUERY\", \"QUERY\"],"
2695 "\"google:verbatimrelevance\":1450,"
2696 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410, 1400, 1390]}]",
2697 { "term", "a1", "a2", "a3", "a4", "a5" } },
2699 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
2700 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
2701 "\"google:verbatimrelevance\":1450,"
2702 "\"google:suggestrelevance\":[1430, 1410, 1390, 1370]}]",
2703 { "term", "a1", "a2", "term2", "a3", "a4" } },
2704 // When the input looks like a URL, we disallow having a query as the
2705 // highest-ranking result. If the query was provided by a suggestion, we
2706 // reset the suggest scores to enforce this (see
2707 // SearchProvider::UpdateMatches()). Even if we reset the suggest scores,
2708 // however, we should still allow navsuggestions to be treated as
2710 { ASCIIToUTF16("a.com"),
2711 "[\"a.com\",[\"a1\", \"a2\", \"a.com/1\", \"a.com/2\"],[],[],"
2712 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"NAVIGATION\","
2714 // A verbatim query for URL-like input scores 850, so the navigation
2715 // scores here should bracket it.
2716 "\"google:suggestrelevance\":[9999, 9998, 900, 800]}]",
2717 { "a.com/1", "a.com", "a.com/2", "a1", kNotApplicable
, kNotApplicable
} },
2720 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
2721 QueryForInput(cases
[i
].input
, false, false);
2722 net::TestURLFetcher
* fetcher
=
2723 test_factory_
.GetFetcherByID(
2724 SearchProvider::kDefaultProviderURLFetcherID
);
2725 ASSERT_TRUE(fetcher
);
2726 fetcher
->set_response_code(200);
2727 fetcher
->SetResponseString(cases
[i
].json
);
2728 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
2729 RunTillProviderDone();
2731 const std::string description
= "for input with json=" + cases
[i
].json
;
2732 const ACMatches
& matches
= provider_
->matches();
2734 // Ensure no extra matches are present.
2735 ASSERT_LE(matches
.size(), ARRAYSIZE_UNSAFE(cases
[i
].matches
));
2738 // Ensure that the returned matches equal the expectations.
2739 for (; j
< matches
.size(); ++j
)
2740 EXPECT_EQ(ASCIIToUTF16(cases
[i
].matches
[j
]),
2741 matches
[j
].contents
) << description
;
2742 // Ensure that no expected matches are missing.
2743 for (; j
< ARRAYSIZE_UNSAFE(cases
[i
].matches
); ++j
)
2744 EXPECT_EQ(kNotApplicable
, cases
[i
].matches
[j
]) <<
2745 "Case # " << i
<< " " << description
;
2749 // Verifies suggest relevance behavior for URL input.
2750 TEST_F(SearchProviderTest
, DefaultProviderSuggestRelevanceScoringUrlInput
) {
2751 struct DefaultFetcherUrlInputMatch
{
2752 const std::string match_contents
;
2753 AutocompleteMatch::Type match_type
;
2754 bool allowed_to_be_default_match
;
2756 const DefaultFetcherUrlInputMatch kEmptyMatch
=
2757 { kNotApplicable
, AutocompleteMatchType::NUM_TYPES
, false };
2759 const std::string input
;
2760 const std::string json
;
2761 const DefaultFetcherUrlInputMatch output
[4];
2763 // Ensure topmost NAVIGATION matches are allowed for URL input.
2764 { "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[],"
2765 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2766 "\"google:suggestrelevance\":[9999]}]",
2767 { { "a.com/a", AutocompleteMatchType::NAVSUGGEST
, true },
2768 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2769 kEmptyMatch
, kEmptyMatch
} },
2770 { "a.com", "[\"a.com\",[\"https://a.com\"],[],[],"
2771 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2772 "\"google:suggestrelevance\":[9999]}]",
2773 { { "https://a.com", AutocompleteMatchType::NAVSUGGEST
, true },
2774 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2775 kEmptyMatch
, kEmptyMatch
} },
2777 // Ensure topmost SUGGEST matches are not allowed for URL input.
2778 // SearchProvider disregards search and verbatim suggested relevances.
2779 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2780 "{\"google:suggestrelevance\":[9999]}]",
2781 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2782 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, true },
2783 kEmptyMatch
, kEmptyMatch
} },
2784 { "a.com", "[\"a.com\",[\"a.com/a\"],[],[],"
2785 "{\"google:suggestrelevance\":[9999]}]",
2786 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2787 { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST
, true },
2788 kEmptyMatch
, kEmptyMatch
} },
2790 // Ensure the fallback mechanism allows inlinable NAVIGATION matches.
2791 { "a.com", "[\"a.com\",[\"a.com/a\", \"http://a.com/b\"],[],[],"
2792 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2793 "\"google:suggestrelevance\":[9999, 9998]}]",
2794 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST
, true },
2795 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2796 { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST
, true },
2798 { "a.com", "[\"a.com\",[\"a.com/a\", \"http://a.com/b\"],[],[],"
2799 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2800 "\"google:suggestrelevance\":[9998, 9997],"
2801 "\"google:verbatimrelevance\":9999}]",
2802 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST
, true },
2803 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2804 { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST
, true },
2807 // Ensure the fallback mechanism disallows non-inlinable NAVIGATION matches.
2808 { "a.com", "[\"a.com\",[\"a.com/a\", \"http://abc.com\"],[],[],"
2809 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2810 "\"google:suggestrelevance\":[9999, 9998]}]",
2811 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2812 { "abc.com", AutocompleteMatchType::NAVSUGGEST
, false },
2813 { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST
, true },
2815 { "a.com", "[\"a.com\",[\"a.com/a\", \"http://abc.com\"],[],[],"
2816 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2817 "\"google:suggestrelevance\":[9998, 9997],"
2818 "\"google:verbatimrelevance\":9999}]",
2819 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2820 { "abc.com", AutocompleteMatchType::NAVSUGGEST
, false },
2821 { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST
, true },
2825 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
2826 QueryForInput(ASCIIToUTF16(cases
[i
].input
), false, false);
2827 net::TestURLFetcher
* fetcher
=
2828 test_factory_
.GetFetcherByID(
2829 SearchProvider::kDefaultProviderURLFetcherID
);
2830 ASSERT_TRUE(fetcher
);
2831 fetcher
->set_response_code(200);
2832 fetcher
->SetResponseString(cases
[i
].json
);
2833 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
2834 RunTillProviderDone();
2837 const ACMatches
& matches
= provider_
->matches();
2838 ASSERT_LE(matches
.size(), ARRAYSIZE_UNSAFE(cases
[i
].output
));
2839 // Ensure that the returned matches equal the expectations.
2840 for (; j
< matches
.size(); ++j
) {
2841 EXPECT_EQ(ASCIIToUTF16(cases
[i
].output
[j
].match_contents
),
2842 matches
[j
].contents
);
2843 EXPECT_EQ(cases
[i
].output
[j
].match_type
, matches
[j
].type
);
2844 EXPECT_EQ(cases
[i
].output
[j
].allowed_to_be_default_match
,
2845 matches
[j
].allowed_to_be_default_match
);
2847 // Ensure that no expected matches are missing.
2848 for (; j
< ARRAYSIZE_UNSAFE(cases
[i
].output
); ++j
) {
2849 EXPECT_EQ(kNotApplicable
, cases
[i
].output
[j
].match_contents
);
2850 EXPECT_EQ(AutocompleteMatchType::NUM_TYPES
,
2851 cases
[i
].output
[j
].match_type
);
2852 EXPECT_FALSE(cases
[i
].output
[j
].allowed_to_be_default_match
);
2857 // This test is like DefaultProviderSuggestRelevanceScoringUrlInput
2858 // above except it enables the field trial that causes the omnibox to
2859 // be willing to reorder matches to guarantee the top result is a
2860 // legal default match. This field trial causes SearchProvider to
2861 // allow some constraints to be violated that it wouldn't normally
2862 // because the omnibox will fix the problems later.
2863 TEST_F(SearchProviderTest
,
2864 DefaultProviderSuggestRelevanceScoringUrlInputWithReorder
) {
2865 struct DefaultFetcherUrlInputMatch
{
2866 const std::string match_contents
;
2867 AutocompleteMatch::Type match_type
;
2868 bool allowed_to_be_default_match
;
2870 const DefaultFetcherUrlInputMatch kEmptyMatch
=
2871 { kNotApplicable
, AutocompleteMatchType::NUM_TYPES
, false };
2873 const std::string input
;
2874 const std::string json
;
2875 const DefaultFetcherUrlInputMatch output
[4];
2877 // Ensure NAVIGATION matches are allowed to be listed first for URL
2878 // input regardless of whether the match is inlineable. Note that
2879 // non-inlineable matches should not be allowed to be the default match.
2880 { "a.com", "[\"a.com\",[\"http://b.com/\"],[],[],"
2881 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2882 "\"google:suggestrelevance\":[9999]}]",
2883 { { "b.com", AutocompleteMatchType::NAVSUGGEST
, false },
2884 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2885 kEmptyMatch
, kEmptyMatch
} },
2886 { "a.com", "[\"a.com\",[\"https://b.com\"],[],[],"
2887 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2888 "\"google:suggestrelevance\":[9999]}]",
2889 { { "https://b.com", AutocompleteMatchType::NAVSUGGEST
, false },
2890 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2891 kEmptyMatch
, kEmptyMatch
} },
2892 { "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[],"
2893 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2894 "\"google:suggestrelevance\":[9999]}]",
2895 { { "a.com/a", AutocompleteMatchType::NAVSUGGEST
, true },
2896 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2897 kEmptyMatch
, kEmptyMatch
} },
2898 { "a.com", "[\"a.com\",[\"https://a.com\"],[],[],"
2899 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2900 "\"google:suggestrelevance\":[9999]}]",
2901 { { "https://a.com", AutocompleteMatchType::NAVSUGGEST
, true },
2902 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2903 kEmptyMatch
, kEmptyMatch
} },
2905 // Ensure topmost inlineable SUGGEST matches are NOT allowed for URL
2906 // input. SearchProvider disregards search and verbatim suggested
2908 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2909 "{\"google:suggestrelevance\":[9999]}]",
2910 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2911 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, true },
2912 kEmptyMatch
, kEmptyMatch
} },
2913 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2914 "{\"google:suggestrelevance\":[9999]}]",
2915 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2916 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, true },
2917 kEmptyMatch
, kEmptyMatch
} },
2919 // Ensure the fallback mechanism allows inlinable NAVIGATION matches.
2920 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2921 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2922 "\"google:suggestrelevance\":[9999, 9998]}]",
2923 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST
, true },
2924 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2925 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, true },
2927 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2928 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2929 "\"google:suggestrelevance\":[9998, 9997],"
2930 "\"google:verbatimrelevance\":9999}]",
2931 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST
, true },
2932 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2933 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST
, true },
2936 // Ensure topmost non-inlineable SUGGEST matches are allowed for URL
2937 // input assuming the top inlineable match is not a query (i.e., is a
2939 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2940 "{\"google:suggestrelevance\":[9999]}]",
2941 { { "info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2942 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2943 kEmptyMatch
, kEmptyMatch
} },
2944 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2945 "{\"google:suggestrelevance\":[9999]}]",
2946 { { "info", AutocompleteMatchType::SEARCH_SUGGEST
, false },
2947 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, true },
2948 kEmptyMatch
, kEmptyMatch
} },
2951 std::map
<std::string
, std::string
> params
;
2952 params
[std::string(OmniboxFieldTrial::kReorderForLegalDefaultMatchRule
) +
2953 ":*:*"] = OmniboxFieldTrial::kReorderForLegalDefaultMatchRuleEnabled
;
2954 ASSERT_TRUE(chrome_variations::AssociateVariationParams(
2955 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
2956 base::FieldTrialList::CreateFieldTrial(
2957 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
2959 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
2960 QueryForInput(ASCIIToUTF16(cases
[i
].input
), false, false);
2961 net::TestURLFetcher
* fetcher
=
2962 test_factory_
.GetFetcherByID(
2963 SearchProvider::kDefaultProviderURLFetcherID
);
2964 ASSERT_TRUE(fetcher
);
2965 fetcher
->set_response_code(200);
2966 fetcher
->SetResponseString(cases
[i
].json
);
2967 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
2968 RunTillProviderDone();
2971 const ACMatches
& matches
= provider_
->matches();
2972 ASSERT_LE(matches
.size(), ARRAYSIZE_UNSAFE(cases
[i
].output
));
2973 // Ensure that the returned matches equal the expectations.
2974 for (; j
< matches
.size(); ++j
) {
2975 EXPECT_EQ(ASCIIToUTF16(cases
[i
].output
[j
].match_contents
),
2976 matches
[j
].contents
);
2977 EXPECT_EQ(cases
[i
].output
[j
].match_type
, matches
[j
].type
);
2978 EXPECT_EQ(cases
[i
].output
[j
].allowed_to_be_default_match
,
2979 matches
[j
].allowed_to_be_default_match
);
2981 // Ensure that no expected matches are missing.
2982 for (; j
< ARRAYSIZE_UNSAFE(cases
[i
].output
); ++j
) {
2983 EXPECT_EQ(kNotApplicable
, cases
[i
].output
[j
].match_contents
);
2984 EXPECT_EQ(AutocompleteMatchType::NUM_TYPES
,
2985 cases
[i
].output
[j
].match_type
);
2986 EXPECT_FALSE(cases
[i
].output
[j
].allowed_to_be_default_match
);
2991 // A basic test that verifies the field trial triggered parsing logic.
2992 TEST_F(SearchProviderTest
, FieldTrialTriggeredParsing
) {
2993 QueryForInput(ASCIIToUTF16("foo"), false, false);
2995 // Make sure the default providers suggest service was queried.
2996 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
2997 SearchProvider::kDefaultProviderURLFetcherID
);
2998 ASSERT_TRUE(fetcher
);
3000 // Tell the SearchProvider the suggest query is done.
3001 fetcher
->set_response_code(200);
3002 fetcher
->SetResponseString(
3003 "[\"foo\",[\"foo bar\"],[\"\"],[],"
3004 "{\"google:suggesttype\":[\"QUERY\"],"
3005 "\"google:fieldtrialtriggered\":true}]");
3006 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3009 // Run till the history results complete.
3010 RunTillProviderDone();
3013 // Check for the match and field trial triggered bits.
3014 AutocompleteMatch match
;
3015 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("foo bar"), &match
));
3016 ProvidersInfo providers_info
;
3017 provider_
->AddProviderInfo(&providers_info
);
3018 ASSERT_EQ(1U, providers_info
.size());
3019 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_size());
3020 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_in_session_size());
3023 // Reset the session and check that bits are reset.
3024 provider_
->ResetSession();
3025 ProvidersInfo providers_info
;
3026 provider_
->AddProviderInfo(&providers_info
);
3027 ASSERT_EQ(1U, providers_info
.size());
3028 EXPECT_EQ(1, providers_info
[0].field_trial_triggered_size());
3029 EXPECT_EQ(0, providers_info
[0].field_trial_triggered_in_session_size());
3033 // Verifies inline autocompletion of navigational results.
3034 TEST_F(SearchProviderTest
, NavigationInline
) {
3036 const std::string input
;
3037 const std::string url
;
3038 // Test the expected fill_into_edit, which may drop "http://".
3039 // Some cases do not trim "http://" to match from the start of the scheme.
3040 const std::string fill_into_edit
;
3041 const std::string inline_autocompletion
;
3042 const bool allowed_to_be_default_match
;
3044 // Do not inline matches that do not contain the input; trim http as needed.
3045 { "x", "http://www.abc.com",
3046 "www.abc.com", std::string(), false },
3047 { "https:", "http://www.abc.com",
3048 "www.abc.com", std::string(), false },
3049 { "abc.com/", "http://www.abc.com",
3050 "www.abc.com", std::string(), false },
3051 { "http://www.abc.com/a", "http://www.abc.com",
3052 "http://www.abc.com", std::string(), false },
3053 { "http://www.abc.com", "https://www.abc.com",
3054 "https://www.abc.com", std::string(), false },
3055 { "http://abc.com", "ftp://abc.com",
3056 "ftp://abc.com", std::string(), false },
3057 { "https://www.abc.com", "http://www.abc.com",
3058 "www.abc.com", std::string(), false },
3059 { "ftp://abc.com", "http://abc.com",
3060 "abc.com", std::string(), false },
3062 // Do not inline matches with invalid input prefixes; trim http as needed.
3063 { "ttp", "http://www.abc.com",
3064 "www.abc.com", std::string(), false },
3065 { "://w", "http://www.abc.com",
3066 "www.abc.com", std::string(), false },
3067 { "ww.", "http://www.abc.com",
3068 "www.abc.com", std::string(), false },
3069 { ".ab", "http://www.abc.com",
3070 "www.abc.com", std::string(), false },
3071 { "bc", "http://www.abc.com",
3072 "www.abc.com", std::string(), false },
3073 { ".com", "http://www.abc.com",
3074 "www.abc.com", std::string(), false },
3076 // Do not inline matches that omit input domain labels; trim http as needed.
3077 { "www.a", "http://a.com",
3078 "a.com", std::string(), false },
3079 { "http://www.a", "http://a.com",
3080 "http://a.com", std::string(), false },
3081 { "www.a", "ftp://a.com",
3082 "ftp://a.com", std::string(), false },
3083 { "ftp://www.a", "ftp://a.com",
3084 "ftp://a.com", std::string(), false },
3086 // Input matching but with nothing to inline will not yield an offset, but
3087 // will be allowed to be default.
3088 { "abc.com", "http://www.abc.com",
3089 "www.abc.com", std::string(), true },
3090 { "http://www.abc.com", "http://www.abc.com",
3091 "http://www.abc.com", std::string(), true },
3093 // Inline matches when the input is a leading substring of the scheme.
3094 { "h", "http://www.abc.com",
3095 "http://www.abc.com", "ttp://www.abc.com", true },
3096 { "http", "http://www.abc.com",
3097 "http://www.abc.com", "://www.abc.com", true },
3099 // Inline matches when the input is a leading substring of the full URL.
3100 { "http:", "http://www.abc.com",
3101 "http://www.abc.com", "//www.abc.com", true },
3102 { "http://w", "http://www.abc.com",
3103 "http://www.abc.com", "ww.abc.com", true },
3104 { "http://www.", "http://www.abc.com",
3105 "http://www.abc.com", "abc.com", true },
3106 { "http://www.ab", "http://www.abc.com",
3107 "http://www.abc.com", "c.com", true },
3108 { "http://www.abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
3109 "http://www.abc.com/path/file.htm?q=x#foo",
3110 "ath/file.htm?q=x#foo",
3112 { "http://abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
3113 "http://abc.com/path/file.htm?q=x#foo",
3114 "ath/file.htm?q=x#foo", true},
3116 // Inline matches with valid URLPrefixes; only trim "http://".
3117 { "w", "http://www.abc.com",
3118 "www.abc.com", "ww.abc.com", true },
3119 { "www.a", "http://www.abc.com",
3120 "www.abc.com", "bc.com", true },
3121 { "abc", "http://www.abc.com",
3122 "www.abc.com", ".com", true },
3123 { "abc.c", "http://www.abc.com",
3124 "www.abc.com", "om", true },
3125 { "abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
3126 "www.abc.com/path/file.htm?q=x#foo",
3127 "ath/file.htm?q=x#foo", true },
3128 { "abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
3129 "abc.com/path/file.htm?q=x#foo",
3130 "ath/file.htm?q=x#foo", true },
3132 // Inline matches using the maximal URLPrefix components.
3133 { "h", "http://help.com",
3134 "help.com", "elp.com", true },
3135 { "http", "http://http.com",
3136 "http.com", ".com", true },
3137 { "h", "http://www.help.com",
3138 "www.help.com", "elp.com", true },
3139 { "http", "http://www.http.com",
3140 "www.http.com", ".com", true },
3141 { "w", "http://www.www.com",
3142 "www.www.com", "ww.com", true },
3144 // Test similar behavior for the ftp and https schemes.
3145 { "ftp://www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
3146 "ftp://www.abc.com/path/file.htm?q=x#foo",
3147 "c.com/path/file.htm?q=x#foo", true },
3148 { "www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
3149 "ftp://www.abc.com/path/file.htm?q=x#foo",
3150 "c.com/path/file.htm?q=x#foo", true },
3151 { "ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
3152 "ftp://www.abc.com/path/file.htm?q=x#foo",
3153 "c.com/path/file.htm?q=x#foo", true },
3154 { "ab", "ftp://abc.com/path/file.htm?q=x#foo",
3155 "ftp://abc.com/path/file.htm?q=x#foo",
3156 "c.com/path/file.htm?q=x#foo", true },
3157 { "https://www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
3158 "https://www.abc.com/path/file.htm?q=x#foo",
3159 "c.com/path/file.htm?q=x#foo", true },
3160 { "www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
3161 "https://www.abc.com/path/file.htm?q=x#foo",
3162 "c.com/path/file.htm?q=x#foo", true },
3163 { "ab", "https://www.abc.com/path/file.htm?q=x#foo",
3164 "https://www.abc.com/path/file.htm?q=x#foo",
3165 "c.com/path/file.htm?q=x#foo", true },
3166 { "ab", "https://abc.com/path/file.htm?q=x#foo",
3167 "https://abc.com/path/file.htm?q=x#foo",
3168 "c.com/path/file.htm?q=x#foo", true },
3170 // Forced query input should inline and retain the "?" prefix.
3171 { "?http://www.ab", "http://www.abc.com",
3172 "?http://www.abc.com", "c.com", true },
3173 { "?www.ab", "http://www.abc.com",
3174 "?www.abc.com", "c.com", true },
3175 { "?ab", "http://www.abc.com",
3176 "?www.abc.com", "c.com", true },
3177 { "?abc.com", "http://www.abc.com",
3178 "?www.abc.com", "", true },
3181 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
3182 QueryForInput(ASCIIToUTF16(cases
[i
].input
), false, false);
3183 AutocompleteMatch
match(
3184 provider_
->NavigationToMatch(SearchProvider::NavigationResult(
3185 *provider_
.get(), GURL(cases
[i
].url
), base::string16(), false, 0,
3186 false, ASCIIToUTF16(cases
[i
].input
), std::string())));
3187 EXPECT_EQ(ASCIIToUTF16(cases
[i
].inline_autocompletion
),
3188 match
.inline_autocompletion
);
3189 EXPECT_EQ(ASCIIToUTF16(cases
[i
].fill_into_edit
), match
.fill_into_edit
);
3190 EXPECT_EQ(cases
[i
].allowed_to_be_default_match
,
3191 match
.allowed_to_be_default_match
);
3195 // Verifies that "http://" is not trimmed for input that is a leading substring.
3196 TEST_F(SearchProviderTest
, NavigationInlineSchemeSubstring
) {
3197 const base::string16
input(ASCIIToUTF16("ht"));
3198 const base::string16
url(ASCIIToUTF16("http://a.com"));
3199 const SearchProvider::NavigationResult
result(
3200 *provider_
.get(), GURL(url
), base::string16(), false, 0, false,
3201 input
, std::string());
3203 // Check the offset and strings when inline autocompletion is allowed.
3204 QueryForInput(input
, false, false);
3205 AutocompleteMatch
match_inline(provider_
->NavigationToMatch(result
));
3206 EXPECT_EQ(url
, match_inline
.fill_into_edit
);
3207 EXPECT_EQ(url
.substr(2), match_inline
.inline_autocompletion
);
3208 EXPECT_TRUE(match_inline
.allowed_to_be_default_match
);
3209 EXPECT_EQ(url
, match_inline
.contents
);
3211 // Check the same offset and strings when inline autocompletion is prevented.
3212 QueryForInput(input
, true, false);
3213 AutocompleteMatch
match_prevent(provider_
->NavigationToMatch(result
));
3214 EXPECT_EQ(url
, match_prevent
.fill_into_edit
);
3215 EXPECT_TRUE(match_prevent
.inline_autocompletion
.empty());
3216 EXPECT_FALSE(match_prevent
.allowed_to_be_default_match
);
3217 EXPECT_EQ(url
, match_prevent
.contents
);
3220 // Verifies that input "w" marks a more significant domain label than "www.".
3221 TEST_F(SearchProviderTest
, NavigationInlineDomainClassify
) {
3222 QueryForInput(ASCIIToUTF16("w"), false, false);
3223 AutocompleteMatch
match(
3224 provider_
->NavigationToMatch(SearchProvider::NavigationResult(
3225 *provider_
.get(), GURL("http://www.wow.com"), base::string16(), false,
3226 0, false, ASCIIToUTF16("w"), std::string())));
3227 EXPECT_EQ(ASCIIToUTF16("ow.com"), match
.inline_autocompletion
);
3228 EXPECT_TRUE(match
.allowed_to_be_default_match
);
3229 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match
.fill_into_edit
);
3230 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match
.contents
);
3232 // Ensure that the match for input "w" is marked on "wow" and not "www".
3233 ASSERT_EQ(3U, match
.contents_class
.size());
3234 EXPECT_EQ(0U, match
.contents_class
[0].offset
);
3235 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
,
3236 match
.contents_class
[0].style
);
3237 EXPECT_EQ(4U, match
.contents_class
[1].offset
);
3238 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
|
3239 AutocompleteMatch::ACMatchClassification::MATCH
,
3240 match
.contents_class
[1].style
);
3241 EXPECT_EQ(5U, match
.contents_class
[2].offset
);
3242 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL
,
3243 match
.contents_class
[2].style
);
3246 TEST_F(SearchProviderTest
, RemoveStaleResultsTest
) {
3247 // TODO(mpearson): Consider expanding this test to explicitly cover
3248 // testing staleness for keyword results.
3250 const std::string omnibox_input
;
3251 const int verbatim_relevance
;
3252 // These cached suggestions should already be sorted.
3253 // The particular number 5 as the length of the array is
3254 // unimportant; it's merely enough cached results to fully test
3255 // the functioning of RemoveAllStaleResults().
3257 const std::string suggestion
;
3258 const bool is_navigation_result
;
3259 const int relevance
;
3260 // |expect_match| is true if this result should survive
3261 // RemoveAllStaleResults() filtering against |omnibox_input| below.
3262 const bool expect_match
;
3265 // Simple case: multiple query suggestions and no navsuggestions.
3266 // All query suggestions score less than search-what-you-typed and
3267 // thus none should be filtered because none will appear first.
3269 { { "food", false, 1299, true },
3270 { "foobar", false, 1298, true },
3271 { "crazy", false, 1297, true },
3272 { "friend", false, 1296, true },
3273 { kNotApplicable
, false, 0, false } } },
3275 // Similarly simple cases, but the query suggestion appears first.
3277 { { "food", false, 1299, true },
3278 { "foobar", false, 1298, true },
3279 { "crazy", false, 1297, true },
3280 { "friend", false, 1296, true },
3281 { kNotApplicable
, false, 0, false } } },
3283 { { "food", false, 1299, false },
3284 { "foobar", false, 1298, false },
3285 { "crazy", false, 1297, true },
3286 { "friend", false, 1296, true },
3287 { kNotApplicable
, false, 0, false } } },
3289 { { "food", false, 1299, false },
3290 { "foobar", false, 1298, false },
3291 { "crazy", false, 1297, false },
3292 { "friend", false, 1296, false },
3293 { kNotApplicable
, false, 0, false } } },
3295 // The same sort of cases, just using a mix of queries and navsuggestions.
3297 { { "http://food.com/", true, 1299, true },
3298 { "foobar", false, 1298, true },
3299 { "http://crazy.com/", true, 1297, true },
3300 { "friend", false, 1296, true },
3301 { "http://friend.com/", true, 1295, true } } },
3303 { { "http://food.com/", true, 1299, true },
3304 { "foobar", false, 1298, true },
3305 { "http://crazy.com/", true, 1297, true },
3306 { "friend", false, 1296, true },
3307 { "http://friend.com/", true, 1295, true } } },
3309 { { "http://food.com/", true, 1299, false },
3310 { "foobar", false, 1298, false },
3311 { "http://crazy.com/", true, 1297, true },
3312 { "friend", false, 1296, true },
3313 { "http://friend.com/", true, 1295, true } } },
3315 { { "http://food.com/", true, 1299, false },
3316 { "foobar", false, 1298, false },
3317 { "http://crazy.com/", true, 1297, false },
3318 { "friend", false, 1296, false },
3319 { "http://friend.com/", true, 1295, false } } },
3321 // Run the three tests immediately above again, just with verbatim
3322 // suppressed. Note that in the last case, all results are filtered.
3323 // Because verbatim is also suppressed, SearchProvider will realize
3324 // in UpdateMatches() that it needs to restore verbatim to fulfill
3325 // its constraints. This restoration does not happen in
3326 // RemoveAllStaleResults() and hence is not tested here. This restoration
3327 // is tested in the DefaultFetcherSuggestRelevance test.
3329 { { "http://food.com/", true, 1299, true },
3330 { "foobar", false, 1298, true },
3331 { "http://crazy.com/", true, 1297, true },
3332 { "friend", false, 1296, true },
3333 { "http://friend.com/", true, 1295, true } } },
3335 { { "http://food.com/", true, 1299, false },
3336 { "foobar", false, 1298, false },
3337 { "http://crazy.com/", true, 1297, true },
3338 { "friend", false, 1296, true },
3339 { "http://friend.com/", true, 1295, true } } },
3341 { { "http://food.com/", true, 1299, false },
3342 { "foobar", false, 1298, false },
3343 { "http://crazy.com/", true, 1297, false },
3344 { "friend", false, 1296, false },
3345 { "http://friend.com/", true, 1295, false } } },
3347 // The same sort of tests again, just with verbatim with a score
3348 // that would place it in between other suggestions.
3350 { { "http://food.com/", true, 1299, true },
3351 { "foobar", false, 1288, true },
3352 { "http://crazy.com/", true, 1277, true },
3353 { "friend", false, 1266, true },
3354 { "http://friend.com/", true, 1255, true } } },
3356 { { "http://food.com/", true, 1299, false },
3357 { "foobar", false, 1288, true },
3358 { "http://crazy.com/", true, 1277, true },
3359 { "friend", false, 1266, true },
3360 { "http://friend.com/", true, 1255, true } } },
3362 { { "http://food.com/", true, 1299, false },
3363 { "foobar", false, 1288, false },
3364 { "http://crazy.com/", true, 1277, true },
3365 { "friend", false, 1266, true },
3366 { "http://friend.com/", true, 1255, true } } },
3368 { { "http://food.com/", true, 1299, false },
3369 { "foobar", false, 1288, false },
3370 { "http://crazy.com/", true, 1277, true },
3371 { "friend", false, 1266, true },
3372 { "http://friend.com/", true, 1255, true } } },
3375 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
3376 // Initialize cached results for this test case.
3377 provider_
->default_results_
.verbatim_relevance
=
3378 cases
[i
].verbatim_relevance
;
3379 provider_
->default_results_
.navigation_results
.clear();
3380 provider_
->default_results_
.suggest_results
.clear();
3381 for (size_t j
= 0; j
< ARRAYSIZE_UNSAFE(cases
[i
].results
); ++j
) {
3382 const std::string
& suggestion
= cases
[i
].results
[j
].suggestion
;
3383 if (suggestion
== kNotApplicable
)
3385 if (cases
[i
].results
[j
].is_navigation_result
) {
3386 provider_
->default_results_
.navigation_results
.push_back(
3387 SearchProvider::NavigationResult(
3388 *provider_
.get(), GURL(suggestion
), base::string16(), false,
3389 cases
[i
].results
[j
].relevance
, false,
3390 ASCIIToUTF16(cases
[i
].omnibox_input
), std::string()));
3392 provider_
->default_results_
.suggest_results
.push_back(
3393 SearchProvider::SuggestResult(
3394 ASCIIToUTF16(suggestion
), AutocompleteMatchType::SEARCH_SUGGEST
,
3395 ASCIIToUTF16(suggestion
), base::string16(), std::string(),
3396 std::string(), false, cases
[i
].results
[j
].relevance
, false,
3397 false, ASCIIToUTF16(cases
[i
].omnibox_input
)));
3401 provider_
->input_
= AutocompleteInput(
3402 ASCIIToUTF16(cases
[i
].omnibox_input
), base::string16::npos
,
3403 base::string16(), GURL(), AutocompleteInput::INVALID_SPEC
, false, false,
3404 true, AutocompleteInput::ALL_MATCHES
);
3405 provider_
->RemoveAllStaleResults();
3407 // Check cached results.
3408 SearchProvider::SuggestResults::const_iterator sug_it
=
3409 provider_
->default_results_
.suggest_results
.begin();
3410 const SearchProvider::SuggestResults::const_iterator sug_end
=
3411 provider_
->default_results_
.suggest_results
.end();
3412 SearchProvider::NavigationResults::const_iterator nav_it
=
3413 provider_
->default_results_
.navigation_results
.begin();
3414 const SearchProvider::NavigationResults::const_iterator nav_end
=
3415 provider_
->default_results_
.navigation_results
.end();
3416 for (size_t j
= 0; j
< ARRAYSIZE_UNSAFE(cases
[i
].results
); ++j
) {
3417 const std::string
& suggestion
= cases
[i
].results
[j
].suggestion
;
3418 if (suggestion
== kNotApplicable
)
3420 if (!cases
[i
].results
[j
].expect_match
)
3422 if (cases
[i
].results
[j
].is_navigation_result
) {
3423 ASSERT_NE(nav_end
, nav_it
) << "Failed to find " << suggestion
;
3424 EXPECT_EQ(suggestion
, nav_it
->url().spec());
3427 ASSERT_NE(sug_end
, sug_it
) << "Failed to find " << suggestion
;
3428 EXPECT_EQ(ASCIIToUTF16(suggestion
), sug_it
->suggestion());
3432 EXPECT_EQ(sug_end
, sug_it
);
3433 EXPECT_EQ(nav_end
, nav_it
);
3437 #if !defined(OS_WIN)
3438 // Verify entity suggestion parsing.
3439 TEST_F(SearchProviderTest
, ParseEntitySuggestion
) {
3441 std::string contents
;
3442 std::string description
;
3443 std::string query_params
;
3444 std::string fill_into_edit
;
3445 AutocompleteMatchType::Type type
;
3447 const Match kEmptyMatch
= {
3448 kNotApplicable
, kNotApplicable
, kNotApplicable
, kNotApplicable
,
3449 AutocompleteMatchType::NUM_TYPES
};
3452 const std::string input_text
;
3453 const std::string response_json
;
3454 const Match matches
[5];
3456 // A query and an entity suggestion with different search terms.
3458 "[\"x\",[\"xy\", \"yy\"],[\"\",\"\"],[],"
3459 " {\"google:suggestdetail\":[{},"
3460 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
3461 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
3462 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3463 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST
},
3464 { "xy", "A", "p=v", "yy",
3465 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY
},
3470 // A query and an entity suggestion with same search terms.
3472 "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
3473 " {\"google:suggestdetail\":[{},"
3474 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
3475 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
3476 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3477 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST
},
3478 { "xy", "A", "p=v", "xy",
3479 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY
},
3485 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
3486 QueryForInput(ASCIIToUTF16(cases
[i
].input_text
), false, false);
3488 // Set up a default fetcher with provided results.
3489 net::TestURLFetcher
* fetcher
=
3490 test_factory_
.GetFetcherByID(
3491 SearchProvider::kDefaultProviderURLFetcherID
);
3492 ASSERT_TRUE(fetcher
);
3493 fetcher
->set_response_code(200);
3494 fetcher
->SetResponseString(cases
[i
].response_json
);
3495 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3497 RunTillProviderDone();
3499 const ACMatches
& matches
= provider_
->matches();
3500 ASSERT_FALSE(matches
.empty());
3502 SCOPED_TRACE("for input with json = " + cases
[i
].response_json
);
3504 ASSERT_LE(matches
.size(), ARRAYSIZE_UNSAFE(cases
[i
].matches
));
3506 // Ensure that the returned matches equal the expectations.
3507 for (; j
< matches
.size(); ++j
) {
3508 const Match
& match
= cases
[i
].matches
[j
];
3509 SCOPED_TRACE(" and match index: " + base::IntToString(j
));
3510 EXPECT_EQ(match
.contents
,
3511 base::UTF16ToUTF8(matches
[j
].contents
));
3512 EXPECT_EQ(match
.description
,
3513 base::UTF16ToUTF8(matches
[j
].description
));
3514 EXPECT_EQ(match
.query_params
,
3515 matches
[j
].search_terms_args
->suggest_query_params
);
3516 EXPECT_EQ(match
.fill_into_edit
,
3517 base::UTF16ToUTF8(matches
[j
].fill_into_edit
));
3518 EXPECT_EQ(match
.type
, matches
[j
].type
);
3520 // Ensure that no expected matches are missing.
3521 for (; j
< ARRAYSIZE_UNSAFE(cases
[i
].matches
); ++j
) {
3522 SCOPED_TRACE(" and match index: " + base::IntToString(j
));
3523 EXPECT_EQ(cases
[i
].matches
[j
].contents
, kNotApplicable
);
3524 EXPECT_EQ(cases
[i
].matches
[j
].description
, kNotApplicable
);
3525 EXPECT_EQ(cases
[i
].matches
[j
].query_params
, kNotApplicable
);
3526 EXPECT_EQ(cases
[i
].matches
[j
].fill_into_edit
, kNotApplicable
);
3527 EXPECT_EQ(cases
[i
].matches
[j
].type
, AutocompleteMatchType::NUM_TYPES
);
3531 #endif // !defined(OS_WIN)
3534 // A basic test that verifies the prefetch metadata parsing logic.
3535 TEST_F(SearchProviderTest
, PrefetchMetadataParsing
) {
3537 std::string contents
;
3538 bool allowed_to_be_prefetched
;
3539 AutocompleteMatchType::Type type
;
3542 const Match kEmptyMatch
= { kNotApplicable
,
3544 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
3548 const std::string input_text
;
3549 bool prefer_keyword_provider_results
;
3550 const std::string default_provider_response_json
;
3551 const std::string keyword_provider_response_json
;
3552 const Match matches
[5];
3554 // Default provider response does not have prefetch details. Ensure that the
3555 // suggestions are not marked as prefetch query.
3558 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
3560 { { "a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
3561 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
3562 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
3567 // Ensure that default provider suggest response prefetch details are
3568 // parsed and recorded in AutocompleteMatch.
3571 "[\"ab\",[\"abc\", \"http://b.com\", \"http://c.com\"],[],[],"
3572 "{\"google:clientdata\":{\"phi\": 0},"
3573 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"NAVIGATION\"],"
3574 "\"google:suggestrelevance\":[999, 12, 1]}]",
3576 { { "ab", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
3577 { "abc", true, AutocompleteMatchType::SEARCH_SUGGEST
, false },
3578 { "b.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
3579 { "c.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
3583 // Default provider suggest response has prefetch details.
3584 // SEARCH_WHAT_YOU_TYPE suggestion outranks SEARCH_SUGGEST suggestion for
3585 // the same query string. Ensure that the prefetch details from
3586 // SEARCH_SUGGEST match are set onto SEARCH_WHAT_YOU_TYPE match.
3589 "[\"ab\",[\"ab\", \"http://ab.com\"],[],[],"
3590 "{\"google:clientdata\":{\"phi\": 0},"
3591 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
3592 "\"google:suggestrelevance\":[99, 98]}]",
3594 { {"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
3595 {"ab.com", false, AutocompleteMatchType::NAVSUGGEST
, false },
3601 // Default provider response has prefetch details. We prefer keyword
3602 // provider results. Ensure that prefetch bit for a suggestion from the
3603 // default search provider does not get copied onto a higher-scoring match
3604 // for the same query string from the keyword provider.
3607 "[\"k a\",[\"a\", \"ab\"],[],[], {\"google:clientdata\":{\"phi\": 0},"
3608 "\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
3609 "\"google:suggestrelevance\":[9, 12]}]",
3610 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
3611 { { "a", false, AutocompleteMatchType::SEARCH_OTHER_ENGINE
, true},
3612 { "k a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
, false },
3613 { "ab", false, AutocompleteMatchType::SEARCH_SUGGEST
, false },
3614 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST
, true },
3615 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST
, true }
3620 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
3621 QueryForInput(ASCIIToUTF16(cases
[i
].input_text
), false,
3622 cases
[i
].prefer_keyword_provider_results
);
3624 // Set up a default fetcher with provided results.
3625 net::TestURLFetcher
* fetcher
=
3626 test_factory_
.GetFetcherByID(
3627 SearchProvider::kDefaultProviderURLFetcherID
);
3628 ASSERT_TRUE(fetcher
);
3629 fetcher
->set_response_code(200);
3630 fetcher
->SetResponseString(cases
[i
].default_provider_response_json
);
3631 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3633 if (cases
[i
].prefer_keyword_provider_results
) {
3634 // Set up a keyword fetcher with provided results.
3635 net::TestURLFetcher
* keyword_fetcher
=
3636 test_factory_
.GetFetcherByID(
3637 SearchProvider::kKeywordProviderURLFetcherID
);
3638 ASSERT_TRUE(keyword_fetcher
);
3639 keyword_fetcher
->set_response_code(200);
3640 keyword_fetcher
->SetResponseString(
3641 cases
[i
].keyword_provider_response_json
);
3642 keyword_fetcher
->delegate()->OnURLFetchComplete(keyword_fetcher
);
3643 keyword_fetcher
= NULL
;
3646 RunTillProviderDone();
3648 const std::string description
=
3649 "for input with json =" + cases
[i
].default_provider_response_json
;
3650 const ACMatches
& matches
= provider_
->matches();
3651 // The top match must inline and score as highly as calculated verbatim.
3652 ASSERT_FALSE(matches
.empty());
3653 EXPECT_GE(matches
[0].relevance
, 1300);
3655 ASSERT_LE(matches
.size(), ARRAYSIZE_UNSAFE(cases
[i
].matches
));
3656 // Ensure that the returned matches equal the expectations.
3657 for (size_t j
= 0; j
< matches
.size(); ++j
) {
3658 SCOPED_TRACE(description
);
3659 EXPECT_EQ(cases
[i
].matches
[j
].contents
,
3660 base::UTF16ToUTF8(matches
[j
].contents
));
3661 EXPECT_EQ(cases
[i
].matches
[j
].allowed_to_be_prefetched
,
3662 SearchProvider::ShouldPrefetch(matches
[j
]));
3663 EXPECT_EQ(cases
[i
].matches
[j
].type
, matches
[j
].type
);
3664 EXPECT_EQ(cases
[i
].matches
[j
].from_keyword
,
3665 matches
[j
].keyword
== ASCIIToUTF16("k"));
3670 TEST_F(SearchProviderTest
, XSSIGuardedJSONParsing_InvalidResponse
) {
3673 std::string
input_str("abc");
3674 QueryForInput(ASCIIToUTF16(input_str
), false, false);
3676 // Set up a default fetcher with provided results.
3677 net::TestURLFetcher
* fetcher
=
3678 test_factory_
.GetFetcherByID(
3679 SearchProvider::kDefaultProviderURLFetcherID
);
3680 ASSERT_TRUE(fetcher
);
3681 fetcher
->set_response_code(200);
3682 fetcher
->SetResponseString("this is a bad non-json response");
3683 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3685 RunTillProviderDone();
3687 const ACMatches
& matches
= provider_
->matches();
3689 // Should have exactly one "search what you typed" match
3690 ASSERT_TRUE(matches
.size() == 1);
3691 EXPECT_EQ(input_str
, base::UTF16ToUTF8(matches
[0].contents
));
3692 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
3696 // A basic test that verifies that the XSSI guarded JSON response is parsed
3698 TEST_F(SearchProviderTest
, XSSIGuardedJSONParsing_ValidResponses
) {
3700 std::string contents
;
3701 AutocompleteMatchType::Type type
;
3703 const Match kEmptyMatch
= {
3704 kNotApplicable
, AutocompleteMatchType::NUM_TYPES
3708 const std::string input_text
;
3709 const std::string default_provider_response_json
;
3710 const Match matches
[4];
3714 "[\"a\",[\"b\", \"c\"],[],[],"
3715 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
3716 "\"google:suggestrelevance\":[1, 2]}]",
3717 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3718 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
3719 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
3723 // Standard XSSI guard - )]}'\n.
3725 ")]}'\n[\"a\",[\"b\", \"c\"],[],[],"
3726 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
3727 "\"google:suggestrelevance\":[1, 2]}]",
3728 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3729 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
3730 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
3734 // Modified XSSI guard - contains "[".
3736 ")]}'\n[)\"[\"a\",[\"b\", \"c\"],[],[],"
3737 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
3738 "\"google:suggestrelevance\":[1, 2]}]",
3739 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3740 { "c", AutocompleteMatchType::SEARCH_SUGGEST
},
3741 { "b", AutocompleteMatchType::SEARCH_SUGGEST
},
3747 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
3749 QueryForInput(ASCIIToUTF16(cases
[i
].input_text
), false, false);
3751 // Set up a default fetcher with provided results.
3752 net::TestURLFetcher
* fetcher
=
3753 test_factory_
.GetFetcherByID(
3754 SearchProvider::kDefaultProviderURLFetcherID
);
3755 ASSERT_TRUE(fetcher
);
3756 fetcher
->set_response_code(200);
3757 fetcher
->SetResponseString(cases
[i
].default_provider_response_json
);
3758 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3760 RunTillProviderDone();
3762 const ACMatches
& matches
= provider_
->matches();
3763 // The top match must inline and score as highly as calculated verbatim.
3764 ASSERT_FALSE(matches
.empty());
3765 EXPECT_GE(matches
[0].relevance
, 1300);
3767 SCOPED_TRACE("for case: " + base::IntToString(i
));
3768 ASSERT_LE(matches
.size(), ARRAYSIZE_UNSAFE(cases
[i
].matches
));
3770 // Ensure that the returned matches equal the expectations.
3771 for (; j
< matches
.size(); ++j
) {
3772 SCOPED_TRACE("and match: " + base::IntToString(j
));
3773 EXPECT_EQ(cases
[i
].matches
[j
].contents
,
3774 base::UTF16ToUTF8(matches
[j
].contents
));
3775 EXPECT_EQ(cases
[i
].matches
[j
].type
, matches
[j
].type
);
3777 for (; j
< ARRAYSIZE_UNSAFE(cases
[i
].matches
); ++j
) {
3778 SCOPED_TRACE("and match: " + base::IntToString(j
));
3779 EXPECT_EQ(cases
[i
].matches
[j
].contents
, kNotApplicable
);
3780 EXPECT_EQ(cases
[i
].matches
[j
].type
, AutocompleteMatchType::NUM_TYPES
);
3785 // Test that deletion url gets set on an AutocompleteMatch when available for a
3786 // personalized query.
3787 TEST_F(SearchProviderTest
, ParseDeletionUrl
) {
3789 std::string contents
;
3790 std::string deletion_url
;
3791 AutocompleteMatchType::Type type
;
3794 const Match kEmptyMatch
= {
3795 kNotApplicable
, "", AutocompleteMatchType::NUM_TYPES
3798 const char url
[] = "https://www.google.com/complete/deleteitems"
3799 "?delq=ab&client=chrome&deltok=xsrf123";
3802 const std::string input_text
;
3803 const std::string response_json
;
3804 const Match matches
[4];
3806 // A deletion URL on a personalized query should be reflected in the
3807 // resulting AutocompleteMatch.
3809 "[\"a\",[\"ab\", \"ac\"],[],[],"
3810 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\"],"
3811 "\"google:suggestrelevance\":[1, 2],"
3812 "\"google:suggestdetail\":[{\"du\":"
3813 "\"https://www.google.com/complete/deleteitems?delq=ab&client=chrome"
3814 "&deltok=xsrf123\"}, {}]}]",
3815 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3816 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3817 { "ab", url
, AutocompleteMatchType::SEARCH_SUGGEST
},
3821 // Personalized queries without deletion URLs shouldn't cause errors.
3823 "[\"a\",[\"ab\", \"ac\"],[],[],"
3824 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\"],"
3825 "\"google:suggestrelevance\":[1, 2],"
3826 "\"google:suggestdetail\":[{}, {}]}]",
3827 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
3828 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3829 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST
},
3835 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); i
++) {
3836 QueryForInput(ASCIIToUTF16(cases
[i
].input_text
), false, false);
3838 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
3839 SearchProvider::kDefaultProviderURLFetcherID
);
3840 ASSERT_TRUE(fetcher
);
3841 fetcher
->set_response_code(200);
3842 fetcher
->SetResponseString(cases
[i
].response_json
);
3843 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
3845 RunTillProviderDone();
3847 const ACMatches
& matches
= provider_
->matches();
3848 ASSERT_FALSE(matches
.empty());
3850 SCOPED_TRACE("for input with json = " + cases
[i
].response_json
);
3852 for (size_t j
= 0; j
< matches
.size(); ++j
) {
3853 const Match
& match
= cases
[i
].matches
[j
];
3854 SCOPED_TRACE(" and match index: " + base::IntToString(j
));
3855 EXPECT_EQ(match
.contents
, base::UTF16ToUTF8(matches
[j
].contents
));
3856 EXPECT_EQ(match
.deletion_url
, matches
[j
].GetAdditionalInfo(
3862 TEST_F(SearchProviderTest
, ReflectsBookmarkBarState
) {
3863 profile_
.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar
, false);
3864 base::string16 term
= term1_
.substr(0, term1_
.length() - 1);
3865 QueryForInput(term
, true, false);
3866 ASSERT_FALSE(provider_
->matches().empty());
3867 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
3868 provider_
->matches()[0].type
);
3869 ASSERT_TRUE(provider_
->matches()[0].search_terms_args
!= NULL
);
3870 EXPECT_FALSE(provider_
->matches()[0].search_terms_args
->bookmark_bar_pinned
);
3872 profile_
.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar
, true);
3873 term
= term1_
.substr(0, term1_
.length() - 1);
3874 QueryForInput(term
, true, false);
3875 ASSERT_FALSE(provider_
->matches().empty());
3876 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
,
3877 provider_
->matches()[0].type
);
3878 ASSERT_TRUE(provider_
->matches()[0].search_terms_args
!= NULL
);
3879 EXPECT_TRUE(provider_
->matches()[0].search_terms_args
->bookmark_bar_pinned
);
3882 TEST_F(SearchProviderTest
, CanSendURL
) {
3883 TemplateURLData template_url_data
;
3884 template_url_data
.short_name
= ASCIIToUTF16("t");
3885 template_url_data
.SetURL("http://www.google.com/{searchTerms}");
3886 template_url_data
.suggestions_url
= "http://www.google.com/{searchTerms}";
3887 template_url_data
.instant_url
= "http://does/not/exist?strk=1";
3888 template_url_data
.search_terms_replacement_key
= "strk";
3889 template_url_data
.id
= SEARCH_ENGINE_GOOGLE
;
3890 TemplateURL
google_template_url(&profile_
, template_url_data
);
3892 // Create field trial.
3893 base::FieldTrial
* field_trial
= base::FieldTrialList::CreateFieldTrial(
3894 "AutocompleteDynamicTrial_2", "EnableZeroSuggest");
3895 field_trial
->group();
3898 EXPECT_FALSE(SearchProvider::CanSendURL(
3899 GURL("http://www.google.com/search"),
3900 GURL("https://www.google.com/complete/search"), &google_template_url
,
3901 AutocompleteInput::OTHER
, &profile_
));
3902 SigninManagerBase
* signin
= SigninManagerFactory::GetForProfile(&profile_
);
3903 signin
->SetAuthenticatedUsername("test");
3905 // All conditions should be met.
3906 EXPECT_TRUE(SearchProvider::CanSendURL(
3907 GURL("http://www.google.com/search"),
3908 GURL("https://www.google.com/complete/search"), &google_template_url
,
3909 AutocompleteInput::OTHER
, &profile_
));
3911 // Not in field trial.
3912 ResetFieldTrialList();
3913 EXPECT_FALSE(SearchProvider::CanSendURL(
3914 GURL("http://www.google.com/search"),
3915 GURL("https://www.google.com/complete/search"), &google_template_url
,
3916 AutocompleteInput::OTHER
, &profile_
));
3917 field_trial
= base::FieldTrialList::CreateFieldTrial(
3918 "AutocompleteDynamicTrial_2", "EnableZeroSuggest");
3919 field_trial
->group();
3921 // Invalid page URL.
3922 EXPECT_FALSE(SearchProvider::CanSendURL(
3924 GURL("https://www.google.com/complete/search"), &google_template_url
,
3925 AutocompleteInput::OTHER
, &profile_
));
3927 // Invalid page classification.
3928 EXPECT_FALSE(SearchProvider::CanSendURL(
3929 GURL("http://www.google.com/search"),
3930 GURL("https://www.google.com/complete/search"), &google_template_url
,
3931 AutocompleteInput::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS
,
3934 // Invalid page classification.
3935 EXPECT_FALSE(SearchProvider::CanSendURL(
3936 GURL("http://www.google.com/search"),
3937 GURL("https://www.google.com/complete/search"), &google_template_url
,
3938 AutocompleteInput::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS
,
3941 // HTTPS page URL on same domain as provider.
3942 EXPECT_TRUE(SearchProvider::CanSendURL(
3943 GURL("https://www.google.com/search"),
3944 GURL("https://www.google.com/complete/search"),
3945 &google_template_url
, AutocompleteInput::OTHER
, &profile_
));
3947 // Non-HTTP[S] page URL on same domain as provider.
3948 EXPECT_FALSE(SearchProvider::CanSendURL(
3949 GURL("ftp://www.google.com/search"),
3950 GURL("https://www.google.com/complete/search"), &google_template_url
,
3951 AutocompleteInput::OTHER
, &profile_
));
3953 // Non-HTTP page URL on different domain.
3954 EXPECT_FALSE(SearchProvider::CanSendURL(
3955 GURL("https://www.notgoogle.com/search"),
3956 GURL("https://www.google.com/complete/search"), &google_template_url
,
3957 AutocompleteInput::OTHER
, &profile_
));
3959 // Non-HTTPS provider.
3960 EXPECT_FALSE(SearchProvider::CanSendURL(
3961 GURL("http://www.google.com/search"),
3962 GURL("http://www.google.com/complete/search"), &google_template_url
,
3963 AutocompleteInput::OTHER
, &profile_
));
3965 // Suggest disabled.
3966 profile_
.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled
, false);
3967 EXPECT_FALSE(SearchProvider::CanSendURL(
3968 GURL("http://www.google.com/search"),
3969 GURL("https://www.google.com/complete/search"), &google_template_url
,
3970 AutocompleteInput::OTHER
, &profile_
));
3971 profile_
.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled
, true);
3974 EXPECT_FALSE(SearchProvider::CanSendURL(
3975 GURL("http://www.google.com/search"),
3976 GURL("https://www.google.com/complete/search"), &google_template_url
,
3977 AutocompleteInput::OTHER
, profile_
.GetOffTheRecordProfile()));
3979 // Tab sync not enabled.
3980 profile_
.GetPrefs()->SetBoolean(prefs::kSyncKeepEverythingSynced
, false);
3981 profile_
.GetPrefs()->SetBoolean(prefs::kSyncTabs
, false);
3982 EXPECT_FALSE(SearchProvider::CanSendURL(
3983 GURL("http://www.google.com/search"),
3984 GURL("https://www.google.com/complete/search"), &google_template_url
,
3985 AutocompleteInput::OTHER
, &profile_
));
3986 profile_
.GetPrefs()->SetBoolean(prefs::kSyncTabs
, true);
3988 // Tab sync is encrypted.
3989 ProfileSyncService
* service
=
3990 ProfileSyncServiceFactory::GetInstance()->GetForProfile(&profile_
);
3991 syncer::ModelTypeSet encrypted_types
= service
->GetEncryptedDataTypes();
3992 encrypted_types
.Put(syncer::SESSIONS
);
3993 service
->OnEncryptedTypesChanged(encrypted_types
, false);
3994 EXPECT_FALSE(SearchProvider::CanSendURL(
3995 GURL("http://www.google.com/search"),
3996 GURL("https://www.google.com/complete/search"), &google_template_url
,
3997 AutocompleteInput::OTHER
, &profile_
));
3998 encrypted_types
.Remove(syncer::SESSIONS
);
3999 service
->OnEncryptedTypesChanged(encrypted_types
, false);
4001 // Check that there were no side effects from previous tests.
4002 EXPECT_TRUE(SearchProvider::CanSendURL(
4003 GURL("http://www.google.com/search"),
4004 GURL("https://www.google.com/complete/search"), &google_template_url
,
4005 AutocompleteInput::OTHER
, &profile_
));
4008 TEST_F(SearchProviderTest
, TestDeleteMatch
) {
4009 AutocompleteMatch
match(provider_
, 0, true,
4010 AutocompleteMatchType::SEARCH_SUGGEST
);
4011 match
.RecordAdditionalInfo(
4012 SearchProvider::kDeletionUrlKey
,
4013 "https://www.google.com/complete/deleteitem?q=foo");
4015 // Test a successful deletion request.
4016 provider_
->matches_
.push_back(match
);
4017 provider_
->DeleteMatch(match
);
4018 EXPECT_FALSE(provider_
->deletion_handlers_
.empty());
4019 EXPECT_TRUE(provider_
->matches_
.empty());
4020 // Set up a default fetcher with provided results.
4021 net::TestURLFetcher
* fetcher
= test_factory_
.GetFetcherByID(
4022 SearchProvider::kDeletionURLFetcherID
);
4023 ASSERT_TRUE(fetcher
);
4024 fetcher
->set_response_code(200);
4025 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
4026 EXPECT_TRUE(provider_
->deletion_handlers_
.empty());
4027 EXPECT_TRUE(provider_
->is_success());
4029 // Test a failing deletion request.
4030 provider_
->matches_
.push_back(match
);
4031 provider_
->DeleteMatch(match
);
4032 EXPECT_FALSE(provider_
->deletion_handlers_
.empty());
4033 // Set up a default fetcher with provided results.
4034 fetcher
= test_factory_
.GetFetcherByID(
4035 SearchProvider::kDeletionURLFetcherID
);
4036 ASSERT_TRUE(fetcher
);
4037 fetcher
->set_response_code(500);
4038 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
4039 EXPECT_TRUE(provider_
->deletion_handlers_
.empty());
4040 EXPECT_FALSE(provider_
->is_success());