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"
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
;
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
,
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
);
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
);
66 class AutocompleteResultTest
: public testing::Test
{
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").
73 // ID of the provider.
80 std::vector
<AutocompleteMatch
> duplicate_matches
;
83 AutocompleteResultTest() {
84 // Destroy the existing FieldTrialList before creating a new one to avoid
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 */);
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
,
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
);
122 scoped_ptr
<TemplateURLService
> template_url_service_
;
125 scoped_ptr
<base::FieldTrialList
> field_trial_list_
;
127 DISALLOW_COPY_AND_ASSIGN(AutocompleteResultTest
);
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
;
144 void AutocompleteResultTest::PopulateAutocompleteMatches(
145 const TestData
* data
,
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,
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
, ¤t_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.
205 EXPECT_EQ(r1
.end(), r1
.default_match());
206 EXPECT_EQ(r2
.end(), r2
.default_match());
208 // Swap with a single match.
210 AutocompleteMatch match
;
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());
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
) {
238 TestData current
[] = {
241 TestData result
[] = {
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
) {
260 TestData current
[] = {
264 TestData result
[] = {
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
279 TEST_F(AutocompleteResultTest
, SortAndCullEmptyDestinationURLs
) {
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,
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
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
));
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,
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
);
377 { 0, 0, 1300, dups
},
380 { 3, 0, 1000, dups
},
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,
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
) {
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,
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
) {
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,
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
) {
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()).
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,
540 TestSchemeClassifier());
541 result
.SortAndCull(input
, template_url_service_
.get());
542 AssertResultMatches(result
, data
, 4);
546 // Check that reorder swaps up a result appropriately.
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,
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
) {
578 // Check that with the field trial disabled, we keep keep the first match
579 // first even if it has an inline autocompletion.
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,
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.
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,
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.
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,
637 TestSchemeClassifier());
638 result
.SortAndCull(input
, template_url_service_
.get());
639 AssertResultMatches(result
, data
, 4);
643 // Try a more complicated situation.
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,
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.
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,
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.
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,
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.
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,
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");
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());
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
),
751 result
.AppendMatches(matches
);
752 EXPECT_FALSE(result
.ShouldHideTopMatch());
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
),
761 result
.AppendMatches(matches
);
762 EXPECT_FALSE(result
.ShouldHideTopMatch());
765 TEST_F(AutocompleteResultTest
, ShouldHideTopMatchAfterCopy
) {
766 base::FieldTrialList::CreateFieldTrial("InstantExtended",
767 "Group1 hide_verbatim:1");
770 // Case 1: Top match is a verbatim match followed by only copied matches.
771 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
,
772 arraysize(kVerbatimMatches
),
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());
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());
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");
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
) {
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());
822 // Case 3: Top match is a verbatim match.
823 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
, 1, &matches
);
824 result
.AppendMatches(matches
);
825 EXPECT_TRUE(result
.TopMatchIsStandaloneVerbatimMatch());
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());
837 // Case 5: Multiple verbatim matches found in AutocompleteResult.
838 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
,
839 arraysize(kVerbatimMatches
),
841 result
.AppendMatches(matches
);
842 EXPECT_FALSE(result
.ShouldHideTopMatch());