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