25b310c4f371f2fb6935c307234f56660b18a811
[platform/framework/web/crosswalk.git] / src / chrome / browser / autocomplete / autocomplete_provider_unittest.cc
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 "components/omnibox/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/chrome_autocomplete_scheme_classifier.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/search_engines/template_url_service_factory.h"
19 #include "chrome/test/base/testing_browser_process.h"
20 #include "chrome/test/base/testing_profile.h"
21 #include "components/metrics/proto/omnibox_event.pb.h"
22 #include "components/omnibox/autocomplete_input.h"
23 #include "components/omnibox/autocomplete_match.h"
24 #include "components/omnibox/autocomplete_provider_listener.h"
25 #include "components/omnibox/keyword_provider.h"
26 #include "components/omnibox/search_provider.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
35 static std::ostream& operator<<(std::ostream& os,
36                                 const AutocompleteResult::const_iterator& it) {
37   return os << static_cast<const AutocompleteMatch*>(&(*it));
38 }
39
40 namespace {
41 const size_t kResultsPerProvider = 3;
42 const 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.
47 class 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
86 void 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
112 void TestProvider::Run() {
113   DCHECK_GT(kResultsPerProvider, 0U);
114   AddResults(1, kResultsPerProvider);
115   done_ = true;
116   DCHECK(listener_);
117   listener_->OnProviderUpdate(true);
118 }
119
120 void 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
128 void 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
159 class 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 base::string16 expected_associated_keyword;
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   // Constructs an AutocompleteResult from |match_data|, sets the |controller_|
189   // to pretend it was running against input |input|, calls the |controller_|'s
190   // UpdateAssociatedKeywords, and checks that the matches have associated
191   // keywords as expected.
192   void RunKeywordTest(const base::string16& input,
193                       const KeywordTestData* match_data,
194                       size_t size);
195
196   void RunAssistedQueryStatsTest(
197       const AssistedQueryStatsTestData* aqs_test_data,
198       size_t size);
199
200   void RunQuery(const base::string16 query);
201
202   void ResetControllerWithKeywordAndSearchProviders();
203   void ResetControllerWithKeywordProvider();
204   void RunExactKeymatchTest(bool allow_exact_keyword_match);
205
206   void CopyResults();
207
208   // Returns match.destination_url as it would be set by
209   // AutocompleteController::UpdateMatchDestinationURL().
210   GURL GetDestinationURL(AutocompleteMatch match,
211                          base::TimeDelta query_formulation_time) const;
212
213   AutocompleteResult result_;
214   scoped_ptr<AutocompleteController> controller_;
215
216  private:
217   // content::NotificationObserver:
218   virtual void Observe(int type,
219                        const content::NotificationSource& source,
220                        const content::NotificationDetails& details) OVERRIDE;
221
222   base::MessageLoopForUI message_loop_;
223   content::NotificationRegistrar registrar_;
224   TestingProfile profile_;
225 };
226
227 void AutocompleteProviderTest::RegisterTemplateURL(
228     const base::string16 keyword,
229     const std::string& template_url) {
230   if (TemplateURLServiceFactory::GetForProfile(&profile_) == NULL) {
231     TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
232         &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
233   }
234   TemplateURLData data;
235   data.SetURL(template_url);
236   data.SetKeyword(keyword);
237   TemplateURL* default_t_url = new TemplateURL(data);
238   TemplateURLService* turl_model =
239       TemplateURLServiceFactory::GetForProfile(&profile_);
240   turl_model->Add(default_t_url);
241   turl_model->SetUserSelectedDefaultSearchProvider(default_t_url);
242   turl_model->Load();
243   TemplateURLID default_provider_id = default_t_url->id();
244   ASSERT_NE(0, default_provider_id);
245 }
246
247 void AutocompleteProviderTest::ResetControllerWithTestProviders(
248     bool same_destinations,
249     TestProvider** provider1_ptr,
250     TestProvider** provider2_ptr) {
251   // TODO: Move it outside this method, after refactoring the existing
252   // unit tests.  Specifically:
253   //   (1) Make sure that AutocompleteMatch.keyword is set iff there is
254   //       a corresponding call to RegisterTemplateURL; otherwise the
255   //       controller flow will crash; this practically means that
256   //       RunTests/ResetControllerXXX/RegisterTemplateURL should
257   //       be coordinated with each other.
258   //   (2) Inject test arguments rather than rely on the hardcoded values, e.g.
259   //       don't rely on kResultsPerProvided and default relevance ordering
260   //       (B > A).
261   RegisterTemplateURL(base::ASCIIToUTF16(kTestTemplateURLKeyword),
262                       "http://aqs/{searchTerms}/{google:assistedQueryStats}");
263
264   AutocompleteController::Providers providers;
265
266   // Construct two new providers, with either the same or different prefixes.
267   TestProvider* provider1 = new TestProvider(
268       kResultsPerProvider,
269       base::ASCIIToUTF16("http://a"),
270       &profile_,
271       base::ASCIIToUTF16(kTestTemplateURLKeyword));
272   providers.push_back(provider1);
273
274   TestProvider* provider2 = new TestProvider(
275       kResultsPerProvider * 2,
276       same_destinations ? base::ASCIIToUTF16("http://a")
277                         : base::ASCIIToUTF16("http://b"),
278       &profile_,
279       base::string16());
280   providers.push_back(provider2);
281
282   // Reset the controller to contain our new providers.
283   controller_.reset(new AutocompleteController(
284       &profile_, TemplateURLServiceFactory::GetForProfile(&profile_), NULL, 0));
285   // We're going to swap the providers vector, but the old vector should be
286   // empty so no elements need to be freed at this point.
287   EXPECT_TRUE(controller_->providers_.empty());
288   controller_->providers_.swap(providers);
289   provider1->set_listener(controller_.get());
290   provider2->set_listener(controller_.get());
291
292   // The providers don't complete synchronously, so listen for "result updated"
293   // notifications.
294   registrar_.Add(this,
295                  chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
296                  content::Source<AutocompleteController>(controller_.get()));
297
298   if (provider1_ptr)
299     *provider1_ptr = provider1;
300   if (provider2_ptr)
301     *provider2_ptr = provider2;
302 }
303
304 void AutocompleteProviderTest::
305     ResetControllerWithKeywordAndSearchProviders() {
306   TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
307       &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
308
309   // Reset the default TemplateURL.
310   TemplateURLData data;
311   data.SetURL("http://defaultturl/{searchTerms}");
312   TemplateURL* default_t_url = new TemplateURL(data);
313   TemplateURLService* turl_model =
314       TemplateURLServiceFactory::GetForProfile(&profile_);
315   turl_model->Add(default_t_url);
316   turl_model->SetUserSelectedDefaultSearchProvider(default_t_url);
317   TemplateURLID default_provider_id = default_t_url->id();
318   ASSERT_NE(0, default_provider_id);
319
320   // Create another TemplateURL for KeywordProvider.
321   TemplateURLData data2;
322   data2.short_name = base::ASCIIToUTF16("k");
323   data2.SetKeyword(base::ASCIIToUTF16("k"));
324   data2.SetURL("http://keyword/{searchTerms}");
325   TemplateURL* keyword_t_url = new TemplateURL(data2);
326   turl_model->Add(keyword_t_url);
327   ASSERT_NE(0, keyword_t_url->id());
328
329   controller_.reset(new AutocompleteController(
330       &profile_, TemplateURLServiceFactory::GetForProfile(&profile_), NULL,
331       AutocompleteProvider::TYPE_KEYWORD | AutocompleteProvider::TYPE_SEARCH));
332 }
333
334 void AutocompleteProviderTest::ResetControllerWithKeywordProvider() {
335   TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
336       &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
337
338   TemplateURLService* turl_model =
339       TemplateURLServiceFactory::GetForProfile(&profile_);
340
341   // Create a TemplateURL for KeywordProvider.
342   TemplateURLData data;
343   data.short_name = base::ASCIIToUTF16("foo.com");
344   data.SetKeyword(base::ASCIIToUTF16("foo.com"));
345   data.SetURL("http://foo.com/{searchTerms}");
346   TemplateURL* keyword_t_url = new TemplateURL(data);
347   turl_model->Add(keyword_t_url);
348   ASSERT_NE(0, keyword_t_url->id());
349
350   // Make a TemplateURL for KeywordProvider that a shorter version of the
351   // first.
352   data.short_name = base::ASCIIToUTF16("f");
353   data.SetKeyword(base::ASCIIToUTF16("f"));
354   data.SetURL("http://f.com/{searchTerms}");
355   keyword_t_url = new TemplateURL(data);
356   turl_model->Add(keyword_t_url);
357   ASSERT_NE(0, keyword_t_url->id());
358
359   // Create another TemplateURL for KeywordProvider.
360   data.short_name = base::ASCIIToUTF16("bar.com");
361   data.SetKeyword(base::ASCIIToUTF16("bar.com"));
362   data.SetURL("http://bar.com/{searchTerms}");
363   keyword_t_url = new TemplateURL(data);
364   turl_model->Add(keyword_t_url);
365   ASSERT_NE(0, keyword_t_url->id());
366
367   controller_.reset(new AutocompleteController(
368       &profile_, TemplateURLServiceFactory::GetForProfile(&profile_), NULL,
369       AutocompleteProvider::TYPE_KEYWORD));
370 }
371
372 void AutocompleteProviderTest::RunTest() {
373   RunQuery(base::ASCIIToUTF16("a"));
374 }
375
376 void AutocompleteProviderTest::RunKeywordTest(const base::string16& input,
377                                               const KeywordTestData* match_data,
378                                               size_t size) {
379   ACMatches matches;
380   for (size_t i = 0; i < size; ++i) {
381     AutocompleteMatch match;
382     match.relevance = 1000;  // Arbitrary non-zero value.
383     match.allowed_to_be_default_match = true;
384     match.fill_into_edit = match_data[i].fill_into_edit;
385     match.transition = ui::PAGE_TRANSITION_KEYWORD;
386     match.keyword = match_data[i].keyword;
387     matches.push_back(match);
388   }
389
390   AutocompleteResult result;
391   result.AppendMatches(matches);
392   controller_->input_ = AutocompleteInput(
393       input, base::string16::npos, base::string16(), GURL(),
394       metrics::OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS,
395       false, true, true, true, ChromeAutocompleteSchemeClassifier(&profile_));
396   controller_->UpdateAssociatedKeywords(&result);
397
398   for (size_t j = 0; j < result.size(); ++j) {
399     EXPECT_EQ(match_data[j].expected_associated_keyword,
400               result.match_at(j)->associated_keyword.get() ?
401                   result.match_at(j)->associated_keyword->keyword :
402                   base::string16());
403   }
404 }
405
406 void AutocompleteProviderTest::RunAssistedQueryStatsTest(
407     const AssistedQueryStatsTestData* aqs_test_data,
408     size_t size) {
409   // Prepare input.
410   const size_t kMaxRelevance = 1000;
411   ACMatches matches;
412   for (size_t i = 0; i < size; ++i) {
413     AutocompleteMatch match(NULL, kMaxRelevance - i, false,
414                             aqs_test_data[i].match_type);
415     match.allowed_to_be_default_match = true;
416     match.keyword = base::ASCIIToUTF16(kTestTemplateURLKeyword);
417     match.search_terms_args.reset(
418         new TemplateURLRef::SearchTermsArgs(base::string16()));
419     matches.push_back(match);
420   }
421   result_.Reset();
422   result_.AppendMatches(matches);
423
424   // Update AQS.
425   controller_->UpdateAssistedQueryStats(&result_);
426
427   // Verify data.
428   for (size_t i = 0; i < size; ++i) {
429     EXPECT_EQ(aqs_test_data[i].expected_aqs,
430               result_.match_at(i)->search_terms_args->assisted_query_stats);
431   }
432 }
433
434 void AutocompleteProviderTest::RunQuery(const base::string16 query) {
435   result_.Reset();
436   controller_->Start(AutocompleteInput(
437       query, base::string16::npos, base::string16(), GURL(),
438       metrics::OmniboxEventProto::INVALID_SPEC, true, false, true, true,
439       ChromeAutocompleteSchemeClassifier(&profile_)));
440
441   if (!controller_->done())
442     // The message loop will terminate when all autocomplete input has been
443     // collected.
444     base::MessageLoop::current()->Run();
445 }
446
447 void AutocompleteProviderTest::RunExactKeymatchTest(
448     bool allow_exact_keyword_match) {
449   // Send the controller input which exactly matches the keyword provider we
450   // created in ResetControllerWithKeywordAndSearchProviders().  The default
451   // match should thus be a search-other-engine match iff
452   // |allow_exact_keyword_match| is true.  Regardless, the match should
453   // be from SearchProvider.  (It provides all verbatim search matches,
454   // keyword or not.)
455   controller_->Start(AutocompleteInput(
456       base::ASCIIToUTF16("k test"), base::string16::npos, base::string16(),
457       GURL(), metrics::OmniboxEventProto::INVALID_SPEC, true, false,
458       allow_exact_keyword_match, false,
459       ChromeAutocompleteSchemeClassifier(&profile_)));
460   EXPECT_TRUE(controller_->done());
461   EXPECT_EQ(AutocompleteProvider::TYPE_SEARCH,
462       controller_->result().default_match()->provider->type());
463   EXPECT_EQ(allow_exact_keyword_match ?
464       AutocompleteMatchType::SEARCH_OTHER_ENGINE :
465       AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
466       controller_->result().default_match()->type);
467 }
468
469 void AutocompleteProviderTest::CopyResults() {
470   result_.CopyFrom(controller_->result());
471 }
472
473 GURL AutocompleteProviderTest::GetDestinationURL(
474     AutocompleteMatch match,
475     base::TimeDelta query_formulation_time) const {
476   controller_->UpdateMatchDestinationURLWithQueryFormulationTime(
477       query_formulation_time, &match);
478   return match.destination_url;
479 }
480
481 void AutocompleteProviderTest::Observe(
482     int type,
483     const content::NotificationSource& source,
484     const content::NotificationDetails& details) {
485   if (controller_->done()) {
486     CopyResults();
487     base::MessageLoop::current()->Quit();
488   }
489 }
490
491 // Tests that the default selection is set properly when updating results.
492 TEST_F(AutocompleteProviderTest, Query) {
493   TestProvider* provider1 = NULL;
494   TestProvider* provider2 = NULL;
495   ResetControllerWithTestProviders(false, &provider1, &provider2);
496   RunTest();
497
498   // Make sure the default match gets set to the highest relevance match.  The
499   // highest relevance matches should come from the second provider.
500   EXPECT_EQ(kResultsPerProvider * 2, result_.size());
501   ASSERT_NE(result_.end(), result_.default_match());
502   EXPECT_EQ(provider2, result_.default_match()->provider);
503 }
504
505 // Tests assisted query stats.
506 TEST_F(AutocompleteProviderTest, AssistedQueryStats) {
507   ResetControllerWithTestProviders(false, NULL, NULL);
508   RunTest();
509
510   ASSERT_EQ(kResultsPerProvider * 2, result_.size());
511
512   // Now, check the results from the second provider, as they should not have
513   // assisted query stats set.
514   for (size_t i = 0; i < kResultsPerProvider; ++i) {
515     EXPECT_TRUE(
516         result_.match_at(i)->search_terms_args->assisted_query_stats.empty());
517   }
518   // The first provider has a test keyword, so AQS should be non-empty.
519   for (size_t i = kResultsPerProvider; i < kResultsPerProvider * 2; ++i) {
520     EXPECT_FALSE(
521         result_.match_at(i)->search_terms_args->assisted_query_stats.empty());
522   }
523 }
524
525 TEST_F(AutocompleteProviderTest, RemoveDuplicates) {
526   TestProvider* provider1 = NULL;
527   TestProvider* provider2 = NULL;
528   ResetControllerWithTestProviders(true, &provider1, &provider2);
529   RunTest();
530
531   // Make sure all the first provider's results were eliminated by the second
532   // provider's.
533   EXPECT_EQ(kResultsPerProvider, result_.size());
534   for (AutocompleteResult::const_iterator i(result_.begin());
535        i != result_.end(); ++i)
536     EXPECT_EQ(provider2, i->provider);
537 }
538
539 TEST_F(AutocompleteProviderTest, AllowExactKeywordMatch) {
540   ResetControllerWithKeywordAndSearchProviders();
541   RunExactKeymatchTest(true);
542   RunExactKeymatchTest(false);
543 }
544
545 // Ensures matches from (only) the default search provider respect any extra
546 // query params set on the command line.
547 TEST_F(AutocompleteProviderTest, ExtraQueryParams) {
548   ResetControllerWithKeywordAndSearchProviders();
549   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
550       switches::kExtraSearchQueryParams, "a=b");
551   RunExactKeymatchTest(true);
552   CopyResults();
553   ASSERT_EQ(2U, result_.size());
554   EXPECT_EQ("http://keyword/test",
555             result_.match_at(0)->destination_url.possibly_invalid_spec());
556   EXPECT_EQ("http://defaultturl/k%20test?a=b",
557             result_.match_at(1)->destination_url.possibly_invalid_spec());
558 }
559
560 // Test that redundant associated keywords are removed.
561 TEST_F(AutocompleteProviderTest, RedundantKeywordsIgnoredInResult) {
562   ResetControllerWithKeywordProvider();
563
564   {
565     KeywordTestData duplicate_url[] = {
566       { base::ASCIIToUTF16("fo"), base::string16(), base::string16() },
567       { base::ASCIIToUTF16("foo.com"), base::string16(),
568         base::ASCIIToUTF16("foo.com") },
569       { base::ASCIIToUTF16("foo.com"), base::string16(), base::string16() }
570     };
571
572     SCOPED_TRACE("Duplicate url");
573     RunKeywordTest(base::ASCIIToUTF16("fo"), duplicate_url,
574                    ARRAYSIZE_UNSAFE(duplicate_url));
575   }
576
577   {
578     KeywordTestData keyword_match[] = {
579       { base::ASCIIToUTF16("foo.com"), base::ASCIIToUTF16("foo.com"),
580         base::string16() },
581       { base::ASCIIToUTF16("foo.com"), base::string16(), base::string16() }
582     };
583
584     SCOPED_TRACE("Duplicate url with keyword match");
585     RunKeywordTest(base::ASCIIToUTF16("fo"), keyword_match,
586                    ARRAYSIZE_UNSAFE(keyword_match));
587   }
588
589   {
590     KeywordTestData multiple_keyword[] = {
591       { base::ASCIIToUTF16("fo"), base::string16(), base::string16() },
592       { base::ASCIIToUTF16("foo.com"), base::string16(),
593         base::ASCIIToUTF16("foo.com") },
594       { base::ASCIIToUTF16("foo.com"), base::string16(), base::string16() },
595       { base::ASCIIToUTF16("bar.com"), base::string16(),
596         base::ASCIIToUTF16("bar.com") },
597     };
598
599     SCOPED_TRACE("Duplicate url with multiple keywords");
600     RunKeywordTest(base::ASCIIToUTF16("fo"), multiple_keyword,
601                    ARRAYSIZE_UNSAFE(multiple_keyword));
602   }
603 }
604
605 // Test that exact match keywords trump keywords associated with
606 // the match.
607 TEST_F(AutocompleteProviderTest, ExactMatchKeywords) {
608   ResetControllerWithKeywordProvider();
609
610   {
611     KeywordTestData keyword_match[] = {
612       { base::ASCIIToUTF16("foo.com"), base::string16(),
613         base::ASCIIToUTF16("foo.com") }
614     };
615
616     SCOPED_TRACE("keyword match as usual");
617     RunKeywordTest(base::ASCIIToUTF16("fo"), keyword_match,
618                    ARRAYSIZE_UNSAFE(keyword_match));
619   }
620
621   // The same result set with an input of "f" (versus "fo") should get
622   // a different associated keyword because "f" is an exact match for
623   // a keyword and that should trump the keyword normally associated with
624   // this match.
625   {
626     KeywordTestData keyword_match[] = {
627       { base::ASCIIToUTF16("foo.com"), base::string16(),
628         base::ASCIIToUTF16("f") }
629     };
630
631     SCOPED_TRACE("keyword exact match");
632     RunKeywordTest(base::ASCIIToUTF16("f"), keyword_match,
633                    ARRAYSIZE_UNSAFE(keyword_match));
634   }
635 }
636
637 TEST_F(AutocompleteProviderTest, UpdateAssistedQueryStats) {
638   ResetControllerWithTestProviders(false, NULL, NULL);
639
640   {
641     AssistedQueryStatsTestData test_data[] = {
642       //  MSVC doesn't support zero-length arrays, so supply some dummy data.
643       { AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, "" }
644     };
645     SCOPED_TRACE("No matches");
646     // Note: We pass 0 here to ignore the dummy data above.
647     RunAssistedQueryStatsTest(test_data, 0);
648   }
649
650   {
651     AssistedQueryStatsTestData test_data[] = {
652       { AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, "chrome..69i57" }
653     };
654     SCOPED_TRACE("One match");
655     RunAssistedQueryStatsTest(test_data, ARRAYSIZE_UNSAFE(test_data));
656   }
657
658   {
659     AssistedQueryStatsTestData test_data[] = {
660       { AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
661         "chrome..69i57j69i58j5l2j0l3j69i59" },
662       { AutocompleteMatchType::URL_WHAT_YOU_TYPED,
663         "chrome..69i57j69i58j5l2j0l3j69i59" },
664       { AutocompleteMatchType::NAVSUGGEST,
665         "chrome.2.69i57j69i58j5l2j0l3j69i59" },
666       { AutocompleteMatchType::NAVSUGGEST,
667         "chrome.3.69i57j69i58j5l2j0l3j69i59" },
668       { AutocompleteMatchType::SEARCH_SUGGEST,
669         "chrome.4.69i57j69i58j5l2j0l3j69i59" },
670       { AutocompleteMatchType::SEARCH_SUGGEST,
671         "chrome.5.69i57j69i58j5l2j0l3j69i59" },
672       { AutocompleteMatchType::SEARCH_SUGGEST,
673         "chrome.6.69i57j69i58j5l2j0l3j69i59" },
674       { AutocompleteMatchType::SEARCH_HISTORY,
675         "chrome.7.69i57j69i58j5l2j0l3j69i59" },
676     };
677     SCOPED_TRACE("Multiple matches");
678     RunAssistedQueryStatsTest(test_data, ARRAYSIZE_UNSAFE(test_data));
679   }
680 }
681
682 TEST_F(AutocompleteProviderTest, GetDestinationURL) {
683   ResetControllerWithKeywordAndSearchProviders();
684
685   // For the destination URL to have aqs parameters for query formulation time
686   // and the field trial triggered bit, many conditions need to be satisfied.
687   AutocompleteMatch match(NULL, 1100, false,
688                           AutocompleteMatchType::SEARCH_SUGGEST);
689   GURL url(GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456)));
690   EXPECT_TRUE(url.path().empty());
691
692   // The protocol needs to be https.
693   RegisterTemplateURL(base::ASCIIToUTF16(kTestTemplateURLKeyword),
694                       "https://aqs/{searchTerms}/{google:assistedQueryStats}");
695   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
696   EXPECT_TRUE(url.path().empty());
697
698   // There needs to be a keyword provider.
699   match.keyword = base::ASCIIToUTF16(kTestTemplateURLKeyword);
700   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
701   EXPECT_TRUE(url.path().empty());
702
703   // search_terms_args needs to be set.
704   match.search_terms_args.reset(
705       new TemplateURLRef::SearchTermsArgs(base::string16()));
706   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
707   EXPECT_TRUE(url.path().empty());
708
709   // assisted_query_stats needs to have been previously set.
710   match.search_terms_args->assisted_query_stats =
711       "chrome.0.69i57j69i58j5l2j0l3j69i59";
712   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
713   EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j0j0&", url.path());
714
715   // Test field trial triggered bit set.
716   controller_->search_provider_->field_trial_triggered_in_session_ = true;
717   EXPECT_TRUE(
718       controller_->search_provider_->field_trial_triggered_in_session());
719   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
720   EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j1j0&", url.path());
721
722   // Test page classification set.
723   controller_->input_.current_page_classification_ =
724       metrics::OmniboxEventProto::OTHER;
725   controller_->search_provider_->field_trial_triggered_in_session_ = false;
726   EXPECT_FALSE(
727       controller_->search_provider_->field_trial_triggered_in_session());
728   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
729   EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j0j4&", url.path());
730
731   // Test page classification and field trial triggered set.
732   controller_->search_provider_->field_trial_triggered_in_session_ = true;
733   EXPECT_TRUE(
734       controller_->search_provider_->field_trial_triggered_in_session());
735   url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456));
736   EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j1j4&", url.path());
737 }