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