Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / autocomplete / search_provider_unittest.cc
blobc608d9b5ec6917d2b455ef6edf8f85ad46149203
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"
7 #include <string>
9 #include "base/command_line.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/time/time.h"
18 #include "build/build_config.h"
19 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
20 #include "chrome/browser/autocomplete/autocomplete_controller.h"
21 #include "chrome/browser/autocomplete/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;
50 namespace {
52 // Returns the first match in |matches| with |allowed_to_be_default_match|
53 // set to true.
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)
57 ++it;
58 return it;
61 class SuggestionDeletionHandler;
62 class SearchProviderForTest : public SearchProvider {
63 public:
64 SearchProviderForTest(
65 AutocompleteProviderListener* listener,
66 Profile* profile);
67 bool is_success() { return is_success_; };
69 protected:
70 virtual ~SearchProviderForTest();
72 private:
73 virtual void RecordDeletionResult(bool success) OVERRIDE;
74 bool is_success_;
75 DISALLOW_COPY_AND_ASSIGN(SearchProviderForTest);
78 SearchProviderForTest::SearchProviderForTest(
79 AutocompleteProviderListener* listener,
80 Profile* profile)
81 : SearchProvider(listener, profile), is_success_(false) {
84 SearchProviderForTest::~SearchProviderForTest() {
87 void SearchProviderForTest::RecordDeletionResult(bool success) {
88 is_success_ = success;
91 } // namespace
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
100 // added to history.
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 {
106 public:
107 struct ResultInfo {
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)
115 : gurl(gurl),
116 result_type(result_type),
117 allowed_to_be_default_match(allowed_to_be_default_match),
118 fill_into_edit(fill_into_edit) {
121 const GURL gurl;
122 const AutocompleteMatch::Type result_type;
123 const bool allowed_to_be_default_match;
124 const base::string16 fill_into_edit;
127 struct TestData {
128 const base::string16 input;
129 const size_t num_results;
130 const ResultInfo output[3];
133 SearchProviderTest()
134 : default_t_url_(NULL),
135 term1_(ASCIIToUTF16("term1")),
136 keyword_t_url_(NULL),
137 keyword_term_(ASCIIToUTF16("keyword")),
138 run_loop_(NULL) {
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);
148 protected:
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_;
208 GURL term1_url_;
209 TemplateURL* keyword_t_url_;
210 const base::string16 keyword_term_;
211 GURL keyword_url_;
213 content::TestBrowserThreadBundle thread_bundle_;
215 // URLFetcherFactory implementation registered.
216 net::TestURLFetcherFactory test_factory_;
218 // Profile we use.
219 TestingProfile profile_;
221 // The provider.
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);
230 // static
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_);
245 turl_model->Load();
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.
288 provider_ = NULL;
291 void SearchProviderTest::RunTest(TestData* cases,
292 int num_cases,
293 bool prefer_keyword) {
294 ACMatches matches;
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: ") +
305 cases[i].input +
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) <<
312 diagnostic_details;
313 EXPECT_EQ(cases[i].output[j].result_type, matches[j].type) <<
314 diagnostic_details;
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()) {
326 run_loop_->Quit();
327 run_loop_ = NULL;
331 void SearchProviderTest::RunTillProviderDone() {
332 if (provider_->done())
333 return;
335 base::RunLoop run_loop;
336 run_loop_ = &run_loop;
337 run_loop.Run();
340 void SearchProviderTest::QueryForInput(const base::string16& text,
341 bool prevent_inline_autocomplete,
342 bool prefer_keyword) {
343 // Start a query.
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
351 // URLFetchers runs.
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());
361 if (!wyt_match)
362 return;
363 ASSERT_GE(provider_->matches().size(), 1u);
364 EXPECT_TRUE(FindMatchWithDestination(GURL(
365 default_t_url_->url_ref().ReplaceSearchTerms(
366 TemplateURLRef::SearchTermsArgs(text))),
367 wyt_match));
370 GURL SearchProviderTest::AddSearchToHistory(TemplateURL* t_url,
371 base::string16 term,
372 int visit_count) {
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);
384 return search;
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) {
392 *match = *i;
393 return true;
396 return false;
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) {
404 *match = *i;
405 return true;
408 return false;
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);
438 size_t i = 0;
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) <<
442 error_description;
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
453 // a DCHECK.
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");
460 trial->group();
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);
488 fetcher = NULL;
490 // Run till the history results complete.
491 RunTillProviderDone();
493 // The SearchProvider is done. Make sure it has a result for the history
494 // term term1.
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,
529 false,
530 false);
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
561 // term keyword.
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[] = {
577 "username:password",
578 "http://username:password",
579 "https://username:password",
580 "username:password@hostname",
581 "http://username:password@hostname/",
582 "file://filename",
583 "data://data",
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[] = {
605 "query",
606 "query with spaces",
607 "http://hostname",
608 "http://hostname/path",
609 "http://hostname #ref",
610 "www.hostname.com #ref",
611 "https://hostname",
612 "#hashtag",
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"),
639 &wyt_match));
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;
654 struct {
655 const std::string json;
656 const std::string matches_in_default_mode[3];
657 const std::string matches_in_forced_query_mode[3];
658 } cases[] = {
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
666 // go second.
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
674 // would go first.
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
701 // words are typed.
702 TEST_F(SearchProviderTest, DontAutocompleteUntilMultipleWordsTyped) {
703 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("one search"),
704 1));
705 profile_.BlockUntilHistoryProcessesPendingRequests();
707 AutocompleteMatch wyt_match;
708 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("on"),
709 &wyt_match));
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"),
718 &wyt_match));
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"),
729 2));
730 profile_.BlockUntilHistoryProcessesPendingRequests();
732 AutocompleteMatch wyt_match;
733 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("tw"),
734 &wyt_match));
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"),
746 2));
747 profile_.BlockUntilHistoryProcessesPendingRequests();
749 AutocompleteMatch wyt_match;
750 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("two "),
751 &wyt_match));
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"),
770 &wyt_match));
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"),
794 &wyt_match));
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"),
807 &wyt_match));
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"),
829 &wyt_match));
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"),
845 &wyt_match));
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) {
903 TestData cases[] = {
904 // Test a simple keyword input.
905 { ASCIIToUTF16("k foo"), 2,
906 { ResultInfo(GURL("http://keyword/foo"),
907 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
908 true,
909 ASCIIToUTF16("k foo")),
910 ResultInfo(GURL("http://defaultturl/k%20foo"),
911 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
912 false,
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,
920 true,
921 ASCIIToUTF16("k foo")),
922 ResultInfo(GURL("http://defaultturl/k%20%20%20foo"),
923 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
924 false,
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
930 // matches.
931 { ASCIIToUTF16("k foo bar"), 2,
932 { ResultInfo(GURL("http://keyword/foo%20%20bar"),
933 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
934 true,
935 ASCIIToUTF16("k foo bar")),
936 ResultInfo(GURL("http://defaultturl/k%20%20foo%20%20bar"),
937 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
938 false,
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,
949 true,
950 ASCIIToUTF16("k foo")),
951 ResultInfo(GURL("http://defaultturl/www.k%20foo"),
952 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
953 false,
954 ASCIIToUTF16("www.k foo")) } },
955 { ASCIIToUTF16("http://k foo"), 2,
956 { ResultInfo(GURL("http://keyword/foo"),
957 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
958 true,
959 ASCIIToUTF16("k foo")),
960 ResultInfo(GURL("http://defaultturl/http%3A//k%20foo"),
961 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
962 false,
963 ASCIIToUTF16("http://k foo")) } },
964 { ASCIIToUTF16("http://www.k foo"), 2,
965 { ResultInfo(GURL("http://keyword/foo"),
966 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
967 true,
968 ASCIIToUTF16("k foo")),
969 ResultInfo(GURL("http://defaultturl/http%3A//www.k%20foo"),
970 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
971 false,
972 ASCIIToUTF16("http://www.k foo")) } },
974 // A keyword with no remaining input shouldn't get a keyword
975 // verbatim match.
976 { ASCIIToUTF16("k"), 1,
977 { ResultInfo(GURL("http://defaultturl/k"),
978 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
979 true,
980 ASCIIToUTF16("k")) } },
981 { ASCIIToUTF16("k "), 1,
982 { ResultInfo(GURL("http://defaultturl/k%20"),
983 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
984 true,
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
1000 // generates.
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,
1022 true,
1023 ASCIIToUTF16("k a")),
1024 ResultInfo(GURL("http://www.bar.com/k%20a?a=b"),
1025 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1026 false,
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);
1050 fetcher = NULL;
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);
1076 fetcher = NULL;
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) {
1101 struct {
1102 const std::string default_provider_json;
1103 const std::string keyword_provider_json;
1104 const std::string matches[5];
1105 } cases[] = {
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));
1149 size_t j = 0;
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) <<
1153 description;
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 };
1171 struct {
1172 const std::string json;
1173 const DefaultFetcherMatch matches[6];
1174 const std::string inline_autocompletion;
1175 } cases[] = {
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 },
1180 std::string() },
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 },
1186 std::string() },
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 },
1194 std::string() },
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,
1201 kEmptyMatch },
1202 std::string() },
1203 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1204 "\"google:suggestrelevance\":[9999]}]",
1205 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1206 kEmptyMatch },
1207 "1" },
1208 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1209 "\"google:suggestrelevance\":[9999]}]",
1210 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1211 kEmptyMatch },
1212 "1" },
1213 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1214 "\"google:suggestrelevance\":[9999]}]",
1215 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1216 kEmptyMatch },
1217 "1" },
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,
1223 kEmptyMatch },
1224 std::string() },
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,
1230 kEmptyMatch },
1231 ".com" },
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,
1237 kEmptyMatch },
1238 ".com" },
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,
1244 kEmptyMatch },
1245 ".com" },
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,
1251 kEmptyMatch },
1252 "1" },
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,
1258 kEmptyMatch },
1259 std::string() },
1260 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1261 "\"google:verbatimrelevance\":0}]",
1262 { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1263 kEmptyMatch },
1264 std::string() },
1265 { "[\"a\",[\"http://b.com\"],[],[],"
1266 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1267 "\"google:suggestrelevance\":[9999]}]",
1268 { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch,
1269 kEmptyMatch, kEmptyMatch },
1270 std::string() },
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 },
1277 std::string() },
1278 { "[\"a\",[\"https://a/\"],[],[],"
1279 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1280 "\"google:suggestrelevance\":[9999]}]",
1281 { { "https://a", true }, { "a", true }, kEmptyMatch, kEmptyMatch,
1282 kEmptyMatch, kEmptyMatch },
1283 std::string() },
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,
1289 kEmptyMatch },
1290 std::string() },
1291 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1292 { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1293 kEmptyMatch },
1294 std::string() },
1295 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1296 "\"google:verbatimrelevance\":0}]",
1297 { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1298 kEmptyMatch },
1299 std::string() },
1300 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1301 "\"google:verbatimrelevance\":0}]",
1302 { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
1303 kEmptyMatch },
1304 std::string() },
1305 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1306 "\"google:verbatimrelevance\":2}]",
1307 { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
1308 kEmptyMatch },
1309 std::string() },
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,
1315 kEmptyMatch },
1316 std::string() },
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 },
1323 std::string() },
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 } },
1330 std::string() },
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\","
1337 "\"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 } },
1341 std::string() },
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,
1346 kEmptyMatch },
1347 std::string() },
1348 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1349 { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1350 kEmptyMatch },
1351 std::string() },
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 },
1357 std::string() },
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 },
1363 std::string() },
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,
1369 kEmptyMatch },
1370 "2" },
1371 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1372 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1373 "\"google:verbatimrelevance\":0}]",
1374 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
1375 kEmptyMatch },
1376 "2" },
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,
1382 kEmptyMatch },
1383 std::string() },
1384 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1385 { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1386 kEmptyMatch },
1387 std::string() },
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));
1410 size_t j = 0;
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 };
1436 struct {
1437 const std::string json;
1438 const DefaultFetcherMatch matches[6];
1439 const std::string inline_autocompletion;
1440 } cases[] = {
1441 // Ensure that suggestrelevance scores reorder matches.
1442 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1443 { { "a", true }, { "c", false }, { "b", false }, kEmptyMatch, kEmptyMatch,
1444 kEmptyMatch },
1445 std::string() },
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 },
1451 std::string() },
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 },
1459 std::string() },
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,
1466 kEmptyMatch },
1467 std::string() },
1468 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1469 "\"google:suggestrelevance\":[9999]}]",
1470 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1471 kEmptyMatch },
1472 "1" },
1473 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1474 "\"google:suggestrelevance\":[9999]}]",
1475 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1476 kEmptyMatch },
1477 "1" },
1478 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1479 "\"google:suggestrelevance\":[9999]}]",
1480 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1481 kEmptyMatch },
1482 "1" },
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,
1488 kEmptyMatch },
1489 std::string() },
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,
1495 kEmptyMatch },
1496 ".com" },
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,
1502 kEmptyMatch },
1503 ".com" },
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,
1509 kEmptyMatch },
1510 ".com" },
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,
1516 kEmptyMatch },
1517 "1" },
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,
1524 kEmptyMatch },
1525 std::string() },
1526 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1527 "\"google:verbatimrelevance\":0}]",
1528 { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1529 kEmptyMatch },
1530 std::string() },
1531 { "[\"a\",[\"http://b.com\"],[],[],"
1532 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1533 "\"google:suggestrelevance\":[9999]}]",
1534 { { "b.com", false }, { "a", true }, kEmptyMatch, kEmptyMatch,
1535 kEmptyMatch, kEmptyMatch },
1536 std::string() },
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 },
1543 std::string() },
1545 // Allow low-scoring matches.
1546 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1547 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1548 kEmptyMatch },
1549 "1" },
1550 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1551 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1552 kEmptyMatch },
1553 "1" },
1554 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1555 "\"google:verbatimrelevance\":0}]",
1556 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1557 kEmptyMatch },
1558 "1" },
1559 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1560 "\"google:verbatimrelevance\":0}]",
1561 { { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1562 kEmptyMatch },
1563 "2" },
1564 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1565 "\"google:verbatimrelevance\":2}]",
1566 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
1567 kEmptyMatch },
1568 "2" },
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,
1574 kEmptyMatch },
1575 ".com" },
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 },
1582 "2.com" },
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 } },
1589 std::string() },
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\","
1596 "\"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 } },
1600 std::string() },
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,
1605 kEmptyMatch },
1606 std::string() },
1607 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1608 { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1609 kEmptyMatch },
1610 std::string() },
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 },
1616 std::string() },
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 },
1622 std::string() },
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,
1628 kEmptyMatch },
1629 "2" },
1630 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1631 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1632 "\"google:verbatimrelevance\":0}]",
1633 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
1634 kEmptyMatch },
1635 "2" },
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,
1641 kEmptyMatch },
1642 std::string() },
1643 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1644 { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1645 kEmptyMatch },
1646 std::string() },
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));
1679 size_t j = 0;
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;
1705 bool from_keyword;
1706 bool allowed_to_be_default_match;
1708 const KeywordFetcherMatch kEmptyMatch = { kNotApplicable, false, false };
1709 struct {
1710 const std::string json;
1711 const KeywordFetcherMatch matches[6];
1712 const std::string inline_autocompletion;
1713 } cases[] = {
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 },
1723 std::string() },
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 },
1738 kEmptyMatch },
1739 std::string() },
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 },
1749 std::string() },
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 },
1759 std::string() },
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 },
1766 "1" },
1767 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1768 "\"google:suggestrelevance\":[9999]}]",
1769 { { "a1", true, true },
1770 { "k a", false, false },
1771 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1772 "1" },
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 },
1779 "1" },
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 },
1788 std::string() },
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 },
1798 "1" },
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 },
1807 std::string() },
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 },
1814 std::string() },
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 },
1822 std::string() },
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 },
1831 std::string() },
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 },
1842 std::string() },
1843 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1844 { { "a", true, true },
1845 { "a1", true, true },
1846 { "k a", false, false },
1847 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1848 std::string() },
1849 // Continuing the same category of tests, but make sure we keep the
1850 // suggested relevance scores even as we discard the verbatim relevance
1851 // scores.
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 },
1858 std::string() },
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 },
1866 std::string() },
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 },
1874 std::string() },
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 } },
1885 std::string() },
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\","
1892 "\"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 } },
1900 std::string() },
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 },
1911 std::string() },
1912 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1913 { { "a", true, true },
1914 { "a1", true, true },
1915 { "k a", false, false },
1916 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1917 std::string() },
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 },
1927 std::string() },
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 },
1935 std::string() },
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 },
1945 "2" },
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 },
1954 "2" },
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 },
1963 std::string() },
1964 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1965 { { "a", true, true },
1966 { "k a", false, false },
1967 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1968 std::string() },
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 },
1984 std::string() },
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 },
1994 std::string() },
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 },
2002 std::string() },
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 },
2014 kEmptyMatch },
2015 std::string() },
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 },
2025 kEmptyMatch },
2026 std::string() },
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 },
2038 kEmptyMatch },
2039 "3" },
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 },
2049 kEmptyMatch },
2050 "3" },
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 },
2060 "3" },
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 },
2070 "3" },
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 },
2086 std::string() },
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 },
2095 std::string() },
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 },
2106 kEmptyMatch },
2107 "3" },
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 },
2117 kEmptyMatch },
2118 "3" },
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));
2153 size_t j = 0;
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;
2179 bool from_keyword;
2180 bool allowed_to_be_default_match;
2182 const KeywordFetcherMatch kEmptyMatch = { kNotApplicable, false, false };
2183 struct {
2184 const std::string json;
2185 const KeywordFetcherMatch matches[6];
2186 const std::string inline_autocompletion;
2187 } cases[] = {
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 },
2197 std::string() },
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 },
2212 kEmptyMatch },
2213 std::string() },
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 },
2223 std::string() },
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 },
2233 std::string() },
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 },
2240 "1" },
2241 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
2242 "\"google:suggestrelevance\":[9999]}]",
2243 { { "a1", true, true },
2244 { "k a", false, false },
2245 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
2246 "1" },
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 },
2253 "1" },
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 },
2262 std::string() },
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 },
2272 "1" },
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 },
2281 std::string() },
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 },
2289 std::string() },
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 },
2298 std::string() },
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 },
2307 std::string() },
2309 // The top result does not have to score as highly as calculated
2310 // verbatim. i.e., there are no minimum score restrictions in
2311 // this provider.
2312 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
2313 { { "a1", true, true },
2314 { "k a", false, false },
2315 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
2316 "1" },
2317 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
2318 { { "a1", true, true },
2319 { "k a", false, false },
2320 { "a", true, true },
2321 kEmptyMatch, kEmptyMatch, kEmptyMatch },
2322 "1" },
2323 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
2324 "\"google:verbatimrelevance\":0}]",
2325 { { "k a", false, false },
2326 { "a1", true, true },
2327 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
2328 "1" },
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 },
2336 "2" },
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 },
2344 "2" },
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 } },
2355 std::string() },
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\","
2362 "\"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 } },
2370 std::string() },
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 },
2381 std::string() },
2382 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
2383 { { "a", true, true },
2384 { "a1", true, true },
2385 { "k a", false, false },
2386 kEmptyMatch, kEmptyMatch, kEmptyMatch },
2387 std::string() },
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 },
2397 std::string() },
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 },
2405 std::string() },
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 },
2415 "2" },
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 },
2424 "2" },
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 },
2433 std::string() },
2434 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
2435 { { "a", true, true },
2436 { "k a", false, false },
2437 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
2438 std::string() },
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 },
2452 std::string() },
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 },
2462 std::string() },
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 },
2470 std::string() },
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 },
2482 kEmptyMatch },
2483 std::string() },
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 },
2493 kEmptyMatch },
2494 std::string() },
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 },
2506 kEmptyMatch },
2507 "3" },
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 },
2517 kEmptyMatch },
2518 "3" },
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 },
2528 "3" },
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 },
2538 "3" },
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 },
2551 std::string() },
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 },
2561 std::string() },
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 },
2572 kEmptyMatch },
2573 "3" },
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 },
2583 kEmptyMatch },
2584 "3" },
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));
2629 size_t j = 0;
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();
2655 struct {
2656 const base::string16 input;
2657 const std::string json;
2658 const std::string matches[6];
2659 } cases[] = {
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.
2663 { term,
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.
2670 { term,
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.
2677 { term,
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.
2685 { term,
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 } },
2691 { term,
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" } },
2698 { term,
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
2709 // server-provided.
2710 { ASCIIToUTF16("a.com"),
2711 "[\"a.com\",[\"a1\", \"a2\", \"a.com/1\", \"a.com/2\"],[],[],"
2712 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"NAVIGATION\","
2713 "\"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));
2737 size_t j = 0;
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 };
2758 struct {
2759 const std::string input;
2760 const std::string json;
2761 const DefaultFetcherUrlInputMatch output[4];
2762 } cases[] = {
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 },
2797 kEmptyMatch } },
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 },
2805 kEmptyMatch } },
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 },
2814 kEmptyMatch } },
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 },
2822 kEmptyMatch } },
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();
2836 size_t j = 0;
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 };
2872 struct {
2873 const std::string input;
2874 const std::string json;
2875 const DefaultFetcherUrlInputMatch output[4];
2876 } cases[] = {
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
2907 // relevances.
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 },
2926 kEmptyMatch } },
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 },
2934 kEmptyMatch } },
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
2938 // NAVSUGGEST).
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();
2970 size_t j = 0;
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);
3007 fetcher = NULL;
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) {
3035 struct {
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;
3043 } cases[] = {
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",
3111 true },
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.
3249 struct {
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().
3256 struct {
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;
3263 } results[5];
3264 } cases[] = {
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.
3268 { "x", 1300,
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.
3276 { "f", 1200,
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 } } },
3282 { "c", 1200,
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 } } },
3288 { "x", 1200,
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.
3296 { "x", 1300,
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 } } },
3302 { "f", 1200,
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 } } },
3308 { "c", 1200,
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 } } },
3314 { "x", 1200,
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.
3328 { "f", 0,
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 } } },
3334 { "c", 0,
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 } } },
3340 { "x", 0,
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.
3349 { "f", 1290,
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 } } },
3355 { "c", 1290,
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 } } },
3361 { "c", 1270,
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 } } },
3367 { "x", 1280,
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)
3384 break;
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()));
3391 } else {
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)
3419 continue;
3420 if (!cases[i].results[j].expect_match)
3421 continue;
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());
3425 ++nav_it;
3426 } else {
3427 ASSERT_NE(sug_end, sug_it) << "Failed to find " << suggestion;
3428 EXPECT_EQ(ASCIIToUTF16(suggestion), sug_it->suggestion());
3429 ++sug_it;
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) {
3440 struct Match {
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};
3451 struct {
3452 const std::string input_text;
3453 const std::string response_json;
3454 const Match matches[5];
3455 } cases[] = {
3456 // A query and an entity suggestion with different search terms.
3457 { "x",
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 },
3466 kEmptyMatch,
3467 kEmptyMatch
3470 // A query and an entity suggestion with same search terms.
3471 { "x",
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 },
3480 kEmptyMatch,
3481 kEmptyMatch
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));
3505 size_t j = 0;
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) {
3536 struct Match {
3537 std::string contents;
3538 bool allowed_to_be_prefetched;
3539 AutocompleteMatchType::Type type;
3540 bool from_keyword;
3542 const Match kEmptyMatch = { kNotApplicable,
3543 false,
3544 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
3545 false };
3547 struct {
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];
3553 } cases[] = {
3554 // Default provider response does not have prefetch details. Ensure that the
3555 // suggestions are not marked as prefetch query.
3556 { "a",
3557 false,
3558 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
3559 std::string(),
3560 { { "a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
3561 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
3562 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
3563 kEmptyMatch,
3564 kEmptyMatch
3567 // Ensure that default provider suggest response prefetch details are
3568 // parsed and recorded in AutocompleteMatch.
3569 { "ab",
3570 false,
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]}]",
3575 std::string(),
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 },
3580 kEmptyMatch
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.
3587 { "ab",
3588 false,
3589 "[\"ab\",[\"ab\", \"http://ab.com\"],[],[],"
3590 "{\"google:clientdata\":{\"phi\": 0},"
3591 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
3592 "\"google:suggestrelevance\":[99, 98]}]",
3593 std::string(),
3594 { {"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
3595 {"ab.com", false, AutocompleteMatchType::NAVSUGGEST, false },
3596 kEmptyMatch,
3597 kEmptyMatch,
3598 kEmptyMatch
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.
3605 { "k a",
3606 true,
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) {
3671 ClearAllResults();
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,
3693 matches[0].type);
3696 // A basic test that verifies that the XSSI guarded JSON response is parsed
3697 // correctly.
3698 TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_ValidResponses) {
3699 struct Match {
3700 std::string contents;
3701 AutocompleteMatchType::Type type;
3703 const Match kEmptyMatch = {
3704 kNotApplicable, AutocompleteMatchType::NUM_TYPES
3707 struct {
3708 const std::string input_text;
3709 const std::string default_provider_response_json;
3710 const Match matches[4];
3711 } cases[] = {
3712 // No XSSI guard.
3713 { "a",
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 },
3720 kEmptyMatch,
3723 // Standard XSSI guard - )]}'\n.
3724 { "a",
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 },
3731 kEmptyMatch,
3734 // Modified XSSI guard - contains "[".
3735 { "a",
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 },
3742 kEmptyMatch,
3747 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
3748 ClearAllResults();
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));
3769 size_t j = 0;
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) {
3788 struct Match {
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";
3801 struct {
3802 const std::string input_text;
3803 const std::string response_json;
3804 const Match matches[4];
3805 } cases[] = {
3806 // A deletion URL on a personalized query should be reflected in the
3807 // resulting AutocompleteMatch.
3808 { "a",
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 },
3818 kEmptyMatch,
3821 // Personalized queries without deletion URLs shouldn't cause errors.
3822 { "a",
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 },
3830 kEmptyMatch,
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(
3857 "deletion_url"));
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();
3897 // Not signed in.
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(
3923 GURL("badpageurl"),
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,
3932 &profile_));
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,
3939 &profile_));
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);
3973 // Incognito.
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());