- add sources.
[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 "chrome/browser/autocomplete/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/autocomplete_input.h"
22 #include "chrome/browser/autocomplete/autocomplete_match.h"
23 #include "chrome/browser/autocomplete/autocomplete_provider.h"
24 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
25 #include "chrome/browser/autocomplete/history_url_provider.h"
26 #include "chrome/browser/history/history_service.h"
27 #include "chrome/browser/history/history_service_factory.h"
28 #include "chrome/browser/omnibox/omnibox_field_trial.h"
29 #include "chrome/browser/search/search.h"
30 #include "chrome/browser/search_engines/template_url.h"
31 #include "chrome/browser/search_engines/template_url_service.h"
32 #include "chrome/browser/search_engines/template_url_service_factory.h"
33 #include "chrome/common/chrome_switches.h"
34 #include "chrome/common/metrics/variations/variations_util.h"
35 #include "chrome/common/pref_names.h"
36 #include "chrome/test/base/testing_browser_process.h"
37 #include "chrome/test/base/testing_profile.h"
38 #include "components/variations/entropy_provider.h"
39 #include "content/public/test/test_browser_thread_bundle.h"
40 #include "net/url_request/test_url_fetcher_factory.h"
41 #include "net/url_request/url_request_status.h"
42 #include "testing/gtest/include/gtest/gtest.h"
43
44 // SearchProviderTest ---------------------------------------------------------
45
46 // The following environment is configured for these tests:
47 // . The TemplateURL default_t_url_ is set as the default provider.
48 // . The TemplateURL keyword_t_url_ is added to the TemplateURLService. This
49 //   TemplateURL has a valid suggest and search URL.
50 // . The URL created by using the search term term1_ with default_t_url_ is
51 //   added to history.
52 // . The URL created by using the search term keyword_term_ with keyword_t_url_
53 //   is added to history.
54 // . test_factory_ is set as the URLFetcherFactory.
55 class SearchProviderTest : public testing::Test,
56                            public AutocompleteProviderListener {
57  public:
58   struct ResultInfo {
59     ResultInfo() : result_type(AutocompleteMatchType::NUM_TYPES) {
60     }
61     ResultInfo(GURL gurl,
62                AutocompleteMatch::Type result_type,
63                string16 fill_into_edit)
64       : gurl(gurl),
65         result_type(result_type),
66         fill_into_edit(fill_into_edit) {
67     }
68
69     const GURL gurl;
70     const AutocompleteMatch::Type result_type;
71     const string16 fill_into_edit;
72   };
73
74   struct TestData {
75     const string16 input;
76     const size_t num_results;
77     const ResultInfo output[3];
78   };
79
80   SearchProviderTest()
81       : default_t_url_(NULL),
82         term1_(ASCIIToUTF16("term1")),
83         keyword_t_url_(NULL),
84         keyword_term_(ASCIIToUTF16("keyword")),
85         run_loop_(NULL) {
86     ResetFieldTrialList();
87   }
88
89   // See description above class for what this registers.
90   virtual void SetUp() OVERRIDE;
91   virtual void TearDown() OVERRIDE;
92
93   void RunTest(TestData* cases, int num_cases, bool prefer_keyword);
94
95  protected:
96   // Needed for AutocompleteFieldTrial::ActivateStaticTrials();
97   scoped_ptr<base::FieldTrialList> field_trial_list_;
98
99   // Default value used for testing.
100   static const std::string kNotApplicable;
101
102   // Adds a search for |term|, using the engine |t_url| to the history, and
103   // returns the URL for that search.
104   GURL AddSearchToHistory(TemplateURL* t_url, string16 term, int visit_count);
105
106   // Looks for a match in |provider_| with |contents| equal to |contents|.
107   // Sets |match| to it if found.  Returns whether |match| was set.
108   bool FindMatchWithContents(const string16& contents,
109                              AutocompleteMatch* match);
110
111   // Looks for a match in |provider_| with destination |url|.  Sets |match| to
112   // it if found.  Returns whether |match| was set.
113   bool FindMatchWithDestination(const GURL& url, AutocompleteMatch* match);
114
115   // AutocompleteProviderListener:
116   // If we're waiting for the provider to finish, this exits the message loop.
117   virtual void OnProviderUpdate(bool updated_matches) OVERRIDE;
118
119   // Runs a nested message loop until provider_ is done. The message loop is
120   // exited by way of OnProviderUpdate.
121   void RunTillProviderDone();
122
123   // Invokes Start on provider_, then runs all pending tasks.
124   void QueryForInput(const string16& text,
125                      bool prevent_inline_autocomplete,
126                      bool prefer_keyword);
127
128   // Calls QueryForInput(), finishes any suggest query, then if |wyt_match| is
129   // non-NULL, sets it to the "what you typed" entry for |text|.
130   void QueryForInputAndSetWYTMatch(const string16& text,
131                                    AutocompleteMatch* wyt_match);
132
133   // Notifies the URLFetcher for the suggest query corresponding to the default
134   // search provider that it's done.
135   // Be sure and wrap calls to this in ASSERT_NO_FATAL_FAILURE.
136   void FinishDefaultSuggestQuery();
137
138   void ResetFieldTrialList();
139
140   void ClearAllResults();
141
142   // See description above class for details of these fields.
143   TemplateURL* default_t_url_;
144   const string16 term1_;
145   GURL term1_url_;
146   TemplateURL* keyword_t_url_;
147   const string16 keyword_term_;
148   GURL keyword_url_;
149
150   content::TestBrowserThreadBundle thread_bundle_;
151
152   // URLFetcherFactory implementation registered.
153   net::TestURLFetcherFactory test_factory_;
154
155   // Profile we use.
156   TestingProfile profile_;
157
158   // The provider.
159   scoped_refptr<SearchProvider> provider_;
160
161   // If non-NULL, OnProviderUpdate quits the current |run_loop_|.
162   base::RunLoop* run_loop_;
163
164   DISALLOW_COPY_AND_ASSIGN(SearchProviderTest);
165 };
166
167 // static
168 const std::string SearchProviderTest::kNotApplicable = "Not Applicable";
169
170 void SearchProviderTest::SetUp() {
171   // Make sure that fetchers are automatically ungregistered upon destruction.
172   test_factory_.set_remove_fetcher_on_delete(true);
173
174   // We need both the history service and template url model loaded.
175   ASSERT_TRUE(profile_.CreateHistoryService(true, false));
176   TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
177       &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
178
179   TemplateURLService* turl_model =
180       TemplateURLServiceFactory::GetForProfile(&profile_);
181
182   turl_model->Load();
183
184   // Reset the default TemplateURL.
185   TemplateURLData data;
186   data.short_name = ASCIIToUTF16("t");
187   data.SetURL("http://defaultturl/{searchTerms}");
188   data.suggestions_url = "http://defaultturl2/{searchTerms}";
189   data.instant_url = "http://does/not/exist?strk=1";
190   data.search_terms_replacement_key = "strk";
191   default_t_url_ = new TemplateURL(&profile_, data);
192   turl_model->Add(default_t_url_);
193   turl_model->SetDefaultSearchProvider(default_t_url_);
194   TemplateURLID default_provider_id = default_t_url_->id();
195   ASSERT_NE(0, default_provider_id);
196
197   // Add url1, with search term term1_.
198   term1_url_ = AddSearchToHistory(default_t_url_, term1_, 1);
199
200   // Create another TemplateURL.
201   data.short_name = ASCIIToUTF16("k");
202   data.SetKeyword(ASCIIToUTF16("k"));
203   data.SetURL("http://keyword/{searchTerms}");
204   data.suggestions_url = "http://suggest_keyword/{searchTerms}";
205   keyword_t_url_ = new TemplateURL(&profile_, data);
206   turl_model->Add(keyword_t_url_);
207   ASSERT_NE(0, keyword_t_url_->id());
208
209   // Add a page and search term for keyword_t_url_.
210   keyword_url_ = AddSearchToHistory(keyword_t_url_, keyword_term_, 1);
211
212   // Keywords are updated by the InMemoryHistoryBackend only after the message
213   // has been processed on the history thread. Block until history processes all
214   // requests to ensure the InMemoryDatabase is the state we expect it.
215   profile_.BlockUntilHistoryProcessesPendingRequests();
216
217   provider_ = new SearchProvider(this, &profile_);
218   provider_->kMinimumTimeBetweenSuggestQueriesMs = 0;
219 }
220
221 void SearchProviderTest::TearDown() {
222   base::RunLoop().RunUntilIdle();
223
224   // Shutdown the provider before the profile.
225   provider_ = NULL;
226 }
227
228 void SearchProviderTest::RunTest(TestData* cases,
229                                  int num_cases,
230                                  bool prefer_keyword) {
231   ACMatches matches;
232   for (int i = 0; i < num_cases; ++i) {
233     AutocompleteInput input(cases[i].input, string16::npos, string16(), GURL(),
234                             AutocompleteInput::INVALID_SPEC, false,
235                             prefer_keyword, true,
236                             AutocompleteInput::ALL_MATCHES);
237     provider_->Start(input, false);
238     matches = provider_->matches();
239     string16 diagnostic_details = ASCIIToUTF16("Input was: ") + cases[i].input +
240         ASCIIToUTF16("; prefer_keyword was: ") +
241         (prefer_keyword ? ASCIIToUTF16("true") : ASCIIToUTF16("false"));
242     EXPECT_EQ(cases[i].num_results, matches.size()) << diagnostic_details;
243     if (matches.size() == cases[i].num_results) {
244       for (size_t j = 0; j < cases[i].num_results; ++j) {
245         EXPECT_EQ(cases[i].output[j].gurl, matches[j].destination_url) <<
246             diagnostic_details;
247         EXPECT_EQ(cases[i].output[j].result_type, matches[j].type) <<
248             diagnostic_details;
249         EXPECT_EQ(cases[i].output[j].fill_into_edit,
250                   matches[j].fill_into_edit) <<
251             diagnostic_details;
252         // All callers that use this helper function at the moment produce
253         // matches that are always allowed to be the default match.
254         EXPECT_TRUE(matches[j].allowed_to_be_default_match);
255       }
256     }
257   }
258 }
259
260 void SearchProviderTest::OnProviderUpdate(bool updated_matches) {
261   if (run_loop_ && provider_->done()) {
262     run_loop_->Quit();
263     run_loop_ = NULL;
264   }
265 }
266
267 void SearchProviderTest::RunTillProviderDone() {
268   if (provider_->done())
269     return;
270
271   base::RunLoop run_loop;
272   run_loop_ = &run_loop;
273   run_loop.Run();
274 }
275
276 void SearchProviderTest::QueryForInput(const string16& text,
277                                        bool prevent_inline_autocomplete,
278                                        bool prefer_keyword) {
279   // Start a query.
280   AutocompleteInput input(text, string16::npos, string16(), GURL(),
281                           AutocompleteInput::INVALID_SPEC,
282                           prevent_inline_autocomplete, prefer_keyword, true,
283                           AutocompleteInput::ALL_MATCHES);
284   provider_->Start(input, false);
285
286   // RunUntilIdle so that the task scheduled by SearchProvider to create the
287   // URLFetchers runs.
288   base::RunLoop().RunUntilIdle();
289 }
290
291 void SearchProviderTest::QueryForInputAndSetWYTMatch(
292     const string16& text,
293     AutocompleteMatch* wyt_match) {
294   QueryForInput(text, false, false);
295   profile_.BlockUntilHistoryProcessesPendingRequests();
296   ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
297   if (!wyt_match)
298     return;
299   ASSERT_GE(provider_->matches().size(), 1u);
300   EXPECT_TRUE(FindMatchWithDestination(GURL(
301       default_t_url_->url_ref().ReplaceSearchTerms(
302           TemplateURLRef::SearchTermsArgs(text))),
303       wyt_match));
304 }
305
306 GURL SearchProviderTest::AddSearchToHistory(TemplateURL* t_url,
307                                             string16 term,
308                                             int visit_count) {
309   HistoryService* history =
310       HistoryServiceFactory::GetForProfile(&profile_,
311                                            Profile::EXPLICIT_ACCESS);
312   GURL search(t_url->url_ref().ReplaceSearchTerms(
313       TemplateURLRef::SearchTermsArgs(term)));
314   static base::Time last_added_time;
315   last_added_time = std::max(base::Time::Now(),
316       last_added_time + base::TimeDelta::FromMicroseconds(1));
317   history->AddPageWithDetails(search, string16(), visit_count, visit_count,
318       last_added_time, false, history::SOURCE_BROWSED);
319   history->SetKeywordSearchTermsForURL(search, t_url->id(), term);
320   return search;
321 }
322
323 bool SearchProviderTest::FindMatchWithContents(const string16& contents,
324                                                AutocompleteMatch* match) {
325   for (ACMatches::const_iterator i = provider_->matches().begin();
326        i != provider_->matches().end(); ++i) {
327     if (i->contents == contents) {
328       *match = *i;
329       return true;
330     }
331   }
332   return false;
333 }
334
335 bool SearchProviderTest::FindMatchWithDestination(const GURL& url,
336                                                   AutocompleteMatch* match) {
337   for (ACMatches::const_iterator i = provider_->matches().begin();
338        i != provider_->matches().end(); ++i) {
339     if (i->destination_url == url) {
340       *match = *i;
341       return true;
342     }
343   }
344   return false;
345 }
346
347 void SearchProviderTest::FinishDefaultSuggestQuery() {
348   net::TestURLFetcher* default_fetcher =
349       test_factory_.GetFetcherByID(
350           SearchProvider::kDefaultProviderURLFetcherID);
351   ASSERT_TRUE(default_fetcher);
352
353   // Tell the SearchProvider the default suggest query is done.
354   default_fetcher->set_response_code(200);
355   default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
356 }
357
358 void SearchProviderTest::ResetFieldTrialList() {
359   // Destroy the existing FieldTrialList before creating a new one to avoid
360   // a DCHECK.
361   field_trial_list_.reset();
362   field_trial_list_.reset(new base::FieldTrialList(
363       new metrics::SHA1EntropyProvider("foo")));
364   chrome_variations::testing::ClearAllVariationParams();
365   base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
366       "AutocompleteDynamicTrial_0", "DefaultGroup");
367   trial->group();
368 }
369
370 void SearchProviderTest::ClearAllResults() {
371   provider_->ClearAllResults();
372 }
373
374 // Actual Tests ---------------------------------------------------------------
375
376 // Make sure we query history for the default provider and a URLFetcher is
377 // created for the default provider suggest results.
378 TEST_F(SearchProviderTest, QueryDefaultProvider) {
379   string16 term = term1_.substr(0, term1_.length() - 1);
380   QueryForInput(term, false, false);
381
382   // Make sure the default providers suggest service was queried.
383   net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
384       SearchProvider::kDefaultProviderURLFetcherID);
385   ASSERT_TRUE(fetcher);
386
387   // And the URL matches what we expected.
388   GURL expected_url(default_t_url_->suggestions_url_ref().ReplaceSearchTerms(
389       TemplateURLRef::SearchTermsArgs(term)));
390   ASSERT_TRUE(fetcher->GetOriginalURL() == expected_url);
391
392   // Tell the SearchProvider the suggest query is done.
393   fetcher->set_response_code(200);
394   fetcher->delegate()->OnURLFetchComplete(fetcher);
395   fetcher = NULL;
396
397   // Run till the history results complete.
398   RunTillProviderDone();
399
400   // The SearchProvider is done. Make sure it has a result for the history
401   // term term1.
402   AutocompleteMatch term1_match;
403   EXPECT_TRUE(FindMatchWithDestination(term1_url_, &term1_match));
404   // Term1 should not have a description, it's set later.
405   EXPECT_TRUE(term1_match.description.empty());
406
407   AutocompleteMatch wyt_match;
408   EXPECT_TRUE(FindMatchWithDestination(
409       GURL(default_t_url_->url_ref().ReplaceSearchTerms(
410           TemplateURLRef::SearchTermsArgs(term))), &wyt_match));
411   EXPECT_TRUE(wyt_match.description.empty());
412
413   // The match for term1 should be more relevant than the what you typed match.
414   EXPECT_GT(term1_match.relevance, wyt_match.relevance);
415   // This longer match should be inlineable.
416   EXPECT_TRUE(term1_match.allowed_to_be_default_match);
417   // The what you typed match should be too, of course.
418   EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
419 }
420
421 TEST_F(SearchProviderTest, HonorPreventInlineAutocomplete) {
422   string16 term = term1_.substr(0, term1_.length() - 1);
423   QueryForInput(term, true, false);
424
425   ASSERT_FALSE(provider_->matches().empty());
426   ASSERT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
427             provider_->matches()[0].type);
428   EXPECT_TRUE(provider_->matches()[0].allowed_to_be_default_match);
429 }
430
431 // Issues a query that matches the registered keyword and makes sure history
432 // is queried as well as URLFetchers getting created.
433 TEST_F(SearchProviderTest, QueryKeywordProvider) {
434   string16 term = keyword_term_.substr(0, keyword_term_.length() - 1);
435   QueryForInput(keyword_t_url_->keyword() + ASCIIToUTF16(" ") + term,
436                 false,
437                 false);
438
439   // Make sure the default providers suggest service was queried.
440   net::TestURLFetcher* default_fetcher = test_factory_.GetFetcherByID(
441       SearchProvider::kDefaultProviderURLFetcherID);
442   ASSERT_TRUE(default_fetcher);
443
444   // Tell the SearchProvider the default suggest query is done.
445   default_fetcher->set_response_code(200);
446   default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
447   default_fetcher = NULL;
448
449   // Make sure the keyword providers suggest service was queried.
450   net::TestURLFetcher* keyword_fetcher = test_factory_.GetFetcherByID(
451       SearchProvider::kKeywordProviderURLFetcherID);
452   ASSERT_TRUE(keyword_fetcher);
453
454   // And the URL matches what we expected.
455   GURL expected_url(keyword_t_url_->suggestions_url_ref().ReplaceSearchTerms(
456       TemplateURLRef::SearchTermsArgs(term)));
457   ASSERT_TRUE(keyword_fetcher->GetOriginalURL() == expected_url);
458
459   // Tell the SearchProvider the keyword suggest query is done.
460   keyword_fetcher->set_response_code(200);
461   keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
462   keyword_fetcher = NULL;
463
464   // Run till the history results complete.
465   RunTillProviderDone();
466
467   // The SearchProvider is done. Make sure it has a result for the history
468   // term keyword.
469   AutocompleteMatch match;
470   EXPECT_TRUE(FindMatchWithDestination(keyword_url_, &match));
471
472   // The match should have an associated keyword.
473   EXPECT_FALSE(match.keyword.empty());
474
475   // The fill into edit should contain the keyword.
476   EXPECT_EQ(keyword_t_url_->keyword() + char16(' ') + keyword_term_,
477             match.fill_into_edit);
478 }
479
480 TEST_F(SearchProviderTest, DontSendPrivateDataToSuggest) {
481   // None of the following input strings should be sent to the suggest server,
482   // because they may contain private data.
483   const char* inputs[] = {
484     "username:password",
485     "http://username:password",
486     "https://username:password",
487     "username:password@hostname",
488     "http://username:password@hostname/",
489     "file://filename",
490     "data://data",
491     "unknownscheme:anything",
492     "http://hostname/?query=q",
493     "http://hostname/path#ref",
494     "http://hostname/path #ref",
495     "https://hostname/path",
496   };
497
498   for (size_t i = 0; i < arraysize(inputs); ++i) {
499     QueryForInput(ASCIIToUTF16(inputs[i]), false, false);
500     // Make sure the default provider's suggest service was not queried.
501     ASSERT_TRUE(test_factory_.GetFetcherByID(
502         SearchProvider::kDefaultProviderURLFetcherID) == NULL);
503     // Run till the history results complete.
504     RunTillProviderDone();
505   }
506 }
507
508 TEST_F(SearchProviderTest, SendNonPrivateDataToSuggest) {
509   // All of the following input strings should be sent to the suggest server,
510   // because they should not get caught by the private data checks.
511   const char* inputs[] = {
512     "query",
513     "query with spaces",
514     "http://hostname",
515     "http://hostname/path",
516     "http://hostname #ref",
517     "www.hostname.com #ref",
518     "https://hostname",
519     "#hashtag",
520     "foo https://hostname/path"
521   };
522
523   profile_.BlockUntilHistoryProcessesPendingRequests();
524   for (size_t i = 0; i < arraysize(inputs); ++i) {
525     QueryForInput(ASCIIToUTF16(inputs[i]), false, false);
526     // Make sure the default provider's suggest service was queried.
527     ASSERT_TRUE(test_factory_.GetFetcherByID(
528         SearchProvider::kDefaultProviderURLFetcherID) != NULL);
529   }
530 }
531
532 TEST_F(SearchProviderTest, DontAutocompleteURLLikeTerms) {
533   AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
534       &profile_, &AutocompleteClassifierFactory::BuildInstanceFor);
535   GURL url = AddSearchToHistory(default_t_url_,
536                                 ASCIIToUTF16("docs.google.com"), 1);
537
538   // Add the term as a url.
539   HistoryServiceFactory::GetForProfile(&profile_, Profile::EXPLICIT_ACCESS)->
540       AddPageWithDetails(GURL("http://docs.google.com"), string16(), 1, 1,
541                          base::Time::Now(), false, history::SOURCE_BROWSED);
542   profile_.BlockUntilHistoryProcessesPendingRequests();
543
544   AutocompleteMatch wyt_match;
545   ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("docs"),
546                                                       &wyt_match));
547
548   // There should be two matches, one for what you typed, the other for
549   // 'docs.google.com'. The search term should have a lower priority than the
550   // what you typed match.
551   ASSERT_EQ(2u, provider_->matches().size());
552   AutocompleteMatch term_match;
553   EXPECT_TRUE(FindMatchWithDestination(url, &term_match));
554   EXPECT_GT(wyt_match.relevance, term_match.relevance);
555   EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
556   EXPECT_TRUE(term_match.allowed_to_be_default_match);
557 }
558
559 // A multiword search with one visit should not autocomplete until multiple
560 // words are typed.
561 TEST_F(SearchProviderTest, DontAutocompleteUntilMultipleWordsTyped) {
562   GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("one search"),
563                                    1));
564   profile_.BlockUntilHistoryProcessesPendingRequests();
565
566   AutocompleteMatch wyt_match;
567   ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("on"),
568                                                       &wyt_match));
569   ASSERT_EQ(2u, provider_->matches().size());
570   AutocompleteMatch term_match;
571   EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
572   EXPECT_GT(wyt_match.relevance, term_match.relevance);
573   EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
574   EXPECT_TRUE(term_match.allowed_to_be_default_match);
575
576   ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("one se"),
577                                                       &wyt_match));
578   ASSERT_EQ(2u, provider_->matches().size());
579   EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
580   EXPECT_GT(term_match.relevance, wyt_match.relevance);
581   EXPECT_TRUE(term_match.allowed_to_be_default_match);
582   EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
583 }
584
585 // A multiword search with more than one visit should autocomplete immediately.
586 TEST_F(SearchProviderTest, AutocompleteMultipleVisitsImmediately) {
587   GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches"),
588                                    2));
589   profile_.BlockUntilHistoryProcessesPendingRequests();
590
591   AutocompleteMatch wyt_match;
592   ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("tw"),
593                                                       &wyt_match));
594   ASSERT_EQ(2u, provider_->matches().size());
595   AutocompleteMatch term_match;
596   EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
597   EXPECT_GT(term_match.relevance, wyt_match.relevance);
598   EXPECT_TRUE(term_match.allowed_to_be_default_match);
599   EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
600 }
601
602 // Autocompletion should work at a word boundary after a space.
603 TEST_F(SearchProviderTest, AutocompleteAfterSpace) {
604   GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches"),
605                                    2));
606   profile_.BlockUntilHistoryProcessesPendingRequests();
607
608   AutocompleteMatch wyt_match;
609   ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("two "),
610                                                       &wyt_match));
611   ASSERT_EQ(2u, provider_->matches().size());
612   AutocompleteMatch term_match;
613   EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
614   EXPECT_GT(term_match.relevance, wyt_match.relevance);
615   EXPECT_TRUE(term_match.allowed_to_be_default_match);
616   EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
617 }
618
619 // Newer multiword searches should score more highly than older ones.
620 TEST_F(SearchProviderTest, ScoreNewerSearchesHigher) {
621   GURL term_url_a(AddSearchToHistory(default_t_url_,
622                                      ASCIIToUTF16("three searches aaa"), 1));
623   GURL term_url_b(AddSearchToHistory(default_t_url_,
624                                      ASCIIToUTF16("three searches bbb"), 1));
625   profile_.BlockUntilHistoryProcessesPendingRequests();
626
627   AutocompleteMatch wyt_match;
628   ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("three se"),
629                                                       &wyt_match));
630   ASSERT_EQ(3u, provider_->matches().size());
631   AutocompleteMatch term_match_a;
632   EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
633   AutocompleteMatch term_match_b;
634   EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
635   EXPECT_GT(term_match_b.relevance, term_match_a.relevance);
636   EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
637   EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
638   EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
639   EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
640 }
641
642 // An autocompleted multiword search should not be replaced by a different
643 // autocompletion while the user is still typing a valid prefix.
644 TEST_F(SearchProviderTest, DontReplacePreviousAutocompletion) {
645   GURL term_url_a(AddSearchToHistory(default_t_url_,
646                                      ASCIIToUTF16("four searches aaa"), 2));
647   GURL term_url_b(AddSearchToHistory(default_t_url_,
648                                      ASCIIToUTF16("four searches bbb"), 1));
649   profile_.BlockUntilHistoryProcessesPendingRequests();
650
651   AutocompleteMatch wyt_match;
652   ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fo"),
653                                                       &wyt_match));
654   ASSERT_EQ(3u, provider_->matches().size());
655   AutocompleteMatch term_match_a;
656   EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
657   AutocompleteMatch term_match_b;
658   EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
659   EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
660   EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
661   EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
662   EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
663   EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
664
665   ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("four se"),
666                                                       &wyt_match));
667   ASSERT_EQ(3u, provider_->matches().size());
668   EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
669   EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
670   EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
671   EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
672   EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
673   EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
674   EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
675 }
676
677 // Non-completable multiword searches should not crowd out single-word searches.
678 TEST_F(SearchProviderTest, DontCrowdOutSingleWords) {
679   GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("five"), 1));
680   AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches bbb"), 1);
681   AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches ccc"), 1);
682   AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches ddd"), 1);
683   AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches eee"), 1);
684   profile_.BlockUntilHistoryProcessesPendingRequests();
685
686   AutocompleteMatch wyt_match;
687   ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fi"),
688                                                       &wyt_match));
689   ASSERT_EQ(AutocompleteProvider::kMaxMatches + 1, provider_->matches().size());
690   AutocompleteMatch term_match;
691   EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
692   EXPECT_GT(term_match.relevance, wyt_match.relevance);
693   EXPECT_TRUE(term_match.allowed_to_be_default_match);
694   EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
695 }
696
697 // Inline autocomplete matches regardless of case differences from the input.
698 TEST_F(SearchProviderTest, InlineMixedCaseMatches) {
699   GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("FOO"), 1));
700   profile_.BlockUntilHistoryProcessesPendingRequests();
701
702   AutocompleteMatch wyt_match;
703   ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
704                                                       &wyt_match));
705   ASSERT_EQ(2u, provider_->matches().size());
706   AutocompleteMatch term_match;
707   EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
708   EXPECT_GT(term_match.relevance, wyt_match.relevance);
709   EXPECT_EQ(ASCIIToUTF16("FOO"), term_match.fill_into_edit);
710   EXPECT_EQ(ASCIIToUTF16("OO"), term_match.inline_autocompletion);
711   EXPECT_TRUE(term_match.allowed_to_be_default_match);
712 }
713
714 // Verifies AutocompleteControllers return results (including keyword
715 // results) in the right order and set descriptions for them correctly.
716 TEST_F(SearchProviderTest, KeywordOrderingAndDescriptions) {
717   // Add an entry that corresponds to a keyword search with 'term2'.
718   AddSearchToHistory(keyword_t_url_, ASCIIToUTF16("term2"), 1);
719   profile_.BlockUntilHistoryProcessesPendingRequests();
720
721   AutocompleteController controller(&profile_, NULL,
722       AutocompleteProvider::TYPE_SEARCH);
723   controller.Start(AutocompleteInput(
724       ASCIIToUTF16("k t"), string16::npos, string16(), GURL(),
725       AutocompleteInput::INVALID_SPEC, false, false, true,
726       AutocompleteInput::ALL_MATCHES));
727   const AutocompleteResult& result = controller.result();
728
729   // There should be three matches, one for the keyword history, one for
730   // keyword provider's what-you-typed, and one for the default provider's
731   // what you typed, in that order.
732   ASSERT_EQ(3u, result.size());
733   EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY, result.match_at(0).type);
734   EXPECT_EQ(AutocompleteMatchType::SEARCH_OTHER_ENGINE,
735             result.match_at(1).type);
736   EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
737             result.match_at(2).type);
738   EXPECT_GT(result.match_at(0).relevance, result.match_at(1).relevance);
739   EXPECT_GT(result.match_at(1).relevance, result.match_at(2).relevance);
740   EXPECT_TRUE(result.match_at(0).allowed_to_be_default_match);
741   EXPECT_TRUE(result.match_at(1).allowed_to_be_default_match);
742   EXPECT_TRUE(result.match_at(2).allowed_to_be_default_match);
743
744   // The two keyword results should come with the keyword we expect.
745   EXPECT_EQ(ASCIIToUTF16("k"), result.match_at(0).keyword);
746   EXPECT_EQ(ASCIIToUTF16("k"), result.match_at(1).keyword);
747   // The default provider has a different keyword.  (We don't explicitly
748   // set it during this test, so all we do is assert that it's different.)
749   EXPECT_NE(result.match_at(0).keyword, result.match_at(2).keyword);
750
751   // The top result will always have a description.  The third result,
752   // coming from a different provider than the first two, should also.
753   // Whether the second result has one doesn't matter much.  (If it was
754   // missing, people would infer that it's the same search provider as
755   // the one above it.)
756   EXPECT_FALSE(result.match_at(0).description.empty());
757   EXPECT_FALSE(result.match_at(2).description.empty());
758   EXPECT_NE(result.match_at(0).description, result.match_at(2).description);
759 }
760
761 TEST_F(SearchProviderTest, KeywordVerbatim) {
762   TestData cases[] = {
763     // Test a simple keyword input.
764     { ASCIIToUTF16("k foo"), 2,
765       { ResultInfo(GURL("http://keyword/foo"),
766                    AutocompleteMatchType::SEARCH_OTHER_ENGINE,
767                    ASCIIToUTF16("k foo")),
768         ResultInfo(GURL("http://defaultturl/k%20foo"),
769                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
770                    ASCIIToUTF16("k foo") ) } },
771
772     // Make sure extra whitespace after the keyword doesn't change the
773     // keyword verbatim query.
774     { ASCIIToUTF16("k   foo"), 2,
775       { ResultInfo(GURL("http://keyword/foo"),
776                    AutocompleteMatchType::SEARCH_OTHER_ENGINE,
777                    ASCIIToUTF16("k foo")),
778         ResultInfo(GURL("http://defaultturl/k%20%20%20foo"),
779                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
780                    ASCIIToUTF16("k   foo")) } },
781     // Leading whitespace should be stripped before SearchProvider gets the
782     // input; hence there are no tests here about how it handles those inputs.
783
784     // But whitespace elsewhere in the query string should matter to both
785     // matches.
786     { ASCIIToUTF16("k  foo  bar"), 2,
787       { ResultInfo(GURL("http://keyword/foo%20%20bar"),
788                    AutocompleteMatchType::SEARCH_OTHER_ENGINE,
789                    ASCIIToUTF16("k foo  bar")),
790         ResultInfo(GURL("http://defaultturl/k%20%20foo%20%20bar"),
791                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
792                    ASCIIToUTF16("k  foo  bar")) } },
793     // Note in the above test case we don't test trailing whitespace because
794     // SearchProvider still doesn't handle this well.  See related bugs:
795     // 102690, 99239, 164635.
796
797     // Keywords can be prefixed by certain things that should get ignored
798     // when constructing the keyword match.
799     { ASCIIToUTF16("www.k foo"), 2,
800       { ResultInfo(GURL("http://keyword/foo"),
801                    AutocompleteMatchType::SEARCH_OTHER_ENGINE,
802                    ASCIIToUTF16("k foo")),
803         ResultInfo(GURL("http://defaultturl/www.k%20foo"),
804                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
805                    ASCIIToUTF16("www.k foo")) } },
806     { ASCIIToUTF16("http://k foo"), 2,
807       { ResultInfo(GURL("http://keyword/foo"),
808                    AutocompleteMatchType::SEARCH_OTHER_ENGINE,
809                    ASCIIToUTF16("k foo")),
810         ResultInfo(GURL("http://defaultturl/http%3A//k%20foo"),
811                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
812                    ASCIIToUTF16("http://k foo")) } },
813     { ASCIIToUTF16("http://www.k foo"), 2,
814       { ResultInfo(GURL("http://keyword/foo"),
815                    AutocompleteMatchType::SEARCH_OTHER_ENGINE,
816                    ASCIIToUTF16("k foo")),
817         ResultInfo(GURL("http://defaultturl/http%3A//www.k%20foo"),
818                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
819                    ASCIIToUTF16("http://www.k foo")) } },
820
821     // A keyword with no remaining input shouldn't get a keyword
822     // verbatim match.
823     { ASCIIToUTF16("k"), 1,
824       { ResultInfo(GURL("http://defaultturl/k"),
825                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
826                    ASCIIToUTF16("k")) } },
827     { ASCIIToUTF16("k "), 1,
828       { ResultInfo(GURL("http://defaultturl/k%20"),
829                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
830                    ASCIIToUTF16("k ")) } }
831
832     // The fact that verbatim queries to keyword are handled by KeywordProvider
833     // not SearchProvider is tested in
834     // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc.
835   };
836
837   // Test not in keyword mode.
838   RunTest(cases, arraysize(cases), false);
839
840   // Test in keyword mode.  (Both modes should give the same result.)
841   RunTest(cases, arraysize(cases), true);
842 }
843
844 // Ensures command-line flags are reflected in the URLs the search provider
845 // generates.
846 TEST_F(SearchProviderTest, CommandLineOverrides) {
847   TemplateURLService* turl_model =
848       TemplateURLServiceFactory::GetForProfile(&profile_);
849
850   TemplateURLData data;
851   data.short_name = ASCIIToUTF16("default");
852   data.SetKeyword(data.short_name);
853   data.SetURL("{google:baseURL}{searchTerms}");
854   default_t_url_ = new TemplateURL(&profile_, data);
855   turl_model->Add(default_t_url_);
856   turl_model->SetDefaultSearchProvider(default_t_url_);
857
858   CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
859                                                       "http://www.bar.com/");
860   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
861       switches::kExtraSearchQueryParams, "a=b");
862
863   TestData cases[] = {
864     { ASCIIToUTF16("k a"), 2,
865       { ResultInfo(GURL("http://keyword/a"),
866                    AutocompleteMatchType::SEARCH_OTHER_ENGINE,
867                    ASCIIToUTF16("k a")),
868         ResultInfo(GURL("http://www.bar.com/k%20a?a=b"),
869                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
870                    ASCIIToUTF16("k a")) } },
871   };
872
873   RunTest(cases, arraysize(cases), false);
874 }
875
876 // Verifies Navsuggest results don't set a TemplateURL, which Instant relies on.
877 // Also verifies that just the *first* navigational result is listed as a match
878 // if suggested relevance scores were not sent.
879 TEST_F(SearchProviderTest, NavSuggestNoSuggestedRelevanceScores) {
880   QueryForInput(ASCIIToUTF16("a.c"), false, false);
881
882   // Make sure the default providers suggest service was queried.
883   net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
884       SearchProvider::kDefaultProviderURLFetcherID);
885   ASSERT_TRUE(fetcher);
886
887   // Tell the SearchProvider the suggest query is done.
888   fetcher->set_response_code(200);
889   fetcher->SetResponseString(
890       "[\"a.c\",[\"a.com\", \"a.com/b\"],[\"a\", \"b\"],[],"
891       "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]");
892   fetcher->delegate()->OnURLFetchComplete(fetcher);
893   fetcher = NULL;
894
895   // Run till the history results complete.
896   RunTillProviderDone();
897
898   // Make sure the only match is 'a.com' and it doesn't have a template_url.
899   AutocompleteMatch nav_match;
900   EXPECT_TRUE(FindMatchWithDestination(GURL("http://a.com"), &nav_match));
901   EXPECT_TRUE(nav_match.keyword.empty());
902   EXPECT_TRUE(nav_match.allowed_to_be_default_match);
903   EXPECT_FALSE(FindMatchWithDestination(GURL("http://a.com/b"), &nav_match));
904 }
905
906 // Verifies that the most relevant suggest results are added properly.
907 TEST_F(SearchProviderTest, SuggestRelevance) {
908   QueryForInput(ASCIIToUTF16("a"), false, false);
909
910   // Make sure the default provider's suggest service was queried.
911   net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
912       SearchProvider::kDefaultProviderURLFetcherID);
913   ASSERT_TRUE(fetcher);
914
915   // Tell the SearchProvider the suggest query is done.
916   fetcher->set_response_code(200);
917   fetcher->SetResponseString("[\"a\",[\"a1\", \"a2\", \"a3\", \"a4\"]]");
918   fetcher->delegate()->OnURLFetchComplete(fetcher);
919   fetcher = NULL;
920
921   // Run till the history results complete.
922   RunTillProviderDone();
923
924   // Check the expected verbatim and (first 3) suggestions' relative relevances.
925   AutocompleteMatch verbatim, match_a1, match_a2, match_a3, match_a4;
926   EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim));
927   EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a1"), &match_a1));
928   EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a2"), &match_a2));
929   EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a3"), &match_a3));
930   EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("a4"), &match_a4));
931   EXPECT_GT(verbatim.relevance, match_a1.relevance);
932   EXPECT_GT(match_a1.relevance, match_a2.relevance);
933   EXPECT_GT(match_a2.relevance, match_a3.relevance);
934   EXPECT_TRUE(verbatim.allowed_to_be_default_match);
935   EXPECT_TRUE(match_a1.allowed_to_be_default_match);
936   EXPECT_TRUE(match_a2.allowed_to_be_default_match);
937   EXPECT_TRUE(match_a3.allowed_to_be_default_match);
938 }
939
940 // Verifies that suggest results with relevance scores are added
941 // properly when using the default fetcher.  When adding a new test
942 // case to this test, please consider adding it to the tests in
943 // KeywordFetcherSuggestRelevance below.
944 TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevance) {
945   struct DefaultFetcherMatch {
946     std::string contents;
947     bool allowed_to_be_default_match;
948   };
949   const DefaultFetcherMatch kEmptyMatch = { kNotApplicable, false };
950   struct {
951     const std::string json;
952     const DefaultFetcherMatch matches[4];
953     const std::string inline_autocompletion;
954   } cases[] = {
955     // Ensure that suggestrelevance scores reorder matches.
956     { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
957       { { "a", true }, { "c", false }, { "b", false }, kEmptyMatch },
958       std::string() },
959     { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
960        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
961         "\"google:suggestrelevance\":[1, 2]}]",
962       { { "a", true }, { "c.com", false }, { "b.com", false }, kEmptyMatch },
963       std::string() },
964
965     // Without suggested relevance scores, we should only allow one
966     // navsuggest result to be be displayed.
967     { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
968        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
969       { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch },
970       std::string() },
971
972     // Ensure that verbatimrelevance scores reorder or suppress verbatim.
973     // Negative values will have no effect; the calculated value will be used.
974     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
975                              "\"google:suggestrelevance\":[9998]}]",
976       { { "a", true}, { "a1", true }, kEmptyMatch, kEmptyMatch },
977       std::string() },
978     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
979                              "\"google:suggestrelevance\":[9999]}]",
980       { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
981       "1" },
982     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
983                              "\"google:suggestrelevance\":[9999]}]",
984       { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
985       "1" },
986     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
987                              "\"google:suggestrelevance\":[9999]}]",
988       { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
989       "1" },
990     { "[\"a\",[\"http://a.com\"],[],[],"
991        "{\"google:suggesttype\":[\"NAVIGATION\"],"
992         "\"google:verbatimrelevance\":9999,"
993         "\"google:suggestrelevance\":[9998]}]",
994       { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch },
995       std::string() },
996     { "[\"a\",[\"http://a.com\"],[],[],"
997        "{\"google:suggesttype\":[\"NAVIGATION\"],"
998         "\"google:verbatimrelevance\":9998,"
999         "\"google:suggestrelevance\":[9999]}]",
1000       { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
1001       ".com" },
1002     { "[\"a\",[\"http://a.com\"],[],[],"
1003        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1004         "\"google:verbatimrelevance\":0,"
1005         "\"google:suggestrelevance\":[9999]}]",
1006       { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1007       ".com" },
1008     { "[\"a\",[\"http://a.com\"],[],[],"
1009        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1010         "\"google:verbatimrelevance\":-1,"
1011         "\"google:suggestrelevance\":[9999]}]",
1012       { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
1013       ".com" },
1014
1015     // Ensure that both types of relevance scores reorder matches together.
1016     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1017                                      "\"google:verbatimrelevance\":9998}]",
1018       { { "a1", true }, { "a", true }, { "a2", true }, kEmptyMatch },
1019       "1" },
1020
1021     // Ensure that only inlinable matches may be ranked as the highest result.
1022     // Ignore all suggested relevance scores if this constraint is violated.
1023     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1024       { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch },
1025       std::string() },
1026     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1027                             "\"google:verbatimrelevance\":0}]",
1028       { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch },
1029       std::string() },
1030     { "[\"a\",[\"http://b.com\"],[],[],"
1031        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1032         "\"google:suggestrelevance\":[9999]}]",
1033       { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch },
1034       std::string() },
1035     { "[\"a\",[\"http://b.com\"],[],[],"
1036        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1037         "\"google:suggestrelevance\":[9999],"
1038         "\"google:verbatimrelevance\":0}]",
1039       { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch },
1040       std::string() },
1041     { "[\"a\",[\"https://a/\"],[],[],"
1042        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1043         "\"google:suggestrelevance\":[9999]}]",
1044       { { "https://a", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
1045       std::string() },
1046
1047     // Ensure that the top result is ranked as highly as calculated verbatim.
1048     // Ignore the suggested verbatim relevance if this constraint is violated.
1049     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1050       { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
1051       std::string() },
1052     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1053       { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
1054       std::string() },
1055     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1056                              "\"google:verbatimrelevance\":0}]",
1057       { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
1058       std::string() },
1059     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1060                                      "\"google:verbatimrelevance\":0}]",
1061       { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch },
1062       std::string() },
1063     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1064       "\"google:verbatimrelevance\":2}]",
1065       { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch },
1066       std::string() },
1067     { "[\"a\",[\"http://a.com\"],[],[],"
1068        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1069         "\"google:suggestrelevance\":[1],"
1070         "\"google:verbatimrelevance\":0}]",
1071       { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch },
1072       std::string() },
1073     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1074        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1075         "\"google:suggestrelevance\":[1, 2],"
1076         "\"google:verbatimrelevance\":0}]",
1077       { { "a", true }, { "a2.com", true }, { "a1.com", true }, kEmptyMatch },
1078       std::string() },
1079
1080     // Ensure that all suggestions are considered, regardless of order.
1081     { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1082        "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1083       { { "a", true }, { "h", false }, { "g", false }, { "f", false } },
1084       std::string() },
1085     { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1086               "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1087               "\"http://h.com\"],[],[],"
1088        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1089                                 "\"NAVIGATION\", \"NAVIGATION\","
1090                                 "\"NAVIGATION\", \"NAVIGATION\","
1091                                 "\"NAVIGATION\"],"
1092         "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1093       { { "a", true }, { "h.com", false }, { "g.com", false },
1094         { "f.com", false } },
1095       std::string() },
1096
1097     // Ensure that incorrectly sized suggestion relevance lists are ignored.
1098     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1099       { { "a", true }, { "a1", true }, { "a2", true }, kEmptyMatch },
1100       std::string() },
1101     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1102       { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
1103       std::string() },
1104     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1105        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1106         "\"google:suggestrelevance\":[1]}]",
1107       { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch },
1108       std::string() },
1109     { "[\"a\",[\"http://a1.com\"],[],[],"
1110        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1111        "\"google:suggestrelevance\":[9999, 1]}]",
1112       { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch },
1113       std::string() },
1114
1115     // Ensure that all 'verbatim' results are merged with their maximum score.
1116     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1117        "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1118       { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch },
1119       "2" },
1120     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1121        "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1122         "\"google:verbatimrelevance\":0}]",
1123       { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch },
1124       "2" },
1125
1126     // Ensure that verbatim is always generated without other suggestions.
1127     // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
1128     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1129       { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1130       std::string() },
1131     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1132       { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1133       std::string() },
1134   };
1135
1136   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1137     QueryForInput(ASCIIToUTF16("a"), false, false);
1138     net::TestURLFetcher* fetcher =
1139         test_factory_.GetFetcherByID(
1140             SearchProvider::kDefaultProviderURLFetcherID);
1141     ASSERT_TRUE(fetcher);
1142     fetcher->set_response_code(200);
1143     fetcher->SetResponseString(cases[i].json);
1144     fetcher->delegate()->OnURLFetchComplete(fetcher);
1145     RunTillProviderDone();
1146
1147     const std::string description = "for input with json=" + cases[i].json;
1148     const ACMatches& matches = provider_->matches();
1149     // The top match must inline and score as highly as calculated verbatim.
1150     ASSERT_FALSE(matches.empty());
1151     EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
1152               matches[0].inline_autocompletion) << description;
1153     EXPECT_GE(matches[0].relevance, 1300) << description;
1154
1155     size_t j = 0;
1156     // Ensure that the returned matches equal the expectations.
1157     for (; j < matches.size(); ++j) {
1158       EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents),
1159                 matches[j].contents) << description;
1160       EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match,
1161                 matches[j].allowed_to_be_default_match) << description;
1162     }
1163     // Ensure that no expected matches are missing.
1164     for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1165       EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) <<
1166           "Case # " << i << " " << description;
1167   }
1168 }
1169
1170 // This test is like DefaultFetcherSuggestRelevance above except it enables
1171 // the field trial that causes the omnibox to be willing to reorder matches
1172 // to guarantee the top result is a legal default match.  This field trial
1173 // causes SearchProvider to allow some constraints to be violated that it
1174 // wouldn't normally because the omnibox will fix the problems later.
1175 TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevanceWithReorder) {
1176   struct DefaultFetcherMatch {
1177     std::string contents;
1178     bool allowed_to_be_default_match;
1179   };
1180   const DefaultFetcherMatch kEmptyMatch = { kNotApplicable, false };
1181   struct {
1182     const std::string json;
1183     const DefaultFetcherMatch matches[4];
1184     const std::string inline_autocompletion;
1185   } cases[] = {
1186     // Ensure that suggestrelevance scores reorder matches.
1187     { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1188       { { "a", true }, { "c", false }, { "b", false }, kEmptyMatch },
1189       std::string() },
1190     { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1191        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1192         "\"google:suggestrelevance\":[1, 2]}]",
1193       { { "a", true }, { "c.com", false }, { "b.com", false }, kEmptyMatch },
1194       std::string() },
1195
1196     // Without suggested relevance scores, we should only allow one
1197     // navsuggest result to be be displayed.
1198     { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1199        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1200       { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch },
1201       std::string() },
1202
1203     // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1204     // Negative values will have no effect; the calculated value will be used.
1205     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1206                              "\"google:suggestrelevance\":[9998]}]",
1207       { { "a", true}, { "a1", true }, kEmptyMatch, kEmptyMatch },
1208       std::string() },
1209     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1210                              "\"google:suggestrelevance\":[9999]}]",
1211       { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
1212       "1" },
1213     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1214                              "\"google:suggestrelevance\":[9999]}]",
1215       { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1216       "1" },
1217     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1218                              "\"google:suggestrelevance\":[9999]}]",
1219       { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
1220       "1" },
1221     { "[\"a\",[\"http://a.com\"],[],[],"
1222        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1223         "\"google:verbatimrelevance\":9999,"
1224         "\"google:suggestrelevance\":[9998]}]",
1225       { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch },
1226       std::string() },
1227     { "[\"a\",[\"http://a.com\"],[],[],"
1228        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1229         "\"google:verbatimrelevance\":9998,"
1230         "\"google:suggestrelevance\":[9999]}]",
1231       { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
1232       ".com" },
1233     { "[\"a\",[\"http://a.com\"],[],[],"
1234        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1235         "\"google:verbatimrelevance\":0,"
1236         "\"google:suggestrelevance\":[9999]}]",
1237       { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1238       ".com" },
1239     { "[\"a\",[\"http://a.com\"],[],[],"
1240        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1241         "\"google:verbatimrelevance\":-1,"
1242         "\"google:suggestrelevance\":[9999]}]",
1243       { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
1244       ".com" },
1245
1246     // Ensure that both types of relevance scores reorder matches together.
1247     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1248                                      "\"google:verbatimrelevance\":9998}]",
1249       { { "a1", true }, { "a", true }, { "a2", true }, kEmptyMatch },
1250       "1" },
1251
1252     // Allow non-inlineable matches to be the highest-scoring match but,
1253     // if the result set lacks a single inlineable result, abandon suggested
1254     // relevance scores entirely.
1255     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1256       { { "b", false }, { "a", true }, kEmptyMatch, kEmptyMatch },
1257       std::string() },
1258     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1259                             "\"google:verbatimrelevance\":0}]",
1260       { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch },
1261       std::string() },
1262     { "[\"a\",[\"http://b.com\"],[],[],"
1263        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1264         "\"google:suggestrelevance\":[9999]}]",
1265       { { "b.com", false }, { "a", true }, kEmptyMatch, kEmptyMatch },
1266       std::string() },
1267     { "[\"a\",[\"http://b.com\"],[],[],"
1268        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1269         "\"google:suggestrelevance\":[9999],"
1270         "\"google:verbatimrelevance\":0}]",
1271       { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch },
1272       std::string() },
1273
1274     // Allow low-scoring matches.
1275     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1276       { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1277       "1" },
1278     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1279       { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
1280       "1" },
1281     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1282                              "\"google:verbatimrelevance\":0}]",
1283       { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1284       "1" },
1285     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1286                                      "\"google:verbatimrelevance\":0}]",
1287       { { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
1288       "2" },
1289     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1290       "\"google:verbatimrelevance\":2}]",
1291       { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch },
1292       "2" },
1293     { "[\"a\",[\"http://a.com\"],[],[],"
1294        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1295         "\"google:suggestrelevance\":[1],"
1296         "\"google:verbatimrelevance\":0}]",
1297       { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1298       ".com" },
1299     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1300        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1301         "\"google:suggestrelevance\":[1, 2],"
1302         "\"google:verbatimrelevance\":0}]",
1303       { { "a2.com", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch },
1304       "2.com" },
1305
1306     // Ensure that all suggestions are considered, regardless of order.
1307     { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1308        "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1309       { { "a", true }, { "h", false }, { "g", false }, { "f", false } },
1310       std::string() },
1311     { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1312               "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1313               "\"http://h.com\"],[],[],"
1314        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1315                                 "\"NAVIGATION\", \"NAVIGATION\","
1316                                 "\"NAVIGATION\", \"NAVIGATION\","
1317                                 "\"NAVIGATION\"],"
1318         "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1319       { { "a", true }, { "h.com", false }, { "g.com", false },
1320         { "f.com", false } },
1321       std::string() },
1322
1323     // Ensure that incorrectly sized suggestion relevance lists are ignored.
1324     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1325       { { "a", true }, { "a1", true }, { "a2", true }, kEmptyMatch },
1326       std::string() },
1327     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1328       { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
1329       std::string() },
1330     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1331        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1332         "\"google:suggestrelevance\":[1]}]",
1333       { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch },
1334       std::string() },
1335     { "[\"a\",[\"http://a1.com\"],[],[],"
1336        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1337        "\"google:suggestrelevance\":[9999, 1]}]",
1338       { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch },
1339       std::string() },
1340
1341     // Ensure that all 'verbatim' results are merged with their maximum score.
1342     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1343        "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1344       { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch },
1345       "2" },
1346     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1347        "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1348         "\"google:verbatimrelevance\":0}]",
1349       { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch },
1350       "2" },
1351
1352     // Ensure that verbatim is always generated without other suggestions.
1353     // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
1354     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1355       { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1356       std::string() },
1357     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1358       { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1359       std::string() },
1360   };
1361
1362   std::map<std::string, std::string> params;
1363   params[std::string(OmniboxFieldTrial::kReorderForLegalDefaultMatchRule) +
1364          ":*:*"] = OmniboxFieldTrial::kReorderForLegalDefaultMatchRuleEnabled;
1365   ASSERT_TRUE(chrome_variations::AssociateVariationParams(
1366       OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
1367   base::FieldTrialList::CreateFieldTrial(
1368       OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
1369
1370   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1371     QueryForInput(ASCIIToUTF16("a"), false, false);
1372     net::TestURLFetcher* fetcher =
1373         test_factory_.GetFetcherByID(
1374             SearchProvider::kDefaultProviderURLFetcherID);
1375     ASSERT_TRUE(fetcher);
1376     fetcher->set_response_code(200);
1377     fetcher->SetResponseString(cases[i].json);
1378     fetcher->delegate()->OnURLFetchComplete(fetcher);
1379     RunTillProviderDone();
1380
1381     const std::string description = "for input with json=" + cases[i].json;
1382     const ACMatches& matches = provider_->matches();
1383     // The top match must inline and score as highly as calculated verbatim.
1384     ASSERT_FALSE(matches.empty());
1385     EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
1386               matches[0].inline_autocompletion) << description;
1387
1388     size_t j = 0;
1389     // Ensure that the returned matches equal the expectations.
1390     for (; j < matches.size(); ++j) {
1391       EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents),
1392                 matches[j].contents) << description;
1393       EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match,
1394                 matches[j].allowed_to_be_default_match) << description;
1395     }
1396     // Ensure that no expected matches are missing.
1397     for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1398       EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) <<
1399           "Case # " << i << " " << description;
1400   }
1401 }
1402
1403 // Verifies that suggest results with relevance scores are added
1404 // properly when using the keyword fetcher.  This is similar to the
1405 // test DefaultFetcherSuggestRelevance above but this uses inputs that
1406 // trigger keyword suggestions (i.e., "k a" rather than "a") and has
1407 // different expectations (because now the results are a mix of
1408 // keyword suggestions and default provider suggestions).  When a new
1409 // test is added to this TEST_F, please consider if it would be
1410 // appropriate to add to DefaultFetcherSuggestRelevance as well.
1411 TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
1412   struct KeywordFetcherMatch {
1413     std::string contents;
1414     bool from_keyword;
1415     bool allowed_to_be_default_match;
1416   };
1417   const KeywordFetcherMatch kEmptyMatch = { kNotApplicable, false, false };
1418   struct {
1419     const std::string json;
1420     const KeywordFetcherMatch matches[5];
1421     const std::string inline_autocompletion;
1422   } cases[] = {
1423     // Ensure that suggest relevance scores reorder matches and that
1424     // the keyword verbatim (lacking a suggested verbatim score) beats
1425     // the default provider verbatim.
1426     { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1427       { { "a",   true,  true },
1428         { "k a", false, true },
1429         { "c",   true,  false },
1430         { "b",   true,  false },
1431         kEmptyMatch },
1432       std::string() },
1433     // Again, check that relevance scores reorder matches, just this
1434     // time with navigation matches.  This also checks that with
1435     // suggested relevance scores we allow multiple navsuggest results.
1436     // It's odd that navsuggest results that come from a keyword
1437     // provider are marked as not a keyword result.  I think this
1438     // comes from them not going to a keyword search engine).
1439     // TODO(mpearson): Investigate the implications (if any) of
1440     // tagging these results appropriately.  If so, do it because it
1441     // makes more sense.
1442     { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
1443        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1444        "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
1445       { { "a",     true,  true },
1446         { "d",     true,  false },
1447         { "c.com", false, false },
1448         { "b.com", false, false },
1449         { "k a",   false, true }, },
1450       std::string() },
1451
1452     // Without suggested relevance scores, we should only allow one
1453     // navsuggest result to be be displayed.
1454     { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1455        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1456       { { "a",     true,  true },
1457         { "b.com", false, false },
1458         { "k a",   false, true },
1459         kEmptyMatch, kEmptyMatch },
1460       std::string() },
1461
1462     // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1463     // Negative values will have no effect; the calculated value will be used.
1464     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1465                              "\"google:suggestrelevance\":[9998]}]",
1466       { { "a",   true,  true },
1467         { "a1",  true,  true },
1468         { "k a", false, true },
1469         kEmptyMatch, kEmptyMatch },
1470       std::string() },
1471     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1472                              "\"google:suggestrelevance\":[9999]}]",
1473       { { "a1",  true,  true },
1474         { "a",   true,  true },
1475         { "k a", false, true },
1476         kEmptyMatch, kEmptyMatch },
1477       "1" },
1478     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1479                              "\"google:suggestrelevance\":[9999]}]",
1480       { { "a1",  true,  true },
1481         { "k a", false, true },
1482         kEmptyMatch, kEmptyMatch, kEmptyMatch },
1483       "1" },
1484     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1485                              "\"google:suggestrelevance\":[9999]}]",
1486       { { "a1",  true,  true },
1487         { "a",   true,  true },
1488         { "k a", false, true },
1489         kEmptyMatch, kEmptyMatch },
1490       "1" },
1491     { "[\"a\",[\"http://a.com\"],[],[],"
1492        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1493         "\"google:verbatimrelevance\":9999,"
1494         "\"google:suggestrelevance\":[9998]}]",
1495       { { "a",     true,  true },
1496         { "a.com", false, true },
1497         { "k a",   false, true },
1498         kEmptyMatch, kEmptyMatch },
1499       std::string() },
1500
1501     // Ensure that both types of relevance scores reorder matches together.
1502     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1503                                      "\"google:verbatimrelevance\":9998}]",
1504       { { "a1",  true,  true },
1505         { "a",   true,  true },
1506         { "a2",  true,  true },
1507         { "k a", false, true },
1508         kEmptyMatch },
1509       "1" },
1510
1511     // Ensure that only inlinable matches may be ranked as the highest result.
1512     // Ignore all suggested relevance scores if this constraint is violated.
1513     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1514       { { "a",   true,  true },
1515         { "b",   true,  false },
1516         { "k a", false, true },
1517         kEmptyMatch, kEmptyMatch },
1518       std::string() },
1519     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1520                             "\"google:verbatimrelevance\":0}]",
1521       { { "a",   true,  true },
1522         { "b",   true,  false },
1523         { "k a", false, true },
1524         kEmptyMatch, kEmptyMatch },
1525       std::string() },
1526     { "[\"a\",[\"http://b.com\"],[],[],"
1527        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1528         "\"google:suggestrelevance\":[9999]}]",
1529       { { "a",     true,  true },
1530         { "b.com", false, false },
1531         { "k a",   false, true },
1532         kEmptyMatch, kEmptyMatch },
1533       std::string() },
1534     { "[\"a\",[\"http://b.com\"],[],[],"
1535        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1536         "\"google:suggestrelevance\":[9999],"
1537         "\"google:verbatimrelevance\":0}]",
1538       { { "a",     true,  true },
1539         { "b.com", false, false },
1540         { "k a",   false, true },
1541         kEmptyMatch, kEmptyMatch },
1542       std::string() },
1543
1544     // Ensure that the top result is ranked as highly as calculated verbatim.
1545     // Ignore the suggested verbatim relevance if this constraint is violated.
1546     // Note that keyword suggestions by default (not in suggested relevance
1547     // mode) score more highly than the default verbatim.
1548     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1549       { { "a",   true,  true },
1550         { "a1",  true,  true },
1551         { "k a", false, true },
1552         kEmptyMatch, kEmptyMatch },
1553       std::string() },
1554     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1555       { { "a",   true,  true },
1556         { "a1",  true,  true },
1557         { "k a", false, true },
1558         kEmptyMatch, kEmptyMatch},
1559       std::string() },
1560     // Continuing the same category of tests, but make sure we keep the
1561     // suggested relevance scores even as we discard the verbatim relevance
1562     // scores.
1563     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1564                              "\"google:verbatimrelevance\":0}]",
1565       { { "a",   true,  true },
1566         { "k a", false, true },
1567         { "a1",   true, true },
1568         kEmptyMatch, kEmptyMatch},
1569       std::string() },
1570     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1571                                      "\"google:verbatimrelevance\":0}]",
1572       { { "a",   true,  true },
1573         { "k a", false, true },
1574         { "a2",  true,  true },
1575         { "a1",  true,  true },
1576         kEmptyMatch },
1577       std::string() },
1578     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1579       "\"google:verbatimrelevance\":2}]",
1580       { { "a",   true,  true },
1581         { "k a", false, true },
1582         { "a2",  true,  true },
1583         { "a1",  true,  true },
1584         kEmptyMatch },
1585       std::string() },
1586
1587     // Ensure that all suggestions are considered, regardless of order.
1588     { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1589        "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1590       { { "a",   true,  true },
1591         { "k a", false, true },
1592         { "h",   true,  false },
1593         { "g",   true,  false },
1594         { "f",   true,  false } },
1595       std::string() },
1596     { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1597               "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1598               "\"http://h.com\"],[],[],"
1599        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1600                                 "\"NAVIGATION\", \"NAVIGATION\","
1601                                 "\"NAVIGATION\", \"NAVIGATION\","
1602                                 "\"NAVIGATION\"],"
1603         "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1604       { { "a",     true,  true },
1605         { "k a",   false, true },
1606         { "h.com", false, false },
1607         { "g.com", false, false },
1608         { "f.com", false, false } },
1609       std::string() },
1610
1611     // Ensure that incorrectly sized suggestion relevance lists are ignored.
1612     // Note that keyword suggestions by default (not in suggested relevance
1613     // mode) score more highly than the default verbatim.
1614     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1615       { { "a",   true,  true },
1616         { "a1",  true,  true },
1617         { "a2",  true,  true },
1618         { "k a", false, true },
1619         kEmptyMatch },
1620       std::string() },
1621     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1622       { { "a",   true,  true },
1623         { "a1",  true,  true },
1624         { "k a", false, true },
1625         kEmptyMatch, kEmptyMatch},
1626       std::string() },
1627     // In this case, ignored the suggested relevance scores means we keep
1628     // only one navsuggest result.
1629     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1630        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1631         "\"google:suggestrelevance\":[1]}]",
1632       { { "a",      true,  true },
1633         { "a1.com", false, true },
1634         { "k a",    false, true },
1635         kEmptyMatch, kEmptyMatch},
1636       std::string() },
1637     { "[\"a\",[\"http://a1.com\"],[],[],"
1638        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1639        "\"google:suggestrelevance\":[9999, 1]}]",
1640       { { "a",      true,  true },
1641         { "a1.com", false, true },
1642         { "k a",    false, true },
1643         kEmptyMatch, kEmptyMatch},
1644       std::string() },
1645
1646     // Ensure that all 'verbatim' results are merged with their maximum score.
1647     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1648        "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1649       { { "a2",  true,  true },
1650         { "a",   true,  true },
1651         { "a1",  true,  true },
1652         { "k a", false, true },
1653         kEmptyMatch },
1654       "2" },
1655     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1656        "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1657         "\"google:verbatimrelevance\":0}]",
1658       { { "a2",  true,  true },
1659         { "a",   true,  true },
1660         { "a1",  true,  true },
1661         { "k a", false, true },
1662         kEmptyMatch },
1663       "2" },
1664
1665     // Ensure that verbatim is always generated without other suggestions.
1666     // TODO(mpearson): Ensure the value of verbatimrelevance is respected
1667     // (except when suggested relevances are ignored).
1668     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1669       { { "a",   true,  true },
1670         { "k a", false, true },
1671         kEmptyMatch, kEmptyMatch, kEmptyMatch},
1672       std::string() },
1673     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1674       { { "a",   true,  true },
1675         { "k a", false, true },
1676         kEmptyMatch, kEmptyMatch, kEmptyMatch},
1677       std::string() },
1678
1679     // Check that navsuggestions will be demoted below queries.
1680     // (Navsuggestions are not allowed to appear first.)  In the process,
1681     // make sure the navsuggestions still remain in the same order.
1682     // First, check the situation where navsuggest scores more than verbatim
1683     // and there are no query suggestions.
1684     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1685        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1686         "\"google:verbatimrelevance\":9990,"
1687         "\"google:suggestrelevance\":[9998, 9999]}]",
1688       { { "a",      true,  true },
1689         { "a2.com", false, true },
1690         { "a1.com", false, true },
1691         { "k a",    false, true },
1692         kEmptyMatch },
1693       std::string() },
1694     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1695        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1696         "\"google:verbatimrelevance\":9990,"
1697         "\"google:suggestrelevance\":[9999, 9998]}]",
1698       { { "a",      true,  true },
1699         { "a1.com", false, true },
1700         { "a2.com", false, true },
1701         { "k a",    false, true },
1702         kEmptyMatch },
1703       std::string() },
1704     { "[\"a\",[\"https://a/\"],[],[],"
1705        "{\"google:suggesttype\":[\"NAVIGATION\"],"
1706         "\"google:suggestrelevance\":[9999]}]",
1707       { { "a",         true, true },
1708         { "https://a", false, true },
1709         { "k a",       false, true },
1710         kEmptyMatch,
1711         kEmptyMatch },
1712       std::string() },
1713     // Check when navsuggest scores more than verbatim and there is query
1714     // suggestion but it scores lower.
1715     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1716        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1717         "\"google:verbatimrelevance\":9990,"
1718         "\"google:suggestrelevance\":[9998, 9999, 1300]}]",
1719       { { "a",      true,  true },
1720         { "a2.com", false, true },
1721         { "a1.com", false, true },
1722         { "a3",     true,  true },
1723         { "k a",    false, true } },
1724       std::string() },
1725     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1726        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1727         "\"google:verbatimrelevance\":9990,"
1728         "\"google:suggestrelevance\":[9999, 9998, 1300]}]",
1729       { { "a",      true,  true },
1730         { "a1.com", false, true },
1731         { "a2.com", false, true },
1732         { "a3",     true,  true },
1733         { "k a",    false, true } },
1734       std::string() },
1735     // Check when navsuggest scores more than a query suggestion.  There is
1736     // a verbatim but it scores lower.
1737     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1738        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1739         "\"google:verbatimrelevance\":9990,"
1740         "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1741       { { "a3",     true,  true },
1742         { "a2.com", false, true },
1743         { "a1.com", false, true },
1744         { "a",      true,  true },
1745         { "k a",    false, true } },
1746       "3" },
1747     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1748        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1749         "\"google:verbatimrelevance\":9990,"
1750         "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1751       { { "a3",     true,  true },
1752         { "a1.com", false, true },
1753         { "a2.com", false, true },
1754         { "a",      true,  true },
1755         { "k a",    false, true } },
1756       "3" },
1757     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1758        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1759         "\"google:verbatimrelevance\":0,"
1760         "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1761       { { "a3",     true,  true },
1762         { "a2.com", false, true },
1763         { "a1.com", false, true },
1764         { "k a",    false, true },
1765         kEmptyMatch },
1766       "3" },
1767     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1768        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1769         "\"google:verbatimrelevance\":0,"
1770         "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1771       { { "a3",     true,  true },
1772         { "a1.com", false, true },
1773         { "a2.com", false, true },
1774         { "k a",    false, true },
1775         kEmptyMatch },
1776       "3" },
1777     // Check when there is neither verbatim nor a query suggestion that,
1778     // because we can't demote navsuggestions below a query suggestion,
1779     // we abandon suggested relevance scores entirely.  One consequence is
1780     // that this means we restore the keyword verbatim match.  Note
1781     // that in this case of abandoning suggested relevance scores, we still
1782     // keep the navsuggestions in the same order, but we revert to only allowing
1783     // one navigation to appear because the scores are completely local.
1784     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1785        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1786         "\"google:verbatimrelevance\":0,"
1787         "\"google:suggestrelevance\":[9998, 9999]}]",
1788       { { "a",      true,  true },
1789         { "a2.com", false, true },
1790         { "k a",    false, true },
1791         kEmptyMatch, kEmptyMatch},
1792       std::string() },
1793     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1794        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1795         "\"google:verbatimrelevance\":0,"
1796         "\"google:suggestrelevance\":[9999, 9998]}]",
1797       { { "a",      true,  true },
1798         { "a1.com", false, true },
1799         { "k a",    false, true },
1800         kEmptyMatch, kEmptyMatch},
1801       std::string() },
1802     // More checks that everything works when it's not necessary to demote.
1803     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1804        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1805         "\"google:verbatimrelevance\":9990,"
1806         "\"google:suggestrelevance\":[9997, 9998, 9999]}]",
1807       { { "a3",     true,  true },
1808         { "a2.com", false, true },
1809         { "a1.com", false, true },
1810         { "a",      true,  true },
1811         { "k a",    false, true } },
1812       "3" },
1813     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1814        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1815         "\"google:verbatimrelevance\":9990,"
1816         "\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1817       { { "a3",     true,  true },
1818         { "a1.com", false, true },
1819         { "a2.com", false, true },
1820         { "a",      true,  true },
1821         { "k a",    false, true } },
1822       "3" },
1823   };
1824
1825   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1826     QueryForInput(ASCIIToUTF16("k a"), false, true);
1827
1828     // Set up a default fetcher with no results.
1829     net::TestURLFetcher* default_fetcher =
1830         test_factory_.GetFetcherByID(
1831             SearchProvider::kDefaultProviderURLFetcherID);
1832     ASSERT_TRUE(default_fetcher);
1833     default_fetcher->set_response_code(200);
1834     default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
1835     default_fetcher = NULL;
1836
1837     // Set up a keyword fetcher with provided results.
1838     net::TestURLFetcher* keyword_fetcher =
1839         test_factory_.GetFetcherByID(
1840             SearchProvider::kKeywordProviderURLFetcherID);
1841     ASSERT_TRUE(keyword_fetcher);
1842     keyword_fetcher->set_response_code(200);
1843     keyword_fetcher->SetResponseString(cases[i].json);
1844     keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
1845     keyword_fetcher = NULL;
1846     RunTillProviderDone();
1847
1848     const std::string description = "for input with json=" + cases[i].json;
1849     const ACMatches& matches = provider_->matches();
1850     // The top match must inline and score as highly as calculated verbatim.
1851     ASSERT_FALSE(matches.empty());
1852     EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
1853               matches[0].inline_autocompletion) << description;
1854     EXPECT_GE(matches[0].relevance, 1300) << description;
1855
1856     size_t j = 0;
1857     // Ensure that the returned matches equal the expectations.
1858     for (; j < matches.size(); ++j) {
1859       EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents),
1860                 matches[j].contents) << description;
1861       EXPECT_EQ(cases[i].matches[j].from_keyword,
1862                 matches[j].keyword == ASCIIToUTF16("k")) << description;
1863       EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match,
1864                 matches[j].allowed_to_be_default_match) << description;
1865     }
1866     // Ensure that no expected matches are missing.
1867     for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1868       EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) <<
1869           "Case # " << i << " " << description;
1870   }
1871 }
1872
1873 TEST_F(SearchProviderTest, LocalAndRemoteRelevances) {
1874   // Enable Instant Extended in order to allow an increased number of
1875   // suggestions.
1876   chrome::EnableInstantExtendedAPIForTesting();
1877
1878   // We hardcode the string "term1" below, so ensure that the search term that
1879   // got added to history already is that string.
1880   ASSERT_EQ(ASCIIToUTF16("term1"), term1_);
1881   string16 term = term1_.substr(0, term1_.length() - 1);
1882
1883   AddSearchToHistory(default_t_url_, term + ASCIIToUTF16("2"), 2);
1884   profile_.BlockUntilHistoryProcessesPendingRequests();
1885
1886   struct {
1887     const string16 input;
1888     const std::string json;
1889     const std::string matches[6];
1890   } cases[] = {
1891     // The history results outscore the default verbatim score.  term2 has more
1892     // visits so it outscores term1.  The suggestions are still returned since
1893     // they're server-scored.
1894     { term,
1895       "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
1896        "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
1897         "\"google:suggestrelevance\":[1, 2, 3]}]",
1898       { "term2", "term1", "term", "a3", "a2", "a1" } },
1899     // Because we already have three suggestions by the time we see the history
1900     // results, they don't get returned.
1901     { term,
1902       "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
1903        "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
1904         "\"google:verbatimrelevance\":1450,"
1905         "\"google:suggestrelevance\":[1440, 1430, 1420]}]",
1906       { "term", "a1", "a2", "a3", kNotApplicable, kNotApplicable } },
1907     // If we only have two suggestions, we have room for a history result.
1908     { term,
1909       "[\"term\",[\"a1\", \"a2\"],[],[],"
1910        "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
1911         "\"google:verbatimrelevance\":1450,"
1912         "\"google:suggestrelevance\":[1430, 1410]}]",
1913       { "term", "a1", "a2", "term2", kNotApplicable, kNotApplicable } },
1914     // If we have more than three suggestions, they should all be returned as
1915     // long as we have enough total space for them.
1916     { term,
1917       "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
1918        "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
1919         "\"google:verbatimrelevance\":1450,"
1920         "\"google:suggestrelevance\":[1440, 1430, 1420, 1410]}]",
1921       { "term", "a1", "a2", "a3", "a4", kNotApplicable } },
1922     { term,
1923       "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\", \"a5\", \"a6\"],[],[],"
1924        "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\","
1925                                 "\"QUERY\", \"QUERY\"],"
1926         "\"google:verbatimrelevance\":1450,"
1927         "\"google:suggestrelevance\":[1440, 1430, 1420, 1410, 1400, 1390]}]",
1928       { "term", "a1", "a2", "a3", "a4", "a5" } },
1929     { term,
1930       "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
1931        "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
1932         "\"google:verbatimrelevance\":1450,"
1933         "\"google:suggestrelevance\":[1430, 1410, 1390, 1370]}]",
1934       { "term", "a1", "a2", "term2", "a3", "a4" } },
1935     // When the input looks like a URL, we disallow having a query as the
1936     // highest-ranking result.  If the query was provided by a suggestion, we
1937     // reset the suggest scores to enforce this (see
1938     // SearchProvider::UpdateMatches()).  Even if we reset the suggest scores,
1939     // however, we should still allow navsuggestions to be treated as
1940     // server-provided.
1941     { ASCIIToUTF16("a.com"),
1942       "[\"a.com\",[\"a1\", \"a2\", \"a.com/1\", \"a.com/2\"],[],[],"
1943        "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"NAVIGATION\","
1944                                 "\"NAVIGATION\"],"
1945         // A verbatim query for URL-like input scores 850, so the navigation
1946         // scores here should bracket it.
1947         "\"google:suggestrelevance\":[9999, 9998, 900, 800]}]",
1948       { "a.com/1", "a.com", "a.com/2", "a1", kNotApplicable, kNotApplicable } },
1949   };
1950
1951   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1952     QueryForInput(cases[i].input, false, false);
1953     net::TestURLFetcher* fetcher =
1954         test_factory_.GetFetcherByID(
1955             SearchProvider::kDefaultProviderURLFetcherID);
1956     ASSERT_TRUE(fetcher);
1957     fetcher->set_response_code(200);
1958     fetcher->SetResponseString(cases[i].json);
1959     fetcher->delegate()->OnURLFetchComplete(fetcher);
1960     RunTillProviderDone();
1961
1962     const std::string description = "for input with json=" + cases[i].json;
1963     const ACMatches& matches = provider_->matches();
1964
1965     // Ensure no extra matches are present.
1966     ASSERT_LE(matches.size(), 6U);
1967
1968     size_t j = 0;
1969     // Ensure that the returned matches equal the expectations.
1970     for (; j < matches.size(); ++j)
1971       EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]),
1972                 matches[j].contents) << description;
1973     // Ensure that no expected matches are missing.
1974     for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1975       EXPECT_EQ(kNotApplicable, cases[i].matches[j]) <<
1976           "Case # " << i << " " << description;
1977   }
1978 }
1979
1980 // Verifies suggest relevance behavior for URL input.
1981 TEST_F(SearchProviderTest, DefaultProviderSuggestRelevanceScoringUrlInput) {
1982   struct DefaultFetcherUrlInputMatch {
1983     const std::string match_contents;
1984     AutocompleteMatch::Type match_type;
1985     bool allowed_to_be_default_match;
1986   };
1987   const DefaultFetcherUrlInputMatch kEmptyMatch =
1988       { kNotApplicable, AutocompleteMatchType::NUM_TYPES, false };
1989   struct {
1990     const std::string input;
1991     const std::string json;
1992     const DefaultFetcherUrlInputMatch output[4];
1993   } cases[] = {
1994     // Ensure topmost NAVIGATION matches are allowed for URL input.
1995     { "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[],"
1996                 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1997                  "\"google:suggestrelevance\":[9999]}]",
1998       { { "a.com/a", AutocompleteMatchType::NAVSUGGEST,            true },
1999         { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2000         kEmptyMatch, kEmptyMatch } },
2001     { "a.com", "[\"a.com\",[\"https://a.com\"],[],[],"
2002                 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2003                  "\"google:suggestrelevance\":[9999]}]",
2004       { { "https://a.com", AutocompleteMatchType::NAVSUGGEST,            true },
2005         { "a.com",         AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2006         kEmptyMatch, kEmptyMatch } },
2007
2008     // Ensure topmost SUGGEST matches are not allowed for URL input.
2009     // SearchProvider disregards search and verbatim suggested relevances.
2010     { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2011                 "{\"google:suggestrelevance\":[9999]}]",
2012       { { "a.com",      AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2013         { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST,        true },
2014         kEmptyMatch, kEmptyMatch } },
2015     { "a.com", "[\"a.com\",[\"a.com/a\"],[],[],"
2016                 "{\"google:suggestrelevance\":[9999]}]",
2017       { { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2018         { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST,        true },
2019         kEmptyMatch, kEmptyMatch } },
2020
2021     // Ensure the fallback mechanism allows inlinable NAVIGATION matches.
2022     { "a.com", "[\"a.com\",[\"a.com/a\", \"http://a.com/b\"],[],[],"
2023                 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2024                  "\"google:suggestrelevance\":[9999, 9998]}]",
2025       { { "a.com/b", AutocompleteMatchType::NAVSUGGEST,            true },
2026         { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2027         { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST,        true },
2028         kEmptyMatch } },
2029     { "a.com", "[\"a.com\",[\"a.com/a\", \"http://a.com/b\"],[],[],"
2030                 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2031                  "\"google:suggestrelevance\":[9998, 9997],"
2032                  "\"google:verbatimrelevance\":9999}]",
2033       { { "a.com/b", AutocompleteMatchType::NAVSUGGEST,            true },
2034         { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2035         { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST,        true },
2036         kEmptyMatch } },
2037
2038     // Ensure the fallback mechanism disallows non-inlinable NAVIGATION matches.
2039     { "a.com", "[\"a.com\",[\"a.com/a\", \"http://abc.com\"],[],[],"
2040                 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2041       "\"google:suggestrelevance\":[9999, 9998]}]",
2042       { { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2043         { "abc.com", AutocompleteMatchType::NAVSUGGEST,            false },
2044         { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST,        true },
2045         kEmptyMatch } },
2046     { "a.com", "[\"a.com\",[\"a.com/a\", \"http://abc.com\"],[],[],"
2047                 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2048                  "\"google:suggestrelevance\":[9998, 9997],"
2049                  "\"google:verbatimrelevance\":9999}]",
2050       { { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2051         { "abc.com", AutocompleteMatchType::NAVSUGGEST,            false },
2052         { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST,        true },
2053         kEmptyMatch } },
2054   };
2055
2056   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2057     QueryForInput(ASCIIToUTF16(cases[i].input), false, false);
2058     net::TestURLFetcher* fetcher =
2059         test_factory_.GetFetcherByID(
2060             SearchProvider::kDefaultProviderURLFetcherID);
2061     ASSERT_TRUE(fetcher);
2062     fetcher->set_response_code(200);
2063     fetcher->SetResponseString(cases[i].json);
2064     fetcher->delegate()->OnURLFetchComplete(fetcher);
2065     RunTillProviderDone();
2066
2067     size_t j = 0;
2068     const ACMatches& matches = provider_->matches();
2069     // Ensure that the returned matches equal the expectations.
2070     for (; j < matches.size(); ++j) {
2071       EXPECT_EQ(ASCIIToUTF16(cases[i].output[j].match_contents),
2072                 matches[j].contents);
2073       EXPECT_EQ(cases[i].output[j].match_type, matches[j].type);
2074       EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match,
2075                 matches[j].allowed_to_be_default_match);
2076     }
2077     // Ensure that no expected matches are missing.
2078     for (; j < ARRAYSIZE_UNSAFE(cases[i].output); ++j) {
2079       EXPECT_EQ(kNotApplicable, cases[i].output[j].match_contents);
2080       EXPECT_EQ(AutocompleteMatchType::NUM_TYPES,
2081                 cases[i].output[j].match_type);
2082       EXPECT_FALSE(cases[i].output[j].allowed_to_be_default_match);
2083     }
2084   }
2085 }
2086
2087 // A basic test that verifies the field trial triggered parsing logic.
2088 TEST_F(SearchProviderTest, FieldTrialTriggeredParsing) {
2089   QueryForInput(ASCIIToUTF16("foo"), false, false);
2090
2091   // Make sure the default providers suggest service was queried.
2092   net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
2093       SearchProvider::kDefaultProviderURLFetcherID);
2094   ASSERT_TRUE(fetcher);
2095
2096   // Tell the SearchProvider the suggest query is done.
2097   fetcher->set_response_code(200);
2098   fetcher->SetResponseString(
2099       "[\"foo\",[\"foo bar\"],[\"\"],[],"
2100       "{\"google:suggesttype\":[\"QUERY\"],"
2101       "\"google:fieldtrialtriggered\":true}]");
2102   fetcher->delegate()->OnURLFetchComplete(fetcher);
2103   fetcher = NULL;
2104
2105   // Run till the history results complete.
2106   RunTillProviderDone();
2107
2108   {
2109     // Check for the match and field trial triggered bits.
2110     AutocompleteMatch match;
2111     EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("foo bar"), &match));
2112     ProvidersInfo providers_info;
2113     provider_->AddProviderInfo(&providers_info);
2114     ASSERT_EQ(1U, providers_info.size());
2115     EXPECT_EQ(1, providers_info[0].field_trial_triggered_size());
2116     EXPECT_EQ(1, providers_info[0].field_trial_triggered_in_session_size());
2117   }
2118   {
2119     // Reset the session and check that bits are reset.
2120     provider_->ResetSession();
2121     ProvidersInfo providers_info;
2122     provider_->AddProviderInfo(&providers_info);
2123     ASSERT_EQ(1U, providers_info.size());
2124     EXPECT_EQ(1, providers_info[0].field_trial_triggered_size());
2125     EXPECT_EQ(0, providers_info[0].field_trial_triggered_in_session_size());
2126   }
2127 }
2128
2129 // Verifies inline autocompletion of navigational results.
2130 TEST_F(SearchProviderTest, NavigationInline) {
2131   struct {
2132     const std::string input;
2133     const std::string url;
2134     // Test the expected fill_into_edit, which may drop "http://".
2135     // Some cases do not trim "http://" to match from the start of the scheme.
2136     const std::string fill_into_edit;
2137     const std::string inline_autocompletion;
2138     const bool allowed_to_be_default_match;
2139   } cases[] = {
2140     // Do not inline matches that do not contain the input; trim http as needed.
2141     { "x",                    "http://www.abc.com",
2142                                      "www.abc.com",  std::string(), false },
2143     { "https:",               "http://www.abc.com",
2144                                      "www.abc.com",  std::string(), false },
2145     { "abc.com/",             "http://www.abc.com",
2146                                      "www.abc.com",  std::string(), false },
2147     { "http://www.abc.com/a", "http://www.abc.com",
2148                               "http://www.abc.com",  std::string(), false },
2149     { "http://www.abc.com",   "https://www.abc.com",
2150                               "https://www.abc.com", std::string(), false },
2151     { "http://abc.com",       "ftp://abc.com",
2152                               "ftp://abc.com",       std::string(), false },
2153     { "https://www.abc.com",  "http://www.abc.com",
2154                                      "www.abc.com",  std::string(), false },
2155     { "ftp://abc.com",        "http://abc.com",
2156                                      "abc.com",      std::string(), false },
2157
2158     // Do not inline matches with invalid input prefixes; trim http as needed.
2159     { "ttp",                  "http://www.abc.com",
2160                                      "www.abc.com", std::string(), false },
2161     { "://w",                 "http://www.abc.com",
2162                                      "www.abc.com", std::string(), false },
2163     { "ww.",                  "http://www.abc.com",
2164                                      "www.abc.com", std::string(), false },
2165     { ".ab",                  "http://www.abc.com",
2166                                      "www.abc.com", std::string(), false },
2167     { "bc",                   "http://www.abc.com",
2168                                      "www.abc.com", std::string(), false },
2169     { ".com",                 "http://www.abc.com",
2170                                      "www.abc.com", std::string(), false },
2171
2172     // Do not inline matches that omit input domain labels; trim http as needed.
2173     { "www.a",                "http://a.com",
2174                                      "a.com",       std::string(), false },
2175     { "http://www.a",         "http://a.com",
2176                               "http://a.com",       std::string(), false },
2177     { "www.a",                "ftp://a.com",
2178                               "ftp://a.com",        std::string(), false },
2179     { "ftp://www.a",          "ftp://a.com",
2180                               "ftp://a.com",        std::string(), false },
2181
2182     // Input matching but with nothing to inline will not yield an offset, but
2183     // will be allowed to be default.
2184     { "abc.com",              "http://www.abc.com",
2185                                      "www.abc.com", std::string(), true },
2186     { "http://www.abc.com",   "http://www.abc.com",
2187                               "http://www.abc.com", std::string(), true },
2188
2189     // Inline matches when the input is a leading substring of the scheme.
2190     { "h",                    "http://www.abc.com",
2191                               "http://www.abc.com", "ttp://www.abc.com", true },
2192     { "http",                 "http://www.abc.com",
2193                               "http://www.abc.com", "://www.abc.com",    true },
2194
2195     // Inline matches when the input is a leading substring of the full URL.
2196     { "http:",                "http://www.abc.com",
2197                               "http://www.abc.com", "//www.abc.com", true },
2198     { "http://w",             "http://www.abc.com",
2199                               "http://www.abc.com", "ww.abc.com",    true },
2200     { "http://www.",          "http://www.abc.com",
2201                               "http://www.abc.com", "abc.com",       true },
2202     { "http://www.ab",        "http://www.abc.com",
2203                               "http://www.abc.com", "c.com",         true },
2204     { "http://www.abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2205                               "http://www.abc.com/path/file.htm?q=x#foo",
2206                                                   "ath/file.htm?q=x#foo",
2207                               true },
2208     { "http://abc.com/p",     "http://abc.com/path/file.htm?q=x#foo",
2209                               "http://abc.com/path/file.htm?q=x#foo",
2210                                               "ath/file.htm?q=x#foo", true},
2211
2212     // Inline matches with valid URLPrefixes; only trim "http://".
2213     { "w",               "http://www.abc.com",
2214                                 "www.abc.com", "ww.abc.com", true },
2215     { "www.a",           "http://www.abc.com",
2216                                 "www.abc.com", "bc.com",     true },
2217     { "abc",             "http://www.abc.com",
2218                                 "www.abc.com", ".com",       true },
2219     { "abc.c",           "http://www.abc.com",
2220                                 "www.abc.com", "om",         true },
2221     { "abc.com/p",       "http://www.abc.com/path/file.htm?q=x#foo",
2222                                 "www.abc.com/path/file.htm?q=x#foo",
2223                                              "ath/file.htm?q=x#foo", true },
2224     { "abc.com/p",       "http://abc.com/path/file.htm?q=x#foo",
2225                                 "abc.com/path/file.htm?q=x#foo",
2226                                          "ath/file.htm?q=x#foo", true },
2227
2228     // Inline matches using the maximal URLPrefix components.
2229     { "h",               "http://help.com",
2230                                 "help.com", "elp.com",     true },
2231     { "http",            "http://http.com",
2232                                 "http.com", ".com",        true },
2233     { "h",               "http://www.help.com",
2234                                 "www.help.com", "elp.com", true },
2235     { "http",            "http://www.http.com",
2236                                 "www.http.com", ".com",    true },
2237     { "w",               "http://www.www.com",
2238                                 "www.www.com",  "ww.com",  true },
2239
2240     // Test similar behavior for the ftp and https schemes.
2241     { "ftp://www.ab",    "ftp://www.abc.com/path/file.htm?q=x#foo",
2242                          "ftp://www.abc.com/path/file.htm?q=x#foo",
2243                                      "c.com/path/file.htm?q=x#foo", true },
2244     { "www.ab",          "ftp://www.abc.com/path/file.htm?q=x#foo",
2245                          "ftp://www.abc.com/path/file.htm?q=x#foo",
2246                                      "c.com/path/file.htm?q=x#foo", true },
2247     { "ab",              "ftp://www.abc.com/path/file.htm?q=x#foo",
2248                          "ftp://www.abc.com/path/file.htm?q=x#foo",
2249                                      "c.com/path/file.htm?q=x#foo", true },
2250     { "ab",              "ftp://abc.com/path/file.htm?q=x#foo",
2251                          "ftp://abc.com/path/file.htm?q=x#foo",
2252                                  "c.com/path/file.htm?q=x#foo",     true },
2253     { "https://www.ab",  "https://www.abc.com/path/file.htm?q=x#foo",
2254                          "https://www.abc.com/path/file.htm?q=x#foo",
2255                                        "c.com/path/file.htm?q=x#foo", true },
2256     { "www.ab",          "https://www.abc.com/path/file.htm?q=x#foo",
2257                          "https://www.abc.com/path/file.htm?q=x#foo",
2258                                        "c.com/path/file.htm?q=x#foo", true },
2259     { "ab",              "https://www.abc.com/path/file.htm?q=x#foo",
2260                          "https://www.abc.com/path/file.htm?q=x#foo",
2261                                        "c.com/path/file.htm?q=x#foo", true },
2262     { "ab",              "https://abc.com/path/file.htm?q=x#foo",
2263                          "https://abc.com/path/file.htm?q=x#foo",
2264                                    "c.com/path/file.htm?q=x#foo", true },
2265
2266     // Forced query input should inline and retain the "?" prefix.
2267     { "?http://www.ab",  "http://www.abc.com",
2268                         "?http://www.abc.com", "c.com", true },
2269     { "?www.ab",         "http://www.abc.com",
2270                                "?www.abc.com", "c.com", true },
2271     { "?ab",             "http://www.abc.com",
2272                                "?www.abc.com", "c.com", true },
2273   };
2274
2275   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2276     QueryForInput(ASCIIToUTF16(cases[i].input), false, false);
2277     AutocompleteMatch match(
2278         provider_->NavigationToMatch(SearchProvider::NavigationResult(
2279             *provider_.get(), GURL(cases[i].url), string16(), false, 0,
2280             false)));
2281     EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
2282               match.inline_autocompletion);
2283     EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit), match.fill_into_edit);
2284     EXPECT_EQ(cases[i].allowed_to_be_default_match,
2285               match.allowed_to_be_default_match);
2286   }
2287 }
2288
2289 // Verifies that "http://" is not trimmed for input that is a leading substring.
2290 TEST_F(SearchProviderTest, NavigationInlineSchemeSubstring) {
2291   const string16 input(ASCIIToUTF16("ht"));
2292   const string16 url(ASCIIToUTF16("http://a.com"));
2293   const SearchProvider::NavigationResult result(
2294       *provider_.get(), GURL(url), string16(), false, 0, false);
2295
2296   // Check the offset and strings when inline autocompletion is allowed.
2297   QueryForInput(input, false, false);
2298   AutocompleteMatch match_inline(provider_->NavigationToMatch(result));
2299   EXPECT_EQ(url, match_inline.fill_into_edit);
2300   EXPECT_EQ(url.substr(2), match_inline.inline_autocompletion);
2301   EXPECT_TRUE(match_inline.allowed_to_be_default_match);
2302   EXPECT_EQ(url, match_inline.contents);
2303
2304   // Check the same offset and strings when inline autocompletion is prevented.
2305   QueryForInput(input, true, false);
2306   AutocompleteMatch match_prevent(provider_->NavigationToMatch(result));
2307   EXPECT_EQ(url, match_prevent.fill_into_edit);
2308   EXPECT_TRUE(match_prevent.inline_autocompletion.empty());
2309   EXPECT_FALSE(match_prevent.allowed_to_be_default_match);
2310   EXPECT_EQ(url, match_prevent.contents);
2311 }
2312
2313 // Verifies that input "w" marks a more significant domain label than "www.".
2314 TEST_F(SearchProviderTest, NavigationInlineDomainClassify) {
2315   QueryForInput(ASCIIToUTF16("w"), false, false);
2316   AutocompleteMatch match(
2317       provider_->NavigationToMatch(SearchProvider::NavigationResult(
2318           *provider_.get(), GURL("http://www.wow.com"), string16(), false, 0,
2319           false)));
2320   EXPECT_EQ(ASCIIToUTF16("ow.com"), match.inline_autocompletion);
2321   EXPECT_TRUE(match.allowed_to_be_default_match);
2322   EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.fill_into_edit);
2323   EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.contents);
2324
2325   // Ensure that the match for input "w" is marked on "wow" and not "www".
2326   ASSERT_EQ(3U, match.contents_class.size());
2327   EXPECT_EQ(0U, match.contents_class[0].offset);
2328   EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL,
2329             match.contents_class[0].style);
2330   EXPECT_EQ(4U, match.contents_class[1].offset);
2331   EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL |
2332             AutocompleteMatch::ACMatchClassification::MATCH,
2333             match.contents_class[1].style);
2334   EXPECT_EQ(5U, match.contents_class[2].offset);
2335   EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL,
2336             match.contents_class[2].style);
2337 }
2338
2339 TEST_F(SearchProviderTest, RemoveStaleResultsTest) {
2340   // TODO(mpearson): Consider expanding this test to explicitly cover
2341   // testing staleness for keyword results.
2342   struct {
2343     const std::string omnibox_input;
2344     const int verbatim_relevance;
2345     // These cached suggestions should already be sorted.
2346     // The particular number 5 as the length of the array is
2347     // unimportant; it's merely enough cached results to fully test
2348     // the functioning of RemoveAllStaleResults().
2349     struct {
2350       const std::string suggestion;
2351       const bool is_navigation_result;
2352       const int relevance;
2353       // |expect_match| is true if this result should survive
2354       // RemoveAllStaleResults() filtering against |omnibox_input| below.
2355       const bool expect_match;
2356     } results[5];
2357   } cases[] = {
2358     // Simple case: multiple query suggestions and no navsuggestions.
2359     // All query suggestions score less than search-what-you-typed and
2360     // thus none should be filtered because none will appear first.
2361     { "x", 1300,
2362       { { "food",         false, 1299, true  },
2363         { "foobar",       false, 1298, true  },
2364         { "crazy",        false, 1297, true  },
2365         { "friend",       false, 1296, true  },
2366         { kNotApplicable, false, 0,    false } } },
2367
2368     // Similarly simple cases, but the query suggestion appears first.
2369     { "f", 1200,
2370       { { "food",         false, 1299, true  },
2371         { "foobar",       false, 1298, true  },
2372         { "crazy",        false, 1297, true  },
2373         { "friend",       false, 1296, true  },
2374         { kNotApplicable, false, 0,    false } } },
2375     { "c", 1200,
2376       { { "food",         false, 1299, false },
2377         { "foobar",       false, 1298, false },
2378         { "crazy",        false, 1297, true  },
2379         { "friend",       false, 1296, true  },
2380         { kNotApplicable, false, 0,    false } } },
2381     { "x", 1200,
2382       { { "food",         false, 1299, false },
2383         { "foobar",       false, 1298, false },
2384         { "crazy",        false, 1297, false },
2385         { "friend",       false, 1296, false },
2386         { kNotApplicable, false, 0,    false } } },
2387
2388     // The same sort of cases, just using a mix of queries and navsuggestions.
2389     { "x", 1300,
2390       { { "http://food.com/",   true,  1299, true },
2391         { "foobar",             false, 1298, true },
2392         { "http://crazy.com/",  true,  1297, true },
2393         { "friend",             false, 1296, true },
2394         { "http://friend.com/", true,  1295, true } } },
2395     { "f", 1200,
2396       { { "http://food.com/",   true,  1299, true },
2397         { "foobar",             false, 1298, true },
2398         { "http://crazy.com/",  true,  1297, true },
2399         { "friend",             false, 1296, true },
2400         { "http://friend.com/", true,  1295, true } } },
2401     { "c", 1200,
2402       { { "http://food.com/",   true,  1299, false },
2403         { "foobar",             false, 1298, false },
2404         { "http://crazy.com/",  true,  1297, true  },
2405         { "friend",             false, 1296, true  },
2406         { "http://friend.com/", true,  1295, true  } } },
2407     { "x", 1200,
2408       { { "http://food.com/",   true,  1299, false },
2409         { "foobar",             false, 1298, false },
2410         { "http://crazy.com/",  true,  1297, false },
2411         { "friend",             false, 1296, false },
2412         { "http://friend.com/", true,  1295, false } } },
2413
2414     // Run the three tests immediately above again, just with verbatim
2415     // suppressed.  Note that in the last case, all results are filtered.
2416     // Because verbatim is also suppressed, SearchProvider will realize
2417     // in UpdateMatches() that it needs to restore verbatim to fulfill
2418     // its constraints.  This restoration does not happen in
2419     // RemoveAllStaleResults() and hence is not tested here.  This restoration
2420     // is tested in the DefaultFetcherSuggestRelevance test.
2421     { "f", 0,
2422       { { "http://food.com/",   true,  1299, true },
2423         { "foobar",             false, 1298, true },
2424         { "http://crazy.com/",  true,  1297, true },
2425         { "friend",             false, 1296, true },
2426         { "http://friend.com/", true,  1295, true } } },
2427     { "c", 0,
2428       { { "http://food.com/",   true,  1299, false },
2429         { "foobar",             false, 1298, false },
2430         { "http://crazy.com/",  true,  1297, true  },
2431         { "friend",             false, 1296, true  },
2432         { "http://friend.com/", true,  1295, true  } } },
2433     { "x", 0,
2434       { { "http://food.com/",   true,  1299, false },
2435         { "foobar",             false, 1298, false },
2436         { "http://crazy.com/",  true,  1297, false },
2437         { "friend",             false, 1296, false },
2438         { "http://friend.com/", true,  1295, false } } },
2439
2440     // The same sort of tests again, just with verbatim with a score
2441     // that would place it in between other suggestions.
2442     { "f", 1290,
2443       { { "http://food.com/",   true,  1299, true },
2444         { "foobar",             false, 1288, true },
2445         { "http://crazy.com/",  true,  1277, true },
2446         { "friend",             false, 1266, true },
2447         { "http://friend.com/", true,  1255, true } } },
2448     { "c", 1290,
2449       { { "http://food.com/",   true,  1299, false },
2450         { "foobar",             false, 1288, true  },
2451         { "http://crazy.com/",  true,  1277, true  },
2452         { "friend",             false, 1266, true  },
2453         { "http://friend.com/", true,  1255, true  } } },
2454     { "c", 1270,
2455       { { "http://food.com/",   true,  1299, false },
2456         { "foobar",             false, 1288, false },
2457         { "http://crazy.com/",  true,  1277, true  },
2458         { "friend",             false, 1266, true  },
2459         { "http://friend.com/", true,  1255, true  } } },
2460     { "x", 1280,
2461       { { "http://food.com/",   true,  1299, false },
2462         { "foobar",             false, 1288, false },
2463         { "http://crazy.com/",  true,  1277, true  },
2464         { "friend",             false, 1266, true  },
2465         { "http://friend.com/", true,  1255, true  } } },
2466   };
2467
2468   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2469     // Initialize cached results for this test case.
2470     provider_->default_results_.verbatim_relevance =
2471         cases[i].verbatim_relevance;
2472     provider_->default_results_.navigation_results.clear();
2473     provider_->default_results_.suggest_results.clear();
2474     for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases[i].results); ++j) {
2475       const std::string& suggestion = cases[i].results[j].suggestion;
2476       if (suggestion == kNotApplicable)
2477         break;
2478       if (cases[i].results[j].is_navigation_result) {
2479         provider_->default_results_.navigation_results.push_back(
2480             SearchProvider::NavigationResult(
2481                 *provider_.get(), GURL(suggestion), string16(), false,
2482                 cases[i].results[j].relevance, false));
2483       } else {
2484         provider_->default_results_.suggest_results.push_back(
2485             SearchProvider::SuggestResult(ASCIIToUTF16(suggestion), string16(),
2486                                           string16(), std::string(), false,
2487                                           cases[i].results[j].relevance,
2488                                           false, false));
2489       }
2490     }
2491
2492     provider_->input_ = AutocompleteInput(
2493         ASCIIToUTF16(cases[i].omnibox_input), string16::npos, string16(),
2494         GURL(), AutocompleteInput::INVALID_SPEC, false, false, true,
2495         AutocompleteInput::ALL_MATCHES);
2496     provider_->RemoveAllStaleResults();
2497
2498     // Check cached results.
2499     SearchProvider::SuggestResults::const_iterator sug_it =
2500         provider_->default_results_.suggest_results.begin();
2501     const SearchProvider::SuggestResults::const_iterator sug_end =
2502         provider_->default_results_.suggest_results.end();
2503     SearchProvider::NavigationResults::const_iterator nav_it =
2504         provider_->default_results_.navigation_results.begin();
2505     const SearchProvider::NavigationResults::const_iterator nav_end =
2506         provider_->default_results_.navigation_results.end();
2507     for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases[i].results); ++j) {
2508       const std::string& suggestion = cases[i].results[j].suggestion;
2509       if (suggestion == kNotApplicable)
2510         continue;
2511       if (!cases[i].results[j].expect_match)
2512         continue;
2513       if (cases[i].results[j].is_navigation_result) {
2514         ASSERT_NE(nav_end, nav_it) << "Failed to find " << suggestion;
2515         EXPECT_EQ(suggestion, nav_it->url().spec());
2516         ++nav_it;
2517       } else {
2518         ASSERT_NE(sug_end, sug_it) << "Failed to find " << suggestion;
2519         EXPECT_EQ(ASCIIToUTF16(suggestion), sug_it->suggestion());
2520         ++sug_it;
2521       }
2522     }
2523     EXPECT_EQ(sug_end, sug_it);
2524     EXPECT_EQ(nav_end, nav_it);
2525   }
2526 }
2527
2528 #if !defined(OS_WIN)
2529 // Verify entity suggestion parsing.
2530 TEST_F(SearchProviderTest, ParseEntitySuggestion) {
2531   struct Match {
2532     std::string contents;
2533     std::string query_params;
2534     std::string fill_into_edit;
2535     AutocompleteMatchType::Type type;
2536     size_t classification_offsets[3];
2537     int classification_styles[3];
2538   };
2539   const size_t invalid_offset = 10;
2540   const int invalid_style = -1;
2541   const Match kEmptyMatch = {
2542     kNotApplicable, kNotApplicable, kNotApplicable,
2543     AutocompleteMatchType::NUM_TYPES,
2544     { invalid_offset, invalid_offset, invalid_offset },
2545     { invalid_style, invalid_style, invalid_style } };
2546
2547   struct {
2548     const std::string input_text;
2549     const std::string response_json;
2550     const Match matches[5];
2551   } cases[] = {
2552     // A query and an entity suggestion with different search terms.
2553     { "x",
2554       "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
2555       " {\"google:suggestdetail\":[{},"
2556       "   {\"a\":\"A\",\"dq\":\"yy\",\"q\":\"p=v\"}],"
2557       "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2558       { { "x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2559           { 0, invalid_offset, invalid_offset },
2560           { ACMatchClassification::NONE, invalid_style, invalid_style } },
2561         { "xy", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST,
2562           { 0, 1, invalid_offset },
2563           { ACMatchClassification::NONE, ACMatchClassification::MATCH,
2564             invalid_style } },
2565         { "xy - A", "p=v", "yy", AutocompleteMatchType::SEARCH_SUGGEST,
2566           { 0, 1, 2 },
2567           { ACMatchClassification::NONE, ACMatchClassification::MATCH,
2568             ACMatchClassification::DIM } },
2569         kEmptyMatch,
2570         kEmptyMatch
2571       },
2572     },
2573     // A query and an entity suggestion with same search terms.
2574     { "x",
2575       "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
2576       " {\"google:suggestdetail\":[{},"
2577       "   {\"a\":\"A\",\"dq\":\"xy\",\"q\":\"p=v\"}],"
2578       "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2579       { { "x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2580           { 0, invalid_offset, invalid_offset },
2581           { ACMatchClassification::NONE, invalid_style, invalid_style } },
2582         { "xy", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST,
2583           { 0, 1, invalid_offset },
2584           { ACMatchClassification::NONE, ACMatchClassification::MATCH,
2585             invalid_style } },
2586         { "xy - A", "p=v", "xy", AutocompleteMatchType::SEARCH_SUGGEST,
2587           { 0, 1, 2 },
2588           { ACMatchClassification::NONE, ACMatchClassification::MATCH,
2589             ACMatchClassification::DIM } },
2590         kEmptyMatch,
2591         kEmptyMatch
2592       },
2593     },
2594   };
2595   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2596     QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
2597
2598     // Set up a default fetcher with provided results.
2599     net::TestURLFetcher* fetcher =
2600         test_factory_.GetFetcherByID(
2601             SearchProvider::kDefaultProviderURLFetcherID);
2602     ASSERT_TRUE(fetcher);
2603     fetcher->set_response_code(200);
2604     fetcher->SetResponseString(cases[i].response_json);
2605     fetcher->delegate()->OnURLFetchComplete(fetcher);
2606
2607     RunTillProviderDone();
2608
2609     const ACMatches& matches = provider_->matches();
2610     ASSERT_FALSE(matches.empty());
2611
2612     SCOPED_TRACE("for input with json = " + cases[i].response_json);
2613
2614     size_t j = 0;
2615     // Ensure that the returned matches equal the expectations.
2616     for (; j < matches.size(); ++j) {
2617       const Match& match = cases[i].matches[j];
2618       SCOPED_TRACE(" and match index: " + base::IntToString(j));
2619       EXPECT_EQ(match.contents,
2620                 UTF16ToUTF8(matches[j].contents));
2621       EXPECT_EQ(match.query_params,
2622                 matches[j].search_terms_args->suggest_query_params);
2623       EXPECT_EQ(match.fill_into_edit,
2624                 UTF16ToUTF8(matches[j].fill_into_edit));
2625       EXPECT_EQ(match.type, matches[j].type);
2626
2627       size_t k = 0;
2628       for (; k < matches[j].contents_class.size(); k++) {
2629         SCOPED_TRACE(" and contents class: " + base::IntToString(k));
2630         EXPECT_EQ(match.classification_offsets[k],
2631             matches[j].contents_class[k].offset);
2632         EXPECT_EQ(match.classification_styles[k],
2633             matches[j].contents_class[k].style);
2634       }
2635       for (; k < ARRAYSIZE_UNSAFE(match.classification_offsets); k++) {
2636         SCOPED_TRACE(" and contents class: " + base::IntToString(k));
2637         EXPECT_EQ(match.classification_offsets[k], invalid_offset);
2638         EXPECT_EQ(match.classification_styles[k], invalid_style);
2639       }
2640     }
2641     // Ensure that no expected matches are missing.
2642     for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
2643       SCOPED_TRACE(" and match index: " + base::IntToString(j));
2644       EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
2645       EXPECT_EQ(cases[i].matches[j].query_params, kNotApplicable);
2646       EXPECT_EQ(cases[i].matches[j].fill_into_edit, kNotApplicable);
2647       EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
2648     }
2649   }
2650 }
2651 #endif  // !defined(OS_WIN)
2652
2653 TEST_F(SearchProviderTest, SearchHistorySuppressesEntitySuggestion) {
2654   struct Match {
2655     std::string contents;
2656     std::string query_params;
2657     std::string fill_into_edit;
2658     AutocompleteMatchType::Type type;
2659   };
2660   const Match kEmptyMatch = { kNotApplicable, kNotApplicable, kNotApplicable,
2661                               AutocompleteMatchType::NUM_TYPES};
2662
2663   struct {
2664     const std::string input_text;
2665     const std::string history_search_term;
2666     const std::string response_json;
2667     const Match matches[5];
2668   } cases[] = {
2669     // Search history suppresses both query and entity suggestions.
2670     { "x", "xy",
2671       "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
2672       " {\"google:suggestdetail\":[{},"
2673       "   {\"a\":\"A\",\"dq\":\"xy\",\"q\":\"p=v\"}],"
2674       "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2675       {
2676         {"xy", "", "xy", AutocompleteMatchType::SEARCH_HISTORY},
2677         {"x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
2678         {"xy - A", "p=v", "xy", AutocompleteMatchType::SEARCH_SUGGEST},
2679         kEmptyMatch,
2680         kEmptyMatch,
2681       },
2682     },
2683     // Search history suppresses only query suggestion.
2684     { "x", "xyy",
2685       "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
2686       " {\"google:suggestdetail\":[{},"
2687       "   {\"a\":\"A\",\"dq\":\"xyy\",\"q\":\"p=v\"}],"
2688       "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2689       {
2690         {"xyy", "", "xyy", AutocompleteMatchType::SEARCH_HISTORY},
2691         {"xy", "", "xy", AutocompleteMatchType::SEARCH_HISTORY},
2692         {"x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
2693         {"xy - A", "p=v", "xyy", AutocompleteMatchType::SEARCH_SUGGEST},
2694         kEmptyMatch,
2695       },
2696     }
2697   };
2698
2699   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2700     GURL term_url(AddSearchToHistory(
2701         default_t_url_, ASCIIToUTF16(cases[i].history_search_term), 10));
2702     profile_.BlockUntilHistoryProcessesPendingRequests();
2703     QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
2704
2705     // Set up a default fetcher with provided results.
2706     net::TestURLFetcher* fetcher =
2707         test_factory_.GetFetcherByID(
2708             SearchProvider::kDefaultProviderURLFetcherID);
2709     ASSERT_TRUE(fetcher);
2710     fetcher->set_response_code(200);
2711     fetcher->SetResponseString(cases[i].response_json);
2712     fetcher->delegate()->OnURLFetchComplete(fetcher);
2713
2714     RunTillProviderDone();
2715
2716     const ACMatches& matches = provider_->matches();
2717     ASSERT_FALSE(matches.empty());
2718     SCOPED_TRACE("for case: " + base::IntToString(i));
2719
2720     size_t j = 0;
2721     // Ensure that the returned matches equal the expectations.
2722     for (; j < matches.size(); ++j) {
2723       SCOPED_TRACE(" and match index: " + base::IntToString(j));
2724       EXPECT_EQ(cases[i].matches[j].contents,
2725                 UTF16ToUTF8(matches[j].contents));
2726       EXPECT_EQ(cases[i].matches[j].query_params,
2727                 matches[j].search_terms_args->suggest_query_params);
2728       EXPECT_EQ(cases[i].matches[j].fill_into_edit,
2729                 UTF16ToUTF8(matches[j].fill_into_edit));
2730       EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
2731     }
2732     // Ensure that no expected matches are missing.
2733     for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
2734       SCOPED_TRACE(" and match index: " + base::IntToString(j));
2735       EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
2736       EXPECT_EQ(cases[i].matches[j].query_params, kNotApplicable);
2737       EXPECT_EQ(cases[i].matches[j].fill_into_edit, kNotApplicable);
2738       EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
2739     }
2740   }
2741 }
2742
2743 // A basic test that verifies the prefetch metadata parsing logic.
2744 TEST_F(SearchProviderTest, PrefetchMetadataParsing) {
2745   struct Match {
2746     std::string contents;
2747     bool allowed_to_be_prefetched;
2748     AutocompleteMatchType::Type type;
2749     bool from_keyword;
2750   };
2751   const Match kEmptyMatch = { kNotApplicable,
2752                               false,
2753                               AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2754                               false };
2755
2756   struct {
2757     const std::string input_text;
2758     bool prefer_keyword_provider_results;
2759     const std::string default_provider_response_json;
2760     const std::string keyword_provider_response_json;
2761     const Match matches[5];
2762   } cases[] = {
2763     // Default provider response does not have prefetch details. Ensure that the
2764     // suggestions are not marked as prefetch query.
2765     { "a",
2766       false,
2767       "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2768       std::string(),
2769       { { "a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2770         { "c", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2771         { "b", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2772         kEmptyMatch,
2773         kEmptyMatch
2774       },
2775     },
2776     // Ensure that default provider suggest response prefetch details are
2777     // parsed and recorded in AutocompleteMatch.
2778     { "ab",
2779       false,
2780       "[\"ab\",[\"abc\", \"http://b.com\", \"http://c.com\"],[],[],"
2781           "{\"google:clientdata\":{\"phi\": 0},"
2782           "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"NAVIGATION\"],"
2783           "\"google:suggestrelevance\":[999, 12, 1]}]",
2784       std::string(),
2785       { { "ab",    false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2786         { "abc",   true,  AutocompleteMatchType::SEARCH_SUGGEST, false },
2787         { "b.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2788         { "c.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2789         kEmptyMatch
2790       },
2791     },
2792     // Default provider suggest response has prefetch details.
2793     // SEARCH_WHAT_YOU_TYPE suggestion outranks SEARCH_SUGGEST suggestion for
2794     // the same query string. Ensure that the prefetch details from
2795     // SEARCH_SUGGEST match are set onto SEARCH_WHAT_YOU_TYPE match.
2796     { "ab",
2797       false,
2798       "[\"ab\",[\"ab\", \"http://ab.com\"],[],[],"
2799           "{\"google:clientdata\":{\"phi\": 0},"
2800           "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2801           "\"google:suggestrelevance\":[99, 98]}]",
2802       std::string(),
2803       { {"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2804         {"ab.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2805         kEmptyMatch,
2806         kEmptyMatch,
2807         kEmptyMatch
2808       },
2809     },
2810     // Default provider response has prefetch details. We prefer keyword
2811     // provider results. Ensure that prefetch bit for a suggestion from the
2812     // default search provider does not get copied onto a higher-scoring match
2813     // for the same query string from the keyword provider.
2814     { "k a",
2815       true,
2816       "[\"k a\",[\"a\", \"ab\"],[],[], {\"google:clientdata\":{\"phi\": 0},"
2817           "\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2818           "\"google:suggestrelevance\":[9, 12]}]",
2819       "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2820       { { "a", false, AutocompleteMatchType::SEARCH_OTHER_ENGINE, true},
2821         { "k a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2822         { "ab", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2823         { "c", false, AutocompleteMatchType::SEARCH_SUGGEST, true },
2824         { "b", false, AutocompleteMatchType::SEARCH_SUGGEST, true }
2825       },
2826     }
2827   };
2828
2829   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2830     QueryForInput(ASCIIToUTF16(cases[i].input_text), false,
2831                   cases[i].prefer_keyword_provider_results);
2832
2833     // Set up a default fetcher with provided results.
2834     net::TestURLFetcher* fetcher =
2835         test_factory_.GetFetcherByID(
2836             SearchProvider::kDefaultProviderURLFetcherID);
2837     ASSERT_TRUE(fetcher);
2838     fetcher->set_response_code(200);
2839     fetcher->SetResponseString(cases[i].default_provider_response_json);
2840     fetcher->delegate()->OnURLFetchComplete(fetcher);
2841
2842     if (cases[i].prefer_keyword_provider_results) {
2843       // Set up a keyword fetcher with provided results.
2844       net::TestURLFetcher* keyword_fetcher =
2845           test_factory_.GetFetcherByID(
2846               SearchProvider::kKeywordProviderURLFetcherID);
2847       ASSERT_TRUE(keyword_fetcher);
2848       keyword_fetcher->set_response_code(200);
2849       keyword_fetcher->SetResponseString(
2850           cases[i].keyword_provider_response_json);
2851       keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
2852       keyword_fetcher = NULL;
2853     }
2854
2855     RunTillProviderDone();
2856
2857     const std::string description =
2858         "for input with json =" + cases[i].default_provider_response_json;
2859     const ACMatches& matches = provider_->matches();
2860     // The top match must inline and score as highly as calculated verbatim.
2861     ASSERT_FALSE(matches.empty());
2862     EXPECT_GE(matches[0].relevance, 1300);
2863
2864     // Ensure that the returned matches equal the expectations.
2865     for (size_t j = 0; j < matches.size(); ++j) {
2866       SCOPED_TRACE(description);
2867       EXPECT_EQ(cases[i].matches[j].contents, UTF16ToUTF8(matches[j].contents));
2868       EXPECT_EQ(cases[i].matches[j].allowed_to_be_prefetched,
2869                 SearchProvider::ShouldPrefetch(matches[j]));
2870       EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
2871       EXPECT_EQ(cases[i].matches[j].from_keyword,
2872                 matches[j].keyword == ASCIIToUTF16("k"));
2873     }
2874   }
2875 }
2876
2877 // A basic test that verifies that the XSSI guarded JSON response is parsed
2878 // correctly.
2879 TEST_F(SearchProviderTest, XSSIGuardedJSONParsing) {
2880   struct Match {
2881     std::string contents;
2882     AutocompleteMatchType::Type type;
2883   };
2884   const Match kEmptyMatch = { kNotApplicable,
2885                               AutocompleteMatchType::NUM_TYPES};
2886
2887   struct {
2888     const std::string input_text;
2889     const std::string default_provider_response_json;
2890     const Match matches[4];
2891   } cases[] = {
2892     // No XSSI guard.
2893     { "a",
2894       "[\"a\",[\"b\", \"c\"],[],[],"
2895       "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2896       "\"google:suggestrelevance\":[1, 2]}]",
2897       { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2898         { "c", AutocompleteMatchType::SEARCH_SUGGEST },
2899         { "b", AutocompleteMatchType::SEARCH_SUGGEST },
2900         kEmptyMatch,
2901       },
2902     },
2903     // Standard XSSI guard - )]}'\n.
2904     { "a",
2905       ")]}'\n[\"a\",[\"b\", \"c\"],[],[],"
2906       "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2907       "\"google:suggestrelevance\":[1, 2]}]",
2908       { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2909         { "c", AutocompleteMatchType::SEARCH_SUGGEST },
2910         { "b", AutocompleteMatchType::SEARCH_SUGGEST },
2911         kEmptyMatch,
2912       },
2913     },
2914     // Modified XSSI guard - contains "[".
2915     { "a",
2916       ")]}'\n[)\"[\"a\",[\"b\", \"c\"],[],[],"
2917       "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2918       "\"google:suggestrelevance\":[1, 2]}]",
2919       { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2920         { "c", AutocompleteMatchType::SEARCH_SUGGEST },
2921         { "b", AutocompleteMatchType::SEARCH_SUGGEST },
2922         kEmptyMatch,
2923       },
2924     },
2925   };
2926
2927   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2928     ClearAllResults();
2929     QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
2930
2931     // Set up a default fetcher with provided results.
2932     net::TestURLFetcher* fetcher =
2933         test_factory_.GetFetcherByID(
2934             SearchProvider::kDefaultProviderURLFetcherID);
2935     ASSERT_TRUE(fetcher);
2936     fetcher->set_response_code(200);
2937     fetcher->SetResponseString(cases[i].default_provider_response_json);
2938     fetcher->delegate()->OnURLFetchComplete(fetcher);
2939
2940     RunTillProviderDone();
2941
2942     const ACMatches& matches = provider_->matches();
2943     // The top match must inline and score as highly as calculated verbatim.
2944     ASSERT_FALSE(matches.empty());
2945     EXPECT_GE(matches[0].relevance, 1300);
2946
2947     SCOPED_TRACE("for case: " + base::IntToString(i));
2948     size_t j = 0;
2949     // Ensure that the returned matches equal the expectations.
2950     for (; j < matches.size(); ++j) {
2951       SCOPED_TRACE("and match: " + base::IntToString(j));
2952       EXPECT_EQ(cases[i].matches[j].contents, UTF16ToUTF8(matches[j].contents));
2953       EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
2954     }
2955     for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
2956       SCOPED_TRACE("and match: " + base::IntToString(j));
2957       EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
2958       EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
2959     }
2960   }
2961 }
2962
2963
2964 TEST_F(SearchProviderTest, ReflectsBookmarkBarState) {
2965   profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, false);
2966   string16 term = term1_.substr(0, term1_.length() - 1);
2967   QueryForInput(term, true, false);
2968   ASSERT_FALSE(provider_->matches().empty());
2969   EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2970             provider_->matches()[0].type);
2971   ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL);
2972   EXPECT_FALSE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned);
2973
2974   profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, true);
2975   term = term1_.substr(0, term1_.length() - 1);
2976   QueryForInput(term, true, false);
2977   ASSERT_FALSE(provider_->matches().empty());
2978   EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2979             provider_->matches()[0].type);
2980   ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL);
2981   EXPECT_TRUE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned);
2982 }