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