OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/omnibox/browser/autocomplete_provider.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/command_line.h" | |
9 #include "base/location.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/single_thread_task_runner.h" | |
12 #include "base/strings/string16.h" | |
13 #include "base/strings/string_number_conversions.h" | |
14 #include "base/strings/string_util.h" | |
15 #include "base/strings/utf_string_conversions.h" | |
16 #include "base/thread_task_runner_handle.h" | |
17 #include "chrome/browser/autocomplete/chrome_autocomplete_provider_client.h" | |
18 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" | |
19 #include "chrome/browser/chrome_notification_types.h" | |
20 #include "chrome/browser/search_engines/template_url_service_factory.h" | |
21 #include "chrome/test/base/testing_browser_process.h" | |
22 #include "chrome/test/base/testing_profile.h" | |
23 #include "components/metrics/proto/omnibox_event.pb.h" | |
24 #include "components/omnibox/browser/autocomplete_controller.h" | |
25 #include "components/omnibox/browser/autocomplete_input.h" | |
26 #include "components/omnibox/browser/autocomplete_match.h" | |
27 #include "components/omnibox/browser/autocomplete_provider_listener.h" | |
28 #include "components/omnibox/browser/keyword_provider.h" | |
29 #include "components/omnibox/browser/search_provider.h" | |
30 #include "components/search_engines/search_engines_switches.h" | |
31 #include "components/search_engines/template_url.h" | |
32 #include "components/search_engines/template_url_service.h" | |
33 #include "content/public/browser/notification_observer.h" | |
34 #include "content/public/browser/notification_registrar.h" | |
35 #include "content/public/browser/notification_source.h" | |
36 #include "content/public/test/test_browser_thread_bundle.h" | |
37 #include "testing/gtest/include/gtest/gtest.h" | |
38 | |
39 static std::ostream& operator<<(std::ostream& os, | |
40 const AutocompleteResult::const_iterator& it) { | |
41 return os << static_cast<const AutocompleteMatch*>(&(*it)); | |
42 } | |
43 | |
44 namespace { | |
45 const size_t kResultsPerProvider = 3; | |
46 const char kTestTemplateURLKeyword[] = "t"; | |
47 } | |
48 | |
49 // Autocomplete provider that provides known results. Note that this is | |
50 // refcounted so that it can also be a task on the message loop. | |
51 class TestProvider : public AutocompleteProvider { | |
52 public: | |
53 TestProvider(int relevance, const base::string16& prefix, | |
54 Profile* profile, | |
55 const base::string16 match_keyword) | |
56 : AutocompleteProvider(AutocompleteProvider::TYPE_SEARCH), | |
57 listener_(NULL), | |
58 profile_(profile), | |
59 relevance_(relevance), | |
60 prefix_(prefix), | |
61 match_keyword_(match_keyword) { | |
62 } | |
63 | |
64 void Start(const AutocompleteInput& input, bool minimal_changes) override; | |
65 | |
66 void set_listener(AutocompleteProviderListener* listener) { | |
67 listener_ = listener; | |
68 } | |
69 | |
70 private: | |
71 ~TestProvider() override {} | |
72 | |
73 void Run(); | |
74 | |
75 void AddResults(int start_at, int num); | |
76 void AddResultsWithSearchTermsArgs( | |
77 int start_at, | |
78 int num, | |
79 AutocompleteMatch::Type type, | |
80 const TemplateURLRef::SearchTermsArgs& search_terms_args); | |
81 | |
82 AutocompleteProviderListener* listener_; | |
83 Profile* profile_; | |
84 int relevance_; | |
85 const base::string16 prefix_; | |
86 const base::string16 match_keyword_; | |
87 }; | |
88 | |
89 void TestProvider::Start(const AutocompleteInput& input, bool minimal_changes) { | |
90 if (minimal_changes) | |
91 return; | |
92 | |
93 matches_.clear(); | |
94 | |
95 if (input.from_omnibox_focus()) | |
96 return; | |
97 | |
98 // Generate 4 results synchronously, the rest later. | |
99 AddResults(0, 1); | |
100 AddResultsWithSearchTermsArgs( | |
101 1, 1, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, | |
102 TemplateURLRef::SearchTermsArgs(base::ASCIIToUTF16("echo"))); | |
103 AddResultsWithSearchTermsArgs( | |
104 2, 1, AutocompleteMatchType::NAVSUGGEST, | |
105 TemplateURLRef::SearchTermsArgs(base::ASCIIToUTF16("nav"))); | |
106 AddResultsWithSearchTermsArgs( | |
107 3, 1, AutocompleteMatchType::SEARCH_SUGGEST, | |
108 TemplateURLRef::SearchTermsArgs(base::ASCIIToUTF16("query"))); | |
109 | |
110 if (input.want_asynchronous_matches()) { | |
111 done_ = false; | |
112 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
113 FROM_HERE, base::Bind(&TestProvider::Run, this)); | |
114 } | |
115 } | |
116 | |
117 void TestProvider::Run() { | |
118 DCHECK_GT(kResultsPerProvider, 0U); | |
119 AddResults(1, kResultsPerProvider); | |
120 done_ = true; | |
121 DCHECK(listener_); | |
122 listener_->OnProviderUpdate(true); | |
123 } | |
124 | |
125 void TestProvider::AddResults(int start_at, int num) { | |
126 AddResultsWithSearchTermsArgs(start_at, | |
127 num, | |
128 AutocompleteMatchType::URL_WHAT_YOU_TYPED, | |
129 TemplateURLRef::SearchTermsArgs( | |
130 base::string16())); | |
131 } | |
132 | |
133 void TestProvider::AddResultsWithSearchTermsArgs( | |
134 int start_at, | |
135 int num, | |
136 AutocompleteMatch::Type type, | |
137 const TemplateURLRef::SearchTermsArgs& search_terms_args) { | |
138 for (int i = start_at; i < num; i++) { | |
139 AutocompleteMatch match(this, relevance_ - i, false, type); | |
140 | |
141 match.fill_into_edit = prefix_ + base::UTF8ToUTF16(base::IntToString(i)); | |
142 match.destination_url = GURL(base::UTF16ToUTF8(match.fill_into_edit)); | |
143 match.allowed_to_be_default_match = true; | |
144 | |
145 match.contents = match.fill_into_edit; | |
146 match.contents_class.push_back( | |
147 ACMatchClassification(0, ACMatchClassification::NONE)); | |
148 match.description = match.fill_into_edit; | |
149 match.description_class.push_back( | |
150 ACMatchClassification(0, ACMatchClassification::NONE)); | |
151 match.search_terms_args.reset( | |
152 new TemplateURLRef::SearchTermsArgs(search_terms_args)); | |
153 if (!match_keyword_.empty()) { | |
154 match.keyword = match_keyword_; | |
155 TemplateURLService* service = | |
156 TemplateURLServiceFactory::GetForProfile(profile_); | |
157 ASSERT_TRUE(match.GetTemplateURL(service, false) != NULL); | |
158 } | |
159 | |
160 matches_.push_back(match); | |
161 } | |
162 } | |
163 | |
164 class AutocompleteProviderTest : public testing::Test, | |
165 public content::NotificationObserver { | |
166 protected: | |
167 struct KeywordTestData { | |
168 const base::string16 fill_into_edit; | |
169 const base::string16 keyword; | |
170 const base::string16 expected_associated_keyword; | |
171 }; | |
172 | |
173 struct AssistedQueryStatsTestData { | |
174 const AutocompleteMatch::Type match_type; | |
175 const std::string expected_aqs; | |
176 }; | |
177 | |
178 protected: | |
179 // Registers a test TemplateURL under the given keyword. | |
180 void RegisterTemplateURL(const base::string16 keyword, | |
181 const std::string& template_url); | |
182 | |
183 // Resets |controller_| with two TestProviders. |provider1_ptr| and | |
184 // |provider2_ptr| are updated to point to the new providers if non-NULL. | |
185 void ResetControllerWithTestProviders(bool same_destinations, | |
186 TestProvider** provider1_ptr, | |
187 TestProvider** provider2_ptr); | |
188 | |
189 // Runs a query on the input "a", and makes sure both providers' input is | |
190 // properly collected. | |
191 void RunTest(); | |
192 | |
193 // Constructs an AutocompleteResult from |match_data|, sets the |controller_| | |
194 // to pretend it was running against input |input|, calls the |controller_|'s | |
195 // UpdateAssociatedKeywords, and checks that the matches have associated | |
196 // keywords as expected. | |
197 void RunKeywordTest(const base::string16& input, | |
198 const KeywordTestData* match_data, | |
199 size_t size); | |
200 | |
201 void RunAssistedQueryStatsTest( | |
202 const AssistedQueryStatsTestData* aqs_test_data, | |
203 size_t size); | |
204 | |
205 void RunQuery(const base::string16 query); | |
206 | |
207 void ResetControllerWithKeywordAndSearchProviders(); | |
208 void ResetControllerWithKeywordProvider(); | |
209 void RunExactKeymatchTest(bool allow_exact_keyword_match); | |
210 | |
211 void CopyResults(); | |
212 | |
213 // Returns match.destination_url as it would be set by | |
214 // AutocompleteController::UpdateMatchDestinationURL(). | |
215 GURL GetDestinationURL(AutocompleteMatch match, | |
216 base::TimeDelta query_formulation_time) const; | |
217 | |
218 void set_search_provider_field_trial_triggered_in_session(bool val) { | |
219 controller_->search_provider_->set_field_trial_triggered_in_session(val); | |
220 } | |
221 bool search_provider_field_trial_triggered_in_session() { | |
222 return controller_->search_provider_->field_trial_triggered_in_session(); | |
223 } | |
224 void set_current_page_classification( | |
225 metrics::OmniboxEventProto::PageClassification classification) { | |
226 controller_->input_.current_page_classification_ = classification; | |
227 } | |
228 | |
229 AutocompleteResult result_; | |
230 | |
231 private: | |
232 // content::NotificationObserver: | |
233 void Observe(int type, | |
234 const content::NotificationSource& source, | |
235 const content::NotificationDetails& details) override; | |
236 | |
237 content::TestBrowserThreadBundle thread_bundle_; | |
238 content::NotificationRegistrar registrar_; | |
239 TestingProfile profile_; | |
240 scoped_ptr<AutocompleteController> controller_; | |
241 }; | |
242 | |
243 void AutocompleteProviderTest::RegisterTemplateURL( | |
244 const base::string16 keyword, | |
245 const std::string& template_url) { | |
246 if (TemplateURLServiceFactory::GetForProfile(&profile_) == NULL) { | |
247 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( | |
248 &profile_, &TemplateURLServiceFactory::BuildInstanceFor); | |
249 } | |
250 TemplateURLData data; | |
251 data.SetURL(template_url); | |
252 data.SetShortName(keyword); | |
253 data.SetKeyword(keyword); | |
254 TemplateURL* default_t_url = new TemplateURL(data); | |
255 TemplateURLService* turl_model = | |
256 TemplateURLServiceFactory::GetForProfile(&profile_); | |
257 turl_model->Add(default_t_url); | |
258 turl_model->SetUserSelectedDefaultSearchProvider(default_t_url); | |
259 turl_model->Load(); | |
260 TemplateURLID default_provider_id = default_t_url->id(); | |
261 ASSERT_NE(0, default_provider_id); | |
262 } | |
263 | |
264 void AutocompleteProviderTest::ResetControllerWithTestProviders( | |
265 bool same_destinations, | |
266 TestProvider** provider1_ptr, | |
267 TestProvider** provider2_ptr) { | |
268 // TODO: Move it outside this method, after refactoring the existing | |
269 // unit tests. Specifically: | |
270 // (1) Make sure that AutocompleteMatch.keyword is set iff there is | |
271 // a corresponding call to RegisterTemplateURL; otherwise the | |
272 // controller flow will crash; this practically means that | |
273 // RunTests/ResetControllerXXX/RegisterTemplateURL should | |
274 // be coordinated with each other. | |
275 // (2) Inject test arguments rather than rely on the hardcoded values, e.g. | |
276 // don't rely on kResultsPerProvided and default relevance ordering | |
277 // (B > A). | |
278 RegisterTemplateURL(base::ASCIIToUTF16(kTestTemplateURLKeyword), | |
279 "http://aqs/{searchTerms}/{google:assistedQueryStats}"); | |
280 | |
281 AutocompleteController::Providers providers; | |
282 | |
283 // Construct two new providers, with either the same or different prefixes. | |
284 TestProvider* provider1 = new TestProvider( | |
285 kResultsPerProvider, | |
286 base::ASCIIToUTF16("http://a"), | |
287 &profile_, | |
288 base::ASCIIToUTF16(kTestTemplateURLKeyword)); | |
289 providers.push_back(provider1); | |
290 | |
291 TestProvider* provider2 = new TestProvider( | |
292 kResultsPerProvider * 2, | |
293 same_destinations ? base::ASCIIToUTF16("http://a") | |
294 : base::ASCIIToUTF16("http://b"), | |
295 &profile_, | |
296 base::string16()); | |
297 providers.push_back(provider2); | |
298 | |
299 // Reset the controller to contain our new providers. | |
300 controller_.reset(new AutocompleteController( | |
301 | |
302 make_scoped_ptr(new ChromeAutocompleteProviderClient(&profile_)), NULL, | |
303 0)); | |
304 // We're going to swap the providers vector, but the old vector should be | |
305 // empty so no elements need to be freed at this point. | |
306 EXPECT_TRUE(controller_->providers_.empty()); | |
307 controller_->providers_.swap(providers); | |
308 provider1->set_listener(controller_.get()); | |
309 provider2->set_listener(controller_.get()); | |
310 | |
311 // The providers don't complete synchronously, so listen for "result updated" | |
312 // notifications. | |
313 registrar_.Add(this, | |
314 chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY, | |
315 content::Source<AutocompleteController>(controller_.get())); | |
316 | |
317 if (provider1_ptr) | |
318 *provider1_ptr = provider1; | |
319 if (provider2_ptr) | |
320 *provider2_ptr = provider2; | |
321 } | |
322 | |
323 void AutocompleteProviderTest:: | |
324 ResetControllerWithKeywordAndSearchProviders() { | |
325 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( | |
326 &profile_, &TemplateURLServiceFactory::BuildInstanceFor); | |
327 | |
328 // Reset the default TemplateURL. | |
329 TemplateURLData data; | |
330 data.SetShortName(base::ASCIIToUTF16("default")); | |
331 data.SetKeyword(base::ASCIIToUTF16("default")); | |
332 data.SetURL("http://defaultturl/{searchTerms}"); | |
333 TemplateURL* default_t_url = new TemplateURL(data); | |
334 TemplateURLService* turl_model = | |
335 TemplateURLServiceFactory::GetForProfile(&profile_); | |
336 turl_model->Add(default_t_url); | |
337 turl_model->SetUserSelectedDefaultSearchProvider(default_t_url); | |
338 TemplateURLID default_provider_id = default_t_url->id(); | |
339 ASSERT_NE(0, default_provider_id); | |
340 | |
341 // Create another TemplateURL for KeywordProvider. | |
342 TemplateURLData data2; | |
343 data2.SetShortName(base::ASCIIToUTF16("k")); | |
344 data2.SetKeyword(base::ASCIIToUTF16("k")); | |
345 data2.SetURL("http://keyword/{searchTerms}"); | |
346 TemplateURL* keyword_t_url = new TemplateURL(data2); | |
347 turl_model->Add(keyword_t_url); | |
348 ASSERT_NE(0, keyword_t_url->id()); | |
349 | |
350 controller_.reset(new AutocompleteController( | |
351 | |
352 make_scoped_ptr(new ChromeAutocompleteProviderClient(&profile_)), NULL, | |
353 AutocompleteProvider::TYPE_KEYWORD | AutocompleteProvider::TYPE_SEARCH)); | |
354 } | |
355 | |
356 void AutocompleteProviderTest::ResetControllerWithKeywordProvider() { | |
357 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( | |
358 &profile_, &TemplateURLServiceFactory::BuildInstanceFor); | |
359 | |
360 TemplateURLService* turl_model = | |
361 TemplateURLServiceFactory::GetForProfile(&profile_); | |
362 | |
363 // Create a TemplateURL for KeywordProvider. | |
364 TemplateURLData data; | |
365 data.SetShortName(base::ASCIIToUTF16("foo.com")); | |
366 data.SetKeyword(base::ASCIIToUTF16("foo.com")); | |
367 data.SetURL("http://foo.com/{searchTerms}"); | |
368 TemplateURL* keyword_t_url = new TemplateURL(data); | |
369 turl_model->Add(keyword_t_url); | |
370 ASSERT_NE(0, keyword_t_url->id()); | |
371 | |
372 // Make a TemplateURL for KeywordProvider that a shorter version of the | |
373 // first. | |
374 data.SetShortName(base::ASCIIToUTF16("f")); | |
375 data.SetKeyword(base::ASCIIToUTF16("f")); | |
376 data.SetURL("http://f.com/{searchTerms}"); | |
377 keyword_t_url = new TemplateURL(data); | |
378 turl_model->Add(keyword_t_url); | |
379 ASSERT_NE(0, keyword_t_url->id()); | |
380 | |
381 // Create another TemplateURL for KeywordProvider. | |
382 data.SetShortName(base::ASCIIToUTF16("bar.com")); | |
383 data.SetKeyword(base::ASCIIToUTF16("bar.com")); | |
384 data.SetURL("http://bar.com/{searchTerms}"); | |
385 keyword_t_url = new TemplateURL(data); | |
386 turl_model->Add(keyword_t_url); | |
387 ASSERT_NE(0, keyword_t_url->id()); | |
388 | |
389 controller_.reset(new AutocompleteController( | |
390 make_scoped_ptr(new ChromeAutocompleteProviderClient(&profile_)), NULL, | |
391 AutocompleteProvider::TYPE_KEYWORD)); | |
392 } | |
393 | |
394 void AutocompleteProviderTest::RunTest() { | |
395 RunQuery(base::ASCIIToUTF16("a")); | |
396 } | |
397 | |
398 void AutocompleteProviderTest::RunKeywordTest(const base::string16& input, | |
399 const KeywordTestData* match_data, | |
400 size_t size) { | |
401 ACMatches matches; | |
402 for (size_t i = 0; i < size; ++i) { | |
403 AutocompleteMatch match; | |
404 match.relevance = 1000; // Arbitrary non-zero value. | |
405 match.allowed_to_be_default_match = true; | |
406 match.fill_into_edit = match_data[i].fill_into_edit; | |
407 match.transition = ui::PAGE_TRANSITION_KEYWORD; | |
408 match.keyword = match_data[i].keyword; | |
409 matches.push_back(match); | |
410 } | |
411 | |
412 controller_->input_ = AutocompleteInput( | |
413 input, base::string16::npos, std::string(), GURL(), | |
414 metrics::OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS, | |
415 false, true, true, true, false, | |
416 ChromeAutocompleteSchemeClassifier(&profile_)); | |
417 AutocompleteResult result; | |
418 result.AppendMatches(controller_->input_, matches); | |
419 controller_->UpdateAssociatedKeywords(&result); | |
420 | |
421 for (size_t j = 0; j < result.size(); ++j) { | |
422 EXPECT_EQ(match_data[j].expected_associated_keyword, | |
423 result.match_at(j)->associated_keyword.get() ? | |
424 result.match_at(j)->associated_keyword->keyword : | |
425 base::string16()); | |
426 } | |
427 } | |
428 | |
429 void AutocompleteProviderTest::RunAssistedQueryStatsTest( | |
430 const AssistedQueryStatsTestData* aqs_test_data, | |
431 size_t size) { | |
432 // Prepare input. | |
433 const size_t kMaxRelevance = 1000; | |
434 ACMatches matches; | |
435 for (size_t i = 0; i < size; ++i) { | |
436 AutocompleteMatch match(NULL, kMaxRelevance - i, false, | |
437 aqs_test_data[i].match_type); | |
438 match.allowed_to_be_default_match = true; | |
439 match.keyword = base::ASCIIToUTF16(kTestTemplateURLKeyword); | |
440 match.search_terms_args.reset( | |
441 new TemplateURLRef::SearchTermsArgs(base::string16())); | |
442 matches.push_back(match); | |
443 } | |
444 result_.Reset(); | |
445 result_.AppendMatches(AutocompleteInput(), matches); | |
446 | |
447 // Update AQS. | |
448 controller_->UpdateAssistedQueryStats(&result_); | |
449 | |
450 // Verify data. | |
451 for (size_t i = 0; i < size; ++i) { | |
452 EXPECT_EQ(aqs_test_data[i].expected_aqs, | |
453 result_.match_at(i)->search_terms_args->assisted_query_stats); | |
454 } | |
455 } | |
456 | |
457 void AutocompleteProviderTest::RunQuery(const base::string16 query) { | |
458 result_.Reset(); | |
459 controller_->Start(AutocompleteInput( | |
460 query, base::string16::npos, std::string(), GURL(), | |
461 metrics::OmniboxEventProto::INVALID_SPEC, true, false, true, true, false, | |
462 ChromeAutocompleteSchemeClassifier(&profile_))); | |
463 | |
464 if (!controller_->done()) | |
465 // The message loop will terminate when all autocomplete input has been | |
466 // collected. | |
467 base::MessageLoop::current()->Run(); | |
468 } | |
469 | |
470 void AutocompleteProviderTest::RunExactKeymatchTest( | |
471 bool allow_exact_keyword_match) { | |
472 // Send the controller input which exactly matches the keyword provider we | |
473 // created in ResetControllerWithKeywordAndSearchProviders(). The default | |
474 // match should thus be a search-other-engine match iff | |
475 // |allow_exact_keyword_match| is true. Regardless, the match should | |
476 // be from SearchProvider. (It provides all verbatim search matches, | |
477 // keyword or not.) | |
478 controller_->Start(AutocompleteInput( | |
479 base::ASCIIToUTF16("k test"), base::string16::npos, std::string(), GURL(), | |
480 metrics::OmniboxEventProto::INVALID_SPEC, true, false, | |
481 allow_exact_keyword_match, false, false, | |
482 ChromeAutocompleteSchemeClassifier(&profile_))); | |
483 EXPECT_TRUE(controller_->done()); | |
484 EXPECT_EQ(AutocompleteProvider::TYPE_SEARCH, | |
485 controller_->result().default_match()->provider->type()); | |
486 EXPECT_EQ(allow_exact_keyword_match ? | |
487 AutocompleteMatchType::SEARCH_OTHER_ENGINE : | |
488 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, | |
489 controller_->result().default_match()->type); | |
490 } | |
491 | |
492 void AutocompleteProviderTest::CopyResults() { | |
493 result_.CopyFrom(controller_->result()); | |
494 } | |
495 | |
496 GURL AutocompleteProviderTest::GetDestinationURL( | |
497 AutocompleteMatch match, | |
498 base::TimeDelta query_formulation_time) const { | |
499 controller_->UpdateMatchDestinationURLWithQueryFormulationTime( | |
500 query_formulation_time, &match); | |
501 return match.destination_url; | |
502 } | |
503 | |
504 void AutocompleteProviderTest::Observe( | |
505 int type, | |
506 const content::NotificationSource& source, | |
507 const content::NotificationDetails& details) { | |
508 if (controller_->done()) { | |
509 CopyResults(); | |
510 base::MessageLoop::current()->QuitWhenIdle(); | |
511 } | |
512 } | |
513 | |
514 // Tests that the default selection is set properly when updating results. | |
515 TEST_F(AutocompleteProviderTest, Query) { | |
516 TestProvider* provider1 = NULL; | |
517 TestProvider* provider2 = NULL; | |
518 ResetControllerWithTestProviders(false, &provider1, &provider2); | |
519 RunTest(); | |
520 | |
521 // Make sure the default match gets set to the highest relevance match. The | |
522 // highest relevance matches should come from the second provider. | |
523 EXPECT_EQ(kResultsPerProvider * 2, result_.size()); | |
524 ASSERT_NE(result_.end(), result_.default_match()); | |
525 EXPECT_EQ(provider2, result_.default_match()->provider); | |
526 } | |
527 | |
528 // Tests assisted query stats. | |
529 TEST_F(AutocompleteProviderTest, AssistedQueryStats) { | |
530 ResetControllerWithTestProviders(false, NULL, NULL); | |
531 RunTest(); | |
532 | |
533 ASSERT_EQ(kResultsPerProvider * 2, result_.size()); | |
534 | |
535 // Now, check the results from the second provider, as they should not have | |
536 // assisted query stats set. | |
537 for (size_t i = 0; i < kResultsPerProvider; ++i) { | |
538 EXPECT_TRUE( | |
539 result_.match_at(i)->search_terms_args->assisted_query_stats.empty()); | |
540 } | |
541 // The first provider has a test keyword, so AQS should be non-empty. | |
542 for (size_t i = kResultsPerProvider; i < kResultsPerProvider * 2; ++i) { | |
543 EXPECT_FALSE( | |
544 result_.match_at(i)->search_terms_args->assisted_query_stats.empty()); | |
545 } | |
546 } | |
547 | |
548 TEST_F(AutocompleteProviderTest, RemoveDuplicates) { | |
549 TestProvider* provider1 = NULL; | |
550 TestProvider* provider2 = NULL; | |
551 ResetControllerWithTestProviders(true, &provider1, &provider2); | |
552 RunTest(); | |
553 | |
554 // Make sure all the first provider's results were eliminated by the second | |
555 // provider's. | |
556 EXPECT_EQ(kResultsPerProvider, result_.size()); | |
557 for (AutocompleteResult::const_iterator i(result_.begin()); | |
558 i != result_.end(); ++i) | |
559 EXPECT_EQ(provider2, i->provider); | |
560 } | |
561 | |
562 TEST_F(AutocompleteProviderTest, AllowExactKeywordMatch) { | |
563 ResetControllerWithKeywordAndSearchProviders(); | |
564 RunExactKeymatchTest(true); | |
565 RunExactKeymatchTest(false); | |
566 } | |
567 | |
568 // Ensures matches from (only) the default search provider respect any extra | |
569 // query params set on the command line. | |
570 TEST_F(AutocompleteProviderTest, ExtraQueryParams) { | |
571 ResetControllerWithKeywordAndSearchProviders(); | |
572 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( | |
573 switches::kExtraSearchQueryParams, "a=b"); | |
574 RunExactKeymatchTest(true); | |
575 CopyResults(); | |
576 ASSERT_EQ(2U, result_.size()); | |
577 EXPECT_EQ("http://keyword/test", | |
578 result_.match_at(0)->destination_url.possibly_invalid_spec()); | |
579 EXPECT_EQ("http://defaultturl/k%20test?a=b", | |
580 result_.match_at(1)->destination_url.possibly_invalid_spec()); | |
581 } | |
582 | |
583 // Test that redundant associated keywords are removed. | |
584 TEST_F(AutocompleteProviderTest, RedundantKeywordsIgnoredInResult) { | |
585 ResetControllerWithKeywordProvider(); | |
586 | |
587 { | |
588 KeywordTestData duplicate_url[] = { | |
589 { base::ASCIIToUTF16("fo"), base::string16(), base::string16() }, | |
590 { base::ASCIIToUTF16("foo.com"), base::string16(), | |
591 base::ASCIIToUTF16("foo.com") }, | |
592 { base::ASCIIToUTF16("foo.com"), base::string16(), base::string16() } | |
593 }; | |
594 | |
595 SCOPED_TRACE("Duplicate url"); | |
596 RunKeywordTest(base::ASCIIToUTF16("fo"), duplicate_url, | |
597 arraysize(duplicate_url)); | |
598 } | |
599 | |
600 { | |
601 KeywordTestData keyword_match[] = { | |
602 { base::ASCIIToUTF16("foo.com"), base::ASCIIToUTF16("foo.com"), | |
603 base::string16() }, | |
604 { base::ASCIIToUTF16("foo.com"), base::string16(), base::string16() } | |
605 }; | |
606 | |
607 SCOPED_TRACE("Duplicate url with keyword match"); | |
608 RunKeywordTest(base::ASCIIToUTF16("fo"), keyword_match, | |
609 arraysize(keyword_match)); | |
610 } | |
611 | |
612 { | |
613 KeywordTestData multiple_keyword[] = { | |
614 { base::ASCIIToUTF16("fo"), base::string16(), base::string16() }, | |
615 { base::ASCIIToUTF16("foo.com"), base::string16(), | |
616 base::ASCIIToUTF16("foo.com") }, | |
617 { base::ASCIIToUTF16("foo.com"), base::string16(), base::string16() }, | |
618 { base::ASCIIToUTF16("bar.com"), base::string16(), | |
619 base::ASCIIToUTF16("bar.com") }, | |
620 }; | |
621 | |
622 SCOPED_TRACE("Duplicate url with multiple keywords"); | |
623 RunKeywordTest(base::ASCIIToUTF16("fo"), multiple_keyword, | |
624 arraysize(multiple_keyword)); | |
625 } | |
626 } | |
627 | |
628 // Test that exact match keywords trump keywords associated with | |
629 // the match. | |
630 TEST_F(AutocompleteProviderTest, ExactMatchKeywords) { | |
631 ResetControllerWithKeywordProvider(); | |
632 | |
633 { | |
634 KeywordTestData keyword_match[] = { | |
635 { base::ASCIIToUTF16("foo.com"), base::string16(), | |
636 base::ASCIIToUTF16("foo.com") } | |
637 }; | |
638 | |
639 SCOPED_TRACE("keyword match as usual"); | |
640 RunKeywordTest(base::ASCIIToUTF16("fo"), keyword_match, | |
641 arraysize(keyword_match)); | |
642 } | |
643 | |
644 // The same result set with an input of "f" (versus "fo") should get | |
645 // a different associated keyword because "f" is an exact match for | |
646 // a keyword and that should trump the keyword normally associated with | |
647 // this match. | |
648 { | |
649 KeywordTestData keyword_match[] = { | |
650 { base::ASCIIToUTF16("foo.com"), base::string16(), | |
651 base::ASCIIToUTF16("f") } | |
652 }; | |
653 | |
654 SCOPED_TRACE("keyword exact match"); | |
655 RunKeywordTest(base::ASCIIToUTF16("f"), keyword_match, | |
656 arraysize(keyword_match)); | |
657 } | |
658 } | |
659 | |
660 TEST_F(AutocompleteProviderTest, UpdateAssistedQueryStats) { | |
661 ResetControllerWithTestProviders(false, NULL, NULL); | |
662 | |
663 { | |
664 AssistedQueryStatsTestData test_data[] = { | |
665 // MSVC doesn't support zero-length arrays, so supply some dummy data. | |
666 { AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, "" } | |
667 }; | |
668 SCOPED_TRACE("No matches"); | |
669 // Note: We pass 0 here to ignore the dummy data above. | |
670 RunAssistedQueryStatsTest(test_data, 0); | |
671 } | |
672 | |
673 { | |
674 AssistedQueryStatsTestData test_data[] = { | |
675 { AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, "chrome..69i57" } | |
676 }; | |
677 SCOPED_TRACE("One match"); | |
678 RunAssistedQueryStatsTest(test_data, arraysize(test_data)); | |
679 } | |
680 | |
681 { | |
682 AssistedQueryStatsTestData test_data[] = { | |
683 { AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, | |
684 "chrome..69i57j69i58j5l2j0l3j69i59" }, | |
685 { AutocompleteMatchType::URL_WHAT_YOU_TYPED, | |
686 "chrome..69i57j69i58j5l2j0l3j69i59" }, | |
687 { AutocompleteMatchType::NAVSUGGEST, | |
688 "chrome.2.69i57j69i58j5l2j0l3j69i59" }, | |
689 { AutocompleteMatchType::NAVSUGGEST, | |
690 "chrome.3.69i57j69i58j5l2j0l3j69i59" }, | |
691 { AutocompleteMatchType::SEARCH_SUGGEST, | |
692 "chrome.4.69i57j69i58j5l2j0l3j69i59" }, | |
693 { AutocompleteMatchType::SEARCH_SUGGEST, | |
694 "chrome.5.69i57j69i58j5l2j0l3j69i59" }, | |
695 { AutocompleteMatchType::SEARCH_SUGGEST, | |
696 "chrome.6.69i57j69i58j5l2j0l3j69i59" }, | |
697 { AutocompleteMatchType::SEARCH_HISTORY, | |
698 "chrome.7.69i57j69i58j5l2j0l3j69i59" }, | |
699 }; | |
700 SCOPED_TRACE("Multiple matches"); | |
701 RunAssistedQueryStatsTest(test_data, arraysize(test_data)); | |
702 } | |
703 } | |
704 | |
705 TEST_F(AutocompleteProviderTest, GetDestinationURL) { | |
706 ResetControllerWithKeywordAndSearchProviders(); | |
707 | |
708 // For the destination URL to have aqs parameters for query formulation time | |
709 // and the field trial triggered bit, many conditions need to be satisfied. | |
710 AutocompleteMatch match(NULL, 1100, false, | |
711 AutocompleteMatchType::SEARCH_SUGGEST); | |
712 GURL url(GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456))); | |
713 EXPECT_TRUE(url.path().empty()); | |
714 | |
715 // The protocol needs to be https. | |
716 RegisterTemplateURL(base::ASCIIToUTF16(kTestTemplateURLKeyword), | |
717 "https://aqs/{searchTerms}/{google:assistedQueryStats}"); | |
718 url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456)); | |
719 EXPECT_TRUE(url.path().empty()); | |
720 | |
721 // There needs to be a keyword provider. | |
722 match.keyword = base::ASCIIToUTF16(kTestTemplateURLKeyword); | |
723 url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456)); | |
724 EXPECT_TRUE(url.path().empty()); | |
725 | |
726 // search_terms_args needs to be set. | |
727 match.search_terms_args.reset( | |
728 new TemplateURLRef::SearchTermsArgs(base::string16())); | |
729 url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456)); | |
730 EXPECT_TRUE(url.path().empty()); | |
731 | |
732 // assisted_query_stats needs to have been previously set. | |
733 match.search_terms_args->assisted_query_stats = | |
734 "chrome.0.69i57j69i58j5l2j0l3j69i59"; | |
735 url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456)); | |
736 EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j0j0&", url.path()); | |
737 | |
738 // Test field trial triggered bit set. | |
739 set_search_provider_field_trial_triggered_in_session(true); | |
740 EXPECT_TRUE(search_provider_field_trial_triggered_in_session()); | |
741 url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456)); | |
742 EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j1j0&", url.path()); | |
743 | |
744 // Test page classification set. | |
745 set_current_page_classification(metrics::OmniboxEventProto::OTHER); | |
746 set_search_provider_field_trial_triggered_in_session(false); | |
747 EXPECT_FALSE(search_provider_field_trial_triggered_in_session()); | |
748 url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456)); | |
749 EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j0j4&", url.path()); | |
750 | |
751 // Test page classification and field trial triggered set. | |
752 set_search_provider_field_trial_triggered_in_session(true); | |
753 EXPECT_TRUE(search_provider_field_trial_triggered_in_session()); | |
754 url = GetDestinationURL(match, base::TimeDelta::FromMilliseconds(2456)); | |
755 EXPECT_EQ("//aqs=chrome.0.69i57j69i58j5l2j0l3j69i59.2456j1j4&", url.path()); | |
756 } | |
OLD | NEW |