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