Home | History | Annotate | Download | only in autocomplete
      1 // Copyright (c) 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/autocomplete_provider.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/strings/string16.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "chrome/browser/autocomplete/autocomplete_controller.h"
     16 #include "chrome/browser/autocomplete/autocomplete_input.h"
     17 #include "chrome/browser/autocomplete/autocomplete_match.h"
     18 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
     19 #include "chrome/browser/autocomplete/keyword_provider.h"
     20 #include "chrome/browser/autocomplete/search_provider.h"
     21 #include "chrome/browser/chrome_notification_types.h"
     22 #include "chrome/browser/search_engines/template_url.h"
     23 #include "chrome/browser/search_engines/template_url_service.h"
     24 #include "chrome/browser/search_engines/template_url_service_factory.h"
     25 #include "chrome/common/chrome_switches.h"
     26 #include "chrome/test/base/testing_browser_process.h"
     27 #include "chrome/test/base/testing_profile.h"
     28 #include "components/metrics/proto/omnibox_event.pb.h"
     29 #include "content/public/browser/notification_observer.h"
     30 #include "content/public/browser/notification_registrar.h"
     31 #include "content/public/browser/notification_source.h"
     32 #include "testing/gtest/include/gtest/gtest.h"
     33 
     34 static std::ostream& operator<<(std::ostream& os,
     35                                 const AutocompleteResult::const_iterator& it) {
     36   return os << static_cast<const AutocompleteMatch*>(&(*it));
     37 }
     38 
     39 namespace {
     40 const size_t kResultsPerProvider = 3;
     41 const char kTestTemplateURLKeyword[] = "t";
     42 }
     43 
     44 // Autocomplete provider that provides known results. Note that this is
     45 // refcounted so that it can also be a task on the message loop.
     46 class TestProvider : public AutocompleteProvider {
     47  public:
     48   TestProvider(int relevance, const base::string16& prefix,
     49                Profile* profile,
     50                const base::string16 match_keyword)
     51       : AutocompleteProvider(NULL, profile, AutocompleteProvider::TYPE_SEARCH),
     52         relevance_(relevance),
     53         prefix_(prefix),
     54         match_keyword_(match_keyword) {
     55   }
     56 
     57   virtual void Start(const AutocompleteInput& input,
     58                      bool minimal_changes) OVERRIDE;
     59 
     60   void set_listener(AutocompleteProviderListener* listener) {
     61     listener_ = listener;
     62   }
     63 
     64  private:
     65   virtual ~TestProvider() {}
     66 
     67   void Run();
     68 
     69   void AddResults(int start_at, int num);
     70   void AddResultsWithSearchTermsArgs(
     71       int start_at,
     72       int num,
     73       AutocompleteMatch::Type type,
     74       const TemplateURLRef::SearchTermsArgs& search_terms_args);
     75 
     76   int relevance_;
     77   const base::string16 prefix_;
     78   const base::string16 match_keyword_;
     79 };
     80 
     81 void TestProvider::Start(const AutocompleteInput& input,
     82                          bool minimal_changes) {
     83   if (minimal_changes)
     84     return;
     85 
     86   matches_.clear();
     87 
     88   // Generate 4 results synchronously, the rest later.
     89   AddResults(0, 1);
     90   AddResultsWithSearchTermsArgs(
     91       1, 1, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
     92       TemplateURLRef::SearchTermsArgs(base::ASCIIToUTF16("echo")));
     93   AddResultsWithSearchTermsArgs(
     94       2, 1, AutocompleteMatchType::NAVSUGGEST,
     95       TemplateURLRef::SearchTermsArgs(base::ASCIIToUTF16("nav")));
     96   AddResultsWithSearchTermsArgs(
     97       3, 1, AutocompleteMatchType::SEARCH_SUGGEST,
     98       TemplateURLRef::SearchTermsArgs(base::ASCIIToUTF16("query")));
     99 
    100   if (input.want_asynchronous_matches()) {
    101     done_ = false;
    102     base::MessageLoop::current()->PostTask(
    103         FROM_HERE, base::Bind(&TestProvider::Run, this));
    104   }
    105 }
    106 
    107 void TestProvider::Run() {
    108   DCHECK_GT(kResultsPerProvider, 0U);
    109   AddResults(1, kResultsPerProvider);
    110   done_ = true;
    111   DCHECK(listener_);
    112   listener_->OnProviderUpdate(true);
    113 }
    114 
    115 void TestProvider::AddResults(int start_at, int num) {
    116   AddResultsWithSearchTermsArgs(start_at,
    117                                 num,
    118                                 AutocompleteMatchType::URL_WHAT_YOU_TYPED,
    119                                 TemplateURLRef::SearchTermsArgs(
    120                                     base::string16()));
    121 }
    122 
    123 void TestProvider::AddResultsWithSearchTermsArgs(
    124     int start_at,
    125     int num,
    126     AutocompleteMatch::Type type,
    127     const TemplateURLRef::SearchTermsArgs& search_terms_args) {
    128   for (int i = start_at; i < num; i++) {
    129     AutocompleteMatch match(this, relevance_ - i, false, type);
    130 
    131     match.fill_into_edit = prefix_ + base::UTF8ToUTF16(base::IntToString(i));
    132     match.destination_url = GURL(base::UTF16ToUTF8(match.fill_into_edit));
    133     match.allowed_to_be_default_match = true;
    134 
    135     match.contents = match.fill_into_edit;
    136     match.contents_class.push_back(
    137         ACMatchClassification(0, ACMatchClassification::NONE));
    138     match.description = match.fill_into_edit;
    139     match.description_class.push_back(
    140         ACMatchClassification(0, ACMatchClassification::NONE));
    141     match.search_terms_args.reset(
    142         new TemplateURLRef::SearchTermsArgs(search_terms_args));
    143     if (!match_keyword_.empty()) {
    144       match.keyword = match_keyword_;
    145       ASSERT_TRUE(match.GetTemplateURL(profile_, false) != NULL);
    146     }
    147 
    148     matches_.push_back(match);
    149   }
    150 }
    151 
    152 class AutocompleteProviderTest : public testing::Test,
    153                                  public content::NotificationObserver {
    154  protected:
    155   struct KeywordTestData {
    156     const base::string16 fill_into_edit;
    157     const base::string16 keyword;
    158     const bool expected_keyword_result;
    159   };
    160 
    161   struct AssistedQueryStatsTestData {
    162     const AutocompleteMatch::Type match_type;
    163     const std::string expected_aqs;
    164   };
    165 
    166  protected:
    167    // Registers a test TemplateURL under the given keyword.
    168   void RegisterTemplateURL(const base::string16 keyword,
    169                            const std::string& template_url);
    170 
    171   // Resets |controller_| with two TestProviders.  |provider1_ptr| and
    172   // |provider2_ptr| are updated to point to the new providers if non-NULL.
    173   void ResetControllerWithTestProviders(bool same_destinations,
    174                                         TestProvider** provider1_ptr,
    175                                         TestProvider** provider2_ptr);
    176 
    177   // Runs a query on the input "a", and makes sure both providers' input is
    178   // properly collected.
    179   void RunTest();
    180 
    181   void RunRedundantKeywordTest(const KeywordTestData* match_data, size_t size);
    182 
    183   void RunAssistedQueryStatsTest(
    184       const AssistedQueryStatsTestData* aqs_test_data,
    185       size_t size);
    186 
    187   void RunQuery(const base::string16 query);
    188 
    189   void ResetControllerWithKeywordAndSearchProviders();
    190   void ResetControllerWithKeywordProvider();
    191   void RunExactKeymatchTest(bool allow_exact_keyword_match);
    192 
    193   void CopyResults();
    194 
    195   // Returns match.destination_url as it would be set by
    196   // AutocompleteController::UpdateMatchDestinationURL().
    197   GURL GetDestinationURL(AutocompleteMatch match,
    198                          base::TimeDelta query_formulation_time) const;
    199 
    200   AutocompleteResult result_;
    201   scoped_ptr<AutocompleteController> controller_;
    202 
    203  private:
    204   // content::NotificationObserver:
    205   virtual void Observe(int type,
    206                        const content::NotificationSource& source,
    207                        const content::NotificationDetails& details) OVERRIDE;
    208 
    209   base::MessageLoopForUI message_loop_;
    210   content::NotificationRegistrar registrar_;
    211   TestingProfile profile_;
    212 };
    213 
    214 void AutocompleteProviderTest::RegisterTemplateURL(
    215     const base::string16 keyword,
    216     const std::string& template_url) {
    217   TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
    218       &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
    219   TemplateURLData data;
    220   data.SetURL(template_url);
    221   data.SetKeyword(keyword);
    222   TemplateURL* default_t_url = new TemplateURL(data);
    223   TemplateURLService* turl_model =
    224       TemplateURLServiceFactory::GetForProfile(&profile_);
    225   turl_model->Add(default_t_url);
    226   turl_model->SetUserSelectedDefaultSearchProvider(default_t_url);
    227   turl_model->Load();
    228   TemplateURLID default_provider_id = default_t_url->id();
    229   ASSERT_NE(0, default_provider_id);
    230 }
    231 
    232 void AutocompleteProviderTest::ResetControllerWithTestProviders(
    233     bool same_destinations,
    234     TestProvider** provider1_ptr,
    235     TestProvider** provider2_ptr) {
    236   // TODO: Move it outside this method, after refactoring the existing
    237   // unit tests.  Specifically:
    238   //   (1) Make sure that AutocompleteMatch.keyword is set iff there is
    239   //       a corresponding call to RegisterTemplateURL; otherwise the
    240   //       controller flow will crash; this practically means that
    241   //       RunTests/ResetControllerXXX/RegisterTemplateURL should
    242   //       be coordinated with each other.
    243   //   (2) Inject test arguments rather than rely on the hardcoded values, e.g.
    244   //       don't rely on kResultsPerProvided and default relevance ordering
    245   //       (B > A).
    246   RegisterTemplateURL(base::ASCIIToUTF16(kTestTemplateURLKeyword),
    247                       "http://aqs/{searchTerms}/{google:assistedQueryStats}");
    248 
    249   ACProviders providers;
    250 
    251   // Construct two new providers, with either the same or different prefixes.
    252   TestProvider* provider1 = new TestProvider(
    253       kResultsPerProvider,
    254       base::ASCIIToUTF16("http://a"),
    255       &profile_,
    256       base::ASCIIToUTF16(kTestTemplateURLKeyword));
    257   provider1->AddRef();
    258   providers.push_back(provider1);
    259 
    260   TestProvider* provider2 = new TestProvider(
    261       kResultsPerProvider * 2,
    262       same_destinations ? base::ASCIIToUTF16("http://a")
    263                         : base::ASCIIToUTF16("http://b"),
    264       &profile_,
    265       base::string16());
    266   provider2->AddRef();
    267   providers.push_back(provider2);
    268 
    269   // Reset the controller to contain our new providers.
    270   controller_.reset(new AutocompleteController(&profile_, NULL, 0));
    271   // We're going to swap the providers vector, but the old vector should be
    272   // empty so no elements need to be freed at this point.
    273   EXPECT_TRUE(controller_->providers_.empty());
    274   controller_->providers_.swap(providers);
    275   provider1->set_listener(controller_.get());
    276   provider2->set_listener(controller_.get());
    277 
    278   // The providers don't complete synchronously, so listen for "result updated"
    279   // notifications.
    280   registrar_.Add(this,
    281                  chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
    282                  content::Source<AutocompleteController>(controller_.get()));
    283 
    284   if (provider1_ptr)
    285     *provider1_ptr = provider1;
    286   if (provider2_ptr)
    287     *provider2_ptr = provider2;
    288 }
    289 
    290 void AutocompleteProviderTest::
    291     ResetControllerWithKeywordAndSearchProviders() {
    292   TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
    293       &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
    294 
    295   // Reset the default TemplateURL.
    296   TemplateURLData data;
    297   data.SetURL("http://defaultturl/{searchTerms}");
    298   TemplateURL* default_t_url = new TemplateURL(data);
    299   TemplateURLService* turl_model =
    300       TemplateURLServiceFactory::GetForProfile(&profile_);
    301   turl_model->Add(default_t_url);
    302   turl_model->SetUserSelectedDefaultSearchProvider(default_t_url);
    303   TemplateURLID default_provider_id = default_t_url->id();
    304   ASSERT_NE(0, default_provider_id);
    305 
    306   // Create another TemplateURL for KeywordProvider.
    307   TemplateURLData data2;
    308   data2.short_name = base::ASCIIToUTF16("k");
    309   data2.SetKeyword(base::ASCIIToUTF16("k"));
    310   data2.SetURL("http://keyword/{searchTerms}");
    311   TemplateURL* keyword_t_url = new TemplateURL(data2);
    312   turl_model->Add(keyword_t_url);
    313   ASSERT_NE(0, keyword_t_url->id());
    314 
    315   controller_.reset(new AutocompleteController(
    316       &profile_, NULL,
    317       AutocompleteProvider::TYPE_KEYWORD | AutocompleteProvider::TYPE_SEARCH));
    318 }
    319 
    320 void AutocompleteProviderTest::ResetControllerWithKeywordProvider() {
    321   TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
    322       &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
    323 
    324   TemplateURLService* turl_model =
    325       TemplateURLServiceFactory::GetForProfile(&profile_);
    326 
    327   // Create a TemplateURL for KeywordProvider.
    328   TemplateURLData data;
    329   data.short_name = base::ASCIIToUTF16("foo.com");
    330   data.SetKeyword(base::ASCIIToUTF16("foo.com"));
    331   data.SetURL("http://foo.com/{searchTerms}");
    332   TemplateURL* keyword_t_url = new TemplateURL(data);
    333   turl_model->Add(keyword_t_url);
    334   ASSERT_NE(0, keyword_t_url->id());
    335 
    336   // Create another TemplateURL for KeywordProvider.
    337   data.short_name = base::ASCIIToUTF16("bar.com");
    338   data.SetKeyword(base::ASCIIToUTF16("bar.com"));
    339   data.SetURL("http://bar.com/{searchTerms}");
    340   keyword_t_url = new TemplateURL(data);
    341   turl_model->Add(keyword_t_url);
    342   ASSERT_NE(0, keyword_t_url->id());
    343 
    344   controller_.reset(new AutocompleteController(
    345       &profile_, NULL, AutocompleteProvider::TYPE_KEYWORD));
    346 }
    347 
    348 void AutocompleteProviderTest::RunTest() {
    349   RunQuery(base::ASCIIToUTF16("a"));
    350 }
    351 
    352 void AutocompleteProviderTest::RunRedundantKeywordTest(
    353     const KeywordTestData* match_data,
    354     size_t size) {
    355   ACMatches matches;
    356   for (size_t i = 0; i < size; ++i) {
    357     AutocompleteMatch match;
    358     match.relevance = 1000;  // Arbitrary non-zero value.
    359     match.allowed_to_be_default_match = true;
    360     match.fill_into_edit = match_data[i].fill_into_edit;
    361     match.transition = content::PAGE_TRANSITION_KEYWORD;
    362     match.keyword = match_data[i].keyword;
    363     matches.push_back(match);
    364   }
    365 
    366   AutocompleteResult result;
    367   result.AppendMatches(matches);
    368   controller_->UpdateAssociatedKeywords(&result);
    369 
    370   for (size_t j = 0; j < result.size(); ++j) {
    371     EXPECT_EQ(match_data[j].expected_keyword_result,
    372         result.match_at(j)->associated_keyword.get() != NULL);
    373   }
    374 }
    375 
    376 void AutocompleteProviderTest::RunAssistedQueryStatsTest(
    377     const AssistedQueryStatsTestData* aqs_test_data,
    378     size_t size) {
    379   // Prepare input.
    380   const size_t kMaxRelevance = 1000;
    381   ACMatches matches;
    382   for (size_t i = 0; i < size; ++i) {
    383     AutocompleteMatch match(NULL, kMaxRelevance - i, false,
    384                             aqs_test_data[i].match_type);
    385     match.allowed_to_be_default_match = true;
    386     match.keyword = base::ASCIIToUTF16(kTestTemplateURLKeyword);
    387     match.search_terms_args.reset(
    388         new TemplateURLRef::SearchTermsArgs(base::string16()));
    389     matches.push_back(match);
    390   }
    391   result_.Reset();
    392   result_.AppendMatches(matches);
    393 
    394   // Update AQS.
    395   controller_->UpdateAssistedQueryStats(&result_);
    396 
    397   // Verify data.
    398   for (size_t i = 0; i < size; ++i) {
    399     EXPECT_EQ(aqs_test_data[i].expected_aqs,
    400               result_.match_at(i)->search_terms_args->assisted_query_stats);
    401   }
    402 }
    403 
    404 void AutocompleteProviderTest::RunQuery(const base::string16 query) {
    405   result_.Reset();
    406   controller_->Start(AutocompleteInput(
    407       query, base::string16::npos, base::string16(), GURL(),
    408       metrics::OmniboxEventProto::INVALID_SPEC, true, false, true, true));
    409 
    410   if (!controller_->done())
    411     // The message loop will terminate when all autocomplete input has been
    412     // collected.
    413     base::MessageLoop::current()->Run();
    414 }
    415 
    416 void AutocompleteProviderTest::RunExactKeymatchTest(
    417     bool allow_exact_keyword_match) {
    418   // Send the controller input which exactly matches the keyword provider we
    419   // created in ResetControllerWithKeywordAndSearchProviders().  The default
    420   // match should thus be a search-other-engine match iff
    421   // |allow_exact_keyword_match| is true.  Regardless, the match should
    422   // be from SearchProvider.  (It provides all verbatim search matches,
    423   // keyword or not.)
    424   controller_->Start(AutocompleteInput(
    425       base::ASCIIToUTF16("k test"), base::string16::npos, base::string16(),
    426       GURL(), metrics::OmniboxEventProto::INVALID_SPEC, true, false,
    427       allow_exact_keyword_match, false));
    428   EXPECT_TRUE(controller_->done());
    429   EXPECT_EQ(AutocompleteProvider::TYPE_SEARCH,
    430       controller_->result().default_match()->provider->type());
    431   EXPECT_EQ(allow_exact_keyword_match ?
    432       AutocompleteMatchType::SEARCH_OTHER_ENGINE :
    433       AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
    434       controller_->result().default_match()->type);
    435 }
    436 
    437 void AutocompleteProviderTest::CopyResults() {
    438   result_.CopyFrom(controller_->result());
    439 }
    440 
    441 GURL AutocompleteProviderTest::GetDestinationURL(
    442     AutocompleteMatch match,
    443     base::TimeDelta query_formulation_time) const {
    444   controller_->UpdateMatchDestinationURL(query_formulation_time, &match);
    445   return match.destination_url;
    446 }
    447 
    448 void AutocompleteProviderTest::Observe(
    449     int type,
    450     const content::NotificationSource& source,
    451     const content::NotificationDetails& details) {
    452   if (controller_->done()) {
    453     CopyResults();
    454     base::MessageLoop::current()->Quit();
    455   }
    456 }
    457 
    458 // Tests that the default selection is set properly when updating results.
    459 TEST_F(AutocompleteProviderTest, Query) {
    460   TestProvider* provider1 = NULL;
    461   TestProvider* provider2 = NULL;
    462   ResetControllerWithTestProviders(false, &provider1, &provider2);
    463   RunTest();
    464 
    465   // Make sure the default match gets set to the highest relevance match.  The
    466   // highest relevance matches should come from the second provider.
    467   EXPECT_EQ(kResultsPerProvider * 2, result_.size());
    468   ASSERT_NE(result_.end(), result_.default_match());
    469   EXPECT_EQ(provider2, result_.default_match()->provider);
    470 }
    471 
    472 // Tests assisted query stats.
    473 TEST_F(AutocompleteProviderTest, AssistedQueryStats) {
    474   ResetControllerWithTestProviders(false, NULL, NULL);
    475   RunTest();
    476 
    477   ASSERT_EQ(kResultsPerProvider * 2, result_.size());
    478 
    479   // Now, check the results from the second provider, as they should not have
    480   // assisted query stats set.
    481   for (size_t i = 0; i < kResultsPerProvider; ++i) {
    482     EXPECT_TRUE(
    483         result_.match_at(i)->search_terms_args->assisted_query_stats.empty());
    484   }
    485   // The first provider has a test keyword, so AQS should be non-empty.
    486   for (size_t i = kResultsPerProvider; i < kResultsPerProvider * 2; ++i) {
    487     EXPECT_FALSE(
    488         result_.match_at(i)->search_terms_args->assisted_query_stats.empty());
    489   }
    490 }
    491 
    492 TEST_F(AutocompleteProviderTest, RemoveDuplicates) {
    493   TestProvider* provider1 = NULL;
    494   TestProvider* provider2 = NULL;
    495   ResetControllerWithTestProviders(true, &provider1, &provider2);
    496   RunTest();
    497 
    498   // Make sure all the first provider's results were eliminated by the second
    499   // provider's.
    500   EXPECT_EQ(kResultsPerProvider, result_.size());
    501   for (AutocompleteResult::const_iterator i(result_.begin());
    502        i != result_.end(); ++i)
    503     EXPECT_EQ(provider2, i->provider);
    504 }
    505 
    506 TEST_F(AutocompleteProviderTest, AllowExactKeywordMatch) {
    507   ResetControllerWithKeywordAndSearchProviders();
    508   RunExactKeymatchTest(true);
    509   RunExactKeymatchTest(false);
    510 }
    511 
    512 // Ensures matches from (only) the default search provider respect any extra
    513 // query params set on the command line.
    514 TEST_F(AutocompleteProviderTest, ExtraQueryParams) {
    515   ResetControllerWithKeywordAndSearchProviders();
    516   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
    517       switches::kExtraSearchQueryParams, "a=b");
    518   RunExactKeymatchTest(true);
    519   CopyResults();
    520   ASSERT_EQ(2U, result_.size());
    521   EXPECT_EQ("http://keyword/test",
    522             result_.match_at(0)->destination_url.possibly_invalid_spec());
    523   EXPECT_EQ("http://defaultturl/k%20test?a=b",
    524             result_.match_at(1)->destination_url.possibly_invalid_spec());
    525 }
    526 
    527 // Test that redundant associated keywords are removed.
    528 TEST_F(AutocompleteProviderTest, RedundantKeywordsIgnoredInResult) {
    529   ResetControllerWithKeywordProvider();
    530 
    531   {
    532     KeywordTestData duplicate_url[] = {
    533       { base::ASCIIToUTF16("fo"), base::string16(), false },
    534       { base::ASCIIToUTF16("foo.com"), base::string16(), true },
    535       { base::ASCIIToUTF16("foo.com"), base::string16(), false }
    536     };
    537 
    538     SCOPED_TRACE("Duplicate url");
    539     RunRedundantKeywordTest(duplicate_url, ARRAYSIZE_UNSAFE(duplicate_url));
    540   }
    541 
    542   {
    543     KeywordTestData keyword_match[] = {
    544       { base::ASCIIToUTF16("foo.com"), base::ASCIIToUTF16("foo.com"), false },
    545       { base::ASCIIToUTF16("foo.com"), base::string16(), false }
    546     };
    547 
    548     SCOPED_TRACE("Duplicate url with keyword match");
    549     RunRedundantKeywordTest(keyword_match, ARRAYSIZE_UNSAFE(keyword_match));
    550   }
    551 
    552   {
    553     KeywordTestData multiple_keyword[] = {
    554       { base::ASCIIToUTF16("fo"), base::string16(), false },
    555       { base::ASCIIToUTF16("foo.com"), base::string16(), true },
    556       { base::ASCIIToUTF16("foo.com"), base::string16(), false },
    557       { base::ASCIIToUTF16("bar.com"), base::string16(), true },
    558     };
    559 
    560     SCOPED_TRACE("Duplicate url with multiple keywords");
    561     RunRedundantKeywordTest(multiple_keyword,
    562         ARRAYSIZE_UNSAFE(multiple_keyword));
    563   }
    564 }
    565 
    566 TEST_F(AutocompleteProviderTest, UpdateAssistedQueryStats) {
    567   ResetControllerWithTestProviders(false, NULL, NULL);
    568 
    569   {
    570     AssistedQueryStatsTestData test_data[] = {
    571       //  MSVC doesn't support zero-length arrays, so supply some dummy data.
    572       { AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, "" }
    573     };
    574     SCOPED_TRACE("No matches");
    575     // Note: We pass 0 here to ignore the dummy data above.
    576     RunAssistedQueryStatsTest(test_data, 0);
    577   }
    578 
    579   {
    580     AssistedQueryStatsTestData test_data[] = {
    581       { AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, "chrome..69i57" }
    582     };
    583     SCOPED_TRACE("One match");
    584     RunAssistedQueryStatsTest(test_data, ARRAYSIZE_UNSAFE(test_data));
    585   }
    586 
    587   {
    588     AssistedQueryStatsTestData test_data[] = {
    589       { AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
    590         "chrome..69i57j69i58j5l2j0l3j69i59" },
    591       { AutocompleteMatchType::URL_WHAT_YOU_TYPED,
    592         "chrome..69i57j69i58j5l2j0l3j69i59" },
    593       { AutocompleteMatchType::NAVSUGGEST,
    594         "chrome.2.69i57j69i58j5l2j0l3j69i59" },
    595       { AutocompleteMatchType::NAVSUGGEST,
    596         "chrome.3.69i57j69i58j5l2j0l3j69i59" },
    597       { AutocompleteMatchType::SEARCH_SUGGEST,
    598         "chrome.4.69i57j69i58j5l2j0l3j69i59" },
    599       { AutocompleteMatchType::SEARCH_SUGGEST,
    600         "chrome.5.69i57j69i58j5l2j0l3j69i59" },
    601       { AutocompleteMatchType::SEARCH_SUGGEST,
    602         "chrome.6.69i57j69i58j5l2j0l3j69i59" },
    603       { AutocompleteMatchType::SEARCH_HISTORY,
    604         "chrome.7.69i57j69i58j5l2j0l3j69i59" },
    605     };
    606     SCOPED_TRACE("Multiple matches");
    607     RunAssistedQueryStatsTest(test_data, ARRAYSIZE_UNSAFE(test_data));
    608   }
    609 }
    610 
    611 TEST_F(AutocompleteProviderTest, GetDestinationURL) {
    612   ResetControllerWithKeywordAndSearchProviders();
    613 
    614   // For the destination URL to have aqs parameters for query formulation time
    615   // and the field trial triggered bit, many conditions need to be satisfied.
    616   AutocompleteMatch match(NULL, 1100, false,
    617                           AutocompleteMatchType::SEARCH_SUGGEST);
    618   GURL url(GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456)));
    619   EXPECT_TRUE(url.path().empty());
    620 
    621   // The protocol needs to be https.
    622   RegisterTemplateURL(base::ASCIIToUTF16(kTestTemplateURLKeyword),
    623                       "https://aqs/{searchTerms}/{google:assistedQueryStats}");
    624   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
    625   EXPECT_TRUE(url.path().empty());
    626 
    627   // There needs to be a keyword provider.
    628   match.keyword = base::ASCIIToUTF16(kTestTemplateURLKeyword);
    629   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
    630   EXPECT_TRUE(url.path().empty());
    631 
    632   // search_terms_args needs to be set.
    633   match.search_terms_args.reset(
    634       new TemplateURLRef::SearchTermsArgs(base::string16()));
    635   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
    636   EXPECT_TRUE(url.path().empty());
    637 
    638   // assisted_query_stats needs to have been previously set.
    639   match.search_terms_args->assisted_query_stats =
    640       "chrome.0.69i57j69i58j5l2j0l3j69i59";
    641   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
    642   EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j0j0&", url.path());
    643 
    644   // Test field trial triggered bit set.
    645   controller_->search_provider_->field_trial_triggered_in_session_ = true;
    646   EXPECT_TRUE(
    647       controller_->search_provider_->field_trial_triggered_in_session());
    648   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
    649   EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j1j0&", url.path());
    650 
    651   // Test page classification set.
    652   controller_->input_.current_page_classification_ =
    653       metrics::OmniboxEventProto::OTHER;
    654   controller_->search_provider_->field_trial_triggered_in_session_ = false;
    655   EXPECT_FALSE(
    656       controller_->search_provider_->field_trial_triggered_in_session());
    657   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
    658   EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j0j4&", url.path());
    659 
    660   // Test page classification and field trial triggered set.
    661   controller_->search_provider_->field_trial_triggered_in_session_ = true;
    662   EXPECT_TRUE(
    663       controller_->search_provider_->field_trial_triggered_in_session());
    664   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
    665   EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j1j4&", url.path());
    666 }
    667