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_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"
26 using metrics::OmniboxEventProto
;
30 struct AutocompleteMatchTestData
{
31 std::string destination_url
;
32 AutocompleteMatch::Type type
;
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
},
41 const AutocompleteMatchTestData kNonVerbatimMatches
[] = {
42 { "http://search-history/", AutocompleteMatchType::SEARCH_HISTORY
},
43 { "http://history-title/", AutocompleteMatchType::HISTORY_TITLE
},
46 // Adds |count| AutocompleteMatches to |matches|.
47 void PopulateAutocompleteMatchesFromTestData(
48 const AutocompleteMatchTestData
* data
,
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
);
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
);
63 // A simple AutocompleteProvider that does nothing.
64 class MockAutocompleteProvider
: public AutocompleteProvider
{
66 MockAutocompleteProvider(Type type
): AutocompleteProvider(type
) {}
68 void Start(const AutocompleteInput
& input
,
70 bool called_due_to_focus
) override
{}
73 ~MockAutocompleteProvider() override
{}
78 class AutocompleteResultTest
: public testing::Test
{
81 // Used to build a url for the AutocompleteMatch. The URL becomes
82 // "http://" + ('a' + |url_id|) (e.g. an ID of 2 yields "http://b").
85 // ID of the provider.
91 // Allowed to be default match status.
92 bool allowed_to_be_default_match
;
95 std::vector
<AutocompleteMatch
> duplicate_matches
;
98 AutocompleteResultTest() {
99 // Destroy the existing FieldTrialList before creating a new one to avoid
101 field_trial_list_
.reset();
102 field_trial_list_
.reset(new base::FieldTrialList(
103 new metrics::SHA1EntropyProvider("foo")));
104 variations::testing::ClearAllVariationParams();
106 // Create the list of mock providers. 5 is enough.
107 for (size_t i
= 0; i
< 5; ++i
) {
108 mock_provider_list_
.push_back(new MockAutocompleteProvider(
109 static_cast<AutocompleteProvider::Type
>(i
)));
113 void SetUp() override
{
114 template_url_service_
.reset(new TemplateURLService(NULL
, 0));
115 template_url_service_
->Load();
118 // Configures |match| from |data|.
119 void PopulateAutocompleteMatch(const TestData
& data
,
120 AutocompleteMatch
* match
);
122 // Adds |count| AutocompleteMatches to |matches|.
123 void PopulateAutocompleteMatches(const TestData
* data
,
127 // Asserts that |result| has |expected_count| matches matching |expected|.
128 void AssertResultMatches(const AutocompleteResult
& result
,
129 const TestData
* expected
,
130 size_t expected_count
);
132 // Creates an AutocompleteResult from |last| and |current|. The two are
133 // merged by |CopyOldMatches| and compared by |AssertResultMatches|.
134 void RunCopyOldMatchesTest(const TestData
* last
, size_t last_size
,
135 const TestData
* current
, size_t current_size
,
136 const TestData
* expected
, size_t expected_size
);
138 // Returns a (mock) AutocompleteProvider of given |provider_id|.
139 MockAutocompleteProvider
* GetProvider(int provider_id
) {
140 EXPECT_LT(provider_id
, static_cast<int>(mock_provider_list_
.size()));
141 return mock_provider_list_
[provider_id
].get();
145 scoped_ptr
<TemplateURLService
> template_url_service_
;
148 scoped_ptr
<base::FieldTrialList
> field_trial_list_
;
150 // For every provider mentioned in TestData, we need a mock provider.
151 std::vector
<scoped_refptr
<MockAutocompleteProvider
> > mock_provider_list_
;
153 DISALLOW_COPY_AND_ASSIGN(AutocompleteResultTest
);
156 void AutocompleteResultTest::PopulateAutocompleteMatch(
157 const TestData
& data
,
158 AutocompleteMatch
* match
) {
159 match
->provider
= GetProvider(data
.provider_id
);
160 match
->fill_into_edit
= base::IntToString16(data
.url_id
);
161 std::string
url_id(1, data
.url_id
+ 'a');
162 match
->destination_url
= GURL("http://" + url_id
);
163 match
->relevance
= data
.relevance
;
164 match
->allowed_to_be_default_match
= data
.allowed_to_be_default_match
;
165 match
->duplicate_matches
= data
.duplicate_matches
;
168 void AutocompleteResultTest::PopulateAutocompleteMatches(
169 const TestData
* data
,
171 ACMatches
* matches
) {
172 for (size_t i
= 0; i
< count
; ++i
) {
173 AutocompleteMatch match
;
174 PopulateAutocompleteMatch(data
[i
], &match
);
175 matches
->push_back(match
);
179 void AutocompleteResultTest::AssertResultMatches(
180 const AutocompleteResult
& result
,
181 const TestData
* expected
,
182 size_t expected_count
) {
183 ASSERT_EQ(expected_count
, result
.size());
184 for (size_t i
= 0; i
< expected_count
; ++i
) {
185 AutocompleteMatch expected_match
;
186 PopulateAutocompleteMatch(expected
[i
], &expected_match
);
187 const AutocompleteMatch
& match
= *(result
.begin() + i
);
188 EXPECT_EQ(expected_match
.provider
, match
.provider
) << i
;
189 EXPECT_EQ(expected_match
.relevance
, match
.relevance
) << i
;
190 EXPECT_EQ(expected_match
.allowed_to_be_default_match
,
191 match
.allowed_to_be_default_match
) << i
;
192 EXPECT_EQ(expected_match
.destination_url
.spec(),
193 match
.destination_url
.spec()) << i
;
197 void AutocompleteResultTest::RunCopyOldMatchesTest(
198 const TestData
* last
, size_t last_size
,
199 const TestData
* current
, size_t current_size
,
200 const TestData
* expected
, size_t expected_size
) {
201 AutocompleteInput
input(base::ASCIIToUTF16("a"), base::string16::npos
,
202 std::string(), GURL(),
203 OmniboxEventProto::INVALID_SPEC
, false, false, false,
205 TestSchemeClassifier());
207 ACMatches last_matches
;
208 PopulateAutocompleteMatches(last
, last_size
, &last_matches
);
209 AutocompleteResult last_result
;
210 last_result
.AppendMatches(last_matches
);
211 last_result
.SortAndCull(input
, template_url_service_
.get());
213 ACMatches current_matches
;
214 PopulateAutocompleteMatches(current
, current_size
, ¤t_matches
);
215 AutocompleteResult current_result
;
216 current_result
.AppendMatches(current_matches
);
217 current_result
.SortAndCull(input
, template_url_service_
.get());
218 current_result
.CopyOldMatches(
219 input
, last_result
, template_url_service_
.get());
221 AssertResultMatches(current_result
, expected
, expected_size
);
224 // Assertion testing for AutocompleteResult::Swap.
225 TEST_F(AutocompleteResultTest
, Swap
) {
226 AutocompleteResult r1
;
227 AutocompleteResult r2
;
229 // Swap with empty shouldn't do anything interesting.
231 EXPECT_EQ(r1
.end(), r1
.default_match());
232 EXPECT_EQ(r2
.end(), r2
.default_match());
234 // Swap with a single match.
236 AutocompleteMatch match
;
238 match
.allowed_to_be_default_match
= true;
239 AutocompleteInput
input(base::ASCIIToUTF16("a"), base::string16::npos
,
240 std::string(), GURL(),
241 OmniboxEventProto::INVALID_SPEC
, false, false, false,
242 true, TestSchemeClassifier());
243 matches
.push_back(match
);
244 r1
.AppendMatches(matches
);
245 r1
.SortAndCull(input
, template_url_service_
.get());
246 EXPECT_EQ(r1
.begin(), r1
.default_match());
247 EXPECT_EQ("http://a/", r1
.alternate_nav_url().spec());
249 EXPECT_TRUE(r1
.empty());
250 EXPECT_EQ(r1
.end(), r1
.default_match());
251 EXPECT_TRUE(r1
.alternate_nav_url().is_empty());
252 ASSERT_FALSE(r2
.empty());
253 EXPECT_EQ(r2
.begin(), r2
.default_match());
254 EXPECT_EQ("http://a/", r2
.alternate_nav_url().spec());
257 // Tests that if the new results have a lower max relevance score than last,
258 // any copied results have their relevance shifted down.
259 TEST_F(AutocompleteResultTest
, CopyOldMatches
) {
261 { 0, 1, 1000, true },
264 TestData current
[] = {
267 TestData result
[] = {
272 ASSERT_NO_FATAL_FAILURE(RunCopyOldMatchesTest(last
, arraysize(last
),
273 current
, arraysize(current
),
274 result
, arraysize(result
)));
277 // Tests that if the new results have a lower max relevance score than last,
278 // any copied results have their relevance shifted down when the allowed to
279 // be default constraint comes into play.
280 TEST_F(AutocompleteResultTest
, CopyOldMatchesAllowedToBeDefault
) {
282 { 0, 1, 1300, true },
283 { 1, 1, 1200, true },
284 { 2, 1, 1100, true },
286 TestData current
[] = {
287 { 3, 1, 1000, false },
290 // The expected results are out of relevance order because the top-scoring
291 // allowed to be default match is always pulled to the top.
292 TestData result
[] = {
294 { 3, 1, 1000, false },
298 ASSERT_NO_FATAL_FAILURE(RunCopyOldMatchesTest(last
, arraysize(last
),
299 current
, arraysize(current
),
300 result
, arraysize(result
)));
303 // Tests that matches are copied correctly from two distinct providers.
304 TEST_F(AutocompleteResultTest
, CopyOldMatchesMultipleProviders
) {
306 { 0, 1, 1300, false },
307 { 1, 2, 1250, true },
308 { 2, 1, 1200, false },
309 { 3, 2, 1150, true },
310 { 4, 1, 1100, false },
312 TestData current
[] = {
313 { 5, 1, 1000, false },
317 // The expected results are out of relevance order because the top-scoring
318 // allowed to be default match is always pulled to the top.
319 TestData result
[] = {
321 { 5, 1, 1000, false },
324 { 4, 1, 499, false },
327 ASSERT_NO_FATAL_FAILURE(RunCopyOldMatchesTest(last
, arraysize(last
),
328 current
, arraysize(current
),
329 result
, arraysize(result
)));
332 // Tests that matches are copied correctly from two distinct providers when
333 // one provider doesn't have a current legal default match.
334 TEST_F(AutocompleteResultTest
, CopyOldMatchesWithOneProviderWithoutDefault
) {
336 { 0, 2, 1250, true },
337 { 1, 2, 1150, true },
338 { 2, 1, 900, false },
339 { 3, 1, 800, false },
340 { 4, 1, 700, false },
342 TestData current
[] = {
343 { 5, 1, 1000, true },
344 { 6, 2, 800, false },
347 TestData result
[] = {
348 { 5, 1, 1000, true },
350 { 6, 2, 800, false },
351 { 4, 1, 700, false },
355 ASSERT_NO_FATAL_FAILURE(RunCopyOldMatchesTest(last
, arraysize(last
),
356 current
, arraysize(current
),
357 result
, arraysize(result
)));
360 // Tests that matches with empty destination URLs aren't treated as duplicates
362 TEST_F(AutocompleteResultTest
, SortAndCullEmptyDestinationURLs
) {
365 { 0, 1, 1100, true },
366 { 1, 1, 1000, true },
367 { 0, 1, 1300, true },
368 { 0, 1, 1200, true },
372 PopulateAutocompleteMatches(data
, arraysize(data
), &matches
);
373 matches
[1].destination_url
= GURL();
374 matches
[3].destination_url
= GURL();
375 matches
[4].destination_url
= GURL();
377 AutocompleteResult result
;
378 result
.AppendMatches(matches
);
379 AutocompleteInput
input(base::string16(), base::string16::npos
,
380 std::string(), GURL(),
381 OmniboxEventProto::INVALID_SPEC
, false, false, false,
383 TestSchemeClassifier());
384 result
.SortAndCull(input
, template_url_service_
.get());
386 // Of the two results with the same non-empty destination URL, the
387 // lower-relevance one should be dropped. All of the results with empty URLs
389 ASSERT_EQ(4U, result
.size());
390 EXPECT_TRUE(result
.match_at(0)->destination_url
.is_empty());
391 EXPECT_EQ(1300, result
.match_at(0)->relevance
);
392 EXPECT_TRUE(result
.match_at(1)->destination_url
.is_empty());
393 EXPECT_EQ(1200, result
.match_at(1)->relevance
);
394 EXPECT_TRUE(result
.match_at(2)->destination_url
.is_empty());
395 EXPECT_EQ(1100, result
.match_at(2)->relevance
);
396 EXPECT_EQ("http://b/", result
.match_at(3)->destination_url
.spec());
397 EXPECT_EQ(1000, result
.match_at(3)->relevance
);
400 TEST_F(AutocompleteResultTest
, SortAndCullDuplicateSearchURLs
) {
401 // Register a template URL that corresponds to 'foo' search engine.
402 TemplateURLData url_data
;
403 url_data
.short_name
= base::ASCIIToUTF16("unittest");
404 url_data
.SetKeyword(base::ASCIIToUTF16("foo"));
405 url_data
.SetURL("http://www.foo.com/s?q={searchTerms}");
406 template_url_service_
.get()->Add(new TemplateURL(url_data
));
409 { 0, 1, 1300, true },
410 { 1, 1, 1200, true },
411 { 2, 1, 1100, true },
412 { 3, 1, 1000, true },
417 PopulateAutocompleteMatches(data
, arraysize(data
), &matches
);
418 matches
[0].destination_url
= GURL("http://www.foo.com/s?q=foo");
419 matches
[1].destination_url
= GURL("http://www.foo.com/s?q=foo2");
420 matches
[2].destination_url
= GURL("http://www.foo.com/s?q=foo&oq=f");
421 matches
[3].destination_url
= GURL("http://www.foo.com/s?q=foo&aqs=0");
422 matches
[4].destination_url
= GURL("http://www.foo.com/");
424 AutocompleteResult result
;
425 result
.AppendMatches(matches
);
426 AutocompleteInput
input(base::string16(), base::string16::npos
,
427 std::string(), GURL(),
428 OmniboxEventProto::INVALID_SPEC
, false, false, false,
430 TestSchemeClassifier());
431 result
.SortAndCull(input
, template_url_service_
.get());
433 // We expect the 3rd and 4th results to be removed.
434 ASSERT_EQ(3U, result
.size());
435 EXPECT_EQ("http://www.foo.com/s?q=foo",
436 result
.match_at(0)->destination_url
.spec());
437 EXPECT_EQ(1300, result
.match_at(0)->relevance
);
438 EXPECT_EQ("http://www.foo.com/s?q=foo2",
439 result
.match_at(1)->destination_url
.spec());
440 EXPECT_EQ(1200, result
.match_at(1)->relevance
);
441 EXPECT_EQ("http://www.foo.com/",
442 result
.match_at(2)->destination_url
.spec());
443 EXPECT_EQ(900, result
.match_at(2)->relevance
);
446 TEST_F(AutocompleteResultTest
, SortAndCullWithMatchDups
) {
447 // Register a template URL that corresponds to 'foo' search engine.
448 TemplateURLData url_data
;
449 url_data
.short_name
= base::ASCIIToUTF16("unittest");
450 url_data
.SetKeyword(base::ASCIIToUTF16("foo"));
451 url_data
.SetURL("http://www.foo.com/s?q={searchTerms}");
452 template_url_service_
.get()->Add(new TemplateURL(url_data
));
454 AutocompleteMatch dup_match
;
455 dup_match
.destination_url
= GURL("http://www.foo.com/s?q=foo&oq=dup");
456 std::vector
<AutocompleteMatch
> dups
;
457 dups
.push_back(dup_match
);
460 { 0, 1, 1300, true, dups
},
461 { 1, 1, 1200, true },
462 { 2, 1, 1100, true },
463 { 3, 1, 1000, true, dups
},
469 PopulateAutocompleteMatches(data
, arraysize(data
), &matches
);
470 matches
[0].destination_url
= GURL("http://www.foo.com/s?q=foo");
471 matches
[1].destination_url
= GURL("http://www.foo.com/s?q=foo2");
472 matches
[2].destination_url
= GURL("http://www.foo.com/s?q=foo&oq=f");
473 matches
[3].destination_url
= GURL("http://www.foo.com/s?q=foo&aqs=0");
474 matches
[4].destination_url
= GURL("http://www.foo.com/");
475 matches
[5].destination_url
= GURL("http://www.foo.com/s?q=foo2&oq=f");
477 AutocompleteResult result
;
478 result
.AppendMatches(matches
);
479 AutocompleteInput
input(base::string16(), base::string16::npos
,
480 std::string(), GURL(),
481 OmniboxEventProto::INVALID_SPEC
, false, false, false,
483 TestSchemeClassifier());
484 result
.SortAndCull(input
, template_url_service_
.get());
486 // Expect 3 unique results after SortAndCull().
487 ASSERT_EQ(3U, result
.size());
489 // Check that 3rd and 4th result got added to the first result as dups
490 // and also duplicates of the 4th match got copied.
491 ASSERT_EQ(4U, result
.match_at(0)->duplicate_matches
.size());
492 const AutocompleteMatch
* first_match
= result
.match_at(0);
493 EXPECT_EQ(matches
[2].destination_url
,
494 first_match
->duplicate_matches
.at(1).destination_url
);
495 EXPECT_EQ(dup_match
.destination_url
,
496 first_match
->duplicate_matches
.at(2).destination_url
);
497 EXPECT_EQ(matches
[3].destination_url
,
498 first_match
->duplicate_matches
.at(3).destination_url
);
500 // Check that 6th result started a new list of dups for the second result.
501 ASSERT_EQ(1U, result
.match_at(1)->duplicate_matches
.size());
502 EXPECT_EQ(matches
[5].destination_url
,
503 result
.match_at(1)->duplicate_matches
.at(0).destination_url
);
506 TEST_F(AutocompleteResultTest
, SortAndCullWithDemotionsByType
) {
509 const AutocompleteMatchTestData data
[] = {
510 { "http://history-url/", AutocompleteMatchType::HISTORY_URL
},
511 { "http://search-what-you-typed/",
512 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
513 { "http://history-title/", AutocompleteMatchType::HISTORY_TITLE
},
514 { "http://search-history/", AutocompleteMatchType::SEARCH_HISTORY
},
516 PopulateAutocompleteMatchesFromTestData(data
, arraysize(data
), &matches
);
518 // Demote the search history match relevance score.
519 matches
.back().relevance
= 500;
521 // Add a rule demoting history-url and killing history-title.
523 std::map
<std::string
, std::string
> params
;
524 params
[std::string(OmniboxFieldTrial::kDemoteByTypeRule
) + ":3:*"] =
525 "1:50,7:100,2:0"; // 3 == HOME_PAGE
526 ASSERT_TRUE(variations::AssociateVariationParams(
527 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
529 base::FieldTrialList::CreateFieldTrial(
530 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
532 AutocompleteResult result
;
533 result
.AppendMatches(matches
);
534 AutocompleteInput
input(base::string16(), base::string16::npos
,
535 std::string(), GURL(),
536 OmniboxEventProto::HOME_PAGE
, false, false, false,
538 TestSchemeClassifier());
539 result
.SortAndCull(input
, template_url_service_
.get());
541 // Check the new ordering. The history-title results should be omitted.
542 // We cannot check relevance scores because the matches are sorted by
543 // demoted relevance but the actual relevance scores are not modified.
544 ASSERT_EQ(3u, result
.size());
545 EXPECT_EQ("http://search-what-you-typed/",
546 result
.match_at(0)->destination_url
.spec());
547 EXPECT_EQ("http://history-url/",
548 result
.match_at(1)->destination_url
.spec());
549 EXPECT_EQ("http://search-history/",
550 result
.match_at(2)->destination_url
.spec());
553 TEST_F(AutocompleteResultTest
, SortAndCullWithMatchDupsAndDemotionsByType
) {
556 const AutocompleteMatchTestData data
[] = {
557 { "http://search-what-you-typed/",
558 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
},
559 { "http://dup-url/", AutocompleteMatchType::HISTORY_URL
},
560 { "http://dup-url/", AutocompleteMatchType::NAVSUGGEST
},
561 { "http://search-url/", AutocompleteMatchType::SEARCH_SUGGEST
},
562 { "http://history-url/", AutocompleteMatchType::HISTORY_URL
},
564 PopulateAutocompleteMatchesFromTestData(data
, arraysize(data
), &matches
);
566 // Add a rule demoting HISTORY_URL.
568 std::map
<std::string
, std::string
> params
;
569 params
[std::string(OmniboxFieldTrial::kDemoteByTypeRule
) + ":8:*"] =
570 "1:50"; // 8 == INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS
571 ASSERT_TRUE(variations::AssociateVariationParams(
572 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "C", params
));
574 base::FieldTrialList::CreateFieldTrial(
575 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "C");
578 AutocompleteResult result
;
579 result
.AppendMatches(matches
);
580 AutocompleteInput
input(
581 base::string16(), base::string16::npos
, std::string(), GURL(),
582 OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS
, false,
584 TestSchemeClassifier());
585 result
.SortAndCull(input
, template_url_service_
.get());
587 // The NAVSUGGEST dup-url stay above search-url since the navsuggest
588 // variant should not be demoted.
589 ASSERT_EQ(4u, result
.size());
590 EXPECT_EQ("http://search-what-you-typed/",
591 result
.match_at(0)->destination_url
.spec());
592 EXPECT_EQ("http://dup-url/",
593 result
.match_at(1)->destination_url
.spec());
594 EXPECT_EQ(AutocompleteMatchType::NAVSUGGEST
,
595 result
.match_at(1)->type
);
596 EXPECT_EQ("http://search-url/",
597 result
.match_at(2)->destination_url
.spec());
598 EXPECT_EQ("http://history-url/",
599 result
.match_at(3)->destination_url
.spec());
603 TEST_F(AutocompleteResultTest
, SortAndCullReorderForDefaultMatch
) {
605 { 0, 1, 1300, true },
606 { 1, 1, 1200, true },
607 { 2, 1, 1100, true },
612 // Check that reorder doesn't do anything if the top result
613 // is already a legal default match (which is the default from
614 // PopulateAutocompleteMatches()).
616 PopulateAutocompleteMatches(data
, arraysize(data
), &matches
);
617 AutocompleteResult result
;
618 result
.AppendMatches(matches
);
619 AutocompleteInput
input(base::string16(), base::string16::npos
,
620 std::string(), GURL(),
621 OmniboxEventProto::HOME_PAGE
, false, false, false,
623 TestSchemeClassifier());
624 result
.SortAndCull(input
, template_url_service_
.get());
625 AssertResultMatches(result
, data
, 4);
629 // Check that reorder swaps up a result appropriately.
631 PopulateAutocompleteMatches(data
, arraysize(data
), &matches
);
632 matches
[0].allowed_to_be_default_match
= false;
633 matches
[1].allowed_to_be_default_match
= false;
634 AutocompleteResult result
;
635 result
.AppendMatches(matches
);
636 AutocompleteInput
input(base::string16(), base::string16::npos
,
637 std::string(), GURL(),
638 OmniboxEventProto::HOME_PAGE
, false, false, false,
640 TestSchemeClassifier());
641 result
.SortAndCull(input
, template_url_service_
.get());
642 ASSERT_EQ(4U, result
.size());
643 EXPECT_EQ("http://c/", result
.match_at(0)->destination_url
.spec());
644 EXPECT_EQ("http://a/", result
.match_at(1)->destination_url
.spec());
645 EXPECT_EQ("http://b/", result
.match_at(2)->destination_url
.spec());
646 EXPECT_EQ("http://d/", result
.match_at(3)->destination_url
.spec());
650 TEST_F(AutocompleteResultTest
, ShouldHideTopMatch
) {
651 base::FieldTrialList::CreateFieldTrial("InstantExtended",
652 "Group1 hide_verbatim:1");
655 // Case 1: Top match is a verbatim match.
656 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
, 1, &matches
);
657 AutocompleteResult result
;
658 result
.AppendMatches(matches
);
659 EXPECT_TRUE(result
.ShouldHideTopMatch());
663 // Case 2: If the verbatim first match is followed by another verbatim match,
664 // don't hide the top verbatim match.
665 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
,
666 arraysize(kVerbatimMatches
),
668 result
.AppendMatches(matches
);
669 EXPECT_FALSE(result
.ShouldHideTopMatch());
673 // Case 3: Top match is not a verbatim match. Do not hide the top match.
674 PopulateAutocompleteMatchesFromTestData(kNonVerbatimMatches
, 1, &matches
);
675 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
,
676 arraysize(kVerbatimMatches
),
678 result
.AppendMatches(matches
);
679 EXPECT_FALSE(result
.ShouldHideTopMatch());
682 TEST_F(AutocompleteResultTest
, ShouldHideTopMatchAfterCopy
) {
683 base::FieldTrialList::CreateFieldTrial("InstantExtended",
684 "Group1 hide_verbatim:1");
687 // Case 1: Top match is a verbatim match followed by only copied matches.
688 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
,
689 arraysize(kVerbatimMatches
),
691 for (size_t i
= 1; i
< arraysize(kVerbatimMatches
); ++i
)
692 matches
[i
].from_previous
= true;
693 AutocompleteResult result
;
694 result
.AppendMatches(matches
);
695 EXPECT_TRUE(result
.ShouldHideTopMatch());
698 // Case 2: The copied matches are then followed by a non-verbatim match.
699 PopulateAutocompleteMatchesFromTestData(kNonVerbatimMatches
, 1, &matches
);
700 result
.AppendMatches(matches
);
701 EXPECT_TRUE(result
.ShouldHideTopMatch());
704 // Case 3: The copied matches are instead followed by a verbatim match.
705 matches
.back().from_previous
= true;
706 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
, 1, &matches
);
707 result
.AppendMatches(matches
);
708 EXPECT_FALSE(result
.ShouldHideTopMatch());
711 TEST_F(AutocompleteResultTest
, DoNotHideTopMatch_FieldTrialFlagDisabled
) {
712 // This test config is identical to ShouldHideTopMatch test ("Case 1") except
713 // that the "hide_verbatim" flag is disabled in the field trials.
714 base::FieldTrialList::CreateFieldTrial("InstantExtended",
715 "Group1 hide_verbatim:0");
717 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
, 1, &matches
);
718 AutocompleteResult result
;
719 result
.AppendMatches(matches
);
720 // Field trial flag "hide_verbatim" is disabled. Do not hide top match.
721 EXPECT_FALSE(result
.ShouldHideTopMatch());
724 TEST_F(AutocompleteResultTest
, TopMatchIsStandaloneVerbatimMatch
) {
726 AutocompleteResult result
;
727 result
.AppendMatches(matches
);
729 // Case 1: Result set is empty.
730 EXPECT_FALSE(result
.TopMatchIsStandaloneVerbatimMatch());
732 // Case 2: Top match is not a verbatim match.
733 PopulateAutocompleteMatchesFromTestData(kNonVerbatimMatches
, 1, &matches
);
734 result
.AppendMatches(matches
);
735 EXPECT_FALSE(result
.TopMatchIsStandaloneVerbatimMatch());
739 // Case 3: Top match is a verbatim match.
740 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
, 1, &matches
);
741 result
.AppendMatches(matches
);
742 EXPECT_TRUE(result
.TopMatchIsStandaloneVerbatimMatch());
746 // Case 4: Standalone verbatim match found in AutocompleteResult.
747 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
, 1, &matches
);
748 PopulateAutocompleteMatchesFromTestData(kNonVerbatimMatches
, 1, &matches
);
749 result
.AppendMatches(matches
);
750 EXPECT_TRUE(result
.TopMatchIsStandaloneVerbatimMatch());
754 // Case 5: Multiple verbatim matches found in AutocompleteResult.
755 PopulateAutocompleteMatchesFromTestData(kVerbatimMatches
,
756 arraysize(kVerbatimMatches
),
758 result
.AppendMatches(matches
);
759 EXPECT_FALSE(result
.ShouldHideTopMatch());