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