Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / omnibox / autocomplete_result_unittest.cc
1 // Copyright 2014 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_result.h"
6
7 #include <vector>
8
9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "components/metrics/proto/omnibox_event.pb.h"
15 #include "components/omnibox/autocomplete_input.h"
16 #include "components/omnibox/autocomplete_match.h"
17 #include "components/omnibox/autocomplete_match_type.h"
18 #include "components/omnibox/autocomplete_provider.h"
19 #include "components/omnibox/omnibox_field_trial.h"
20 #include "components/omnibox/test_scheme_classifier.h"
21 #include "components/search_engines/template_url_service.h"
22 #include "components/variations/entropy_provider.h"
23 #include "components/variations/variations_associated_data.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using metrics::OmniboxEventProto;
27
28 namespace {
29
30 struct AutocompleteMatchTestData {
31   std::string destination_url;
32   AutocompleteMatch::Type type;
33 };
34
35 const AutocompleteMatchTestData kVerbatimMatches[] = {
36   { "http://search-what-you-typed/",
37     AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
38   { "http://url-what-you-typed/", AutocompleteMatchType::URL_WHAT_YOU_TYPED },
39 };
40
41 const AutocompleteMatchTestData kNonVerbatimMatches[] = {
42   { "http://search-history/", AutocompleteMatchType::SEARCH_HISTORY },
43   { "http://history-title/", AutocompleteMatchType::HISTORY_TITLE },
44 };
45
46 // Adds |count| AutocompleteMatches to |matches|.
47 void PopulateAutocompleteMatchesFromTestData(
48     const AutocompleteMatchTestData* data,
49     size_t count,
50     ACMatches* matches) {
51   ASSERT_TRUE(matches != NULL);
52   for (size_t i = 0; i < count; ++i) {
53     AutocompleteMatch match;
54     match.destination_url = GURL(data[i].destination_url);
55     match.relevance =
56         matches->empty() ? 1300 : (matches->back().relevance - 100);
57     match.allowed_to_be_default_match = true;
58     match.type = data[i].type;
59     matches->push_back(match);
60   }
61 }
62
63 }  // namespace
64
65 class AutocompleteResultTest : public testing::Test  {
66  public:
67   struct TestData {
68     // Used to build a url for the AutocompleteMatch. The URL becomes
69     // "http://" + ('a' + |url_id|) (e.g. an ID of 2 yields "http://b").
70     int url_id;
71
72     // ID of the provider.
73     int provider_id;
74
75     // Relevance score.
76     int relevance;
77
78     // Duplicate matches.
79     std::vector<AutocompleteMatch> duplicate_matches;
80   };
81
82   AutocompleteResultTest() {
83     // Destroy the existing FieldTrialList before creating a new one to avoid
84     // a DCHECK.
85     field_trial_list_.reset();
86     field_trial_list_.reset(new base::FieldTrialList(
87         new metrics::SHA1EntropyProvider("foo")));
88     variations::testing::ClearAllVariationParams();
89   }
90
91   void SetUp() override {
92     template_url_service_.reset(new TemplateURLService(NULL, 0));
93     template_url_service_->Load();
94   }
95
96   // Configures |match| from |data|.
97   static void PopulateAutocompleteMatch(const TestData& data,
98                                         AutocompleteMatch* match);
99
100   // Adds |count| AutocompleteMatches to |matches|.
101   static void PopulateAutocompleteMatches(const TestData* data,
102                                           size_t count,
103                                           ACMatches* matches);
104
105   // Asserts that |result| has |expected_count| matches matching |expected|.
106   void AssertResultMatches(const AutocompleteResult& result,
107                            const TestData* expected,
108                            size_t expected_count);
109
110   // Creates an AutocompleteResult from |last| and |current|. The two are
111   // merged by |CopyOldMatches| and compared by |AssertResultMatches|.
112   void RunCopyOldMatchesTest(const TestData* last, size_t last_size,
113                              const TestData* current, size_t current_size,
114                              const TestData* expected, size_t expected_size);
115
116  protected:
117   scoped_ptr<TemplateURLService> template_url_service_;
118
119  private:
120   scoped_ptr<base::FieldTrialList> field_trial_list_;
121
122   DISALLOW_COPY_AND_ASSIGN(AutocompleteResultTest);
123 };
124
125 // static
126 void AutocompleteResultTest::PopulateAutocompleteMatch(
127     const TestData& data,
128     AutocompleteMatch* match) {
129   match->provider = reinterpret_cast<AutocompleteProvider*>(data.provider_id);
130   match->fill_into_edit = base::IntToString16(data.url_id);
131   std::string url_id(1, data.url_id + 'a');
132   match->destination_url = GURL("http://" + url_id);
133   match->relevance = data.relevance;
134   match->allowed_to_be_default_match = true;
135   match->duplicate_matches = data.duplicate_matches;
136 }
137
138 // static
139 void AutocompleteResultTest::PopulateAutocompleteMatches(
140     const TestData* data,
141     size_t count,
142     ACMatches* matches) {
143   for (size_t i = 0; i < count; ++i) {
144     AutocompleteMatch match;
145     PopulateAutocompleteMatch(data[i], &match);
146     matches->push_back(match);
147   }
148 }
149
150 void AutocompleteResultTest::AssertResultMatches(
151     const AutocompleteResult& result,
152     const TestData* expected,
153     size_t expected_count) {
154   ASSERT_EQ(expected_count, result.size());
155   for (size_t i = 0; i < expected_count; ++i) {
156     AutocompleteMatch expected_match;
157     PopulateAutocompleteMatch(expected[i], &expected_match);
158     const AutocompleteMatch& match = *(result.begin() + i);
159     EXPECT_EQ(expected_match.provider, match.provider) << i;
160     EXPECT_EQ(expected_match.relevance, match.relevance) << i;
161     EXPECT_EQ(expected_match.destination_url.spec(),
162               match.destination_url.spec()) << i;
163   }
164 }
165
166 void AutocompleteResultTest::RunCopyOldMatchesTest(
167     const TestData* last, size_t last_size,
168     const TestData* current, size_t current_size,
169     const TestData* expected, size_t expected_size) {
170   AutocompleteInput input(base::ASCIIToUTF16("a"), base::string16::npos,
171                           std::string(), GURL(),
172                           OmniboxEventProto::INVALID_SPEC, false, false, false,
173                           true,
174                           TestSchemeClassifier());
175
176   ACMatches last_matches;
177   PopulateAutocompleteMatches(last, last_size, &last_matches);
178   AutocompleteResult last_result;
179   last_result.AppendMatches(last_matches);
180   last_result.SortAndCull(input, template_url_service_.get());
181
182   ACMatches current_matches;
183   PopulateAutocompleteMatches(current, current_size, &current_matches);
184   AutocompleteResult current_result;
185   current_result.AppendMatches(current_matches);
186   current_result.SortAndCull(input, template_url_service_.get());
187   current_result.CopyOldMatches(
188       input, last_result, template_url_service_.get());
189
190   AssertResultMatches(current_result, expected, expected_size);
191 }
192
193 // Assertion testing for AutocompleteResult::Swap.
194 TEST_F(AutocompleteResultTest, Swap) {
195   AutocompleteResult r1;
196   AutocompleteResult r2;
197
198   // Swap with empty shouldn't do anything interesting.
199   r1.Swap(&r2);
200   EXPECT_EQ(r1.end(), r1.default_match());
201   EXPECT_EQ(r2.end(), r2.default_match());
202
203   // Swap with a single match.
204   ACMatches matches;
205   AutocompleteMatch match;
206   match.relevance = 1;
207   match.allowed_to_be_default_match = true;
208   AutocompleteInput input(base::ASCIIToUTF16("a"), base::string16::npos,
209                           std::string(), GURL(),
210                           OmniboxEventProto::INVALID_SPEC, false, false, false,
211                           true, TestSchemeClassifier());
212   matches.push_back(match);
213   r1.AppendMatches(matches);
214   r1.SortAndCull(input, template_url_service_.get());
215   EXPECT_EQ(r1.begin(), r1.default_match());
216   EXPECT_EQ("http://a/", r1.alternate_nav_url().spec());
217   r1.Swap(&r2);
218   EXPECT_TRUE(r1.empty());
219   EXPECT_EQ(r1.end(), r1.default_match());
220   EXPECT_TRUE(r1.alternate_nav_url().is_empty());
221   ASSERT_FALSE(r2.empty());
222   EXPECT_EQ(r2.begin(), r2.default_match());
223   EXPECT_EQ("http://a/", r2.alternate_nav_url().spec());
224 }
225
226 // Tests that if the new results have a lower max relevance score than last,
227 // any copied results have their relevance shifted down.
228 TEST_F(AutocompleteResultTest, CopyOldMatches) {
229   TestData last[] = {
230     { 0, 0, 1000 },
231     { 1, 0, 500 },
232   };
233   TestData current[] = {
234     { 2, 0, 400 },
235   };
236   TestData result[] = {
237     { 2, 0, 400 },
238     { 1, 0, 399 },
239   };
240
241   ASSERT_NO_FATAL_FAILURE(RunCopyOldMatchesTest(last, arraysize(last),
242                                                 current, arraysize(current),
243                                                 result, arraysize(result)));
244 }
245
246 // Tests that matches are copied correctly from two distinct providers.
247 TEST_F(AutocompleteResultTest, CopyOldMatches2) {
248   TestData last[] = {
249     { 0, 0, 1000 },
250     { 1, 1, 500 },
251     { 2, 0, 400 },
252     { 3, 1, 300 },
253   };
254   TestData current[] = {
255     { 4, 0, 1100 },
256     { 5, 1, 550 },
257   };
258   TestData result[] = {
259     { 4, 0, 1100 },
260     { 5, 1, 550 },
261     { 2, 0, 400 },
262     { 3, 1, 300 },
263   };
264
265   ASSERT_NO_FATAL_FAILURE(RunCopyOldMatchesTest(last, arraysize(last),
266                                                 current, arraysize(current),
267                                                 result, arraysize(result)));
268 }
269
270 // Tests that matches with empty destination URLs aren't treated as duplicates
271 // and culled.
272 TEST_F(AutocompleteResultTest, SortAndCullEmptyDestinationURLs) {
273   TestData data[] = {
274     { 1, 0, 500 },
275     { 0, 0, 1100 },
276     { 1, 0, 1000 },
277     { 0, 0, 1300 },
278     { 0, 0, 1200 },
279   };
280
281   ACMatches matches;
282   PopulateAutocompleteMatches(data, arraysize(data), &matches);
283   matches[1].destination_url = GURL();
284   matches[3].destination_url = GURL();
285   matches[4].destination_url = GURL();
286
287   AutocompleteResult result;
288   result.AppendMatches(matches);
289   AutocompleteInput input(base::string16(), base::string16::npos,
290                           std::string(), GURL(),
291                           OmniboxEventProto::INVALID_SPEC, false, false, false,
292                           true,
293                           TestSchemeClassifier());
294   result.SortAndCull(input, template_url_service_.get());
295
296   // Of the two results with the same non-empty destination URL, the
297   // lower-relevance one should be dropped.  All of the results with empty URLs
298   // should be kept.
299   ASSERT_EQ(4U, result.size());
300   EXPECT_TRUE(result.match_at(0)->destination_url.is_empty());
301   EXPECT_EQ(1300, result.match_at(0)->relevance);
302   EXPECT_TRUE(result.match_at(1)->destination_url.is_empty());
303   EXPECT_EQ(1200, result.match_at(1)->relevance);
304   EXPECT_TRUE(result.match_at(2)->destination_url.is_empty());
305   EXPECT_EQ(1100, result.match_at(2)->relevance);
306   EXPECT_EQ("http://b/", result.match_at(3)->destination_url.spec());
307   EXPECT_EQ(1000, result.match_at(3)->relevance);
308 }
309
310 TEST_F(AutocompleteResultTest, SortAndCullDuplicateSearchURLs) {
311   // Register a template URL that corresponds to 'foo' search engine.
312   TemplateURLData url_data;
313   url_data.short_name = base::ASCIIToUTF16("unittest");
314   url_data.SetKeyword(base::ASCIIToUTF16("foo"));
315   url_data.SetURL("http://www.foo.com/s?q={searchTerms}");
316   template_url_service_.get()->Add(new TemplateURL(url_data));
317
318   TestData data[] = {
319     { 0, 0, 1300 },
320     { 1, 0, 1200 },
321     { 2, 0, 1100 },
322     { 3, 0, 1000 },
323     { 4, 1, 900 },
324   };
325
326   ACMatches matches;
327   PopulateAutocompleteMatches(data, arraysize(data), &matches);
328   matches[0].destination_url = GURL("http://www.foo.com/s?q=foo");
329   matches[1].destination_url = GURL("http://www.foo.com/s?q=foo2");
330   matches[2].destination_url = GURL("http://www.foo.com/s?q=foo&oq=f");
331   matches[3].destination_url = GURL("http://www.foo.com/s?q=foo&aqs=0");
332   matches[4].destination_url = GURL("http://www.foo.com/");
333
334   AutocompleteResult result;
335   result.AppendMatches(matches);
336   AutocompleteInput input(base::string16(), base::string16::npos,
337                           std::string(), GURL(),
338                           OmniboxEventProto::INVALID_SPEC, false, false, false,
339                           true,
340                           TestSchemeClassifier());
341   result.SortAndCull(input, template_url_service_.get());
342
343   // We expect the 3rd and 4th results to be removed.
344   ASSERT_EQ(3U, result.size());
345   EXPECT_EQ("http://www.foo.com/s?q=foo",
346             result.match_at(0)->destination_url.spec());
347   EXPECT_EQ(1300, result.match_at(0)->relevance);
348   EXPECT_EQ("http://www.foo.com/s?q=foo2",
349             result.match_at(1)->destination_url.spec());
350   EXPECT_EQ(1200, result.match_at(1)->relevance);
351   EXPECT_EQ("http://www.foo.com/",
352             result.match_at(2)->destination_url.spec());
353   EXPECT_EQ(900, result.match_at(2)->relevance);
354 }
355
356 TEST_F(AutocompleteResultTest, SortAndCullWithMatchDups) {
357   // Register a template URL that corresponds to 'foo' search engine.
358   TemplateURLData url_data;
359   url_data.short_name = base::ASCIIToUTF16("unittest");
360   url_data.SetKeyword(base::ASCIIToUTF16("foo"));
361   url_data.SetURL("http://www.foo.com/s?q={searchTerms}");
362   template_url_service_.get()->Add(new TemplateURL(url_data));
363
364   AutocompleteMatch dup_match;
365   dup_match.destination_url = GURL("http://www.foo.com/s?q=foo&oq=dup");
366   std::vector<AutocompleteMatch> dups;
367   dups.push_back(dup_match);
368
369   TestData data[] = {
370     { 0, 0, 1300, dups },
371     { 1, 0, 1200 },
372     { 2, 0, 1100 },
373     { 3, 0, 1000, dups },
374     { 4, 1, 900 },
375     { 5, 0, 800 },
376   };
377
378   ACMatches matches;
379   PopulateAutocompleteMatches(data, arraysize(data), &matches);
380   matches[0].destination_url = GURL("http://www.foo.com/s?q=foo");
381   matches[1].destination_url = GURL("http://www.foo.com/s?q=foo2");
382   matches[2].destination_url = GURL("http://www.foo.com/s?q=foo&oq=f");
383   matches[3].destination_url = GURL("http://www.foo.com/s?q=foo&aqs=0");
384   matches[4].destination_url = GURL("http://www.foo.com/");
385   matches[5].destination_url = GURL("http://www.foo.com/s?q=foo2&oq=f");
386
387   AutocompleteResult result;
388   result.AppendMatches(matches);
389   AutocompleteInput input(base::string16(), base::string16::npos,
390                           std::string(), GURL(),
391                           OmniboxEventProto::INVALID_SPEC, false, false, false,
392                           true,
393                           TestSchemeClassifier());
394   result.SortAndCull(input, template_url_service_.get());
395
396   // Expect 3 unique results after SortAndCull().
397   ASSERT_EQ(3U, result.size());
398
399   // Check that 3rd and 4th result got added to the first result as dups
400   // and also duplicates of the 4th match got copied.
401   ASSERT_EQ(4U, result.match_at(0)->duplicate_matches.size());
402   const AutocompleteMatch* first_match = result.match_at(0);
403   EXPECT_EQ(matches[2].destination_url,
404             first_match->duplicate_matches.at(1).destination_url);
405   EXPECT_EQ(dup_match.destination_url,
406             first_match->duplicate_matches.at(2).destination_url);
407   EXPECT_EQ(matches[3].destination_url,
408             first_match->duplicate_matches.at(3).destination_url);
409
410   // Check that 6th result started a new list of dups for the second result.
411   ASSERT_EQ(1U, result.match_at(1)->duplicate_matches.size());
412   EXPECT_EQ(matches[5].destination_url,
413             result.match_at(1)->duplicate_matches.at(0).destination_url);
414 }
415
416 TEST_F(AutocompleteResultTest, SortAndCullWithDemotionsByType) {
417   // Add some matches.
418   ACMatches matches;
419   const AutocompleteMatchTestData data[] = {
420     { "http://history-url/", AutocompleteMatchType::HISTORY_URL },
421     { "http://search-what-you-typed/",
422       AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
423     { "http://history-title/", AutocompleteMatchType::HISTORY_TITLE },
424     { "http://search-history/", AutocompleteMatchType::SEARCH_HISTORY },
425   };
426   PopulateAutocompleteMatchesFromTestData(data, arraysize(data), &matches);
427
428   // Demote the search history match relevance score.
429   matches.back().relevance = 500;
430
431   // Add a rule demoting history-url and killing history-title.
432   {
433     std::map<std::string, std::string> params;
434     params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":3:*"] =
435         "1:50,7:100,2:0";  // 3 == HOME_PAGE
436     ASSERT_TRUE(variations::AssociateVariationParams(
437         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
438   }
439   base::FieldTrialList::CreateFieldTrial(
440       OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
441
442   AutocompleteResult result;
443   result.AppendMatches(matches);
444   AutocompleteInput input(base::string16(), base::string16::npos,
445                           std::string(), GURL(),
446                           OmniboxEventProto::HOME_PAGE, false, false, false,
447                           true,
448                           TestSchemeClassifier());
449   result.SortAndCull(input, template_url_service_.get());
450
451   // Check the new ordering.  The history-title results should be omitted.
452   // We cannot check relevance scores because the matches are sorted by
453   // demoted relevance but the actual relevance scores are not modified.
454   ASSERT_EQ(3u, result.size());
455   EXPECT_EQ("http://search-what-you-typed/",
456             result.match_at(0)->destination_url.spec());
457   EXPECT_EQ("http://history-url/",
458             result.match_at(1)->destination_url.spec());
459   EXPECT_EQ("http://search-history/",
460             result.match_at(2)->destination_url.spec());
461 }
462
463 TEST_F(AutocompleteResultTest, SortAndCullWithMatchDupsAndDemotionsByType) {
464   // Add some matches.
465   ACMatches matches;
466   const AutocompleteMatchTestData data[] = {
467     { "http://search-what-you-typed/",
468       AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
469     { "http://dup-url/", AutocompleteMatchType::HISTORY_URL },
470     { "http://dup-url/", AutocompleteMatchType::NAVSUGGEST },
471     { "http://search-url/", AutocompleteMatchType::SEARCH_SUGGEST },
472     { "http://history-url/", AutocompleteMatchType::HISTORY_URL },
473   };
474   PopulateAutocompleteMatchesFromTestData(data, arraysize(data), &matches);
475
476   // Add a rule demoting HISTORY_URL.
477   {
478     std::map<std::string, std::string> params;
479     params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":8:*"] =
480         "1:50";  // 8 == INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS
481     ASSERT_TRUE(variations::AssociateVariationParams(
482         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "C", params));
483   }
484   base::FieldTrialList::CreateFieldTrial(
485       OmniboxFieldTrial::kBundledExperimentFieldTrialName, "C");
486
487   {
488     AutocompleteResult result;
489     result.AppendMatches(matches);
490     AutocompleteInput input(
491         base::string16(), base::string16::npos, std::string(), GURL(),
492         OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS, false,
493         false, false, true,
494         TestSchemeClassifier());
495     result.SortAndCull(input, template_url_service_.get());
496
497     // The NAVSUGGEST dup-url stay above search-url since the navsuggest
498     // variant should not be demoted.
499     ASSERT_EQ(4u, result.size());
500     EXPECT_EQ("http://search-what-you-typed/",
501               result.match_at(0)->destination_url.spec());
502     EXPECT_EQ("http://dup-url/",
503               result.match_at(1)->destination_url.spec());
504     EXPECT_EQ(AutocompleteMatchType::NAVSUGGEST,
505               result.match_at(1)->type);
506     EXPECT_EQ("http://search-url/",
507               result.match_at(2)->destination_url.spec());
508     EXPECT_EQ("http://history-url/",
509               result.match_at(3)->destination_url.spec());
510   }
511 }
512
513 TEST_F(AutocompleteResultTest, SortAndCullReorderForDefaultMatch) {
514   TestData data[] = {
515     { 0, 0, 1300 },
516     { 1, 0, 1200 },
517     { 2, 0, 1100 },
518     { 3, 0, 1000 }
519   };
520
521   {
522     // Check that reorder doesn't do anything if the top result
523     // is already a legal default match (which is the default from
524     // PopulateAutocompleteMatches()).
525     ACMatches matches;
526     PopulateAutocompleteMatches(data, arraysize(data), &matches);
527     AutocompleteResult result;
528     result.AppendMatches(matches);
529     AutocompleteInput input(base::string16(), base::string16::npos,
530                             std::string(), GURL(),
531                             OmniboxEventProto::HOME_PAGE, false, false, false,
532                             true,
533                             TestSchemeClassifier());
534     result.SortAndCull(input, template_url_service_.get());
535     AssertResultMatches(result, data, 4);
536   }
537
538   {
539     // Check that reorder swaps up a result appropriately.
540     ACMatches matches;
541     PopulateAutocompleteMatches(data, arraysize(data), &matches);
542     matches[0].allowed_to_be_default_match = false;
543     matches[1].allowed_to_be_default_match = false;
544     AutocompleteResult result;
545     result.AppendMatches(matches);
546     AutocompleteInput input(base::string16(), base::string16::npos,
547                             std::string(), GURL(),
548                             OmniboxEventProto::HOME_PAGE, false, false, false,
549                             true,
550                             TestSchemeClassifier());
551     result.SortAndCull(input, template_url_service_.get());
552     ASSERT_EQ(4U, result.size());
553     EXPECT_EQ("http://c/", result.match_at(0)->destination_url.spec());
554     EXPECT_EQ("http://a/", result.match_at(1)->destination_url.spec());
555     EXPECT_EQ("http://b/", result.match_at(2)->destination_url.spec());
556     EXPECT_EQ("http://d/", result.match_at(3)->destination_url.spec());
557   }
558 }
559
560
561
562 TEST_F(AutocompleteResultTest, SortAndCullWithDisableInlining) {
563   TestData data[] = {
564     { 0, 0, 1300 },
565     { 1, 0, 1200 },
566     { 2, 0, 1100 },
567     { 3, 0, 1000 }
568   };
569
570   {
571     // Check that with the field trial disabled, we keep keep the first match
572     // first even if it has an inline autocompletion.
573     ACMatches matches;
574     PopulateAutocompleteMatches(data, arraysize(data), &matches);
575     matches[0].inline_autocompletion = base::ASCIIToUTF16("completion");
576     AutocompleteResult result;
577     result.AppendMatches(matches);
578     AutocompleteInput input(base::string16(), base::string16::npos,
579                             std::string(), GURL(),
580                             OmniboxEventProto::HOME_PAGE, false, false, false,
581                             true,
582                             TestSchemeClassifier());
583     result.SortAndCull(input, template_url_service_.get());
584     AssertResultMatches(result, data, 4);
585   }
586
587   // Enable the field trial to disable inlining.
588   {
589     std::map<std::string, std::string> params;
590     params[OmniboxFieldTrial::kDisableInliningRule] = "true";
591     ASSERT_TRUE(variations::AssociateVariationParams(
592         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "D", params));
593   }
594   base::FieldTrialList::CreateFieldTrial(
595       OmniboxFieldTrial::kBundledExperimentFieldTrialName, "D");
596
597   {
598     // Now the first match should be demoted past the second.
599     ACMatches matches;
600     PopulateAutocompleteMatches(data, arraysize(data), &matches);
601     matches[0].inline_autocompletion = base::ASCIIToUTF16("completion");
602     AutocompleteResult result;
603     result.AppendMatches(matches);
604     AutocompleteInput input(base::string16(), base::string16::npos,
605                             std::string(), GURL(),
606                             OmniboxEventProto::HOME_PAGE, false, false, false,
607                             true,
608                             TestSchemeClassifier());
609     result.SortAndCull(input, template_url_service_.get());
610     ASSERT_EQ(4U, result.size());
611     EXPECT_EQ("http://b/", result.match_at(0)->destination_url.spec());
612     EXPECT_EQ("http://a/", result.match_at(1)->destination_url.spec());
613     EXPECT_EQ("http://c/", result.match_at(2)->destination_url.spec());
614     EXPECT_EQ("http://d/", result.match_at(3)->destination_url.spec());
615   }
616
617   {
618     // But if there was no inline autocompletion on the first match, then
619     // the order should stay the same.  This is true even if there are
620     // inline autocompletions elsewhere.
621     ACMatches matches;
622     PopulateAutocompleteMatches(data, arraysize(data), &matches);
623     matches[2].inline_autocompletion = base::ASCIIToUTF16("completion");
624     AutocompleteResult result;
625     result.AppendMatches(matches);
626     AutocompleteInput input(base::string16(), base::string16::npos,
627                             std::string(), GURL(),
628                             OmniboxEventProto::HOME_PAGE, false, false, false,
629                             true,
630                             TestSchemeClassifier());
631     result.SortAndCull(input, template_url_service_.get());
632     AssertResultMatches(result, data, 4);
633   }
634
635   {
636     // Try a more complicated situation.
637     ACMatches matches;
638     PopulateAutocompleteMatches(data, arraysize(data), &matches);
639     matches[0].allowed_to_be_default_match = false;
640     matches[1].inline_autocompletion = base::ASCIIToUTF16("completion");
641     AutocompleteResult result;
642     result.AppendMatches(matches);
643     AutocompleteInput input(base::string16(), base::string16::npos,
644                             std::string(), GURL(),
645                             OmniboxEventProto::HOME_PAGE, false, false, false,
646                             true,
647                             TestSchemeClassifier());
648     result.SortAndCull(input, template_url_service_.get());
649     ASSERT_EQ(4U, result.size());
650     EXPECT_EQ("http://c/", result.match_at(0)->destination_url.spec());
651     EXPECT_EQ("http://a/", result.match_at(1)->destination_url.spec());
652     EXPECT_EQ("http://b/", result.match_at(2)->destination_url.spec());
653     EXPECT_EQ("http://d/", result.match_at(3)->destination_url.spec());
654   }
655
656   {
657     // Try another complicated situation.
658     ACMatches matches;
659     PopulateAutocompleteMatches(data, arraysize(data), &matches);
660     matches[0].inline_autocompletion = base::ASCIIToUTF16("completion");
661     matches[1].allowed_to_be_default_match = false;
662     AutocompleteResult result;
663     result.AppendMatches(matches);
664     AutocompleteInput input(base::string16(), base::string16::npos,
665                             std::string(), GURL(),
666                             OmniboxEventProto::HOME_PAGE, false, false, false,
667                             true,
668                             TestSchemeClassifier());
669     result.SortAndCull(input, template_url_service_.get());
670     ASSERT_EQ(4U, result.size());
671     EXPECT_EQ("http://c/", result.match_at(0)->destination_url.spec());
672     EXPECT_EQ("http://a/", result.match_at(1)->destination_url.spec());
673     EXPECT_EQ("http://b/", result.match_at(2)->destination_url.spec());
674     EXPECT_EQ("http://d/", result.match_at(3)->destination_url.spec());
675   }
676
677   {
678     // Check that disaster doesn't strike if we can't demote the top inline
679     // autocompletion because every match either has a completion or isn't
680     // allowed to be the default match.  In this case, we should leave
681     // everything untouched.
682     ACMatches matches;
683     PopulateAutocompleteMatches(data, arraysize(data), &matches);
684     matches[0].inline_autocompletion = base::ASCIIToUTF16("completion");
685     matches[1].allowed_to_be_default_match = false;
686     matches[2].allowed_to_be_default_match = false;
687     matches[3].inline_autocompletion = base::ASCIIToUTF16("completion");
688     AutocompleteResult result;
689     result.AppendMatches(matches);
690     AutocompleteInput input(base::string16(), base::string16::npos,
691                             std::string(), GURL(),
692                             OmniboxEventProto::HOME_PAGE, false, false, false,
693                             true,
694                             TestSchemeClassifier());
695     result.SortAndCull(input, template_url_service_.get());
696     AssertResultMatches(result, data, 4);
697   }
698
699   {
700     // Check a similar situation, except in this case the top match is not
701     // allowed to the default match, so it still needs to be demoted so we
702     // get a legal default match first.  That match will have an inline
703     // autocompletion because we don't have any better options.
704     ACMatches matches;
705     PopulateAutocompleteMatches(data, arraysize(data), &matches);
706     matches[0].allowed_to_be_default_match = false;
707     matches[1].inline_autocompletion = base::ASCIIToUTF16("completion");
708     matches[2].allowed_to_be_default_match = false;
709     matches[3].inline_autocompletion = base::ASCIIToUTF16("completion");
710     AutocompleteResult result;
711     result.AppendMatches(matches);
712     AutocompleteInput input(base::string16(), base::string16::npos,
713                             std::string(), GURL(),
714                             OmniboxEventProto::HOME_PAGE, false, false, false,
715                             true,
716                             TestSchemeClassifier());
717     result.SortAndCull(input, template_url_service_.get());
718     ASSERT_EQ(4U, result.size());
719     EXPECT_EQ("http://b/", result.match_at(0)->destination_url.spec());
720     EXPECT_EQ("http://a/", result.match_at(1)->destination_url.spec());
721     EXPECT_EQ("http://c/", result.match_at(2)->destination_url.spec());
722     EXPECT_EQ("http://d/", result.match_at(3)->destination_url.spec());
723   }
724 }
725
726 TEST_F(AutocompleteResultTest, ShouldHideTopMatch) {
727   base::FieldTrialList::CreateFieldTrial("InstantExtended",
728                                          "Group1 hide_verbatim:1");
729   ACMatches matches;
730
731   // Case 1: Top match is a verbatim match.
732   PopulateAutocompleteMatchesFromTestData(kVerbatimMatches, 1, &matches);
733   AutocompleteResult result;
734   result.AppendMatches(matches);
735   EXPECT_TRUE(result.ShouldHideTopMatch());
736   matches.clear();
737   result.Reset();
738
739   // Case 2: If the verbatim first match is followed by another verbatim match,
740   // don't hide the top verbatim match.
741   PopulateAutocompleteMatchesFromTestData(kVerbatimMatches,
742                                           arraysize(kVerbatimMatches),
743                                           &matches);
744   result.AppendMatches(matches);
745   EXPECT_FALSE(result.ShouldHideTopMatch());
746   matches.clear();
747   result.Reset();
748
749   // Case 3: Top match is not a verbatim match. Do not hide the top match.
750   PopulateAutocompleteMatchesFromTestData(kNonVerbatimMatches, 1, &matches);
751   PopulateAutocompleteMatchesFromTestData(kVerbatimMatches,
752                                           arraysize(kVerbatimMatches),
753                                           &matches);
754   result.AppendMatches(matches);
755   EXPECT_FALSE(result.ShouldHideTopMatch());
756 }
757
758 TEST_F(AutocompleteResultTest, ShouldHideTopMatchAfterCopy) {
759   base::FieldTrialList::CreateFieldTrial("InstantExtended",
760                                          "Group1 hide_verbatim:1");
761   ACMatches matches;
762
763   // Case 1: Top match is a verbatim match followed by only copied matches.
764   PopulateAutocompleteMatchesFromTestData(kVerbatimMatches,
765                                           arraysize(kVerbatimMatches),
766                                           &matches);
767   for (size_t i = 1; i < arraysize(kVerbatimMatches); ++i)
768     matches[i].from_previous = true;
769   AutocompleteResult result;
770   result.AppendMatches(matches);
771   EXPECT_TRUE(result.ShouldHideTopMatch());
772   result.Reset();
773
774   // Case 2: The copied matches are then followed by a non-verbatim match.
775   PopulateAutocompleteMatchesFromTestData(kNonVerbatimMatches, 1, &matches);
776   result.AppendMatches(matches);
777   EXPECT_TRUE(result.ShouldHideTopMatch());
778   result.Reset();
779
780   // Case 3: The copied matches are instead followed by a verbatim match.
781   matches.back().from_previous = true;
782   PopulateAutocompleteMatchesFromTestData(kVerbatimMatches, 1, &matches);
783   result.AppendMatches(matches);
784   EXPECT_FALSE(result.ShouldHideTopMatch());
785 }
786
787 TEST_F(AutocompleteResultTest, DoNotHideTopMatch_FieldTrialFlagDisabled) {
788   // This test config is identical to ShouldHideTopMatch test ("Case 1") except
789   // that the "hide_verbatim" flag is disabled in the field trials.
790   base::FieldTrialList::CreateFieldTrial("InstantExtended",
791                                          "Group1 hide_verbatim:0");
792   ACMatches matches;
793   PopulateAutocompleteMatchesFromTestData(kVerbatimMatches, 1, &matches);
794   AutocompleteResult result;
795   result.AppendMatches(matches);
796   // Field trial flag "hide_verbatim" is disabled. Do not hide top match.
797   EXPECT_FALSE(result.ShouldHideTopMatch());
798 }
799
800 TEST_F(AutocompleteResultTest, TopMatchIsStandaloneVerbatimMatch) {
801   ACMatches matches;
802   AutocompleteResult result;
803   result.AppendMatches(matches);
804
805   // Case 1: Result set is empty.
806   EXPECT_FALSE(result.TopMatchIsStandaloneVerbatimMatch());
807
808   // Case 2: Top match is not a verbatim match.
809   PopulateAutocompleteMatchesFromTestData(kNonVerbatimMatches, 1, &matches);
810   result.AppendMatches(matches);
811   EXPECT_FALSE(result.TopMatchIsStandaloneVerbatimMatch());
812   result.Reset();
813   matches.clear();
814
815   // Case 3: Top match is a verbatim match.
816   PopulateAutocompleteMatchesFromTestData(kVerbatimMatches, 1, &matches);
817   result.AppendMatches(matches);
818   EXPECT_TRUE(result.TopMatchIsStandaloneVerbatimMatch());
819   result.Reset();
820   matches.clear();
821
822   // Case 4: Standalone verbatim match found in AutocompleteResult.
823   PopulateAutocompleteMatchesFromTestData(kVerbatimMatches, 1, &matches);
824   PopulateAutocompleteMatchesFromTestData(kNonVerbatimMatches, 1, &matches);
825   result.AppendMatches(matches);
826   EXPECT_TRUE(result.TopMatchIsStandaloneVerbatimMatch());
827   result.Reset();
828   matches.clear();
829
830   // Case 5: Multiple verbatim matches found in AutocompleteResult.
831   PopulateAutocompleteMatchesFromTestData(kVerbatimMatches,
832                                           arraysize(kVerbatimMatches),
833                                           &matches);
834   result.AppendMatches(matches);
835   EXPECT_FALSE(result.ShouldHideTopMatch());
836 }