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