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