GoogleURLTrackerInfoBarDelegate: Initialize uninitialized member in constructor.
[chromium-blink-merge.git] / chrome / browser / autocomplete / search_provider_unittest.cc
blobf1b459e27261c05bc5fc5769436bd08b0297240a
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_factory.h"
34 #include "chrome/browser/sync/profile_sync_service.h"
35 #include "chrome/browser/sync/profile_sync_service_factory.h"
36 #include "chrome/common/chrome_switches.h"
37 #include "chrome/common/pref_names.h"
38 #include "chrome/test/base/testing_browser_process.h"
39 #include "chrome/test/base/testing_profile.h"
40 #include "components/google/core/browser/google_switches.h"
41 #include "components/signin/core/browser/signin_manager.h"
42 #include "components/sync_driver/pref_names.h"
43 #include "components/variations/entropy_provider.h"
44 #include "components/variations/variations_associated_data.h"
45 #include "content/public/test/test_browser_thread_bundle.h"
46 #include "net/url_request/test_url_fetcher_factory.h"
47 #include "net/url_request/url_request_status.h"
48 #include "testing/gtest/include/gtest/gtest.h"
50 using base::ASCIIToUTF16;
52 namespace {
54 // Returns the first match in |matches| with |allowed_to_be_default_match|
55 // set to true.
56 ACMatches::const_iterator FindDefaultMatch(const ACMatches& matches) {
57 ACMatches::const_iterator it = matches.begin();
58 while ((it != matches.end()) && !it->allowed_to_be_default_match)
59 ++it;
60 return it;
63 class SuggestionDeletionHandler;
64 class SearchProviderForTest : public SearchProvider {
65 public:
66 SearchProviderForTest(
67 AutocompleteProviderListener* listener,
68 Profile* profile);
69 bool is_success() { return is_success_; };
71 protected:
72 virtual ~SearchProviderForTest();
74 private:
75 virtual void RecordDeletionResult(bool success) OVERRIDE;
76 bool is_success_;
77 DISALLOW_COPY_AND_ASSIGN(SearchProviderForTest);
80 SearchProviderForTest::SearchProviderForTest(
81 AutocompleteProviderListener* listener,
82 Profile* profile)
83 : SearchProvider(listener, profile), is_success_(false) {
86 SearchProviderForTest::~SearchProviderForTest() {
89 void SearchProviderForTest::RecordDeletionResult(bool success) {
90 is_success_ = success;
93 } // namespace
95 // SearchProviderTest ---------------------------------------------------------
97 // The following environment is configured for these tests:
98 // . The TemplateURL default_t_url_ is set as the default provider.
99 // . The TemplateURL keyword_t_url_ is added to the TemplateURLService. This
100 // TemplateURL has a valid suggest and search URL.
101 // . The URL created by using the search term term1_ with default_t_url_ is
102 // added to history.
103 // . The URL created by using the search term keyword_term_ with keyword_t_url_
104 // is added to history.
105 // . test_factory_ is set as the URLFetcherFactory.
106 class SearchProviderTest : public testing::Test,
107 public AutocompleteProviderListener {
108 public:
109 struct ResultInfo {
110 ResultInfo() : result_type(AutocompleteMatchType::NUM_TYPES),
111 allowed_to_be_default_match(false) {
113 ResultInfo(GURL gurl,
114 AutocompleteMatch::Type result_type,
115 bool allowed_to_be_default_match,
116 base::string16 fill_into_edit)
117 : gurl(gurl),
118 result_type(result_type),
119 allowed_to_be_default_match(allowed_to_be_default_match),
120 fill_into_edit(fill_into_edit) {
123 const GURL gurl;
124 const AutocompleteMatch::Type result_type;
125 const bool allowed_to_be_default_match;
126 const base::string16 fill_into_edit;
129 struct TestData {
130 const base::string16 input;
131 const size_t num_results;
132 const ResultInfo output[3];
135 SearchProviderTest()
136 : default_t_url_(NULL),
137 term1_(ASCIIToUTF16("term1")),
138 keyword_t_url_(NULL),
139 keyword_term_(ASCIIToUTF16("keyword")),
140 run_loop_(NULL) {
141 ResetFieldTrialList();
144 // See description above class for what this registers.
145 virtual void SetUp() OVERRIDE;
146 virtual void TearDown() OVERRIDE;
148 void RunTest(TestData* cases, int num_cases, bool prefer_keyword);
150 protected:
151 // Needed for AutocompleteFieldTrial::ActivateStaticTrials();
152 scoped_ptr<base::FieldTrialList> field_trial_list_;
154 // Default value used for testing.
155 static const std::string kNotApplicable;
157 // Adds a search for |term|, using the engine |t_url| to the history, and
158 // returns the URL for that search.
159 GURL AddSearchToHistory(TemplateURL* t_url, base::string16 term, int visit_count);
161 // Looks for a match in |provider_| with |contents| equal to |contents|.
162 // Sets |match| to it if found. Returns whether |match| was set.
163 bool FindMatchWithContents(const base::string16& contents,
164 AutocompleteMatch* match);
166 // Looks for a match in |provider_| with destination |url|. Sets |match| to
167 // it if found. Returns whether |match| was set.
168 bool FindMatchWithDestination(const GURL& url, AutocompleteMatch* match);
170 // AutocompleteProviderListener:
171 // If we're waiting for the provider to finish, this exits the message loop.
172 virtual void OnProviderUpdate(bool updated_matches) OVERRIDE;
174 // Runs a nested message loop until provider_ is done. The message loop is
175 // exited by way of OnProviderUpdate.
176 void RunTillProviderDone();
178 // Invokes Start on provider_, then runs all pending tasks.
179 void QueryForInput(const base::string16& text,
180 bool prevent_inline_autocomplete,
181 bool prefer_keyword);
183 // Calls QueryForInput(), finishes any suggest query, then if |wyt_match| is
184 // non-NULL, sets it to the "what you typed" entry for |text|.
185 void QueryForInputAndSetWYTMatch(const base::string16& text,
186 AutocompleteMatch* wyt_match);
188 // Notifies the URLFetcher for the suggest query corresponding to the default
189 // search provider that it's done.
190 // Be sure and wrap calls to this in ASSERT_NO_FATAL_FAILURE.
191 void FinishDefaultSuggestQuery();
193 // Runs SearchProvider on |input|, for which the suggest server replies
194 // with |json|, and expects that the resulting matches' contents equals
195 // that in |matches|. An empty entry in |matches| means no match should
196 // be returned in that position. Reports any errors with a message that
197 // includes |error_description|.
198 void ForcedQueryTestHelper(const std::string& input,
199 const std::string& json,
200 const std::string matches[3],
201 const std::string& error_description);
203 void ResetFieldTrialList();
205 void ClearAllResults();
207 // See description above class for details of these fields.
208 TemplateURL* default_t_url_;
209 const base::string16 term1_;
210 GURL term1_url_;
211 TemplateURL* keyword_t_url_;
212 const base::string16 keyword_term_;
213 GURL keyword_url_;
215 content::TestBrowserThreadBundle thread_bundle_;
217 // URLFetcherFactory implementation registered.
218 net::TestURLFetcherFactory test_factory_;
220 // Profile we use.
221 TestingProfile profile_;
223 // The provider.
224 scoped_refptr<SearchProviderForTest> provider_;
226 // If non-NULL, OnProviderUpdate quits the current |run_loop_|.
227 base::RunLoop* run_loop_;
229 DISALLOW_COPY_AND_ASSIGN(SearchProviderTest);
232 // static
233 const std::string SearchProviderTest::kNotApplicable = "Not Applicable";
235 void SearchProviderTest::SetUp() {
236 // Make sure that fetchers are automatically ungregistered upon destruction.
237 test_factory_.set_remove_fetcher_on_delete(true);
239 // We need both the history service and template url model loaded.
240 ASSERT_TRUE(profile_.CreateHistoryService(true, false));
241 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
242 &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
244 TemplateURLService* turl_model =
245 TemplateURLServiceFactory::GetForProfile(&profile_);
247 turl_model->Load();
249 // Reset the default TemplateURL.
250 TemplateURLData data;
251 data.short_name = ASCIIToUTF16("t");
252 data.SetURL("http://defaultturl/{searchTerms}");
253 data.suggestions_url = "http://defaultturl2/{searchTerms}";
254 data.instant_url = "http://does/not/exist?strk=1";
255 data.search_terms_replacement_key = "strk";
256 default_t_url_ = new TemplateURL(&profile_, data);
257 turl_model->Add(default_t_url_);
258 turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
259 TemplateURLID default_provider_id = default_t_url_->id();
260 ASSERT_NE(0, default_provider_id);
262 // Add url1, with search term term1_.
263 term1_url_ = AddSearchToHistory(default_t_url_, term1_, 1);
265 // Create another TemplateURL.
266 data.short_name = ASCIIToUTF16("k");
267 data.SetKeyword(ASCIIToUTF16("k"));
268 data.SetURL("http://keyword/{searchTerms}");
269 data.suggestions_url = "http://suggest_keyword/{searchTerms}";
270 keyword_t_url_ = new TemplateURL(&profile_, data);
271 turl_model->Add(keyword_t_url_);
272 ASSERT_NE(0, keyword_t_url_->id());
274 // Add a page and search term for keyword_t_url_.
275 keyword_url_ = AddSearchToHistory(keyword_t_url_, keyword_term_, 1);
277 // Keywords are updated by the InMemoryHistoryBackend only after the message
278 // has been processed on the history thread. Block until history processes all
279 // requests to ensure the InMemoryDatabase is the state we expect it.
280 profile_.BlockUntilHistoryProcessesPendingRequests();
282 provider_ = new SearchProviderForTest(this, &profile_);
283 provider_->kMinimumTimeBetweenSuggestQueriesMs = 0;
286 void SearchProviderTest::TearDown() {
287 base::RunLoop().RunUntilIdle();
289 // Shutdown the provider before the profile.
290 provider_ = NULL;
293 void SearchProviderTest::RunTest(TestData* cases,
294 int num_cases,
295 bool prefer_keyword) {
296 ACMatches matches;
297 for (int i = 0; i < num_cases; ++i) {
298 AutocompleteInput input(cases[i].input, base::string16::npos,
299 base::string16(), GURL(),
300 AutocompleteInput::INVALID_SPEC, false,
301 prefer_keyword, true, true);
302 provider_->Start(input, false);
303 matches = provider_->matches();
304 base::string16 diagnostic_details =
305 ASCIIToUTF16("Input was: ") +
306 cases[i].input +
307 ASCIIToUTF16("; prefer_keyword was: ") +
308 (prefer_keyword ? ASCIIToUTF16("true") : ASCIIToUTF16("false"));
309 EXPECT_EQ(cases[i].num_results, matches.size()) << diagnostic_details;
310 if (matches.size() == cases[i].num_results) {
311 for (size_t j = 0; j < cases[i].num_results; ++j) {
312 EXPECT_EQ(cases[i].output[j].gurl, matches[j].destination_url) <<
313 diagnostic_details;
314 EXPECT_EQ(cases[i].output[j].result_type, matches[j].type) <<
315 diagnostic_details;
316 EXPECT_EQ(cases[i].output[j].fill_into_edit,
317 matches[j].fill_into_edit) << diagnostic_details;
318 EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match,
319 matches[j].allowed_to_be_default_match) << diagnostic_details;
325 void SearchProviderTest::OnProviderUpdate(bool updated_matches) {
326 if (run_loop_ && provider_->done()) {
327 run_loop_->Quit();
328 run_loop_ = NULL;
332 void SearchProviderTest::RunTillProviderDone() {
333 if (provider_->done())
334 return;
336 base::RunLoop run_loop;
337 run_loop_ = &run_loop;
338 run_loop.Run();
341 void SearchProviderTest::QueryForInput(const base::string16& text,
342 bool prevent_inline_autocomplete,
343 bool prefer_keyword) {
344 // Start a query.
345 AutocompleteInput input(text, base::string16::npos, base::string16(), GURL(),
346 AutocompleteInput::INVALID_SPEC,
347 prevent_inline_autocomplete, prefer_keyword, true,
348 true);
349 provider_->Start(input, false);
351 // RunUntilIdle so that the task scheduled by SearchProvider to create the
352 // URLFetchers runs.
353 base::RunLoop().RunUntilIdle();
356 void SearchProviderTest::QueryForInputAndSetWYTMatch(
357 const base::string16& text,
358 AutocompleteMatch* wyt_match) {
359 QueryForInput(text, false, false);
360 profile_.BlockUntilHistoryProcessesPendingRequests();
361 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
362 if (!wyt_match)
363 return;
364 ASSERT_GE(provider_->matches().size(), 1u);
365 EXPECT_TRUE(FindMatchWithDestination(GURL(
366 default_t_url_->url_ref().ReplaceSearchTerms(
367 TemplateURLRef::SearchTermsArgs(base::CollapseWhitespace(
368 text, false)))),
369 wyt_match));
372 GURL SearchProviderTest::AddSearchToHistory(TemplateURL* t_url,
373 base::string16 term,
374 int visit_count) {
375 HistoryService* history =
376 HistoryServiceFactory::GetForProfile(&profile_,
377 Profile::EXPLICIT_ACCESS);
378 GURL search(t_url->url_ref().ReplaceSearchTerms(
379 TemplateURLRef::SearchTermsArgs(term)));
380 static base::Time last_added_time;
381 last_added_time = std::max(base::Time::Now(),
382 last_added_time + base::TimeDelta::FromMicroseconds(1));
383 history->AddPageWithDetails(search, base::string16(), visit_count, visit_count,
384 last_added_time, false, history::SOURCE_BROWSED);
385 history->SetKeywordSearchTermsForURL(search, t_url->id(), term);
386 return search;
389 bool SearchProviderTest::FindMatchWithContents(const base::string16& contents,
390 AutocompleteMatch* match) {
391 for (ACMatches::const_iterator i = provider_->matches().begin();
392 i != provider_->matches().end(); ++i) {
393 if (i->contents == contents) {
394 *match = *i;
395 return true;
398 return false;
401 bool SearchProviderTest::FindMatchWithDestination(const GURL& url,
402 AutocompleteMatch* match) {
403 for (ACMatches::const_iterator i = provider_->matches().begin();
404 i != provider_->matches().end(); ++i) {
405 if (i->destination_url == url) {
406 *match = *i;
407 return true;
410 return false;
413 void SearchProviderTest::FinishDefaultSuggestQuery() {
414 net::TestURLFetcher* default_fetcher =
415 test_factory_.GetFetcherByID(
416 SearchProvider::kDefaultProviderURLFetcherID);
417 ASSERT_TRUE(default_fetcher);
419 // Tell the SearchProvider the default suggest query is done.
420 default_fetcher->set_response_code(200);
421 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
424 void SearchProviderTest::ForcedQueryTestHelper(
425 const std::string& input,
426 const std::string& json,
427 const std::string expected_matches[3],
428 const std::string& error_description) {
429 QueryForInput(ASCIIToUTF16(input), false, false);
430 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
431 SearchProvider::kDefaultProviderURLFetcherID);
432 ASSERT_TRUE(fetcher);
433 fetcher->set_response_code(200);
434 fetcher->SetResponseString(json);
435 fetcher->delegate()->OnURLFetchComplete(fetcher);
436 RunTillProviderDone();
438 const ACMatches& matches = provider_->matches();
439 ASSERT_LE(matches.size(), 3u);
440 size_t i = 0;
441 // Ensure that the returned matches equal the expectations.
442 for (; i < matches.size(); ++i) {
443 EXPECT_EQ(ASCIIToUTF16(expected_matches[i]), matches[i].contents) <<
444 error_description;
446 // Ensure that no expected matches are missing.
447 for (; i < 3u; ++i) {
448 EXPECT_EQ(std::string(), expected_matches[i]) <<
449 "Case #" << i << ": " << error_description;
453 void SearchProviderTest::ResetFieldTrialList() {
454 // Destroy the existing FieldTrialList before creating a new one to avoid
455 // a DCHECK.
456 field_trial_list_.reset();
457 field_trial_list_.reset(new base::FieldTrialList(
458 new metrics::SHA1EntropyProvider("foo")));
459 chrome_variations::testing::ClearAllVariationParams();
460 base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
461 "AutocompleteDynamicTrial_0", "DefaultGroup");
462 trial->group();
465 void SearchProviderTest::ClearAllResults() {
466 provider_->ClearAllResults();
469 // Actual Tests ---------------------------------------------------------------
471 // Make sure we query history for the default provider and a URLFetcher is
472 // created for the default provider suggest results.
473 TEST_F(SearchProviderTest, QueryDefaultProvider) {
474 base::string16 term = term1_.substr(0, term1_.length() - 1);
475 QueryForInput(term, false, false);
477 // Make sure the default providers suggest service was queried.
478 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
479 SearchProvider::kDefaultProviderURLFetcherID);
480 ASSERT_TRUE(fetcher);
482 // And the URL matches what we expected.
483 GURL expected_url(default_t_url_->suggestions_url_ref().ReplaceSearchTerms(
484 TemplateURLRef::SearchTermsArgs(term)));
485 ASSERT_TRUE(fetcher->GetOriginalURL() == expected_url);
487 // Tell the SearchProvider the suggest query is done.
488 fetcher->set_response_code(200);
489 fetcher->delegate()->OnURLFetchComplete(fetcher);
490 fetcher = NULL;
492 // Run till the history results complete.
493 RunTillProviderDone();
495 // The SearchProvider is done. Make sure it has a result for the history
496 // term term1.
497 AutocompleteMatch term1_match;
498 EXPECT_TRUE(FindMatchWithDestination(term1_url_, &term1_match));
499 // Term1 should not have a description, it's set later.
500 EXPECT_TRUE(term1_match.description.empty());
502 AutocompleteMatch wyt_match;
503 EXPECT_TRUE(FindMatchWithDestination(
504 GURL(default_t_url_->url_ref().ReplaceSearchTerms(
505 TemplateURLRef::SearchTermsArgs(term))), &wyt_match));
506 EXPECT_TRUE(wyt_match.description.empty());
508 // The match for term1 should be more relevant than the what you typed match.
509 EXPECT_GT(term1_match.relevance, wyt_match.relevance);
510 // This longer match should be inlineable.
511 EXPECT_TRUE(term1_match.allowed_to_be_default_match);
512 // The what you typed match should be too, of course.
513 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
516 TEST_F(SearchProviderTest, HonorPreventInlineAutocomplete) {
517 base::string16 term = term1_.substr(0, term1_.length() - 1);
518 QueryForInput(term, true, false);
520 ASSERT_FALSE(provider_->matches().empty());
521 ASSERT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
522 provider_->matches()[0].type);
523 EXPECT_TRUE(provider_->matches()[0].allowed_to_be_default_match);
526 // Issues a query that matches the registered keyword and makes sure history
527 // is queried as well as URLFetchers getting created.
528 TEST_F(SearchProviderTest, QueryKeywordProvider) {
529 base::string16 term = keyword_term_.substr(0, keyword_term_.length() - 1);
530 QueryForInput(keyword_t_url_->keyword() + ASCIIToUTF16(" ") + term,
531 false,
532 false);
534 // Make sure the default providers suggest service was queried.
535 net::TestURLFetcher* default_fetcher = test_factory_.GetFetcherByID(
536 SearchProvider::kDefaultProviderURLFetcherID);
537 ASSERT_TRUE(default_fetcher);
539 // Tell the SearchProvider the default suggest query is done.
540 default_fetcher->set_response_code(200);
541 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
542 default_fetcher = NULL;
544 // Make sure the keyword providers suggest service was queried.
545 net::TestURLFetcher* keyword_fetcher = test_factory_.GetFetcherByID(
546 SearchProvider::kKeywordProviderURLFetcherID);
547 ASSERT_TRUE(keyword_fetcher);
549 // And the URL matches what we expected.
550 GURL expected_url(keyword_t_url_->suggestions_url_ref().ReplaceSearchTerms(
551 TemplateURLRef::SearchTermsArgs(term)));
552 ASSERT_TRUE(keyword_fetcher->GetOriginalURL() == expected_url);
554 // Tell the SearchProvider the keyword suggest query is done.
555 keyword_fetcher->set_response_code(200);
556 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
557 keyword_fetcher = NULL;
559 // Run till the history results complete.
560 RunTillProviderDone();
562 // The SearchProvider is done. Make sure it has a result for the history
563 // term keyword.
564 AutocompleteMatch match;
565 EXPECT_TRUE(FindMatchWithDestination(keyword_url_, &match));
567 // The match should have an associated keyword.
568 EXPECT_FALSE(match.keyword.empty());
570 // The fill into edit should contain the keyword.
571 EXPECT_EQ(keyword_t_url_->keyword() + base::char16(' ') + keyword_term_,
572 match.fill_into_edit);
575 TEST_F(SearchProviderTest, DontSendPrivateDataToSuggest) {
576 // None of the following input strings should be sent to the suggest server,
577 // because they may contain private data.
578 const char* inputs[] = {
579 "username:password",
580 "http://username:password",
581 "https://username:password",
582 "username:password@hostname",
583 "http://username:password@hostname/",
584 "file://filename",
585 "data://data",
586 "unknownscheme:anything",
587 "http://hostname/?query=q",
588 "http://hostname/path#ref",
589 "http://hostname/path #ref",
590 "https://hostname/path",
593 for (size_t i = 0; i < arraysize(inputs); ++i) {
594 QueryForInput(ASCIIToUTF16(inputs[i]), false, false);
595 // Make sure the default provider's suggest service was not queried.
596 ASSERT_TRUE(test_factory_.GetFetcherByID(
597 SearchProvider::kDefaultProviderURLFetcherID) == NULL);
598 // Run till the history results complete.
599 RunTillProviderDone();
603 TEST_F(SearchProviderTest, SendNonPrivateDataToSuggest) {
604 // All of the following input strings should be sent to the suggest server,
605 // because they should not get caught by the private data checks.
606 const char* inputs[] = {
607 "query",
608 "query with spaces",
609 "http://hostname",
610 "http://hostname/path",
611 "http://hostname #ref",
612 "www.hostname.com #ref",
613 "https://hostname",
614 "#hashtag",
615 "foo https://hostname/path"
618 profile_.BlockUntilHistoryProcessesPendingRequests();
619 for (size_t i = 0; i < arraysize(inputs); ++i) {
620 QueryForInput(ASCIIToUTF16(inputs[i]), false, false);
621 // Make sure the default provider's suggest service was queried.
622 ASSERT_TRUE(test_factory_.GetFetcherByID(
623 SearchProvider::kDefaultProviderURLFetcherID) != NULL);
627 TEST_F(SearchProviderTest, DontAutocompleteURLLikeTerms) {
628 AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
629 &profile_, &AutocompleteClassifierFactory::BuildInstanceFor);
630 GURL url = AddSearchToHistory(default_t_url_,
631 ASCIIToUTF16("docs.google.com"), 1);
633 // Add the term as a url.
634 HistoryServiceFactory::GetForProfile(&profile_, Profile::EXPLICIT_ACCESS)->
635 AddPageWithDetails(GURL("http://docs.google.com"), base::string16(), 1, 1,
636 base::Time::Now(), false, history::SOURCE_BROWSED);
637 profile_.BlockUntilHistoryProcessesPendingRequests();
639 AutocompleteMatch wyt_match;
640 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("docs"),
641 &wyt_match));
643 // There should be two matches, one for what you typed, the other for
644 // 'docs.google.com'. The search term should have a lower priority than the
645 // what you typed match.
646 ASSERT_EQ(2u, provider_->matches().size());
647 AutocompleteMatch term_match;
648 EXPECT_TRUE(FindMatchWithDestination(url, &term_match));
649 EXPECT_GT(wyt_match.relevance, term_match.relevance);
650 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
651 EXPECT_TRUE(term_match.allowed_to_be_default_match);
654 TEST_F(SearchProviderTest, DontGiveNavsuggestionsInForcedQueryMode) {
655 const std::string kEmptyMatch;
656 struct {
657 const std::string json;
658 const std::string matches_in_default_mode[3];
659 const std::string matches_in_forced_query_mode[3];
660 } cases[] = {
661 // Without suggested relevance scores.
662 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
663 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]}]",
664 { "a", "a1.com", "a2" },
665 { "a", "a2", kEmptyMatch } },
667 // With suggested relevance scores in a situation where navsuggest would
668 // go second.
669 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
670 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
671 "\"google:suggestrelevance\":[1250, 1200]}]",
672 { "a", "a1.com", "a2" },
673 { "a", "a2", kEmptyMatch } },
675 // With suggested relevance scores in a situation where navsuggest
676 // would go first.
677 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
678 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
679 "\"google:suggestrelevance\":[1350, 1250]}]",
680 { "a1.com", "a", "a2" },
681 { "a", "a2", kEmptyMatch } },
683 // With suggested relevance scores in a situation where navsuggest
684 // would go first only because verbatim has been demoted.
685 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
686 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
687 "\"google:suggestrelevance\":[1450, 1400],"
688 "\"google:verbatimrelevance\":1350}]",
689 { "a1.com", "a2", "a" },
690 { "a2", "a", kEmptyMatch } },
693 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
694 ForcedQueryTestHelper("a", cases[i].json, cases[i].matches_in_default_mode,
695 "regular input with json=" + cases[i].json);
696 ForcedQueryTestHelper("?a", cases[i].json,
697 cases[i].matches_in_forced_query_mode,
698 "forced query input with json=" + cases[i].json);
702 // A multiword search with one visit should not autocomplete until multiple
703 // words are typed.
704 TEST_F(SearchProviderTest, DontAutocompleteUntilMultipleWordsTyped) {
705 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("one search"),
706 1));
707 profile_.BlockUntilHistoryProcessesPendingRequests();
709 AutocompleteMatch wyt_match;
710 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("on"),
711 &wyt_match));
712 ASSERT_EQ(2u, provider_->matches().size());
713 AutocompleteMatch term_match;
714 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
715 EXPECT_GT(wyt_match.relevance, term_match.relevance);
716 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
717 EXPECT_TRUE(term_match.allowed_to_be_default_match);
719 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("one se"),
720 &wyt_match));
721 ASSERT_EQ(2u, provider_->matches().size());
722 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
723 EXPECT_GT(term_match.relevance, wyt_match.relevance);
724 EXPECT_TRUE(term_match.allowed_to_be_default_match);
725 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
728 // A multiword search with more than one visit should autocomplete immediately.
729 TEST_F(SearchProviderTest, AutocompleteMultipleVisitsImmediately) {
730 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches"),
731 2));
732 profile_.BlockUntilHistoryProcessesPendingRequests();
734 AutocompleteMatch wyt_match;
735 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("tw"),
736 &wyt_match));
737 ASSERT_EQ(2u, provider_->matches().size());
738 AutocompleteMatch term_match;
739 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
740 EXPECT_GT(term_match.relevance, wyt_match.relevance);
741 EXPECT_TRUE(term_match.allowed_to_be_default_match);
742 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
745 // Autocompletion should work at a word boundary after a space, and should
746 // offer a suggestion for the trimmed search query.
747 TEST_F(SearchProviderTest, AutocompleteAfterSpace) {
748 AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches "), 2);
749 GURL suggested_url(default_t_url_->url_ref().ReplaceSearchTerms(
750 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("two searches"))));
751 profile_.BlockUntilHistoryProcessesPendingRequests();
753 AutocompleteMatch wyt_match;
754 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("two "),
755 &wyt_match));
756 ASSERT_EQ(2u, provider_->matches().size());
757 AutocompleteMatch term_match;
758 EXPECT_TRUE(FindMatchWithDestination(suggested_url, &term_match));
759 EXPECT_GT(term_match.relevance, wyt_match.relevance);
760 EXPECT_TRUE(term_match.allowed_to_be_default_match);
761 EXPECT_EQ(ASCIIToUTF16("searches"), term_match.inline_autocompletion);
762 EXPECT_EQ(ASCIIToUTF16("two searches"), term_match.fill_into_edit);
763 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
766 // Newer multiword searches should score more highly than older ones.
767 TEST_F(SearchProviderTest, ScoreNewerSearchesHigher) {
768 GURL term_url_a(AddSearchToHistory(default_t_url_,
769 ASCIIToUTF16("three searches aaa"), 1));
770 GURL term_url_b(AddSearchToHistory(default_t_url_,
771 ASCIIToUTF16("three searches bbb"), 1));
772 profile_.BlockUntilHistoryProcessesPendingRequests();
774 AutocompleteMatch wyt_match;
775 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("three se"),
776 &wyt_match));
777 ASSERT_EQ(3u, provider_->matches().size());
778 AutocompleteMatch term_match_a;
779 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
780 AutocompleteMatch term_match_b;
781 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
782 EXPECT_GT(term_match_b.relevance, term_match_a.relevance);
783 EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
784 EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
785 EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
786 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
789 // An autocompleted multiword search should not be replaced by a different
790 // autocompletion while the user is still typing a valid prefix.
791 TEST_F(SearchProviderTest, DontReplacePreviousAutocompletion) {
792 GURL term_url_a(AddSearchToHistory(default_t_url_,
793 ASCIIToUTF16("four searches aaa"), 2));
794 GURL term_url_b(AddSearchToHistory(default_t_url_,
795 ASCIIToUTF16("four searches bbb"), 1));
796 profile_.BlockUntilHistoryProcessesPendingRequests();
798 AutocompleteMatch wyt_match;
799 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fo"),
800 &wyt_match));
801 ASSERT_EQ(3u, provider_->matches().size());
802 AutocompleteMatch term_match_a;
803 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
804 AutocompleteMatch term_match_b;
805 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
806 EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
807 EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
808 EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
809 EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
810 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
812 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("four se"),
813 &wyt_match));
814 ASSERT_EQ(3u, provider_->matches().size());
815 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
816 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
817 EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
818 EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
819 EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
820 EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
821 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
824 // Non-completable multiword searches should not crowd out single-word searches.
825 TEST_F(SearchProviderTest, DontCrowdOutSingleWords) {
826 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("five"), 1));
827 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches bbb"), 1);
828 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches ccc"), 1);
829 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches ddd"), 1);
830 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches eee"), 1);
831 profile_.BlockUntilHistoryProcessesPendingRequests();
833 AutocompleteMatch wyt_match;
834 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fi"),
835 &wyt_match));
836 ASSERT_EQ(AutocompleteProvider::kMaxMatches + 1, provider_->matches().size());
837 AutocompleteMatch term_match;
838 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
839 EXPECT_GT(term_match.relevance, wyt_match.relevance);
840 EXPECT_TRUE(term_match.allowed_to_be_default_match);
841 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
844 // Inline autocomplete matches regardless of case differences from the input.
845 TEST_F(SearchProviderTest, InlineMixedCaseMatches) {
846 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("FOO"), 1));
847 profile_.BlockUntilHistoryProcessesPendingRequests();
849 AutocompleteMatch wyt_match;
850 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
851 &wyt_match));
852 ASSERT_EQ(2u, provider_->matches().size());
853 AutocompleteMatch term_match;
854 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
855 EXPECT_GT(term_match.relevance, wyt_match.relevance);
856 EXPECT_EQ(ASCIIToUTF16("FOO"), term_match.fill_into_edit);
857 EXPECT_EQ(ASCIIToUTF16("OO"), term_match.inline_autocompletion);
858 EXPECT_TRUE(term_match.allowed_to_be_default_match);
861 // Verifies AutocompleteControllers return results (including keyword
862 // results) in the right order and set descriptions for them correctly.
863 TEST_F(SearchProviderTest, KeywordOrderingAndDescriptions) {
864 // Add an entry that corresponds to a keyword search with 'term2'.
865 AddSearchToHistory(keyword_t_url_, ASCIIToUTF16("term2"), 1);
866 profile_.BlockUntilHistoryProcessesPendingRequests();
868 AutocompleteController controller(&profile_, NULL,
869 AutocompleteProvider::TYPE_SEARCH);
870 controller.Start(AutocompleteInput(
871 ASCIIToUTF16("k t"), base::string16::npos, base::string16(), GURL(),
872 AutocompleteInput::INVALID_SPEC, false, false, true, true));
873 const AutocompleteResult& result = controller.result();
875 // There should be three matches, one for the keyword history, one for
876 // keyword provider's what-you-typed, and one for the default provider's
877 // what you typed, in that order.
878 ASSERT_EQ(3u, result.size());
879 EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY, result.match_at(0).type);
880 EXPECT_EQ(AutocompleteMatchType::SEARCH_OTHER_ENGINE,
881 result.match_at(1).type);
882 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
883 result.match_at(2).type);
884 EXPECT_GT(result.match_at(0).relevance, result.match_at(1).relevance);
885 EXPECT_GT(result.match_at(1).relevance, result.match_at(2).relevance);
886 EXPECT_TRUE(result.match_at(0).allowed_to_be_default_match);
887 EXPECT_TRUE(result.match_at(1).allowed_to_be_default_match);
888 EXPECT_FALSE(result.match_at(2).allowed_to_be_default_match);
890 // The two keyword results should come with the keyword we expect.
891 EXPECT_EQ(ASCIIToUTF16("k"), result.match_at(0).keyword);
892 EXPECT_EQ(ASCIIToUTF16("k"), result.match_at(1).keyword);
893 // The default provider has a different keyword. (We don't explicitly
894 // set it during this test, so all we do is assert that it's different.)
895 EXPECT_NE(result.match_at(0).keyword, result.match_at(2).keyword);
897 // The top result will always have a description. The third result,
898 // coming from a different provider than the first two, should also.
899 // Whether the second result has one doesn't matter much. (If it was
900 // missing, people would infer that it's the same search provider as
901 // the one above it.)
902 EXPECT_FALSE(result.match_at(0).description.empty());
903 EXPECT_FALSE(result.match_at(2).description.empty());
904 EXPECT_NE(result.match_at(0).description, result.match_at(2).description);
907 TEST_F(SearchProviderTest, KeywordVerbatim) {
908 TestData cases[] = {
909 // Test a simple keyword input.
910 { ASCIIToUTF16("k foo"), 2,
911 { ResultInfo(GURL("http://keyword/foo"),
912 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
913 true,
914 ASCIIToUTF16("k foo")),
915 ResultInfo(GURL("http://defaultturl/k%20foo"),
916 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
917 false,
918 ASCIIToUTF16("k foo") ) } },
920 // Make sure extra whitespace after the keyword doesn't change the
921 // keyword verbatim query. Also verify that interior consecutive
922 // whitespace gets trimmed.
923 { ASCIIToUTF16("k foo"), 2,
924 { ResultInfo(GURL("http://keyword/foo"),
925 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
926 true,
927 ASCIIToUTF16("k foo")),
928 ResultInfo(GURL("http://defaultturl/k%20foo"),
929 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
930 false,
931 ASCIIToUTF16("k foo")) } },
932 // Leading whitespace should be stripped before SearchProvider gets the
933 // input; hence there are no tests here about how it handles those inputs.
935 // Verify that interior consecutive whitespace gets trimmed in either case.
936 { ASCIIToUTF16("k foo bar"), 2,
937 { ResultInfo(GURL("http://keyword/foo%20bar"),
938 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
939 true,
940 ASCIIToUTF16("k foo bar")),
941 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
942 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
943 false,
944 ASCIIToUTF16("k foo bar")) } },
946 // Verify that trailing whitespace gets trimmed.
947 { ASCIIToUTF16("k foo bar "), 2,
948 { ResultInfo(GURL("http://keyword/foo%20bar"),
949 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
950 true,
951 ASCIIToUTF16("k foo bar")),
952 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
953 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
954 false,
955 ASCIIToUTF16("k foo bar")) } },
957 // Keywords can be prefixed by certain things that should get ignored
958 // when constructing the keyword match.
959 { ASCIIToUTF16("www.k foo"), 2,
960 { ResultInfo(GURL("http://keyword/foo"),
961 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
962 true,
963 ASCIIToUTF16("k foo")),
964 ResultInfo(GURL("http://defaultturl/www.k%20foo"),
965 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
966 false,
967 ASCIIToUTF16("www.k foo")) } },
968 { ASCIIToUTF16("http://k foo"), 2,
969 { ResultInfo(GURL("http://keyword/foo"),
970 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
971 true,
972 ASCIIToUTF16("k foo")),
973 ResultInfo(GURL("http://defaultturl/http%3A//k%20foo"),
974 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
975 false,
976 ASCIIToUTF16("http://k foo")) } },
977 { ASCIIToUTF16("http://www.k foo"), 2,
978 { ResultInfo(GURL("http://keyword/foo"),
979 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
980 true,
981 ASCIIToUTF16("k foo")),
982 ResultInfo(GURL("http://defaultturl/http%3A//www.k%20foo"),
983 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
984 false,
985 ASCIIToUTF16("http://www.k foo")) } },
987 // A keyword with no remaining input shouldn't get a keyword
988 // verbatim match.
989 { ASCIIToUTF16("k"), 1,
990 { ResultInfo(GURL("http://defaultturl/k"),
991 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
992 true,
993 ASCIIToUTF16("k")) } },
994 // Ditto. Trailing whitespace shouldn't make a difference.
995 { ASCIIToUTF16("k "), 1,
996 { ResultInfo(GURL("http://defaultturl/k"),
997 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
998 true,
999 ASCIIToUTF16("k")) } }
1001 // The fact that verbatim queries to keyword are handled by KeywordProvider
1002 // not SearchProvider is tested in
1003 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc.
1006 // Test not in keyword mode.
1007 RunTest(cases, arraysize(cases), false);
1009 // Test in keyword mode. (Both modes should give the same result.)
1010 RunTest(cases, arraysize(cases), true);
1013 // Ensures command-line flags are reflected in the URLs the search provider
1014 // generates.
1015 TEST_F(SearchProviderTest, CommandLineOverrides) {
1016 TemplateURLService* turl_model =
1017 TemplateURLServiceFactory::GetForProfile(&profile_);
1019 TemplateURLData data;
1020 data.short_name = ASCIIToUTF16("default");
1021 data.SetKeyword(data.short_name);
1022 data.SetURL("{google:baseURL}{searchTerms}");
1023 default_t_url_ = new TemplateURL(&profile_, data);
1024 turl_model->Add(default_t_url_);
1025 turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
1027 CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
1028 "http://www.bar.com/");
1029 CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1030 switches::kExtraSearchQueryParams, "a=b");
1032 TestData cases[] = {
1033 { ASCIIToUTF16("k a"), 2,
1034 { ResultInfo(GURL("http://keyword/a"),
1035 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
1036 true,
1037 ASCIIToUTF16("k a")),
1038 ResultInfo(GURL("http://www.bar.com/k%20a?a=b"),
1039 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1040 false,
1041 ASCIIToUTF16("k a")) } },
1044 RunTest(cases, arraysize(cases), false);
1047 // Verifies Navsuggest results don't set a TemplateURL, which Instant relies on.
1048 // Also verifies that just the *first* navigational result is listed as a match
1049 // if suggested relevance scores were not sent.
1050 TEST_F(SearchProviderTest, NavSuggestNoSuggestedRelevanceScores) {
1051 QueryForInput(ASCIIToUTF16("a.c"), false, false);
1053 // Make sure the default providers suggest service was queried.
1054 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
1055 SearchProvider::kDefaultProviderURLFetcherID);
1056 ASSERT_TRUE(fetcher);
1058 // Tell the SearchProvider the suggest query is done.
1059 fetcher->set_response_code(200);
1060 fetcher->SetResponseString(
1061 "[\"a.c\",[\"a.com\", \"a.com/b\"],[\"a\", \"b\"],[],"
1062 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]");
1063 fetcher->delegate()->OnURLFetchComplete(fetcher);
1064 fetcher = NULL;
1066 // Run till the history results complete.
1067 RunTillProviderDone();
1069 // Make sure the only match is 'a.com' and it doesn't have a template_url.
1070 AutocompleteMatch nav_match;
1071 EXPECT_TRUE(FindMatchWithDestination(GURL("http://a.com"), &nav_match));
1072 EXPECT_TRUE(nav_match.keyword.empty());
1073 EXPECT_TRUE(nav_match.allowed_to_be_default_match);
1074 EXPECT_FALSE(FindMatchWithDestination(GURL("http://a.com/b"), &nav_match));
1077 // Verifies that the most relevant suggest results are added properly.
1078 TEST_F(SearchProviderTest, SuggestRelevance) {
1079 QueryForInput(ASCIIToUTF16("a"), false, false);
1081 // Make sure the default provider's suggest service was queried.
1082 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
1083 SearchProvider::kDefaultProviderURLFetcherID);
1084 ASSERT_TRUE(fetcher);
1086 // Tell the SearchProvider the suggest query is done.
1087 fetcher->set_response_code(200);
1088 fetcher->SetResponseString("[\"a\",[\"a1\", \"a2\", \"a3\", \"a4\"]]");
1089 fetcher->delegate()->OnURLFetchComplete(fetcher);
1090 fetcher = NULL;
1092 // Run till the history results complete.
1093 RunTillProviderDone();
1095 // Check the expected verbatim and (first 3) suggestions' relative relevances.
1096 AutocompleteMatch verbatim, match_a1, match_a2, match_a3, match_a4;
1097 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim));
1098 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a1"), &match_a1));
1099 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a2"), &match_a2));
1100 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a3"), &match_a3));
1101 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("a4"), &match_a4));
1102 EXPECT_GT(verbatim.relevance, match_a1.relevance);
1103 EXPECT_GT(match_a1.relevance, match_a2.relevance);
1104 EXPECT_GT(match_a2.relevance, match_a3.relevance);
1105 EXPECT_TRUE(verbatim.allowed_to_be_default_match);
1106 EXPECT_TRUE(match_a1.allowed_to_be_default_match);
1107 EXPECT_TRUE(match_a2.allowed_to_be_default_match);
1108 EXPECT_TRUE(match_a3.allowed_to_be_default_match);
1111 // Verifies that the default provider abandons suggested relevance scores
1112 // when in keyword mode. This should happen regardless of whether the
1113 // keyword provider returns suggested relevance scores.
1114 TEST_F(SearchProviderTest, DefaultProviderNoSuggestRelevanceInKeywordMode) {
1115 struct {
1116 const std::string default_provider_json;
1117 const std::string keyword_provider_json;
1118 const std::string matches[5];
1119 } cases[] = {
1120 // First, try an input where the keyword provider does not deliver
1121 // suggested relevance scores.
1122 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1123 "{\"google:verbatimrelevance\":9700,"
1124 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1125 "\"google:suggestrelevance\":[9900, 9800]}]",
1126 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"]}]",
1127 { "a", "akeyword-query", "k a", "adefault.com", "k adefault-query" } },
1129 // Now try with keyword provider suggested relevance scores.
1130 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1131 "{\"google:verbatimrelevance\":9700,"
1132 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1133 "\"google:suggestrelevance\":[9900, 9800]}]",
1134 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"],"
1135 "\"google:verbatimrelevance\":9500,"
1136 "\"google:suggestrelevance\":[9600]}]",
1137 { "akeyword-query", "a", "k a", "adefault.com", "k adefault-query" } }
1140 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1141 QueryForInput(ASCIIToUTF16("k a"), false, true);
1142 net::TestURLFetcher* default_fetcher =
1143 test_factory_.GetFetcherByID(
1144 SearchProvider::kDefaultProviderURLFetcherID);
1145 ASSERT_TRUE(default_fetcher);
1146 default_fetcher->set_response_code(200);
1147 default_fetcher->SetResponseString(cases[i].default_provider_json);
1148 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
1149 net::TestURLFetcher* keyword_fetcher =
1150 test_factory_.GetFetcherByID(
1151 SearchProvider::kKeywordProviderURLFetcherID);
1152 ASSERT_TRUE(keyword_fetcher);
1153 keyword_fetcher->set_response_code(200);
1154 keyword_fetcher->SetResponseString(cases[i].keyword_provider_json);
1155 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
1156 RunTillProviderDone();
1158 const std::string description = "for input with default_provider_json=" +
1159 cases[i].default_provider_json + " and keyword_provider_json=" +
1160 cases[i].keyword_provider_json;
1161 const ACMatches& matches = provider_->matches();
1162 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
1163 size_t j = 0;
1164 // Ensure that the returned matches equal the expectations.
1165 for (; j < matches.size(); ++j) {
1166 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]), matches[j].contents) <<
1167 description;
1169 // Ensure that no expected matches are missing.
1170 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1171 EXPECT_EQ(std::string(), cases[i].matches[j]) << description;
1175 // Verifies that suggest results with relevance scores are added
1176 // properly when using the default fetcher. When adding a new test
1177 // case to this test, please consider adding it to the tests in
1178 // KeywordFetcherSuggestRelevance below.
1179 TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevance) {
1180 struct DefaultFetcherMatch {
1181 std::string contents;
1182 bool allowed_to_be_default_match;
1184 const DefaultFetcherMatch kEmptyMatch = { kNotApplicable, false };
1185 struct {
1186 const std::string json;
1187 const DefaultFetcherMatch matches[6];
1188 const std::string inline_autocompletion;
1189 } cases[] = {
1190 // Ensure that suggestrelevance scores reorder matches.
1191 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1192 { { "a", true }, { "c", false }, { "b", false }, kEmptyMatch, kEmptyMatch,
1193 kEmptyMatch },
1194 std::string() },
1195 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1196 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1197 "\"google:suggestrelevance\":[1, 2]}]",
1198 { { "a", true }, { "c.com", false }, { "b.com", false }, kEmptyMatch,
1199 kEmptyMatch, kEmptyMatch },
1200 std::string() },
1202 // Without suggested relevance scores, we should only allow one
1203 // navsuggest result to be be displayed.
1204 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1205 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1206 { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch,
1207 kEmptyMatch, kEmptyMatch },
1208 std::string() },
1210 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1211 // Negative values will have no effect; the calculated value will be used.
1212 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1213 "\"google:suggestrelevance\":[9998]}]",
1214 { { "a", true}, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1215 kEmptyMatch },
1216 std::string() },
1217 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1218 "\"google:suggestrelevance\":[9999]}]",
1219 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1220 kEmptyMatch },
1221 "1" },
1222 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1223 "\"google:suggestrelevance\":[9999]}]",
1224 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1225 kEmptyMatch },
1226 "1" },
1227 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1228 "\"google:suggestrelevance\":[9999]}]",
1229 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1230 kEmptyMatch },
1231 "1" },
1232 { "[\"a\",[\"http://a.com\"],[],[],"
1233 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1234 "\"google:verbatimrelevance\":9999,"
1235 "\"google:suggestrelevance\":[9998]}]",
1236 { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1237 kEmptyMatch },
1238 std::string() },
1239 { "[\"a\",[\"http://a.com\"],[],[],"
1240 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1241 "\"google:verbatimrelevance\":9998,"
1242 "\"google:suggestrelevance\":[9999]}]",
1243 { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1244 kEmptyMatch },
1245 ".com" },
1246 { "[\"a\",[\"http://a.com\"],[],[],"
1247 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1248 "\"google:verbatimrelevance\":0,"
1249 "\"google:suggestrelevance\":[9999]}]",
1250 { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1251 kEmptyMatch },
1252 ".com" },
1253 { "[\"a\",[\"http://a.com\"],[],[],"
1254 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1255 "\"google:verbatimrelevance\":-1,"
1256 "\"google:suggestrelevance\":[9999]}]",
1257 { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1258 kEmptyMatch },
1259 ".com" },
1261 // Ensure that both types of relevance scores reorder matches together.
1262 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1263 "\"google:verbatimrelevance\":9998}]",
1264 { { "a1", true }, { "a", true }, { "a2", true }, kEmptyMatch, kEmptyMatch,
1265 kEmptyMatch },
1266 "1" },
1268 // Allow non-inlineable matches to be the highest-scoring match but,
1269 // if the result set lacks a single inlineable result, abandon suggested
1270 // relevance scores entirely.
1271 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1272 { { "b", false }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1273 kEmptyMatch },
1274 std::string() },
1275 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1276 "\"google:verbatimrelevance\":0}]",
1277 { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1278 kEmptyMatch },
1279 std::string() },
1280 { "[\"a\",[\"http://b.com\"],[],[],"
1281 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1282 "\"google:suggestrelevance\":[9999]}]",
1283 { { "b.com", false }, { "a", true }, kEmptyMatch, kEmptyMatch,
1284 kEmptyMatch, kEmptyMatch },
1285 std::string() },
1286 { "[\"a\",[\"http://b.com\"],[],[],"
1287 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1288 "\"google:suggestrelevance\":[9999],"
1289 "\"google:verbatimrelevance\":0}]",
1290 { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch,
1291 kEmptyMatch, kEmptyMatch },
1292 std::string() },
1294 // Allow low-scoring matches.
1295 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1296 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1297 kEmptyMatch },
1298 "1" },
1299 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1300 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1301 kEmptyMatch },
1302 "1" },
1303 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1304 "\"google:verbatimrelevance\":0}]",
1305 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1306 kEmptyMatch },
1307 "1" },
1308 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1309 "\"google:verbatimrelevance\":0}]",
1310 { { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1311 kEmptyMatch },
1312 "2" },
1313 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1314 "\"google:verbatimrelevance\":2}]",
1315 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
1316 kEmptyMatch },
1317 "2" },
1318 { "[\"a\",[\"http://a.com\"],[],[],"
1319 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1320 "\"google:suggestrelevance\":[1],"
1321 "\"google:verbatimrelevance\":0}]",
1322 { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1323 kEmptyMatch },
1324 ".com" },
1325 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1326 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1327 "\"google:suggestrelevance\":[1, 2],"
1328 "\"google:verbatimrelevance\":0}]",
1329 { { "a2.com", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch,
1330 kEmptyMatch, kEmptyMatch },
1331 "2.com" },
1333 // Ensure that all suggestions are considered, regardless of order.
1334 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1335 "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1336 { { "a", true }, { "h", false }, { "g", false }, { "f", false },
1337 { "e", false }, { "d", false } },
1338 std::string() },
1339 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1340 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1341 "\"http://h.com\"],[],[],"
1342 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1343 "\"NAVIGATION\", \"NAVIGATION\","
1344 "\"NAVIGATION\", \"NAVIGATION\","
1345 "\"NAVIGATION\"],"
1346 "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1347 { { "a", true }, { "h.com", false }, { "g.com", false },
1348 { "f.com", false }, { "e.com", false }, { "d.com", false } },
1349 std::string() },
1351 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1352 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1353 { { "a", true }, { "a1", true }, { "a2", true }, kEmptyMatch, kEmptyMatch,
1354 kEmptyMatch },
1355 std::string() },
1356 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1357 { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1358 kEmptyMatch },
1359 std::string() },
1360 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1361 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1362 "\"google:suggestrelevance\":[1]}]",
1363 { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch,
1364 kEmptyMatch, kEmptyMatch },
1365 std::string() },
1366 { "[\"a\",[\"http://a1.com\"],[],[],"
1367 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1368 "\"google:suggestrelevance\":[9999, 1]}]",
1369 { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch,
1370 kEmptyMatch, kEmptyMatch },
1371 std::string() },
1373 // Ensure that all 'verbatim' results are merged with their maximum score.
1374 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1375 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1376 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
1377 kEmptyMatch },
1378 "2" },
1379 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1380 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1381 "\"google:verbatimrelevance\":0}]",
1382 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
1383 kEmptyMatch },
1384 "2" },
1386 // Ensure that verbatim is always generated without other suggestions.
1387 // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
1388 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1389 { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1390 kEmptyMatch },
1391 std::string() },
1392 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1393 { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1394 kEmptyMatch },
1395 std::string() },
1398 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1399 QueryForInput(ASCIIToUTF16("a"), false, false);
1400 net::TestURLFetcher* fetcher =
1401 test_factory_.GetFetcherByID(
1402 SearchProvider::kDefaultProviderURLFetcherID);
1403 ASSERT_TRUE(fetcher);
1404 fetcher->set_response_code(200);
1405 fetcher->SetResponseString(cases[i].json);
1406 fetcher->delegate()->OnURLFetchComplete(fetcher);
1407 RunTillProviderDone();
1409 const std::string description = "for input with json=" + cases[i].json;
1410 const ACMatches& matches = provider_->matches();
1411 ASSERT_FALSE(matches.empty());
1412 // Find the first match that's allowed to be the default match and check
1413 // its inline_autocompletion.
1414 ACMatches::const_iterator it = FindDefaultMatch(matches);
1415 ASSERT_NE(matches.end(), it);
1416 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
1417 it->inline_autocompletion) << description;
1419 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
1420 size_t j = 0;
1421 // Ensure that the returned matches equal the expectations.
1422 for (; j < matches.size(); ++j) {
1423 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents),
1424 matches[j].contents) << description;
1425 EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match,
1426 matches[j].allowed_to_be_default_match) << description;
1428 // Ensure that no expected matches are missing.
1429 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1430 EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) <<
1431 "Case # " << i << " " << description;
1435 // Verifies that suggest results with relevance scores are added
1436 // properly when using the keyword fetcher. This is similar to the
1437 // test DefaultFetcherSuggestRelevance above but this uses inputs that
1438 // trigger keyword suggestions (i.e., "k a" rather than "a") and has
1439 // different expectations (because now the results are a mix of
1440 // keyword suggestions and default provider suggestions). When a new
1441 // test is added to this TEST_F, please consider if it would be
1442 // appropriate to add to DefaultFetcherSuggestRelevance as well.
1443 TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
1444 struct KeywordFetcherMatch {
1445 std::string contents;
1446 bool from_keyword;
1447 bool allowed_to_be_default_match;
1449 const KeywordFetcherMatch kEmptyMatch = { kNotApplicable, false, false };
1450 struct {
1451 const std::string json;
1452 const KeywordFetcherMatch matches[6];
1453 const std::string inline_autocompletion;
1454 } cases[] = {
1455 // Ensure that suggest relevance scores reorder matches and that
1456 // the keyword verbatim (lacking a suggested verbatim score) beats
1457 // the default provider verbatim.
1458 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1459 { { "a", true, true },
1460 { "k a", false, false },
1461 { "c", true, false },
1462 { "b", true, false },
1463 kEmptyMatch, kEmptyMatch },
1464 std::string() },
1465 // Again, check that relevance scores reorder matches, just this
1466 // time with navigation matches. This also checks that with
1467 // suggested relevance scores we allow multiple navsuggest results.
1468 // Note that navsuggest results that come from a keyword provider
1469 // are marked as not a keyword result. (They don't go to a
1470 // keyword search engine.)
1471 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
1472 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1473 "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
1474 { { "a", true, true },
1475 { "d", true, false },
1476 { "c.com", false, false },
1477 { "b.com", false, false },
1478 { "k a", false, false },
1479 kEmptyMatch },
1480 std::string() },
1482 // Without suggested relevance scores, we should only allow one
1483 // navsuggest result to be be displayed.
1484 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1485 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1486 { { "a", true, true },
1487 { "b.com", false, false },
1488 { "k a", false, false },
1489 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1490 std::string() },
1492 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1493 // Negative values will have no effect; the calculated value will be used.
1494 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1495 "\"google:suggestrelevance\":[9998]}]",
1496 { { "a", true, true },
1497 { "a1", true, true },
1498 { "k a", false, false },
1499 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1500 std::string() },
1501 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1502 "\"google:suggestrelevance\":[9999]}]",
1503 { { "a1", true, true },
1504 { "a", true, true },
1505 { "k a", false, false },
1506 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1507 "1" },
1508 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1509 "\"google:suggestrelevance\":[9999]}]",
1510 { { "a1", true, true },
1511 { "k a", false, false },
1512 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1513 "1" },
1514 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1515 "\"google:suggestrelevance\":[9999]}]",
1516 { { "a1", true, true },
1517 { "a", true, true },
1518 { "k a", false, false },
1519 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1520 "1" },
1521 { "[\"a\",[\"http://a.com\"],[],[],"
1522 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1523 "\"google:verbatimrelevance\":9999,"
1524 "\"google:suggestrelevance\":[9998]}]",
1525 { { "a", true, true },
1526 { "a.com", false, false },
1527 { "k a", false, false },
1528 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1529 std::string() },
1531 // Ensure that both types of relevance scores reorder matches together.
1532 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1533 "\"google:verbatimrelevance\":9998}]",
1534 { { "a1", true, true },
1535 { "a", true, true },
1536 { "a2", true, true },
1537 { "k a", false, false },
1538 kEmptyMatch, kEmptyMatch },
1539 "1" },
1541 // Check that non-inlinable matches may be ranked as the highest result
1542 // if there is at least one inlineable match.
1543 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1544 { { "b", true, false },
1545 { "a", true, true },
1546 { "k a", false, false },
1547 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1548 std::string() },
1549 { "[\"a\",[\"http://b.com\"],[],[],"
1550 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1551 "\"google:suggestrelevance\":[9999]}]",
1552 { { "b.com", false, false },
1553 { "a", true, true },
1554 { "k a", false, false },
1555 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1556 std::string() },
1557 // On the other hand, if there is no inlineable match, restore
1558 // the keyword verbatim score.
1559 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1560 "\"google:verbatimrelevance\":0}]",
1561 { { "b", true, false },
1562 { "a", true, true },
1563 { "k a", false, false },
1564 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1565 std::string() },
1566 { "[\"a\",[\"http://b.com\"],[],[],"
1567 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1568 "\"google:suggestrelevance\":[9999],"
1569 "\"google:verbatimrelevance\":0}]",
1570 { { "b.com", false, false },
1571 { "a", true, true },
1572 { "k a", false, false },
1573 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1574 std::string() },
1576 // The top result does not have to score as highly as calculated
1577 // verbatim. i.e., there are no minimum score restrictions in
1578 // this provider.
1579 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1580 { { "a1", true, true },
1581 { "k a", false, false },
1582 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1583 "1" },
1584 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1585 { { "a1", true, true },
1586 { "k a", false, false },
1587 { "a", true, true },
1588 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1589 "1" },
1590 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1591 "\"google:verbatimrelevance\":0}]",
1592 { { "k a", false, false },
1593 { "a1", true, true },
1594 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1595 "1" },
1596 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1597 "\"google:verbatimrelevance\":0}]",
1599 { "k a", false, false },
1600 { "a2", true, true },
1601 { "a1", true, true },
1602 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1603 "2" },
1604 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1605 "\"google:verbatimrelevance\":2}]",
1606 { { "k a", false, false },
1607 { "a2", true, true },
1608 { "a", true, true },
1609 { "a1", true, true },
1610 kEmptyMatch, kEmptyMatch },
1611 "2" },
1613 // Ensure that all suggestions are considered, regardless of order.
1614 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1615 "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1616 { { "a", true, true },
1617 { "k a", false, false },
1618 { "h", true, false },
1619 { "g", true, false },
1620 { "f", true, false },
1621 { "e", true, false } },
1622 std::string() },
1623 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1624 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1625 "\"http://h.com\"],[],[],"
1626 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1627 "\"NAVIGATION\", \"NAVIGATION\","
1628 "\"NAVIGATION\", \"NAVIGATION\","
1629 "\"NAVIGATION\"],"
1630 "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1631 { { "a", true, true },
1632 { "k a", false, false },
1633 { "h.com", false, false },
1634 { "g.com", false, false },
1635 { "f.com", false, false },
1636 { "e.com", false, false } },
1637 std::string() },
1639 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1640 // Note that keyword suggestions by default (not in suggested relevance
1641 // mode) score more highly than the default verbatim.
1642 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1643 { { "a", true, true },
1644 { "a1", true, true },
1645 { "a2", true, true },
1646 { "k a", false, false },
1647 kEmptyMatch, kEmptyMatch },
1648 std::string() },
1649 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1650 { { "a", true, true },
1651 { "a1", true, true },
1652 { "k a", false, false },
1653 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1654 std::string() },
1655 // In this case, ignoring the suggested relevance scores means we keep
1656 // only one navsuggest result.
1657 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1658 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1659 "\"google:suggestrelevance\":[1]}]",
1660 { { "a", true, true },
1661 { "a1.com", false, false },
1662 { "k a", false, false },
1663 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1664 std::string() },
1665 { "[\"a\",[\"http://a1.com\"],[],[],"
1666 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1667 "\"google:suggestrelevance\":[9999, 1]}]",
1668 { { "a", true, true },
1669 { "a1.com", false, false },
1670 { "k a", false, false },
1671 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1672 std::string() },
1674 // Ensure that all 'verbatim' results are merged with their maximum score.
1675 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1676 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1677 { { "a2", true, true },
1678 { "a", true, true },
1679 { "a1", true, true },
1680 { "k a", false, false },
1681 kEmptyMatch, kEmptyMatch },
1682 "2" },
1683 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1684 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1685 "\"google:verbatimrelevance\":0}]",
1686 { { "a2", true, true },
1687 { "a", true, true },
1688 { "a1", true, true },
1689 { "k a", false, false },
1690 kEmptyMatch, kEmptyMatch },
1691 "2" },
1693 // Ensure that verbatim is always generated without other suggestions.
1694 // TODO(mpearson): Ensure the value of verbatimrelevance is respected
1695 // (except when suggested relevances are ignored).
1696 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1697 { { "k a", false, false },
1698 { "a", true, true },
1699 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1700 std::string() },
1701 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1702 { { "a", true, true },
1703 { "k a", false, false },
1704 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1705 std::string() },
1707 // In reorder mode, navsuggestions will not need to be demoted (because
1708 // they are marked as not allowed to be default match and will be
1709 // reordered as necessary).
1710 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1711 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1712 "\"google:verbatimrelevance\":9990,"
1713 "\"google:suggestrelevance\":[9998, 9999]}]",
1714 { { "a2.com", false, false },
1715 { "a1.com", false, false },
1716 { "a", true, true },
1717 { "k a", false, false },
1718 kEmptyMatch, kEmptyMatch },
1719 std::string() },
1720 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1721 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1722 "\"google:verbatimrelevance\":9990,"
1723 "\"google:suggestrelevance\":[9999, 9998]}]",
1724 { { "a1.com", false, false },
1725 { "a2.com", false, false },
1726 { "a", true, true },
1727 { "k a", false, false },
1728 kEmptyMatch, kEmptyMatch },
1729 std::string() },
1730 { "[\"a\",[\"https://a/\"],[],[],"
1731 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1732 "\"google:suggestrelevance\":[9999]}]",
1733 { { "https://a", false, false },
1734 { "a", true, true },
1735 { "k a", false, false },
1736 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1737 std::string() },
1738 // Check when navsuggest scores more than verbatim and there is query
1739 // suggestion but it scores lower.
1740 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1741 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1742 "\"google:verbatimrelevance\":9990,"
1743 "\"google:suggestrelevance\":[9998, 9999, 1300]}]",
1744 { { "a2.com", false, false },
1745 { "a1.com", false, false },
1746 { "a", true, true },
1747 { "a3", true, true },
1748 { "k a", false, false },
1749 kEmptyMatch },
1750 std::string() },
1751 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1752 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1753 "\"google:verbatimrelevance\":9990,"
1754 "\"google:suggestrelevance\":[9999, 9998, 1300]}]",
1755 { { "a1.com", false, false },
1756 { "a2.com", false, false },
1757 { "a", true, true },
1758 { "a3", true, true },
1759 { "k a", false, false },
1760 kEmptyMatch },
1761 std::string() },
1762 // Check when navsuggest scores more than a query suggestion. There is
1763 // a verbatim but it scores lower.
1764 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1765 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1766 "\"google:verbatimrelevance\":9990,"
1767 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1768 { { "a2.com", false, false },
1769 { "a1.com", false, false },
1770 { "a3", true, true },
1771 { "a", true, true },
1772 { "k a", false, false },
1773 kEmptyMatch },
1774 "3" },
1775 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1776 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1777 "\"google:verbatimrelevance\":9990,"
1778 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1779 { { "a1.com", false, false },
1780 { "a2.com", false, false },
1781 { "a3", true, true },
1782 { "a", true, true },
1783 { "k a", false, false },
1784 kEmptyMatch },
1785 "3" },
1786 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1787 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1788 "\"google:verbatimrelevance\":0,"
1789 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1790 { { "a2.com", false, false },
1791 { "a1.com", false, false },
1792 { "a3", true, true },
1793 { "k a", false, false },
1794 kEmptyMatch, kEmptyMatch },
1795 "3" },
1796 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1797 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1798 "\"google:verbatimrelevance\":0,"
1799 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1800 { { "a1.com", false, false },
1801 { "a2.com", false, false },
1802 { "a3", true, true },
1803 { "k a", false, false },
1804 kEmptyMatch, kEmptyMatch },
1805 "3" },
1806 // Check when there is neither verbatim nor a query suggestion that,
1807 // because we can't demote navsuggestions below a query suggestion,
1808 // we restore the keyword verbatim score.
1809 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1810 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1811 "\"google:verbatimrelevance\":0,"
1812 "\"google:suggestrelevance\":[9998, 9999]}]",
1813 { { "a2.com", false, false },
1814 { "a1.com", false, false },
1815 { "a", true, true },
1816 { "k a", false, false },
1817 kEmptyMatch, kEmptyMatch },
1818 std::string() },
1819 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1820 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1821 "\"google:verbatimrelevance\":0,"
1822 "\"google:suggestrelevance\":[9999, 9998]}]",
1823 { { "a1.com", false, false },
1824 { "a2.com", false, false },
1825 { "a", true, true },
1826 { "k a", false, false },
1827 kEmptyMatch, kEmptyMatch },
1828 std::string() },
1829 // More checks that everything works when it's not necessary to demote.
1830 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1831 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1832 "\"google:verbatimrelevance\":9990,"
1833 "\"google:suggestrelevance\":[9997, 9998, 9999]}]",
1834 { { "a3", true, true },
1835 { "a2.com", false, false },
1836 { "a1.com", false, false },
1837 { "a", true, true },
1838 { "k a", false, false },
1839 kEmptyMatch },
1840 "3" },
1841 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1842 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1843 "\"google:verbatimrelevance\":9990,"
1844 "\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1845 { { "a3", true, true },
1846 { "a1.com", false, false },
1847 { "a2.com", false, false },
1848 { "a", true, true },
1849 { "k a", false, false },
1850 kEmptyMatch },
1851 "3" },
1854 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1855 QueryForInput(ASCIIToUTF16("k a"), false, true);
1857 // Set up a default fetcher with no results.
1858 net::TestURLFetcher* default_fetcher =
1859 test_factory_.GetFetcherByID(
1860 SearchProvider::kDefaultProviderURLFetcherID);
1861 ASSERT_TRUE(default_fetcher);
1862 default_fetcher->set_response_code(200);
1863 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
1864 default_fetcher = NULL;
1866 // Set up a keyword fetcher with provided results.
1867 net::TestURLFetcher* keyword_fetcher =
1868 test_factory_.GetFetcherByID(
1869 SearchProvider::kKeywordProviderURLFetcherID);
1870 ASSERT_TRUE(keyword_fetcher);
1871 keyword_fetcher->set_response_code(200);
1872 keyword_fetcher->SetResponseString(cases[i].json);
1873 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
1874 keyword_fetcher = NULL;
1875 RunTillProviderDone();
1877 const std::string description = "for input with json=" + cases[i].json;
1878 const ACMatches& matches = provider_->matches();
1879 ASSERT_FALSE(matches.empty());
1880 // Find the first match that's allowed to be the default match and check
1881 // its inline_autocompletion.
1882 ACMatches::const_iterator it = FindDefaultMatch(matches);
1883 ASSERT_NE(matches.end(), it);
1884 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
1885 it->inline_autocompletion) << description;
1887 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
1888 size_t j = 0;
1889 // Ensure that the returned matches equal the expectations.
1890 for (; j < matches.size(); ++j) {
1891 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents),
1892 matches[j].contents) << description;
1893 EXPECT_EQ(cases[i].matches[j].from_keyword,
1894 matches[j].keyword == ASCIIToUTF16("k")) << description;
1895 EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match,
1896 matches[j].allowed_to_be_default_match) << description;
1898 // Ensure that no expected matches are missing.
1899 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1900 EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) <<
1901 "Case # " << i << " " << description;
1905 TEST_F(SearchProviderTest, LocalAndRemoteRelevances) {
1906 // We hardcode the string "term1" below, so ensure that the search term that
1907 // got added to history already is that string.
1908 ASSERT_EQ(ASCIIToUTF16("term1"), term1_);
1909 base::string16 term = term1_.substr(0, term1_.length() - 1);
1911 AddSearchToHistory(default_t_url_, term + ASCIIToUTF16("2"), 2);
1912 profile_.BlockUntilHistoryProcessesPendingRequests();
1914 struct {
1915 const base::string16 input;
1916 const std::string json;
1917 const std::string matches[6];
1918 } cases[] = {
1919 // The history results outscore the default verbatim score. term2 has more
1920 // visits so it outscores term1. The suggestions are still returned since
1921 // they're server-scored.
1922 { term,
1923 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
1924 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
1925 "\"google:suggestrelevance\":[1, 2, 3]}]",
1926 { "term2", "term1", "term", "a3", "a2", "a1" } },
1927 // Because we already have three suggestions by the time we see the history
1928 // results, they don't get returned.
1929 { term,
1930 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
1931 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
1932 "\"google:verbatimrelevance\":1450,"
1933 "\"google:suggestrelevance\":[1440, 1430, 1420]}]",
1934 { "term", "a1", "a2", "a3", kNotApplicable, kNotApplicable } },
1935 // If we only have two suggestions, we have room for a history result.
1936 { term,
1937 "[\"term\",[\"a1\", \"a2\"],[],[],"
1938 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
1939 "\"google:verbatimrelevance\":1450,"
1940 "\"google:suggestrelevance\":[1430, 1410]}]",
1941 { "term", "a1", "a2", "term2", kNotApplicable, kNotApplicable } },
1942 // If we have more than three suggestions, they should all be returned as
1943 // long as we have enough total space for them.
1944 { term,
1945 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
1946 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
1947 "\"google:verbatimrelevance\":1450,"
1948 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410]}]",
1949 { "term", "a1", "a2", "a3", "a4", kNotApplicable } },
1950 { term,
1951 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\", \"a5\", \"a6\"],[],[],"
1952 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\","
1953 "\"QUERY\", \"QUERY\"],"
1954 "\"google:verbatimrelevance\":1450,"
1955 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410, 1400, 1390]}]",
1956 { "term", "a1", "a2", "a3", "a4", "a5" } },
1957 { term,
1958 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
1959 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
1960 "\"google:verbatimrelevance\":1450,"
1961 "\"google:suggestrelevance\":[1430, 1410, 1390, 1370]}]",
1962 { "term", "a1", "a2", "term2", "a3", "a4" } }
1965 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1966 QueryForInput(cases[i].input, false, false);
1967 net::TestURLFetcher* fetcher =
1968 test_factory_.GetFetcherByID(
1969 SearchProvider::kDefaultProviderURLFetcherID);
1970 ASSERT_TRUE(fetcher);
1971 fetcher->set_response_code(200);
1972 fetcher->SetResponseString(cases[i].json);
1973 fetcher->delegate()->OnURLFetchComplete(fetcher);
1974 RunTillProviderDone();
1976 const std::string description = "for input with json=" + cases[i].json;
1977 const ACMatches& matches = provider_->matches();
1979 // Ensure no extra matches are present.
1980 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
1982 size_t j = 0;
1983 // Ensure that the returned matches equal the expectations.
1984 for (; j < matches.size(); ++j)
1985 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]),
1986 matches[j].contents) << description;
1987 // Ensure that no expected matches are missing.
1988 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1989 EXPECT_EQ(kNotApplicable, cases[i].matches[j]) <<
1990 "Case # " << i << " " << description;
1994 // Verifies suggest relevance behavior for URL input.
1995 TEST_F(SearchProviderTest, DefaultProviderSuggestRelevanceScoringUrlInput) {
1996 struct DefaultFetcherUrlInputMatch {
1997 const std::string match_contents;
1998 AutocompleteMatch::Type match_type;
1999 bool allowed_to_be_default_match;
2001 const DefaultFetcherUrlInputMatch kEmptyMatch =
2002 { kNotApplicable, AutocompleteMatchType::NUM_TYPES, false };
2003 struct {
2004 const std::string input;
2005 const std::string json;
2006 const DefaultFetcherUrlInputMatch output[4];
2007 } cases[] = {
2008 // Ensure NAVIGATION matches are allowed to be listed first for URL
2009 // input regardless of whether the match is inlineable. Note that
2010 // non-inlineable matches should not be allowed to be the default match.
2011 { "a.com", "[\"a.com\",[\"http://b.com/\"],[],[],"
2012 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2013 "\"google:suggestrelevance\":[9999]}]",
2014 { { "b.com", AutocompleteMatchType::NAVSUGGEST, false },
2015 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2016 kEmptyMatch, kEmptyMatch } },
2017 { "a.com", "[\"a.com\",[\"https://b.com\"],[],[],"
2018 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2019 "\"google:suggestrelevance\":[9999]}]",
2020 { { "https://b.com", AutocompleteMatchType::NAVSUGGEST, false },
2021 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2022 kEmptyMatch, kEmptyMatch } },
2023 { "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[],"
2024 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2025 "\"google:suggestrelevance\":[9999]}]",
2026 { { "a.com/a", AutocompleteMatchType::NAVSUGGEST, true },
2027 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2028 kEmptyMatch, kEmptyMatch } },
2029 { "a.com", "[\"a.com\",[\"https://a.com\"],[],[],"
2030 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2031 "\"google:suggestrelevance\":[9999]}]",
2032 { { "https://a.com", AutocompleteMatchType::NAVSUGGEST, true },
2033 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2034 kEmptyMatch, kEmptyMatch } },
2036 // Ensure topmost inlineable SUGGEST matches are NOT allowed for URL
2037 // input. SearchProvider disregards search and verbatim suggested
2038 // relevances.
2039 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2040 "{\"google:suggestrelevance\":[9999]}]",
2041 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2042 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
2043 kEmptyMatch, kEmptyMatch } },
2044 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2045 "{\"google:suggestrelevance\":[9999]}]",
2046 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2047 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
2048 kEmptyMatch, kEmptyMatch } },
2050 // Ensure the fallback mechanism allows inlinable NAVIGATION matches.
2051 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2052 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2053 "\"google:suggestrelevance\":[9999, 9998]}]",
2054 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true },
2055 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2056 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
2057 kEmptyMatch } },
2058 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2059 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2060 "\"google:suggestrelevance\":[9998, 9997],"
2061 "\"google:verbatimrelevance\":9999}]",
2062 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true },
2063 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2064 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
2065 kEmptyMatch } },
2067 // Ensure topmost non-inlineable SUGGEST matches are allowed for URL
2068 // input assuming the top inlineable match is not a query (i.e., is a
2069 // NAVSUGGEST).
2070 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2071 "{\"google:suggestrelevance\":[9999]}]",
2072 { { "info", AutocompleteMatchType::SEARCH_SUGGEST, false },
2073 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2074 kEmptyMatch, kEmptyMatch } },
2075 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2076 "{\"google:suggestrelevance\":[9999]}]",
2077 { { "info", AutocompleteMatchType::SEARCH_SUGGEST, false },
2078 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2079 kEmptyMatch, kEmptyMatch } },
2082 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2083 QueryForInput(ASCIIToUTF16(cases[i].input), false, false);
2084 net::TestURLFetcher* fetcher =
2085 test_factory_.GetFetcherByID(
2086 SearchProvider::kDefaultProviderURLFetcherID);
2087 ASSERT_TRUE(fetcher);
2088 fetcher->set_response_code(200);
2089 fetcher->SetResponseString(cases[i].json);
2090 fetcher->delegate()->OnURLFetchComplete(fetcher);
2091 RunTillProviderDone();
2093 size_t j = 0;
2094 const ACMatches& matches = provider_->matches();
2095 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].output));
2096 // Ensure that the returned matches equal the expectations.
2097 for (; j < matches.size(); ++j) {
2098 EXPECT_EQ(ASCIIToUTF16(cases[i].output[j].match_contents),
2099 matches[j].contents);
2100 EXPECT_EQ(cases[i].output[j].match_type, matches[j].type);
2101 EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match,
2102 matches[j].allowed_to_be_default_match);
2104 // Ensure that no expected matches are missing.
2105 for (; j < ARRAYSIZE_UNSAFE(cases[i].output); ++j) {
2106 EXPECT_EQ(kNotApplicable, cases[i].output[j].match_contents);
2107 EXPECT_EQ(AutocompleteMatchType::NUM_TYPES,
2108 cases[i].output[j].match_type);
2109 EXPECT_FALSE(cases[i].output[j].allowed_to_be_default_match);
2114 // A basic test that verifies the field trial triggered parsing logic.
2115 TEST_F(SearchProviderTest, FieldTrialTriggeredParsing) {
2116 QueryForInput(ASCIIToUTF16("foo"), false, false);
2118 // Make sure the default providers suggest service was queried.
2119 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
2120 SearchProvider::kDefaultProviderURLFetcherID);
2121 ASSERT_TRUE(fetcher);
2123 // Tell the SearchProvider the suggest query is done.
2124 fetcher->set_response_code(200);
2125 fetcher->SetResponseString(
2126 "[\"foo\",[\"foo bar\"],[\"\"],[],"
2127 "{\"google:suggesttype\":[\"QUERY\"],"
2128 "\"google:fieldtrialtriggered\":true}]");
2129 fetcher->delegate()->OnURLFetchComplete(fetcher);
2130 fetcher = NULL;
2132 // Run till the history results complete.
2133 RunTillProviderDone();
2136 // Check for the match and field trial triggered bits.
2137 AutocompleteMatch match;
2138 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("foo bar"), &match));
2139 ProvidersInfo providers_info;
2140 provider_->AddProviderInfo(&providers_info);
2141 ASSERT_EQ(1U, providers_info.size());
2142 EXPECT_EQ(1, providers_info[0].field_trial_triggered_size());
2143 EXPECT_EQ(1, providers_info[0].field_trial_triggered_in_session_size());
2146 // Reset the session and check that bits are reset.
2147 provider_->ResetSession();
2148 ProvidersInfo providers_info;
2149 provider_->AddProviderInfo(&providers_info);
2150 ASSERT_EQ(1U, providers_info.size());
2151 EXPECT_EQ(1, providers_info[0].field_trial_triggered_size());
2152 EXPECT_EQ(0, providers_info[0].field_trial_triggered_in_session_size());
2156 // Verifies inline autocompletion of navigational results.
2157 TEST_F(SearchProviderTest, NavigationInline) {
2158 struct {
2159 const std::string input;
2160 const std::string url;
2161 // Test the expected fill_into_edit, which may drop "http://".
2162 // Some cases do not trim "http://" to match from the start of the scheme.
2163 const std::string fill_into_edit;
2164 const std::string inline_autocompletion;
2165 const bool allowed_to_be_default_match_in_regular_mode;
2166 const bool allowed_to_be_default_match_in_prevent_inline_mode;
2167 } cases[] = {
2168 // Do not inline matches that do not contain the input; trim http as needed.
2169 { "x", "http://www.abc.com",
2170 "www.abc.com", std::string(), false, false },
2171 { "https:", "http://www.abc.com",
2172 "www.abc.com", std::string(), false, false },
2173 { "http://www.abc.com/a", "http://www.abc.com",
2174 "http://www.abc.com", std::string(), false,
2175 false },
2176 { "http://www.abc.com", "https://www.abc.com",
2177 "https://www.abc.com", std::string(), false,
2178 false },
2179 { "http://abc.com", "ftp://abc.com",
2180 "ftp://abc.com", std::string(), false,
2181 false },
2182 { "https://www.abc.com", "http://www.abc.com",
2183 "www.abc.com", std::string(), false,
2184 false },
2185 { "ftp://abc.com", "http://abc.com",
2186 "abc.com", std::string(), false,
2187 false },
2189 // Do not inline matches with invalid input prefixes; trim http as needed.
2190 { "ttp", "http://www.abc.com",
2191 "www.abc.com", std::string(), false, false },
2192 { "://w", "http://www.abc.com",
2193 "www.abc.com", std::string(), false, false },
2194 { "ww.", "http://www.abc.com",
2195 "www.abc.com", std::string(), false, false },
2196 { ".ab", "http://www.abc.com",
2197 "www.abc.com", std::string(), false, false },
2198 { "bc", "http://www.abc.com",
2199 "www.abc.com", std::string(), false, false },
2200 { ".com", "http://www.abc.com",
2201 "www.abc.com", std::string(), false, false },
2203 // Do not inline matches that omit input domain labels; trim http as needed.
2204 { "www.a", "http://a.com",
2205 "a.com", std::string(), false, false },
2206 { "http://www.a", "http://a.com",
2207 "http://a.com", std::string(), false, false },
2208 { "www.a", "ftp://a.com",
2209 "ftp://a.com", std::string(), false, false },
2210 { "ftp://www.a", "ftp://a.com",
2211 "ftp://a.com", std::string(), false, false },
2213 // Input matching but with nothing to inline will not yield an offset, but
2214 // will be allowed to be default.
2215 { "abc.com", "http://www.abc.com",
2216 "www.abc.com", std::string(), true, true },
2217 { "abc.com/", "http://www.abc.com",
2218 "www.abc.com", std::string(), true, true },
2219 { "http://www.abc.com", "http://www.abc.com",
2220 "http://www.abc.com", std::string(), true, true },
2221 { "http://www.abc.com/", "http://www.abc.com",
2222 "http://www.abc.com", std::string(), true, true },
2224 // Inputs with trailing whitespace should inline when possible.
2225 { "abc.com ", "http://www.abc.com",
2226 "www.abc.com", std::string(), true, true },
2227 { "abc.com/ ", "http://www.abc.com",
2228 "www.abc.com", std::string(), true, true },
2229 { "abc.com ", "http://www.abc.com/bar",
2230 "www.abc.com/bar", "/bar", false, false },
2232 // Inline matches when the input is a leading substring of the scheme.
2233 { "h", "http://www.abc.com",
2234 "http://www.abc.com", "ttp://www.abc.com", true, false },
2235 { "http", "http://www.abc.com",
2236 "http://www.abc.com", "://www.abc.com", true, false },
2238 // Inline matches when the input is a leading substring of the full URL.
2239 { "http:", "http://www.abc.com",
2240 "http://www.abc.com", "//www.abc.com", true, false },
2241 { "http://w", "http://www.abc.com",
2242 "http://www.abc.com", "ww.abc.com", true, false },
2243 { "http://www.", "http://www.abc.com",
2244 "http://www.abc.com", "abc.com", true, false },
2245 { "http://www.ab", "http://www.abc.com",
2246 "http://www.abc.com", "c.com", true, false },
2247 { "http://www.abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2248 "http://www.abc.com/path/file.htm?q=x#foo",
2249 "ath/file.htm?q=x#foo",
2250 true, false },
2251 { "http://abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2252 "http://abc.com/path/file.htm?q=x#foo",
2253 "ath/file.htm?q=x#foo",
2254 true, false},
2256 // Inline matches with valid URLPrefixes; only trim "http://".
2257 { "w", "http://www.abc.com",
2258 "www.abc.com", "ww.abc.com", true, false },
2259 { "www.a", "http://www.abc.com",
2260 "www.abc.com", "bc.com", true, false },
2261 { "abc", "http://www.abc.com",
2262 "www.abc.com", ".com", true, false },
2263 { "abc.c", "http://www.abc.com",
2264 "www.abc.com", "om", true, false },
2265 { "abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2266 "www.abc.com/path/file.htm?q=x#foo",
2267 "ath/file.htm?q=x#foo",
2268 true, false },
2269 { "abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2270 "abc.com/path/file.htm?q=x#foo",
2271 "ath/file.htm?q=x#foo",
2272 true, false },
2274 // Inline matches using the maximal URLPrefix components.
2275 { "h", "http://help.com",
2276 "help.com", "elp.com", true, false },
2277 { "http", "http://http.com",
2278 "http.com", ".com", true, false },
2279 { "h", "http://www.help.com",
2280 "www.help.com", "elp.com", true, false },
2281 { "http", "http://www.http.com",
2282 "www.http.com", ".com", true, false },
2283 { "w", "http://www.www.com",
2284 "www.www.com", "ww.com", true, false },
2286 // Test similar behavior for the ftp and https schemes.
2287 { "ftp://www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2288 "ftp://www.abc.com/path/file.htm?q=x#foo",
2289 "c.com/path/file.htm?q=x#foo", true, false },
2290 { "www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2291 "ftp://www.abc.com/path/file.htm?q=x#foo",
2292 "c.com/path/file.htm?q=x#foo", true, false },
2293 { "ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2294 "ftp://www.abc.com/path/file.htm?q=x#foo",
2295 "c.com/path/file.htm?q=x#foo", true, false },
2296 { "ab", "ftp://abc.com/path/file.htm?q=x#foo",
2297 "ftp://abc.com/path/file.htm?q=x#foo",
2298 "c.com/path/file.htm?q=x#foo", true, false },
2299 { "https://www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2300 "https://www.abc.com/path/file.htm?q=x#foo",
2301 "c.com/path/file.htm?q=x#foo",
2302 true, false },
2303 { "www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2304 "https://www.abc.com/path/file.htm?q=x#foo",
2305 "c.com/path/file.htm?q=x#foo", true, false },
2306 { "ab", "https://www.abc.com/path/file.htm?q=x#foo",
2307 "https://www.abc.com/path/file.htm?q=x#foo",
2308 "c.com/path/file.htm?q=x#foo", true, false },
2309 { "ab", "https://abc.com/path/file.htm?q=x#foo",
2310 "https://abc.com/path/file.htm?q=x#foo",
2311 "c.com/path/file.htm?q=x#foo", true, false },
2313 // Forced query input should inline and retain the "?" prefix.
2314 { "?http://www.ab", "http://www.abc.com",
2315 "?http://www.abc.com", "c.com", true, false },
2316 { "?www.ab", "http://www.abc.com",
2317 "?www.abc.com", "c.com", true, false },
2318 { "?ab", "http://www.abc.com",
2319 "?www.abc.com", "c.com", true, false },
2320 { "?abc.com", "http://www.abc.com",
2321 "?www.abc.com", "", true, true },
2324 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2325 // First test regular mode.
2326 QueryForInput(ASCIIToUTF16(cases[i].input), false, false);
2327 AutocompleteMatch match(
2328 provider_->NavigationToMatch(SearchProvider::NavigationResult(
2329 *provider_.get(), GURL(cases[i].url),
2330 AutocompleteMatchType::NAVSUGGEST, base::string16(), std::string(),
2331 false, 0, false, ASCIIToUTF16(cases[i].input), std::string())));
2332 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
2333 match.inline_autocompletion);
2334 EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit), match.fill_into_edit);
2335 EXPECT_EQ(cases[i].allowed_to_be_default_match_in_regular_mode,
2336 match.allowed_to_be_default_match);
2338 // Then test prevent-inline-autocomplete mode.
2339 QueryForInput(ASCIIToUTF16(cases[i].input), true, false);
2340 AutocompleteMatch match_prevent_inline(
2341 provider_->NavigationToMatch(SearchProvider::NavigationResult(
2342 *provider_.get(), GURL(cases[i].url),
2343 AutocompleteMatchType::NAVSUGGEST, base::string16(), std::string(),
2344 false, 0, false, ASCIIToUTF16(cases[i].input), std::string())));
2345 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
2346 match_prevent_inline.inline_autocompletion);
2347 EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit),
2348 match_prevent_inline.fill_into_edit);
2349 EXPECT_EQ(cases[i].allowed_to_be_default_match_in_prevent_inline_mode,
2350 match_prevent_inline.allowed_to_be_default_match);
2354 // Verifies that "http://" is not trimmed for input that is a leading substring.
2355 TEST_F(SearchProviderTest, NavigationInlineSchemeSubstring) {
2356 const base::string16 input(ASCIIToUTF16("ht"));
2357 const base::string16 url(ASCIIToUTF16("http://a.com"));
2358 const SearchProvider::NavigationResult result(
2359 *provider_.get(), GURL(url), AutocompleteMatchType::NAVSUGGEST,
2360 base::string16(), std::string(), false, 0, false, input, std::string());
2362 // Check the offset and strings when inline autocompletion is allowed.
2363 QueryForInput(input, false, false);
2364 AutocompleteMatch match_inline(provider_->NavigationToMatch(result));
2365 EXPECT_EQ(url, match_inline.fill_into_edit);
2366 EXPECT_EQ(url.substr(2), match_inline.inline_autocompletion);
2367 EXPECT_TRUE(match_inline.allowed_to_be_default_match);
2368 EXPECT_EQ(url, match_inline.contents);
2370 // Check the same strings when inline autocompletion is prevented.
2371 QueryForInput(input, true, false);
2372 AutocompleteMatch match_prevent(provider_->NavigationToMatch(result));
2373 EXPECT_EQ(url, match_prevent.fill_into_edit);
2374 EXPECT_FALSE(match_prevent.allowed_to_be_default_match);
2375 EXPECT_EQ(url, match_prevent.contents);
2378 // Verifies that input "w" marks a more significant domain label than "www.".
2379 TEST_F(SearchProviderTest, NavigationInlineDomainClassify) {
2380 QueryForInput(ASCIIToUTF16("w"), false, false);
2381 AutocompleteMatch match(
2382 provider_->NavigationToMatch(SearchProvider::NavigationResult(
2383 *provider_.get(), GURL("http://www.wow.com"),
2384 AutocompleteMatchType::NAVSUGGEST, base::string16(), std::string(),
2385 false, 0, false, ASCIIToUTF16("w"), std::string())));
2386 EXPECT_EQ(ASCIIToUTF16("ow.com"), match.inline_autocompletion);
2387 EXPECT_TRUE(match.allowed_to_be_default_match);
2388 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.fill_into_edit);
2389 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.contents);
2391 // Ensure that the match for input "w" is marked on "wow" and not "www".
2392 ASSERT_EQ(3U, match.contents_class.size());
2393 EXPECT_EQ(0U, match.contents_class[0].offset);
2394 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL,
2395 match.contents_class[0].style);
2396 EXPECT_EQ(4U, match.contents_class[1].offset);
2397 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL |
2398 AutocompleteMatch::ACMatchClassification::MATCH,
2399 match.contents_class[1].style);
2400 EXPECT_EQ(5U, match.contents_class[2].offset);
2401 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL,
2402 match.contents_class[2].style);
2405 #if !defined(OS_WIN)
2406 // Verify entity suggestion parsing.
2407 TEST_F(SearchProviderTest, ParseEntitySuggestion) {
2408 struct Match {
2409 std::string contents;
2410 std::string description;
2411 std::string query_params;
2412 std::string fill_into_edit;
2413 AutocompleteMatchType::Type type;
2415 const Match kEmptyMatch = {
2416 kNotApplicable, kNotApplicable, kNotApplicable, kNotApplicable,
2417 AutocompleteMatchType::NUM_TYPES};
2419 struct {
2420 const std::string input_text;
2421 const std::string response_json;
2422 const Match matches[5];
2423 } cases[] = {
2424 // A query and an entity suggestion with different search terms.
2425 { "x",
2426 "[\"x\",[\"xy\", \"yy\"],[\"\",\"\"],[],"
2427 " {\"google:suggestdetail\":[{},"
2428 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2429 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2430 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2431 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST },
2432 { "xy", "A", "p=v", "yy",
2433 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY },
2434 kEmptyMatch,
2435 kEmptyMatch
2438 // A query and an entity suggestion with same search terms.
2439 { "x",
2440 "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
2441 " {\"google:suggestdetail\":[{},"
2442 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2443 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2444 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2445 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST },
2446 { "xy", "A", "p=v", "xy",
2447 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY },
2448 kEmptyMatch,
2449 kEmptyMatch
2453 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2454 QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
2456 // Set up a default fetcher with provided results.
2457 net::TestURLFetcher* fetcher =
2458 test_factory_.GetFetcherByID(
2459 SearchProvider::kDefaultProviderURLFetcherID);
2460 ASSERT_TRUE(fetcher);
2461 fetcher->set_response_code(200);
2462 fetcher->SetResponseString(cases[i].response_json);
2463 fetcher->delegate()->OnURLFetchComplete(fetcher);
2465 RunTillProviderDone();
2467 const ACMatches& matches = provider_->matches();
2468 ASSERT_FALSE(matches.empty());
2470 SCOPED_TRACE("for input with json = " + cases[i].response_json);
2472 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
2473 size_t j = 0;
2474 // Ensure that the returned matches equal the expectations.
2475 for (; j < matches.size(); ++j) {
2476 const Match& match = cases[i].matches[j];
2477 SCOPED_TRACE(" and match index: " + base::IntToString(j));
2478 EXPECT_EQ(match.contents,
2479 base::UTF16ToUTF8(matches[j].contents));
2480 EXPECT_EQ(match.description,
2481 base::UTF16ToUTF8(matches[j].description));
2482 EXPECT_EQ(match.query_params,
2483 matches[j].search_terms_args->suggest_query_params);
2484 EXPECT_EQ(match.fill_into_edit,
2485 base::UTF16ToUTF8(matches[j].fill_into_edit));
2486 EXPECT_EQ(match.type, matches[j].type);
2488 // Ensure that no expected matches are missing.
2489 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
2490 SCOPED_TRACE(" and match index: " + base::IntToString(j));
2491 EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
2492 EXPECT_EQ(cases[i].matches[j].description, kNotApplicable);
2493 EXPECT_EQ(cases[i].matches[j].query_params, kNotApplicable);
2494 EXPECT_EQ(cases[i].matches[j].fill_into_edit, kNotApplicable);
2495 EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
2499 #endif // !defined(OS_WIN)
2502 // A basic test that verifies the prefetch metadata parsing logic.
2503 TEST_F(SearchProviderTest, PrefetchMetadataParsing) {
2504 struct Match {
2505 std::string contents;
2506 bool allowed_to_be_prefetched;
2507 AutocompleteMatchType::Type type;
2508 bool from_keyword;
2510 const Match kEmptyMatch = { kNotApplicable,
2511 false,
2512 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2513 false };
2515 struct {
2516 const std::string input_text;
2517 bool prefer_keyword_provider_results;
2518 const std::string default_provider_response_json;
2519 const std::string keyword_provider_response_json;
2520 const Match matches[5];
2521 } cases[] = {
2522 // Default provider response does not have prefetch details. Ensure that the
2523 // suggestions are not marked as prefetch query.
2524 { "a",
2525 false,
2526 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2527 std::string(),
2528 { { "a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2529 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2530 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2531 kEmptyMatch,
2532 kEmptyMatch
2535 // Ensure that default provider suggest response prefetch details are
2536 // parsed and recorded in AutocompleteMatch.
2537 { "ab",
2538 false,
2539 "[\"ab\",[\"abc\", \"http://b.com\", \"http://c.com\"],[],[],"
2540 "{\"google:clientdata\":{\"phi\": 0},"
2541 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"NAVIGATION\"],"
2542 "\"google:suggestrelevance\":[999, 12, 1]}]",
2543 std::string(),
2544 { { "ab", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2545 { "abc", true, AutocompleteMatchType::SEARCH_SUGGEST, false },
2546 { "b.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2547 { "c.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2548 kEmptyMatch
2551 // Default provider suggest response has prefetch details.
2552 // SEARCH_WHAT_YOU_TYPE suggestion outranks SEARCH_SUGGEST suggestion for
2553 // the same query string. Ensure that the prefetch details from
2554 // SEARCH_SUGGEST match are set onto SEARCH_WHAT_YOU_TYPE match.
2555 { "ab",
2556 false,
2557 "[\"ab\",[\"ab\", \"http://ab.com\"],[],[],"
2558 "{\"google:clientdata\":{\"phi\": 0},"
2559 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2560 "\"google:suggestrelevance\":[99, 98]}]",
2561 std::string(),
2562 { {"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2563 {"ab.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2564 kEmptyMatch,
2565 kEmptyMatch,
2566 kEmptyMatch
2569 // Default provider response has prefetch details. We prefer keyword
2570 // provider results. Ensure that prefetch bit for a suggestion from the
2571 // default search provider does not get copied onto a higher-scoring match
2572 // for the same query string from the keyword provider.
2573 { "k a",
2574 true,
2575 "[\"k a\",[\"a\", \"ab\"],[],[], {\"google:clientdata\":{\"phi\": 0},"
2576 "\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2577 "\"google:suggestrelevance\":[9, 12]}]",
2578 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2579 { { "a", false, AutocompleteMatchType::SEARCH_OTHER_ENGINE, true},
2580 { "k a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2581 { "ab", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2582 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST, true },
2583 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST, true }
2588 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2589 QueryForInput(ASCIIToUTF16(cases[i].input_text), false,
2590 cases[i].prefer_keyword_provider_results);
2592 // Set up a default fetcher with provided results.
2593 net::TestURLFetcher* fetcher =
2594 test_factory_.GetFetcherByID(
2595 SearchProvider::kDefaultProviderURLFetcherID);
2596 ASSERT_TRUE(fetcher);
2597 fetcher->set_response_code(200);
2598 fetcher->SetResponseString(cases[i].default_provider_response_json);
2599 fetcher->delegate()->OnURLFetchComplete(fetcher);
2601 if (cases[i].prefer_keyword_provider_results) {
2602 // Set up a keyword fetcher with provided results.
2603 net::TestURLFetcher* keyword_fetcher =
2604 test_factory_.GetFetcherByID(
2605 SearchProvider::kKeywordProviderURLFetcherID);
2606 ASSERT_TRUE(keyword_fetcher);
2607 keyword_fetcher->set_response_code(200);
2608 keyword_fetcher->SetResponseString(
2609 cases[i].keyword_provider_response_json);
2610 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
2611 keyword_fetcher = NULL;
2614 RunTillProviderDone();
2616 const std::string description =
2617 "for input with json =" + cases[i].default_provider_response_json;
2618 const ACMatches& matches = provider_->matches();
2619 // The top match must inline and score as highly as calculated verbatim.
2620 ASSERT_FALSE(matches.empty());
2621 EXPECT_GE(matches[0].relevance, 1300);
2623 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
2624 // Ensure that the returned matches equal the expectations.
2625 for (size_t j = 0; j < matches.size(); ++j) {
2626 SCOPED_TRACE(description);
2627 EXPECT_EQ(cases[i].matches[j].contents,
2628 base::UTF16ToUTF8(matches[j].contents));
2629 EXPECT_EQ(cases[i].matches[j].allowed_to_be_prefetched,
2630 SearchProvider::ShouldPrefetch(matches[j]));
2631 EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
2632 EXPECT_EQ(cases[i].matches[j].from_keyword,
2633 matches[j].keyword == ASCIIToUTF16("k"));
2638 TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_InvalidResponse) {
2639 ClearAllResults();
2641 std::string input_str("abc");
2642 QueryForInput(ASCIIToUTF16(input_str), false, false);
2644 // Set up a default fetcher with provided results.
2645 net::TestURLFetcher* fetcher =
2646 test_factory_.GetFetcherByID(
2647 SearchProvider::kDefaultProviderURLFetcherID);
2648 ASSERT_TRUE(fetcher);
2649 fetcher->set_response_code(200);
2650 fetcher->SetResponseString("this is a bad non-json response");
2651 fetcher->delegate()->OnURLFetchComplete(fetcher);
2653 RunTillProviderDone();
2655 const ACMatches& matches = provider_->matches();
2657 // Should have exactly one "search what you typed" match
2658 ASSERT_TRUE(matches.size() == 1);
2659 EXPECT_EQ(input_str, base::UTF16ToUTF8(matches[0].contents));
2660 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2661 matches[0].type);
2664 // A basic test that verifies that the XSSI guarded JSON response is parsed
2665 // correctly.
2666 TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_ValidResponses) {
2667 struct Match {
2668 std::string contents;
2669 AutocompleteMatchType::Type type;
2671 const Match kEmptyMatch = {
2672 kNotApplicable, AutocompleteMatchType::NUM_TYPES
2675 struct {
2676 const std::string input_text;
2677 const std::string default_provider_response_json;
2678 const Match matches[4];
2679 } cases[] = {
2680 // No XSSI guard.
2681 { "a",
2682 "[\"a\",[\"b\", \"c\"],[],[],"
2683 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2684 "\"google:suggestrelevance\":[1, 2]}]",
2685 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2686 { "c", AutocompleteMatchType::SEARCH_SUGGEST },
2687 { "b", AutocompleteMatchType::SEARCH_SUGGEST },
2688 kEmptyMatch,
2691 // Standard XSSI guard - )]}'\n.
2692 { "a",
2693 ")]}'\n[\"a\",[\"b\", \"c\"],[],[],"
2694 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2695 "\"google:suggestrelevance\":[1, 2]}]",
2696 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2697 { "c", AutocompleteMatchType::SEARCH_SUGGEST },
2698 { "b", AutocompleteMatchType::SEARCH_SUGGEST },
2699 kEmptyMatch,
2702 // Modified XSSI guard - contains "[".
2703 { "a",
2704 ")]}'\n[)\"[\"a\",[\"b\", \"c\"],[],[],"
2705 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2706 "\"google:suggestrelevance\":[1, 2]}]",
2707 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2708 { "c", AutocompleteMatchType::SEARCH_SUGGEST },
2709 { "b", AutocompleteMatchType::SEARCH_SUGGEST },
2710 kEmptyMatch,
2715 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2716 ClearAllResults();
2717 QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
2719 // Set up a default fetcher with provided results.
2720 net::TestURLFetcher* fetcher =
2721 test_factory_.GetFetcherByID(
2722 SearchProvider::kDefaultProviderURLFetcherID);
2723 ASSERT_TRUE(fetcher);
2724 fetcher->set_response_code(200);
2725 fetcher->SetResponseString(cases[i].default_provider_response_json);
2726 fetcher->delegate()->OnURLFetchComplete(fetcher);
2728 RunTillProviderDone();
2730 const ACMatches& matches = provider_->matches();
2731 // The top match must inline and score as highly as calculated verbatim.
2732 ASSERT_FALSE(matches.empty());
2733 EXPECT_GE(matches[0].relevance, 1300);
2735 SCOPED_TRACE("for case: " + base::IntToString(i));
2736 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 SCOPED_TRACE("and match: " + base::IntToString(j));
2741 EXPECT_EQ(cases[i].matches[j].contents,
2742 base::UTF16ToUTF8(matches[j].contents));
2743 EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
2745 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
2746 SCOPED_TRACE("and match: " + base::IntToString(j));
2747 EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
2748 EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
2753 // Test that deletion url gets set on an AutocompleteMatch when available for a
2754 // personalized query or a personalized URL.
2755 TEST_F(SearchProviderTest, ParseDeletionUrl) {
2756 struct Match {
2757 std::string contents;
2758 std::string deletion_url;
2759 AutocompleteMatchType::Type type;
2762 const Match kEmptyMatch = {
2763 kNotApplicable, "", AutocompleteMatchType::NUM_TYPES
2766 const char* url[] = {
2767 "http://defaultturl/complete/deleteitems"
2768 "?delq=ab&client=chrome&deltok=xsrf124",
2769 "http://defaultturl/complete/deleteitems"
2770 "?delq=www.amazon.com&client=chrome&deltok=xsrf123",
2773 struct {
2774 const std::string input_text;
2775 const std::string response_json;
2776 const Match matches[5];
2777 } cases[] = {
2778 // A deletion URL on a personalized query should be reflected in the
2779 // resulting AutocompleteMatch.
2780 { "a",
2781 "[\"a\",[\"ab\", \"ac\",\"www.amazon.com\"],[],[],"
2782 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
2783 "\"PERSONALIZED_NAVIGATION\"],"
2784 "\"google:suggestrelevance\":[3, 2, 1],"
2785 "\"google:suggestdetail\":[{\"du\":"
2786 "\"/complete/deleteitems?delq=ab&client=chrome"
2787 "&deltok=xsrf124\"}, {}, {\"du\":"
2788 "\"/complete/deleteitems?delq=www.amazon.com&"
2789 "client=chrome&deltok=xsrf123\"}]}]",
2790 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2791 { "ab", url[0], AutocompleteMatchType::SEARCH_SUGGEST },
2792 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
2793 { "www.amazon.com", url[1],
2794 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
2795 kEmptyMatch,
2798 // Personalized queries or a personalized URL without deletion URLs
2799 // shouldn't cause errors.
2800 { "a",
2801 "[\"a\",[\"ab\", \"ac\"],[],[],"
2802 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
2803 "\"PERSONALIZED_NAVIGATION\"],"
2804 "\"google:suggestrelevance\":[1, 2],"
2805 "\"google:suggestdetail\":[{}, {}]}]",
2806 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2807 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
2808 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST },
2809 { "www.amazon.com", "",
2810 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
2811 kEmptyMatch,
2814 // Personalized queries or a personalized URL without
2815 // google:suggestdetail shouldn't cause errors.
2816 { "a",
2817 "[\"a\",[\"ab\", \"ac\"],[],[],"
2818 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
2819 "\"PERSONALIZED_NAVIGATION\"],"
2820 "\"google:suggestrelevance\":[1, 2]}]",
2821 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2822 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
2823 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST },
2824 { "www.amazon.com", "",
2825 AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
2826 kEmptyMatch,
2831 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2832 QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
2834 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
2835 SearchProvider::kDefaultProviderURLFetcherID);
2836 ASSERT_TRUE(fetcher);
2837 fetcher->set_response_code(200);
2838 fetcher->SetResponseString(cases[i].response_json);
2839 fetcher->delegate()->OnURLFetchComplete(fetcher);
2841 RunTillProviderDone();
2843 const ACMatches& matches = provider_->matches();
2844 ASSERT_FALSE(matches.empty());
2846 SCOPED_TRACE("for input with json = " + cases[i].response_json);
2848 for (size_t j = 0; j < matches.size(); ++j) {
2849 const Match& match = cases[i].matches[j];
2850 SCOPED_TRACE(" and match index: " + base::IntToString(j));
2851 EXPECT_EQ(match.contents, base::UTF16ToUTF8(matches[j].contents));
2852 EXPECT_EQ(match.deletion_url, matches[j].GetAdditionalInfo(
2853 "deletion_url"));
2858 TEST_F(SearchProviderTest, ReflectsBookmarkBarState) {
2859 profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, false);
2860 base::string16 term = term1_.substr(0, term1_.length() - 1);
2861 QueryForInput(term, true, false);
2862 ASSERT_FALSE(provider_->matches().empty());
2863 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2864 provider_->matches()[0].type);
2865 ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL);
2866 EXPECT_FALSE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned);
2868 profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, true);
2869 term = term1_.substr(0, term1_.length() - 1);
2870 QueryForInput(term, true, false);
2871 ASSERT_FALSE(provider_->matches().empty());
2872 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2873 provider_->matches()[0].type);
2874 ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL);
2875 EXPECT_TRUE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned);
2878 TEST_F(SearchProviderTest, CanSendURL) {
2879 TemplateURLData template_url_data;
2880 template_url_data.short_name = ASCIIToUTF16("t");
2881 template_url_data.SetURL("http://www.google.com/{searchTerms}");
2882 template_url_data.suggestions_url = "http://www.google.com/{searchTerms}";
2883 template_url_data.instant_url = "http://does/not/exist?strk=1";
2884 template_url_data.search_terms_replacement_key = "strk";
2885 template_url_data.id = SEARCH_ENGINE_GOOGLE;
2886 TemplateURL google_template_url(&profile_, template_url_data);
2888 // Create field trial.
2889 base::FieldTrial* field_trial = base::FieldTrialList::CreateFieldTrial(
2890 "AutocompleteDynamicTrial_2", "EnableZeroSuggest");
2891 field_trial->group();
2893 // Not signed in.
2894 EXPECT_FALSE(SearchProvider::CanSendURL(
2895 GURL("http://www.google.com/search"),
2896 GURL("https://www.google.com/complete/search"), &google_template_url,
2897 AutocompleteInput::OTHER, &profile_));
2898 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(&profile_);
2899 signin->SetAuthenticatedUsername("test");
2901 // All conditions should be met.
2902 EXPECT_TRUE(SearchProvider::CanSendURL(
2903 GURL("http://www.google.com/search"),
2904 GURL("https://www.google.com/complete/search"), &google_template_url,
2905 AutocompleteInput::OTHER, &profile_));
2907 // Not in field trial.
2908 ResetFieldTrialList();
2909 EXPECT_FALSE(SearchProvider::CanSendURL(
2910 GURL("http://www.google.com/search"),
2911 GURL("https://www.google.com/complete/search"), &google_template_url,
2912 AutocompleteInput::OTHER, &profile_));
2913 field_trial = base::FieldTrialList::CreateFieldTrial(
2914 "AutocompleteDynamicTrial_2", "EnableZeroSuggest");
2915 field_trial->group();
2917 // Invalid page URL.
2918 EXPECT_FALSE(SearchProvider::CanSendURL(
2919 GURL("badpageurl"),
2920 GURL("https://www.google.com/complete/search"), &google_template_url,
2921 AutocompleteInput::OTHER, &profile_));
2923 // Invalid page classification.
2924 EXPECT_FALSE(SearchProvider::CanSendURL(
2925 GURL("http://www.google.com/search"),
2926 GURL("https://www.google.com/complete/search"), &google_template_url,
2927 AutocompleteInput::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS,
2928 &profile_));
2930 // Invalid page classification.
2931 EXPECT_FALSE(SearchProvider::CanSendURL(
2932 GURL("http://www.google.com/search"),
2933 GURL("https://www.google.com/complete/search"), &google_template_url,
2934 AutocompleteInput::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS,
2935 &profile_));
2937 // HTTPS page URL on same domain as provider.
2938 EXPECT_TRUE(SearchProvider::CanSendURL(
2939 GURL("https://www.google.com/search"),
2940 GURL("https://www.google.com/complete/search"),
2941 &google_template_url, AutocompleteInput::OTHER, &profile_));
2943 // Non-HTTP[S] page URL on same domain as provider.
2944 EXPECT_FALSE(SearchProvider::CanSendURL(
2945 GURL("ftp://www.google.com/search"),
2946 GURL("https://www.google.com/complete/search"), &google_template_url,
2947 AutocompleteInput::OTHER, &profile_));
2949 // Non-HTTP page URL on different domain.
2950 EXPECT_FALSE(SearchProvider::CanSendURL(
2951 GURL("https://www.notgoogle.com/search"),
2952 GURL("https://www.google.com/complete/search"), &google_template_url,
2953 AutocompleteInput::OTHER, &profile_));
2955 // Non-HTTPS provider.
2956 EXPECT_FALSE(SearchProvider::CanSendURL(
2957 GURL("http://www.google.com/search"),
2958 GURL("http://www.google.com/complete/search"), &google_template_url,
2959 AutocompleteInput::OTHER, &profile_));
2961 // Suggest disabled.
2962 profile_.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false);
2963 EXPECT_FALSE(SearchProvider::CanSendURL(
2964 GURL("http://www.google.com/search"),
2965 GURL("https://www.google.com/complete/search"), &google_template_url,
2966 AutocompleteInput::OTHER, &profile_));
2967 profile_.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
2969 // Incognito.
2970 EXPECT_FALSE(SearchProvider::CanSendURL(
2971 GURL("http://www.google.com/search"),
2972 GURL("https://www.google.com/complete/search"), &google_template_url,
2973 AutocompleteInput::OTHER, profile_.GetOffTheRecordProfile()));
2975 // Tab sync not enabled.
2976 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncKeepEverythingSynced,
2977 false);
2978 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs, false);
2979 EXPECT_FALSE(SearchProvider::CanSendURL(
2980 GURL("http://www.google.com/search"),
2981 GURL("https://www.google.com/complete/search"), &google_template_url,
2982 AutocompleteInput::OTHER, &profile_));
2983 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs, true);
2985 // Tab sync is encrypted.
2986 ProfileSyncService* service =
2987 ProfileSyncServiceFactory::GetInstance()->GetForProfile(&profile_);
2988 syncer::ModelTypeSet encrypted_types = service->GetEncryptedDataTypes();
2989 encrypted_types.Put(syncer::SESSIONS);
2990 service->OnEncryptedTypesChanged(encrypted_types, false);
2991 EXPECT_FALSE(SearchProvider::CanSendURL(
2992 GURL("http://www.google.com/search"),
2993 GURL("https://www.google.com/complete/search"), &google_template_url,
2994 AutocompleteInput::OTHER, &profile_));
2995 encrypted_types.Remove(syncer::SESSIONS);
2996 service->OnEncryptedTypesChanged(encrypted_types, false);
2998 // Check that there were no side effects from previous tests.
2999 EXPECT_TRUE(SearchProvider::CanSendURL(
3000 GURL("http://www.google.com/search"),
3001 GURL("https://www.google.com/complete/search"), &google_template_url,
3002 AutocompleteInput::OTHER, &profile_));
3005 TEST_F(SearchProviderTest, TestDeleteMatch) {
3006 AutocompleteMatch match(provider_, 0, true,
3007 AutocompleteMatchType::SEARCH_SUGGEST);
3008 match.RecordAdditionalInfo(
3009 SearchProvider::kDeletionUrlKey,
3010 "https://www.google.com/complete/deleteitem?q=foo");
3012 // Test a successful deletion request.
3013 provider_->matches_.push_back(match);
3014 provider_->DeleteMatch(match);
3015 EXPECT_FALSE(provider_->deletion_handlers_.empty());
3016 EXPECT_TRUE(provider_->matches_.empty());
3017 // Set up a default fetcher with provided results.
3018 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
3019 SearchProvider::kDeletionURLFetcherID);
3020 ASSERT_TRUE(fetcher);
3021 fetcher->set_response_code(200);
3022 fetcher->delegate()->OnURLFetchComplete(fetcher);
3023 EXPECT_TRUE(provider_->deletion_handlers_.empty());
3024 EXPECT_TRUE(provider_->is_success());
3026 // Test a failing deletion request.
3027 provider_->matches_.push_back(match);
3028 provider_->DeleteMatch(match);
3029 EXPECT_FALSE(provider_->deletion_handlers_.empty());
3030 // Set up a default fetcher with provided results.
3031 fetcher = test_factory_.GetFetcherByID(
3032 SearchProvider::kDeletionURLFetcherID);
3033 ASSERT_TRUE(fetcher);
3034 fetcher->set_response_code(500);
3035 fetcher->delegate()->OnURLFetchComplete(fetcher);
3036 EXPECT_TRUE(provider_->deletion_handlers_.empty());
3037 EXPECT_FALSE(provider_->is_success());
3040 TEST_F(SearchProviderTest, TestDeleteHistoryQueryMatch) {
3041 GURL term_url(
3042 AddSearchToHistory(default_t_url_, ASCIIToUTF16("flash games"), 1));
3043 profile_.BlockUntilHistoryProcessesPendingRequests();
3045 AutocompleteMatch games;
3046 QueryForInput(ASCIIToUTF16("fla"), false, false);
3047 profile_.BlockUntilHistoryProcessesPendingRequests();
3048 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3049 ASSERT_TRUE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games));
3051 size_t matches_before = provider_->matches().size();
3052 provider_->DeleteMatch(games);
3053 EXPECT_EQ(matches_before - 1, provider_->matches().size());
3055 // Process history deletions.
3056 profile_.BlockUntilHistoryProcessesPendingRequests();
3058 // Check that the match is gone.
3059 QueryForInput(ASCIIToUTF16("fla"), false, false);
3060 profile_.BlockUntilHistoryProcessesPendingRequests();
3061 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3062 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games));
3065 // Verifies that duplicates are preserved in AddMatchToMap().
3066 TEST_F(SearchProviderTest, CheckDuplicateMatchesSaved) {
3067 AddSearchToHistory(default_t_url_, ASCIIToUTF16("a"), 1);
3068 AddSearchToHistory(default_t_url_, ASCIIToUTF16("alpha"), 1);
3069 AddSearchToHistory(default_t_url_, ASCIIToUTF16("avid"), 1);
3071 profile_.BlockUntilHistoryProcessesPendingRequests();
3072 QueryForInput(ASCIIToUTF16("a"), false, false);
3074 // Make sure the default provider's suggest service was queried.
3075 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
3076 SearchProvider::kDefaultProviderURLFetcherID);
3077 ASSERT_TRUE(fetcher);
3079 // Tell the SearchProvider the suggest query is done.
3080 fetcher->set_response_code(200);
3081 fetcher->SetResponseString(
3082 "[\"a\",[\"a\", \"alpha\", \"avid\", \"apricot\"],[],[],"
3083 "{\"google:suggestrelevance\":[1450, 1200, 1150, 1100],"
3084 "\"google:verbatimrelevance\":1350}]");
3085 fetcher->delegate()->OnURLFetchComplete(fetcher);
3086 fetcher = NULL;
3088 // Run till the history results complete.
3089 RunTillProviderDone();
3091 AutocompleteMatch verbatim, match_alpha, match_apricot, match_avid;
3092 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim));
3093 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("alpha"), &match_alpha));
3094 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("apricot"), &match_apricot));
3095 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("avid"), &match_avid));
3097 // Verbatim match duplicates are added such that each one has a higher
3098 // relevance than the previous one.
3099 EXPECT_EQ(2U, verbatim.duplicate_matches.size());
3101 // Other match duplicates are added in descending relevance order.
3102 EXPECT_EQ(1U, match_alpha.duplicate_matches.size());
3103 EXPECT_EQ(1U, match_avid.duplicate_matches.size());
3105 EXPECT_EQ(0U, match_apricot.duplicate_matches.size());
3108 TEST_F(SearchProviderTest, SuggestQueryUsesToken) {
3109 CommandLine::ForCurrentProcess()->AppendSwitch(
3110 switches::kEnableAnswersInSuggest);
3112 TemplateURLService* turl_model =
3113 TemplateURLServiceFactory::GetForProfile(&profile_);
3115 TemplateURLData data;
3116 data.short_name = ASCIIToUTF16("default");
3117 data.SetKeyword(data.short_name);
3118 data.SetURL("http://example/{searchTerms}{google:sessionToken}");
3119 data.suggestions_url =
3120 "http://suggest/?q={searchTerms}&{google:sessionToken}";
3121 default_t_url_ = new TemplateURL(&profile_, data);
3122 turl_model->Add(default_t_url_);
3123 turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
3125 base::string16 term = term1_.substr(0, term1_.length() - 1);
3126 QueryForInput(term, false, false);
3128 // Make sure the default provider's suggest service was queried.
3129 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
3130 SearchProvider::kDefaultProviderURLFetcherID);
3131 ASSERT_TRUE(fetcher);
3133 // And the URL matches what we expected.
3134 TemplateURLRef::SearchTermsArgs search_terms_args(term);
3135 search_terms_args.session_token = provider_->current_token_;
3136 GURL expected_url(default_t_url_->suggestions_url_ref().ReplaceSearchTerms(
3137 search_terms_args));
3138 EXPECT_EQ(fetcher->GetOriginalURL().spec(), expected_url.spec());
3140 // Complete running the fetcher to clean up.
3141 fetcher->set_response_code(200);
3142 fetcher->delegate()->OnURLFetchComplete(fetcher);
3143 RunTillProviderDone();
3146 TEST_F(SearchProviderTest, SessionToken) {
3147 // Subsequent calls always get the same token.
3148 std::string token = provider_->GetSessionToken();
3149 std::string token2 = provider_->GetSessionToken();
3150 EXPECT_EQ(token, token2);
3151 EXPECT_FALSE(token.empty());
3153 // Calls do not regenerate a token.
3154 provider_->current_token_ = "PRE-EXISTING TOKEN";
3155 token = provider_->GetSessionToken();
3156 EXPECT_EQ(token, "PRE-EXISTING TOKEN");
3158 // ... unless the token has expired.
3159 provider_->current_token_.clear();
3160 const base::TimeDelta kSmallDelta = base::TimeDelta::FromMilliseconds(1);
3161 provider_->token_expiration_time_ = base::TimeTicks::Now() - kSmallDelta;
3162 token = provider_->GetSessionToken();
3163 EXPECT_FALSE(token.empty());
3164 EXPECT_EQ(token, provider_->current_token_);
3166 // The expiration time is always updated.
3167 provider_->GetSessionToken();
3168 base::TimeTicks expiration_time_1 = provider_->token_expiration_time_;
3169 base::PlatformThread::Sleep(kSmallDelta);
3170 provider_->GetSessionToken();
3171 base::TimeTicks expiration_time_2 = provider_->token_expiration_time_;
3172 EXPECT_GT(expiration_time_2, expiration_time_1);
3173 EXPECT_GE(expiration_time_2, expiration_time_1 + kSmallDelta);