Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / autocomplete / search_provider_unittest.cc
blobc8a3c117f614dc3866f1606a0127fda94fe0ab45
1 // Copyright 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.
5 #include "chrome/browser/autocomplete/search_provider.h"
7 #include <string>
9 #include "base/command_line.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/time/time.h"
18 #include "build/build_config.h"
19 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
20 #include "chrome/browser/autocomplete/autocomplete_controller.h"
21 #include "chrome/browser/autocomplete/autocomplete_input.h"
22 #include "chrome/browser/autocomplete/autocomplete_match.h"
23 #include "chrome/browser/autocomplete/autocomplete_provider.h"
24 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
25 #include "chrome/browser/autocomplete/history_url_provider.h"
26 #include "chrome/browser/history/history_service.h"
27 #include "chrome/browser/history/history_service_factory.h"
28 #include "chrome/browser/omnibox/omnibox_field_trial.h"
29 #include "chrome/browser/search_engines/search_engine_type.h"
30 #include "chrome/browser/search_engines/template_url.h"
31 #include "chrome/browser/search_engines/template_url_service.h"
32 #include "chrome/browser/search_engines/template_url_service_factory.h"
33 #include "chrome/browser/signin/signin_manager_factory.h"
34 #include "chrome/browser/sync/profile_sync_service.h"
35 #include "chrome/browser/sync/profile_sync_service_factory.h"
36 #include "chrome/common/chrome_switches.h"
37 #include "chrome/common/metrics/variations/variations_util.h"
38 #include "chrome/common/pref_names.h"
39 #include "chrome/test/base/testing_browser_process.h"
40 #include "chrome/test/base/testing_profile.h"
41 #include "components/signin/core/browser/signin_manager.h"
42 #include "components/sync_driver/pref_names.h"
43 #include "components/variations/entropy_provider.h"
44 #include "content/public/test/test_browser_thread_bundle.h"
45 #include "net/url_request/test_url_fetcher_factory.h"
46 #include "net/url_request/url_request_status.h"
47 #include "testing/gtest/include/gtest/gtest.h"
49 using base::ASCIIToUTF16;
51 namespace {
53 // Returns the first match in |matches| with |allowed_to_be_default_match|
54 // set to true.
55 ACMatches::const_iterator FindDefaultMatch(const ACMatches& matches) {
56 ACMatches::const_iterator it = matches.begin();
57 while ((it != matches.end()) && !it->allowed_to_be_default_match)
58 ++it;
59 return it;
62 class SuggestionDeletionHandler;
63 class SearchProviderForTest : public SearchProvider {
64 public:
65 SearchProviderForTest(
66 AutocompleteProviderListener* listener,
67 Profile* profile);
68 bool is_success() { return is_success_; };
70 protected:
71 virtual ~SearchProviderForTest();
73 private:
74 virtual void RecordDeletionResult(bool success) OVERRIDE;
75 bool is_success_;
76 DISALLOW_COPY_AND_ASSIGN(SearchProviderForTest);
79 SearchProviderForTest::SearchProviderForTest(
80 AutocompleteProviderListener* listener,
81 Profile* profile)
82 : SearchProvider(listener, profile), is_success_(false) {
85 SearchProviderForTest::~SearchProviderForTest() {
88 void SearchProviderForTest::RecordDeletionResult(bool success) {
89 is_success_ = success;
92 } // namespace
94 // SearchProviderTest ---------------------------------------------------------
96 // The following environment is configured for these tests:
97 // . The TemplateURL default_t_url_ is set as the default provider.
98 // . The TemplateURL keyword_t_url_ is added to the TemplateURLService. This
99 // TemplateURL has a valid suggest and search URL.
100 // . The URL created by using the search term term1_ with default_t_url_ is
101 // added to history.
102 // . The URL created by using the search term keyword_term_ with keyword_t_url_
103 // is added to history.
104 // . test_factory_ is set as the URLFetcherFactory.
105 class SearchProviderTest : public testing::Test,
106 public AutocompleteProviderListener {
107 public:
108 struct ResultInfo {
109 ResultInfo() : result_type(AutocompleteMatchType::NUM_TYPES),
110 allowed_to_be_default_match(false) {
112 ResultInfo(GURL gurl,
113 AutocompleteMatch::Type result_type,
114 bool allowed_to_be_default_match,
115 base::string16 fill_into_edit)
116 : gurl(gurl),
117 result_type(result_type),
118 allowed_to_be_default_match(allowed_to_be_default_match),
119 fill_into_edit(fill_into_edit) {
122 const GURL gurl;
123 const AutocompleteMatch::Type result_type;
124 const bool allowed_to_be_default_match;
125 const base::string16 fill_into_edit;
128 struct TestData {
129 const base::string16 input;
130 const size_t num_results;
131 const ResultInfo output[3];
134 SearchProviderTest()
135 : default_t_url_(NULL),
136 term1_(ASCIIToUTF16("term1")),
137 keyword_t_url_(NULL),
138 keyword_term_(ASCIIToUTF16("keyword")),
139 run_loop_(NULL) {
140 ResetFieldTrialList();
143 // See description above class for what this registers.
144 virtual void SetUp() OVERRIDE;
145 virtual void TearDown() OVERRIDE;
147 void RunTest(TestData* cases, int num_cases, bool prefer_keyword);
149 protected:
150 // Needed for AutocompleteFieldTrial::ActivateStaticTrials();
151 scoped_ptr<base::FieldTrialList> field_trial_list_;
153 // Default value used for testing.
154 static const std::string kNotApplicable;
156 // Adds a search for |term|, using the engine |t_url| to the history, and
157 // returns the URL for that search.
158 GURL AddSearchToHistory(TemplateURL* t_url, base::string16 term, int visit_count);
160 // Looks for a match in |provider_| with |contents| equal to |contents|.
161 // Sets |match| to it if found. Returns whether |match| was set.
162 bool FindMatchWithContents(const base::string16& contents,
163 AutocompleteMatch* match);
165 // Looks for a match in |provider_| with destination |url|. Sets |match| to
166 // it if found. Returns whether |match| was set.
167 bool FindMatchWithDestination(const GURL& url, AutocompleteMatch* match);
169 // AutocompleteProviderListener:
170 // If we're waiting for the provider to finish, this exits the message loop.
171 virtual void OnProviderUpdate(bool updated_matches) OVERRIDE;
173 // Runs a nested message loop until provider_ is done. The message loop is
174 // exited by way of OnProviderUpdate.
175 void RunTillProviderDone();
177 // Invokes Start on provider_, then runs all pending tasks.
178 void QueryForInput(const base::string16& text,
179 bool prevent_inline_autocomplete,
180 bool prefer_keyword);
182 // Calls QueryForInput(), finishes any suggest query, then if |wyt_match| is
183 // non-NULL, sets it to the "what you typed" entry for |text|.
184 void QueryForInputAndSetWYTMatch(const base::string16& text,
185 AutocompleteMatch* wyt_match);
187 // Notifies the URLFetcher for the suggest query corresponding to the default
188 // search provider that it's done.
189 // Be sure and wrap calls to this in ASSERT_NO_FATAL_FAILURE.
190 void FinishDefaultSuggestQuery();
192 // Runs SearchProvider on |input|, for which the suggest server replies
193 // with |json|, and expects that the resulting matches' contents equals
194 // that in |matches|. An empty entry in |matches| means no match should
195 // be returned in that position. Reports any errors with a message that
196 // includes |error_description|.
197 void ForcedQueryTestHelper(const std::string& input,
198 const std::string& json,
199 const std::string matches[3],
200 const std::string& error_description);
202 void ResetFieldTrialList();
204 void ClearAllResults();
206 // See description above class for details of these fields.
207 TemplateURL* default_t_url_;
208 const base::string16 term1_;
209 GURL term1_url_;
210 TemplateURL* keyword_t_url_;
211 const base::string16 keyword_term_;
212 GURL keyword_url_;
214 content::TestBrowserThreadBundle thread_bundle_;
216 // URLFetcherFactory implementation registered.
217 net::TestURLFetcherFactory test_factory_;
219 // Profile we use.
220 TestingProfile profile_;
222 // The provider.
223 scoped_refptr<SearchProviderForTest> provider_;
225 // If non-NULL, OnProviderUpdate quits the current |run_loop_|.
226 base::RunLoop* run_loop_;
228 DISALLOW_COPY_AND_ASSIGN(SearchProviderTest);
231 // static
232 const std::string SearchProviderTest::kNotApplicable = "Not Applicable";
234 void SearchProviderTest::SetUp() {
235 // Make sure that fetchers are automatically ungregistered upon destruction.
236 test_factory_.set_remove_fetcher_on_delete(true);
238 // We need both the history service and template url model loaded.
239 ASSERT_TRUE(profile_.CreateHistoryService(true, false));
240 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
241 &profile_, &TemplateURLServiceFactory::BuildInstanceFor);
243 TemplateURLService* turl_model =
244 TemplateURLServiceFactory::GetForProfile(&profile_);
246 turl_model->Load();
248 // Reset the default TemplateURL.
249 TemplateURLData data;
250 data.short_name = ASCIIToUTF16("t");
251 data.SetURL("http://defaultturl/{searchTerms}");
252 data.suggestions_url = "http://defaultturl2/{searchTerms}";
253 data.instant_url = "http://does/not/exist?strk=1";
254 data.search_terms_replacement_key = "strk";
255 default_t_url_ = new TemplateURL(&profile_, data);
256 turl_model->Add(default_t_url_);
257 turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
258 TemplateURLID default_provider_id = default_t_url_->id();
259 ASSERT_NE(0, default_provider_id);
261 // Add url1, with search term term1_.
262 term1_url_ = AddSearchToHistory(default_t_url_, term1_, 1);
264 // Create another TemplateURL.
265 data.short_name = ASCIIToUTF16("k");
266 data.SetKeyword(ASCIIToUTF16("k"));
267 data.SetURL("http://keyword/{searchTerms}");
268 data.suggestions_url = "http://suggest_keyword/{searchTerms}";
269 keyword_t_url_ = new TemplateURL(&profile_, data);
270 turl_model->Add(keyword_t_url_);
271 ASSERT_NE(0, keyword_t_url_->id());
273 // Add a page and search term for keyword_t_url_.
274 keyword_url_ = AddSearchToHistory(keyword_t_url_, keyword_term_, 1);
276 // Keywords are updated by the InMemoryHistoryBackend only after the message
277 // has been processed on the history thread. Block until history processes all
278 // requests to ensure the InMemoryDatabase is the state we expect it.
279 profile_.BlockUntilHistoryProcessesPendingRequests();
281 provider_ = new SearchProviderForTest(this, &profile_);
282 provider_->kMinimumTimeBetweenSuggestQueriesMs = 0;
285 void SearchProviderTest::TearDown() {
286 base::RunLoop().RunUntilIdle();
288 // Shutdown the provider before the profile.
289 provider_ = NULL;
292 void SearchProviderTest::RunTest(TestData* cases,
293 int num_cases,
294 bool prefer_keyword) {
295 ACMatches matches;
296 for (int i = 0; i < num_cases; ++i) {
297 AutocompleteInput input(cases[i].input, base::string16::npos,
298 base::string16(), GURL(),
299 AutocompleteInput::INVALID_SPEC, false,
300 prefer_keyword, true, true);
301 provider_->Start(input, false);
302 matches = provider_->matches();
303 base::string16 diagnostic_details =
304 ASCIIToUTF16("Input was: ") +
305 cases[i].input +
306 ASCIIToUTF16("; prefer_keyword was: ") +
307 (prefer_keyword ? ASCIIToUTF16("true") : ASCIIToUTF16("false"));
308 EXPECT_EQ(cases[i].num_results, matches.size()) << diagnostic_details;
309 if (matches.size() == cases[i].num_results) {
310 for (size_t j = 0; j < cases[i].num_results; ++j) {
311 EXPECT_EQ(cases[i].output[j].gurl, matches[j].destination_url) <<
312 diagnostic_details;
313 EXPECT_EQ(cases[i].output[j].result_type, matches[j].type) <<
314 diagnostic_details;
315 EXPECT_EQ(cases[i].output[j].fill_into_edit,
316 matches[j].fill_into_edit) << diagnostic_details;
317 EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match,
318 matches[j].allowed_to_be_default_match) << diagnostic_details;
324 void SearchProviderTest::OnProviderUpdate(bool updated_matches) {
325 if (run_loop_ && provider_->done()) {
326 run_loop_->Quit();
327 run_loop_ = NULL;
331 void SearchProviderTest::RunTillProviderDone() {
332 if (provider_->done())
333 return;
335 base::RunLoop run_loop;
336 run_loop_ = &run_loop;
337 run_loop.Run();
340 void SearchProviderTest::QueryForInput(const base::string16& text,
341 bool prevent_inline_autocomplete,
342 bool prefer_keyword) {
343 // Start a query.
344 AutocompleteInput input(text, base::string16::npos, base::string16(), GURL(),
345 AutocompleteInput::INVALID_SPEC,
346 prevent_inline_autocomplete, prefer_keyword, true,
347 true);
348 provider_->Start(input, false);
350 // RunUntilIdle so that the task scheduled by SearchProvider to create the
351 // URLFetchers runs.
352 base::RunLoop().RunUntilIdle();
355 void SearchProviderTest::QueryForInputAndSetWYTMatch(
356 const base::string16& text,
357 AutocompleteMatch* wyt_match) {
358 QueryForInput(text, false, false);
359 profile_.BlockUntilHistoryProcessesPendingRequests();
360 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
361 if (!wyt_match)
362 return;
363 ASSERT_GE(provider_->matches().size(), 1u);
364 EXPECT_TRUE(FindMatchWithDestination(GURL(
365 default_t_url_->url_ref().ReplaceSearchTerms(
366 TemplateURLRef::SearchTermsArgs(base::CollapseWhitespace(
367 text, false)))),
368 wyt_match));
371 GURL SearchProviderTest::AddSearchToHistory(TemplateURL* t_url,
372 base::string16 term,
373 int visit_count) {
374 HistoryService* history =
375 HistoryServiceFactory::GetForProfile(&profile_,
376 Profile::EXPLICIT_ACCESS);
377 GURL search(t_url->url_ref().ReplaceSearchTerms(
378 TemplateURLRef::SearchTermsArgs(term)));
379 static base::Time last_added_time;
380 last_added_time = std::max(base::Time::Now(),
381 last_added_time + base::TimeDelta::FromMicroseconds(1));
382 history->AddPageWithDetails(search, base::string16(), visit_count, visit_count,
383 last_added_time, false, history::SOURCE_BROWSED);
384 history->SetKeywordSearchTermsForURL(search, t_url->id(), term);
385 return search;
388 bool SearchProviderTest::FindMatchWithContents(const base::string16& contents,
389 AutocompleteMatch* match) {
390 for (ACMatches::const_iterator i = provider_->matches().begin();
391 i != provider_->matches().end(); ++i) {
392 if (i->contents == contents) {
393 *match = *i;
394 return true;
397 return false;
400 bool SearchProviderTest::FindMatchWithDestination(const GURL& url,
401 AutocompleteMatch* match) {
402 for (ACMatches::const_iterator i = provider_->matches().begin();
403 i != provider_->matches().end(); ++i) {
404 if (i->destination_url == url) {
405 *match = *i;
406 return true;
409 return false;
412 void SearchProviderTest::FinishDefaultSuggestQuery() {
413 net::TestURLFetcher* default_fetcher =
414 test_factory_.GetFetcherByID(
415 SearchProvider::kDefaultProviderURLFetcherID);
416 ASSERT_TRUE(default_fetcher);
418 // Tell the SearchProvider the default suggest query is done.
419 default_fetcher->set_response_code(200);
420 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
423 void SearchProviderTest::ForcedQueryTestHelper(
424 const std::string& input,
425 const std::string& json,
426 const std::string expected_matches[3],
427 const std::string& error_description) {
428 QueryForInput(ASCIIToUTF16(input), false, false);
429 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
430 SearchProvider::kDefaultProviderURLFetcherID);
431 ASSERT_TRUE(fetcher);
432 fetcher->set_response_code(200);
433 fetcher->SetResponseString(json);
434 fetcher->delegate()->OnURLFetchComplete(fetcher);
435 RunTillProviderDone();
437 const ACMatches& matches = provider_->matches();
438 ASSERT_LE(matches.size(), 3u);
439 size_t i = 0;
440 // Ensure that the returned matches equal the expectations.
441 for (; i < matches.size(); ++i) {
442 EXPECT_EQ(ASCIIToUTF16(expected_matches[i]), matches[i].contents) <<
443 error_description;
445 // Ensure that no expected matches are missing.
446 for (; i < 3u; ++i) {
447 EXPECT_EQ(std::string(), expected_matches[i]) <<
448 "Case #" << i << ": " << error_description;
452 void SearchProviderTest::ResetFieldTrialList() {
453 // Destroy the existing FieldTrialList before creating a new one to avoid
454 // a DCHECK.
455 field_trial_list_.reset();
456 field_trial_list_.reset(new base::FieldTrialList(
457 new metrics::SHA1EntropyProvider("foo")));
458 chrome_variations::testing::ClearAllVariationParams();
459 base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
460 "AutocompleteDynamicTrial_0", "DefaultGroup");
461 trial->group();
464 void SearchProviderTest::ClearAllResults() {
465 provider_->ClearAllResults();
468 // Actual Tests ---------------------------------------------------------------
470 // Make sure we query history for the default provider and a URLFetcher is
471 // created for the default provider suggest results.
472 TEST_F(SearchProviderTest, QueryDefaultProvider) {
473 base::string16 term = term1_.substr(0, term1_.length() - 1);
474 QueryForInput(term, false, false);
476 // Make sure the default providers suggest service was queried.
477 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
478 SearchProvider::kDefaultProviderURLFetcherID);
479 ASSERT_TRUE(fetcher);
481 // And the URL matches what we expected.
482 GURL expected_url(default_t_url_->suggestions_url_ref().ReplaceSearchTerms(
483 TemplateURLRef::SearchTermsArgs(term)));
484 ASSERT_TRUE(fetcher->GetOriginalURL() == expected_url);
486 // Tell the SearchProvider the suggest query is done.
487 fetcher->set_response_code(200);
488 fetcher->delegate()->OnURLFetchComplete(fetcher);
489 fetcher = NULL;
491 // Run till the history results complete.
492 RunTillProviderDone();
494 // The SearchProvider is done. Make sure it has a result for the history
495 // term term1.
496 AutocompleteMatch term1_match;
497 EXPECT_TRUE(FindMatchWithDestination(term1_url_, &term1_match));
498 // Term1 should not have a description, it's set later.
499 EXPECT_TRUE(term1_match.description.empty());
501 AutocompleteMatch wyt_match;
502 EXPECT_TRUE(FindMatchWithDestination(
503 GURL(default_t_url_->url_ref().ReplaceSearchTerms(
504 TemplateURLRef::SearchTermsArgs(term))), &wyt_match));
505 EXPECT_TRUE(wyt_match.description.empty());
507 // The match for term1 should be more relevant than the what you typed match.
508 EXPECT_GT(term1_match.relevance, wyt_match.relevance);
509 // This longer match should be inlineable.
510 EXPECT_TRUE(term1_match.allowed_to_be_default_match);
511 // The what you typed match should be too, of course.
512 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
515 TEST_F(SearchProviderTest, HonorPreventInlineAutocomplete) {
516 base::string16 term = term1_.substr(0, term1_.length() - 1);
517 QueryForInput(term, true, false);
519 ASSERT_FALSE(provider_->matches().empty());
520 ASSERT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
521 provider_->matches()[0].type);
522 EXPECT_TRUE(provider_->matches()[0].allowed_to_be_default_match);
525 // Issues a query that matches the registered keyword and makes sure history
526 // is queried as well as URLFetchers getting created.
527 TEST_F(SearchProviderTest, QueryKeywordProvider) {
528 base::string16 term = keyword_term_.substr(0, keyword_term_.length() - 1);
529 QueryForInput(keyword_t_url_->keyword() + ASCIIToUTF16(" ") + term,
530 false,
531 false);
533 // Make sure the default providers suggest service was queried.
534 net::TestURLFetcher* default_fetcher = test_factory_.GetFetcherByID(
535 SearchProvider::kDefaultProviderURLFetcherID);
536 ASSERT_TRUE(default_fetcher);
538 // Tell the SearchProvider the default suggest query is done.
539 default_fetcher->set_response_code(200);
540 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
541 default_fetcher = NULL;
543 // Make sure the keyword providers suggest service was queried.
544 net::TestURLFetcher* keyword_fetcher = test_factory_.GetFetcherByID(
545 SearchProvider::kKeywordProviderURLFetcherID);
546 ASSERT_TRUE(keyword_fetcher);
548 // And the URL matches what we expected.
549 GURL expected_url(keyword_t_url_->suggestions_url_ref().ReplaceSearchTerms(
550 TemplateURLRef::SearchTermsArgs(term)));
551 ASSERT_TRUE(keyword_fetcher->GetOriginalURL() == expected_url);
553 // Tell the SearchProvider the keyword suggest query is done.
554 keyword_fetcher->set_response_code(200);
555 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
556 keyword_fetcher = NULL;
558 // Run till the history results complete.
559 RunTillProviderDone();
561 // The SearchProvider is done. Make sure it has a result for the history
562 // term keyword.
563 AutocompleteMatch match;
564 EXPECT_TRUE(FindMatchWithDestination(keyword_url_, &match));
566 // The match should have an associated keyword.
567 EXPECT_FALSE(match.keyword.empty());
569 // The fill into edit should contain the keyword.
570 EXPECT_EQ(keyword_t_url_->keyword() + base::char16(' ') + keyword_term_,
571 match.fill_into_edit);
574 TEST_F(SearchProviderTest, DontSendPrivateDataToSuggest) {
575 // None of the following input strings should be sent to the suggest server,
576 // because they may contain private data.
577 const char* inputs[] = {
578 "username:password",
579 "http://username:password",
580 "https://username:password",
581 "username:password@hostname",
582 "http://username:password@hostname/",
583 "file://filename",
584 "data://data",
585 "unknownscheme:anything",
586 "http://hostname/?query=q",
587 "http://hostname/path#ref",
588 "http://hostname/path #ref",
589 "https://hostname/path",
592 for (size_t i = 0; i < arraysize(inputs); ++i) {
593 QueryForInput(ASCIIToUTF16(inputs[i]), false, false);
594 // Make sure the default provider's suggest service was not queried.
595 ASSERT_TRUE(test_factory_.GetFetcherByID(
596 SearchProvider::kDefaultProviderURLFetcherID) == NULL);
597 // Run till the history results complete.
598 RunTillProviderDone();
602 TEST_F(SearchProviderTest, SendNonPrivateDataToSuggest) {
603 // All of the following input strings should be sent to the suggest server,
604 // because they should not get caught by the private data checks.
605 const char* inputs[] = {
606 "query",
607 "query with spaces",
608 "http://hostname",
609 "http://hostname/path",
610 "http://hostname #ref",
611 "www.hostname.com #ref",
612 "https://hostname",
613 "#hashtag",
614 "foo https://hostname/path"
617 profile_.BlockUntilHistoryProcessesPendingRequests();
618 for (size_t i = 0; i < arraysize(inputs); ++i) {
619 QueryForInput(ASCIIToUTF16(inputs[i]), false, false);
620 // Make sure the default provider's suggest service was queried.
621 ASSERT_TRUE(test_factory_.GetFetcherByID(
622 SearchProvider::kDefaultProviderURLFetcherID) != NULL);
626 TEST_F(SearchProviderTest, DontAutocompleteURLLikeTerms) {
627 AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
628 &profile_, &AutocompleteClassifierFactory::BuildInstanceFor);
629 GURL url = AddSearchToHistory(default_t_url_,
630 ASCIIToUTF16("docs.google.com"), 1);
632 // Add the term as a url.
633 HistoryServiceFactory::GetForProfile(&profile_, Profile::EXPLICIT_ACCESS)->
634 AddPageWithDetails(GURL("http://docs.google.com"), base::string16(), 1, 1,
635 base::Time::Now(), false, history::SOURCE_BROWSED);
636 profile_.BlockUntilHistoryProcessesPendingRequests();
638 AutocompleteMatch wyt_match;
639 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("docs"),
640 &wyt_match));
642 // There should be two matches, one for what you typed, the other for
643 // 'docs.google.com'. The search term should have a lower priority than the
644 // what you typed match.
645 ASSERT_EQ(2u, provider_->matches().size());
646 AutocompleteMatch term_match;
647 EXPECT_TRUE(FindMatchWithDestination(url, &term_match));
648 EXPECT_GT(wyt_match.relevance, term_match.relevance);
649 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
650 EXPECT_TRUE(term_match.allowed_to_be_default_match);
653 TEST_F(SearchProviderTest, DontGiveNavsuggestionsInForcedQueryMode) {
654 const std::string kEmptyMatch;
655 struct {
656 const std::string json;
657 const std::string matches_in_default_mode[3];
658 const std::string matches_in_forced_query_mode[3];
659 } cases[] = {
660 // Without suggested relevance scores.
661 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
662 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]}]",
663 { "a", "a1.com", "a2" },
664 { "a", "a2", kEmptyMatch } },
666 // With suggested relevance scores in a situation where navsuggest would
667 // go second.
668 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
669 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
670 "\"google:suggestrelevance\":[1250, 1200]}]",
671 { "a", "a1.com", "a2" },
672 { "a", "a2", kEmptyMatch } },
674 // With suggested relevance scores in a situation where navsuggest
675 // would go first.
676 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
677 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
678 "\"google:suggestrelevance\":[1350, 1250]}]",
679 { "a1.com", "a", "a2" },
680 { "a", "a2", kEmptyMatch } },
682 // With suggested relevance scores in a situation where navsuggest
683 // would go first only because verbatim has been demoted.
684 { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
685 "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
686 "\"google:suggestrelevance\":[1450, 1400],"
687 "\"google:verbatimrelevance\":1350}]",
688 { "a1.com", "a2", "a" },
689 { "a2", "a", kEmptyMatch } },
692 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
693 ForcedQueryTestHelper("a", cases[i].json, cases[i].matches_in_default_mode,
694 "regular input with json=" + cases[i].json);
695 ForcedQueryTestHelper("?a", cases[i].json,
696 cases[i].matches_in_forced_query_mode,
697 "forced query input with json=" + cases[i].json);
701 // A multiword search with one visit should not autocomplete until multiple
702 // words are typed.
703 TEST_F(SearchProviderTest, DontAutocompleteUntilMultipleWordsTyped) {
704 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("one search"),
705 1));
706 profile_.BlockUntilHistoryProcessesPendingRequests();
708 AutocompleteMatch wyt_match;
709 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("on"),
710 &wyt_match));
711 ASSERT_EQ(2u, provider_->matches().size());
712 AutocompleteMatch term_match;
713 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
714 EXPECT_GT(wyt_match.relevance, term_match.relevance);
715 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
716 EXPECT_TRUE(term_match.allowed_to_be_default_match);
718 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("one se"),
719 &wyt_match));
720 ASSERT_EQ(2u, provider_->matches().size());
721 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
722 EXPECT_GT(term_match.relevance, wyt_match.relevance);
723 EXPECT_TRUE(term_match.allowed_to_be_default_match);
724 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
727 // A multiword search with more than one visit should autocomplete immediately.
728 TEST_F(SearchProviderTest, AutocompleteMultipleVisitsImmediately) {
729 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches"),
730 2));
731 profile_.BlockUntilHistoryProcessesPendingRequests();
733 AutocompleteMatch wyt_match;
734 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("tw"),
735 &wyt_match));
736 ASSERT_EQ(2u, provider_->matches().size());
737 AutocompleteMatch term_match;
738 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
739 EXPECT_GT(term_match.relevance, wyt_match.relevance);
740 EXPECT_TRUE(term_match.allowed_to_be_default_match);
741 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
744 // Autocompletion should work at a word boundary after a space, and should
745 // offer a suggestion for the trimmed search query.
746 TEST_F(SearchProviderTest, AutocompleteAfterSpace) {
747 AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches "), 2);
748 GURL suggested_url(default_t_url_->url_ref().ReplaceSearchTerms(
749 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("two searches"))));
750 profile_.BlockUntilHistoryProcessesPendingRequests();
752 AutocompleteMatch wyt_match;
753 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("two "),
754 &wyt_match));
755 ASSERT_EQ(2u, provider_->matches().size());
756 AutocompleteMatch term_match;
757 EXPECT_TRUE(FindMatchWithDestination(suggested_url, &term_match));
758 EXPECT_GT(term_match.relevance, wyt_match.relevance);
759 EXPECT_TRUE(term_match.allowed_to_be_default_match);
760 EXPECT_EQ(ASCIIToUTF16("searches"), term_match.inline_autocompletion);
761 EXPECT_EQ(ASCIIToUTF16("two searches"), term_match.fill_into_edit);
762 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
765 // Newer multiword searches should score more highly than older ones.
766 TEST_F(SearchProviderTest, ScoreNewerSearchesHigher) {
767 GURL term_url_a(AddSearchToHistory(default_t_url_,
768 ASCIIToUTF16("three searches aaa"), 1));
769 GURL term_url_b(AddSearchToHistory(default_t_url_,
770 ASCIIToUTF16("three searches bbb"), 1));
771 profile_.BlockUntilHistoryProcessesPendingRequests();
773 AutocompleteMatch wyt_match;
774 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("three se"),
775 &wyt_match));
776 ASSERT_EQ(3u, provider_->matches().size());
777 AutocompleteMatch term_match_a;
778 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
779 AutocompleteMatch term_match_b;
780 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
781 EXPECT_GT(term_match_b.relevance, term_match_a.relevance);
782 EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
783 EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
784 EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
785 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
788 // An autocompleted multiword search should not be replaced by a different
789 // autocompletion while the user is still typing a valid prefix.
790 TEST_F(SearchProviderTest, DontReplacePreviousAutocompletion) {
791 GURL term_url_a(AddSearchToHistory(default_t_url_,
792 ASCIIToUTF16("four searches aaa"), 2));
793 GURL term_url_b(AddSearchToHistory(default_t_url_,
794 ASCIIToUTF16("four searches bbb"), 1));
795 profile_.BlockUntilHistoryProcessesPendingRequests();
797 AutocompleteMatch wyt_match;
798 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fo"),
799 &wyt_match));
800 ASSERT_EQ(3u, provider_->matches().size());
801 AutocompleteMatch term_match_a;
802 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
803 AutocompleteMatch term_match_b;
804 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
805 EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
806 EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
807 EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
808 EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
809 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
811 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("four se"),
812 &wyt_match));
813 ASSERT_EQ(3u, provider_->matches().size());
814 EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
815 EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
816 EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
817 EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
818 EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
819 EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
820 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
823 // Non-completable multiword searches should not crowd out single-word searches.
824 TEST_F(SearchProviderTest, DontCrowdOutSingleWords) {
825 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("five"), 1));
826 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches bbb"), 1);
827 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches ccc"), 1);
828 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches ddd"), 1);
829 AddSearchToHistory(default_t_url_, ASCIIToUTF16("five searches eee"), 1);
830 profile_.BlockUntilHistoryProcessesPendingRequests();
832 AutocompleteMatch wyt_match;
833 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fi"),
834 &wyt_match));
835 ASSERT_EQ(AutocompleteProvider::kMaxMatches + 1, provider_->matches().size());
836 AutocompleteMatch term_match;
837 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
838 EXPECT_GT(term_match.relevance, wyt_match.relevance);
839 EXPECT_TRUE(term_match.allowed_to_be_default_match);
840 EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
843 // Inline autocomplete matches regardless of case differences from the input.
844 TEST_F(SearchProviderTest, InlineMixedCaseMatches) {
845 GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("FOO"), 1));
846 profile_.BlockUntilHistoryProcessesPendingRequests();
848 AutocompleteMatch wyt_match;
849 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("f"),
850 &wyt_match));
851 ASSERT_EQ(2u, provider_->matches().size());
852 AutocompleteMatch term_match;
853 EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
854 EXPECT_GT(term_match.relevance, wyt_match.relevance);
855 EXPECT_EQ(ASCIIToUTF16("FOO"), term_match.fill_into_edit);
856 EXPECT_EQ(ASCIIToUTF16("OO"), term_match.inline_autocompletion);
857 EXPECT_TRUE(term_match.allowed_to_be_default_match);
860 // Verifies AutocompleteControllers return results (including keyword
861 // results) in the right order and set descriptions for them correctly.
862 TEST_F(SearchProviderTest, KeywordOrderingAndDescriptions) {
863 // Add an entry that corresponds to a keyword search with 'term2'.
864 AddSearchToHistory(keyword_t_url_, ASCIIToUTF16("term2"), 1);
865 profile_.BlockUntilHistoryProcessesPendingRequests();
867 AutocompleteController controller(&profile_, NULL,
868 AutocompleteProvider::TYPE_SEARCH);
869 controller.Start(AutocompleteInput(
870 ASCIIToUTF16("k t"), base::string16::npos, base::string16(), GURL(),
871 AutocompleteInput::INVALID_SPEC, false, false, true, true));
872 const AutocompleteResult& result = controller.result();
874 // There should be three matches, one for the keyword history, one for
875 // keyword provider's what-you-typed, and one for the default provider's
876 // what you typed, in that order.
877 ASSERT_EQ(3u, result.size());
878 EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY, result.match_at(0).type);
879 EXPECT_EQ(AutocompleteMatchType::SEARCH_OTHER_ENGINE,
880 result.match_at(1).type);
881 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
882 result.match_at(2).type);
883 EXPECT_GT(result.match_at(0).relevance, result.match_at(1).relevance);
884 EXPECT_GT(result.match_at(1).relevance, result.match_at(2).relevance);
885 EXPECT_TRUE(result.match_at(0).allowed_to_be_default_match);
886 EXPECT_TRUE(result.match_at(1).allowed_to_be_default_match);
887 EXPECT_FALSE(result.match_at(2).allowed_to_be_default_match);
889 // The two keyword results should come with the keyword we expect.
890 EXPECT_EQ(ASCIIToUTF16("k"), result.match_at(0).keyword);
891 EXPECT_EQ(ASCIIToUTF16("k"), result.match_at(1).keyword);
892 // The default provider has a different keyword. (We don't explicitly
893 // set it during this test, so all we do is assert that it's different.)
894 EXPECT_NE(result.match_at(0).keyword, result.match_at(2).keyword);
896 // The top result will always have a description. The third result,
897 // coming from a different provider than the first two, should also.
898 // Whether the second result has one doesn't matter much. (If it was
899 // missing, people would infer that it's the same search provider as
900 // the one above it.)
901 EXPECT_FALSE(result.match_at(0).description.empty());
902 EXPECT_FALSE(result.match_at(2).description.empty());
903 EXPECT_NE(result.match_at(0).description, result.match_at(2).description);
906 TEST_F(SearchProviderTest, KeywordVerbatim) {
907 TestData cases[] = {
908 // Test a simple keyword input.
909 { ASCIIToUTF16("k foo"), 2,
910 { ResultInfo(GURL("http://keyword/foo"),
911 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
912 true,
913 ASCIIToUTF16("k foo")),
914 ResultInfo(GURL("http://defaultturl/k%20foo"),
915 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
916 false,
917 ASCIIToUTF16("k foo") ) } },
919 // Make sure extra whitespace after the keyword doesn't change the
920 // keyword verbatim query. Also verify that interior consecutive
921 // whitespace gets trimmed.
922 { ASCIIToUTF16("k foo"), 2,
923 { ResultInfo(GURL("http://keyword/foo"),
924 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
925 true,
926 ASCIIToUTF16("k foo")),
927 ResultInfo(GURL("http://defaultturl/k%20foo"),
928 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
929 false,
930 ASCIIToUTF16("k foo")) } },
931 // Leading whitespace should be stripped before SearchProvider gets the
932 // input; hence there are no tests here about how it handles those inputs.
934 // Verify that interior consecutive whitespace gets trimmed in either case.
935 { ASCIIToUTF16("k foo bar"), 2,
936 { ResultInfo(GURL("http://keyword/foo%20bar"),
937 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
938 true,
939 ASCIIToUTF16("k foo bar")),
940 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
941 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
942 false,
943 ASCIIToUTF16("k foo bar")) } },
945 // Verify that trailing whitespace gets trimmed.
946 { ASCIIToUTF16("k foo bar "), 2,
947 { ResultInfo(GURL("http://keyword/foo%20bar"),
948 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
949 true,
950 ASCIIToUTF16("k foo bar")),
951 ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
952 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
953 false,
954 ASCIIToUTF16("k foo bar")) } },
956 // Keywords can be prefixed by certain things that should get ignored
957 // when constructing the keyword match.
958 { ASCIIToUTF16("www.k foo"), 2,
959 { ResultInfo(GURL("http://keyword/foo"),
960 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
961 true,
962 ASCIIToUTF16("k foo")),
963 ResultInfo(GURL("http://defaultturl/www.k%20foo"),
964 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
965 false,
966 ASCIIToUTF16("www.k foo")) } },
967 { ASCIIToUTF16("http://k foo"), 2,
968 { ResultInfo(GURL("http://keyword/foo"),
969 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
970 true,
971 ASCIIToUTF16("k foo")),
972 ResultInfo(GURL("http://defaultturl/http%3A//k%20foo"),
973 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
974 false,
975 ASCIIToUTF16("http://k foo")) } },
976 { ASCIIToUTF16("http://www.k foo"), 2,
977 { ResultInfo(GURL("http://keyword/foo"),
978 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
979 true,
980 ASCIIToUTF16("k foo")),
981 ResultInfo(GURL("http://defaultturl/http%3A//www.k%20foo"),
982 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
983 false,
984 ASCIIToUTF16("http://www.k foo")) } },
986 // A keyword with no remaining input shouldn't get a keyword
987 // verbatim match.
988 { ASCIIToUTF16("k"), 1,
989 { ResultInfo(GURL("http://defaultturl/k"),
990 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
991 true,
992 ASCIIToUTF16("k")) } },
993 // Ditto. Trailing whitespace shouldn't make a difference.
994 { ASCIIToUTF16("k "), 1,
995 { ResultInfo(GURL("http://defaultturl/k"),
996 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
997 true,
998 ASCIIToUTF16("k")) } }
1000 // The fact that verbatim queries to keyword are handled by KeywordProvider
1001 // not SearchProvider is tested in
1002 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc.
1005 // Test not in keyword mode.
1006 RunTest(cases, arraysize(cases), false);
1008 // Test in keyword mode. (Both modes should give the same result.)
1009 RunTest(cases, arraysize(cases), true);
1012 // Ensures command-line flags are reflected in the URLs the search provider
1013 // generates.
1014 TEST_F(SearchProviderTest, CommandLineOverrides) {
1015 TemplateURLService* turl_model =
1016 TemplateURLServiceFactory::GetForProfile(&profile_);
1018 TemplateURLData data;
1019 data.short_name = ASCIIToUTF16("default");
1020 data.SetKeyword(data.short_name);
1021 data.SetURL("{google:baseURL}{searchTerms}");
1022 default_t_url_ = new TemplateURL(&profile_, data);
1023 turl_model->Add(default_t_url_);
1024 turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
1026 CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
1027 "http://www.bar.com/");
1028 CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1029 switches::kExtraSearchQueryParams, "a=b");
1031 TestData cases[] = {
1032 { ASCIIToUTF16("k a"), 2,
1033 { ResultInfo(GURL("http://keyword/a"),
1034 AutocompleteMatchType::SEARCH_OTHER_ENGINE,
1035 true,
1036 ASCIIToUTF16("k a")),
1037 ResultInfo(GURL("http://www.bar.com/k%20a?a=b"),
1038 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1039 false,
1040 ASCIIToUTF16("k a")) } },
1043 RunTest(cases, arraysize(cases), false);
1046 // Verifies Navsuggest results don't set a TemplateURL, which Instant relies on.
1047 // Also verifies that just the *first* navigational result is listed as a match
1048 // if suggested relevance scores were not sent.
1049 TEST_F(SearchProviderTest, NavSuggestNoSuggestedRelevanceScores) {
1050 QueryForInput(ASCIIToUTF16("a.c"), false, false);
1052 // Make sure the default providers suggest service was queried.
1053 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
1054 SearchProvider::kDefaultProviderURLFetcherID);
1055 ASSERT_TRUE(fetcher);
1057 // Tell the SearchProvider the suggest query is done.
1058 fetcher->set_response_code(200);
1059 fetcher->SetResponseString(
1060 "[\"a.c\",[\"a.com\", \"a.com/b\"],[\"a\", \"b\"],[],"
1061 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]");
1062 fetcher->delegate()->OnURLFetchComplete(fetcher);
1063 fetcher = NULL;
1065 // Run till the history results complete.
1066 RunTillProviderDone();
1068 // Make sure the only match is 'a.com' and it doesn't have a template_url.
1069 AutocompleteMatch nav_match;
1070 EXPECT_TRUE(FindMatchWithDestination(GURL("http://a.com"), &nav_match));
1071 EXPECT_TRUE(nav_match.keyword.empty());
1072 EXPECT_TRUE(nav_match.allowed_to_be_default_match);
1073 EXPECT_FALSE(FindMatchWithDestination(GURL("http://a.com/b"), &nav_match));
1076 // Verifies that the most relevant suggest results are added properly.
1077 TEST_F(SearchProviderTest, SuggestRelevance) {
1078 QueryForInput(ASCIIToUTF16("a"), false, false);
1080 // Make sure the default provider's suggest service was queried.
1081 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
1082 SearchProvider::kDefaultProviderURLFetcherID);
1083 ASSERT_TRUE(fetcher);
1085 // Tell the SearchProvider the suggest query is done.
1086 fetcher->set_response_code(200);
1087 fetcher->SetResponseString("[\"a\",[\"a1\", \"a2\", \"a3\", \"a4\"]]");
1088 fetcher->delegate()->OnURLFetchComplete(fetcher);
1089 fetcher = NULL;
1091 // Run till the history results complete.
1092 RunTillProviderDone();
1094 // Check the expected verbatim and (first 3) suggestions' relative relevances.
1095 AutocompleteMatch verbatim, match_a1, match_a2, match_a3, match_a4;
1096 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim));
1097 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a1"), &match_a1));
1098 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a2"), &match_a2));
1099 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a3"), &match_a3));
1100 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("a4"), &match_a4));
1101 EXPECT_GT(verbatim.relevance, match_a1.relevance);
1102 EXPECT_GT(match_a1.relevance, match_a2.relevance);
1103 EXPECT_GT(match_a2.relevance, match_a3.relevance);
1104 EXPECT_TRUE(verbatim.allowed_to_be_default_match);
1105 EXPECT_TRUE(match_a1.allowed_to_be_default_match);
1106 EXPECT_TRUE(match_a2.allowed_to_be_default_match);
1107 EXPECT_TRUE(match_a3.allowed_to_be_default_match);
1110 // Verifies that the default provider abandons suggested relevance scores
1111 // when in keyword mode. This should happen regardless of whether the
1112 // keyword provider returns suggested relevance scores.
1113 TEST_F(SearchProviderTest, DefaultProviderNoSuggestRelevanceInKeywordMode) {
1114 struct {
1115 const std::string default_provider_json;
1116 const std::string keyword_provider_json;
1117 const std::string matches[5];
1118 } cases[] = {
1119 // First, try an input where the keyword provider does not deliver
1120 // suggested relevance scores.
1121 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1122 "{\"google:verbatimrelevance\":9700,"
1123 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1124 "\"google:suggestrelevance\":[9900, 9800]}]",
1125 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"]}]",
1126 { "a", "akeyword-query", "k a", "adefault.com", "k adefault-query" } },
1128 // Now try with keyword provider suggested relevance scores.
1129 { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
1130 "{\"google:verbatimrelevance\":9700,"
1131 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
1132 "\"google:suggestrelevance\":[9900, 9800]}]",
1133 "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"],"
1134 "\"google:verbatimrelevance\":9500,"
1135 "\"google:suggestrelevance\":[9600]}]",
1136 { "akeyword-query", "a", "k a", "adefault.com", "k adefault-query" } }
1139 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1140 QueryForInput(ASCIIToUTF16("k a"), false, true);
1141 net::TestURLFetcher* default_fetcher =
1142 test_factory_.GetFetcherByID(
1143 SearchProvider::kDefaultProviderURLFetcherID);
1144 ASSERT_TRUE(default_fetcher);
1145 default_fetcher->set_response_code(200);
1146 default_fetcher->SetResponseString(cases[i].default_provider_json);
1147 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
1148 net::TestURLFetcher* keyword_fetcher =
1149 test_factory_.GetFetcherByID(
1150 SearchProvider::kKeywordProviderURLFetcherID);
1151 ASSERT_TRUE(keyword_fetcher);
1152 keyword_fetcher->set_response_code(200);
1153 keyword_fetcher->SetResponseString(cases[i].keyword_provider_json);
1154 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
1155 RunTillProviderDone();
1157 const std::string description = "for input with default_provider_json=" +
1158 cases[i].default_provider_json + " and keyword_provider_json=" +
1159 cases[i].keyword_provider_json;
1160 const ACMatches& matches = provider_->matches();
1161 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
1162 size_t j = 0;
1163 // Ensure that the returned matches equal the expectations.
1164 for (; j < matches.size(); ++j) {
1165 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]), matches[j].contents) <<
1166 description;
1168 // Ensure that no expected matches are missing.
1169 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1170 EXPECT_EQ(std::string(), cases[i].matches[j]) << description;
1174 // Verifies that suggest results with relevance scores are added
1175 // properly when using the default fetcher. When adding a new test
1176 // case to this test, please consider adding it to the tests in
1177 // KeywordFetcherSuggestRelevance below.
1178 TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevance) {
1179 struct DefaultFetcherMatch {
1180 std::string contents;
1181 bool allowed_to_be_default_match;
1183 const DefaultFetcherMatch kEmptyMatch = { kNotApplicable, false };
1184 struct {
1185 const std::string json;
1186 const DefaultFetcherMatch matches[6];
1187 const std::string inline_autocompletion;
1188 } cases[] = {
1189 // Ensure that suggestrelevance scores reorder matches.
1190 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1191 { { "a", true }, { "c", false }, { "b", false }, kEmptyMatch, kEmptyMatch,
1192 kEmptyMatch },
1193 std::string() },
1194 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1195 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1196 "\"google:suggestrelevance\":[1, 2]}]",
1197 { { "a", true }, { "c.com", false }, { "b.com", false }, kEmptyMatch,
1198 kEmptyMatch, kEmptyMatch },
1199 std::string() },
1201 // Without suggested relevance scores, we should only allow one
1202 // navsuggest result to be be displayed.
1203 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1204 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1205 { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch,
1206 kEmptyMatch, kEmptyMatch },
1207 std::string() },
1209 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1210 // Negative values will have no effect; the calculated value will be used.
1211 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1212 "\"google:suggestrelevance\":[9998]}]",
1213 { { "a", true}, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1214 kEmptyMatch },
1215 std::string() },
1216 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1217 "\"google:suggestrelevance\":[9999]}]",
1218 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1219 kEmptyMatch },
1220 "1" },
1221 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1222 "\"google:suggestrelevance\":[9999]}]",
1223 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1224 kEmptyMatch },
1225 "1" },
1226 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1227 "\"google:suggestrelevance\":[9999]}]",
1228 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1229 kEmptyMatch },
1230 "1" },
1231 { "[\"a\",[\"http://a.com\"],[],[],"
1232 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1233 "\"google:verbatimrelevance\":9999,"
1234 "\"google:suggestrelevance\":[9998]}]",
1235 { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1236 kEmptyMatch },
1237 std::string() },
1238 { "[\"a\",[\"http://a.com\"],[],[],"
1239 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1240 "\"google:verbatimrelevance\":9998,"
1241 "\"google:suggestrelevance\":[9999]}]",
1242 { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1243 kEmptyMatch },
1244 ".com" },
1245 { "[\"a\",[\"http://a.com\"],[],[],"
1246 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1247 "\"google:verbatimrelevance\":0,"
1248 "\"google:suggestrelevance\":[9999]}]",
1249 { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1250 kEmptyMatch },
1251 ".com" },
1252 { "[\"a\",[\"http://a.com\"],[],[],"
1253 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1254 "\"google:verbatimrelevance\":-1,"
1255 "\"google:suggestrelevance\":[9999]}]",
1256 { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1257 kEmptyMatch },
1258 ".com" },
1260 // Ensure that both types of relevance scores reorder matches together.
1261 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1262 "\"google:verbatimrelevance\":9998}]",
1263 { { "a1", true }, { "a", true }, { "a2", true }, kEmptyMatch, kEmptyMatch,
1264 kEmptyMatch },
1265 "1" },
1267 // Allow non-inlineable matches to be the highest-scoring match but,
1268 // if the result set lacks a single inlineable result, abandon suggested
1269 // relevance scores entirely.
1270 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1271 { { "b", false }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1272 kEmptyMatch },
1273 std::string() },
1274 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1275 "\"google:verbatimrelevance\":0}]",
1276 { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1277 kEmptyMatch },
1278 std::string() },
1279 { "[\"a\",[\"http://b.com\"],[],[],"
1280 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1281 "\"google:suggestrelevance\":[9999]}]",
1282 { { "b.com", false }, { "a", true }, kEmptyMatch, kEmptyMatch,
1283 kEmptyMatch, kEmptyMatch },
1284 std::string() },
1285 { "[\"a\",[\"http://b.com\"],[],[],"
1286 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1287 "\"google:suggestrelevance\":[9999],"
1288 "\"google:verbatimrelevance\":0}]",
1289 { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch,
1290 kEmptyMatch, kEmptyMatch },
1291 std::string() },
1293 // Allow low-scoring matches.
1294 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1295 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1296 kEmptyMatch },
1297 "1" },
1298 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1299 { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1300 kEmptyMatch },
1301 "1" },
1302 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1303 "\"google:verbatimrelevance\":0}]",
1304 { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1305 kEmptyMatch },
1306 "1" },
1307 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1308 "\"google:verbatimrelevance\":0}]",
1309 { { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1310 kEmptyMatch },
1311 "2" },
1312 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1313 "\"google:verbatimrelevance\":2}]",
1314 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
1315 kEmptyMatch },
1316 "2" },
1317 { "[\"a\",[\"http://a.com\"],[],[],"
1318 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1319 "\"google:suggestrelevance\":[1],"
1320 "\"google:verbatimrelevance\":0}]",
1321 { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1322 kEmptyMatch },
1323 ".com" },
1324 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1325 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1326 "\"google:suggestrelevance\":[1, 2],"
1327 "\"google:verbatimrelevance\":0}]",
1328 { { "a2.com", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch,
1329 kEmptyMatch, kEmptyMatch },
1330 "2.com" },
1332 // Ensure that all suggestions are considered, regardless of order.
1333 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1334 "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1335 { { "a", true }, { "h", false }, { "g", false }, { "f", false },
1336 { "e", false }, { "d", false } },
1337 std::string() },
1338 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1339 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1340 "\"http://h.com\"],[],[],"
1341 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1342 "\"NAVIGATION\", \"NAVIGATION\","
1343 "\"NAVIGATION\", \"NAVIGATION\","
1344 "\"NAVIGATION\"],"
1345 "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1346 { { "a", true }, { "h.com", false }, { "g.com", false },
1347 { "f.com", false }, { "e.com", false }, { "d.com", false } },
1348 std::string() },
1350 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1351 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1352 { { "a", true }, { "a1", true }, { "a2", true }, kEmptyMatch, kEmptyMatch,
1353 kEmptyMatch },
1354 std::string() },
1355 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1356 { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1357 kEmptyMatch },
1358 std::string() },
1359 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1360 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1361 "\"google:suggestrelevance\":[1]}]",
1362 { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch,
1363 kEmptyMatch, kEmptyMatch },
1364 std::string() },
1365 { "[\"a\",[\"http://a1.com\"],[],[],"
1366 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1367 "\"google:suggestrelevance\":[9999, 1]}]",
1368 { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch,
1369 kEmptyMatch, kEmptyMatch },
1370 std::string() },
1372 // Ensure that all 'verbatim' results are merged with their maximum score.
1373 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1374 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1375 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
1376 kEmptyMatch },
1377 "2" },
1378 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1379 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1380 "\"google:verbatimrelevance\":0}]",
1381 { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
1382 kEmptyMatch },
1383 "2" },
1385 // Ensure that verbatim is always generated without other suggestions.
1386 // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
1387 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1388 { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1389 kEmptyMatch },
1390 std::string() },
1391 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1392 { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
1393 kEmptyMatch },
1394 std::string() },
1397 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1398 QueryForInput(ASCIIToUTF16("a"), false, false);
1399 net::TestURLFetcher* fetcher =
1400 test_factory_.GetFetcherByID(
1401 SearchProvider::kDefaultProviderURLFetcherID);
1402 ASSERT_TRUE(fetcher);
1403 fetcher->set_response_code(200);
1404 fetcher->SetResponseString(cases[i].json);
1405 fetcher->delegate()->OnURLFetchComplete(fetcher);
1406 RunTillProviderDone();
1408 const std::string description = "for input with json=" + cases[i].json;
1409 const ACMatches& matches = provider_->matches();
1410 ASSERT_FALSE(matches.empty());
1411 // Find the first match that's allowed to be the default match and check
1412 // its inline_autocompletion.
1413 ACMatches::const_iterator it = FindDefaultMatch(matches);
1414 ASSERT_NE(matches.end(), it);
1415 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
1416 it->inline_autocompletion) << description;
1418 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
1419 size_t j = 0;
1420 // Ensure that the returned matches equal the expectations.
1421 for (; j < matches.size(); ++j) {
1422 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents),
1423 matches[j].contents) << description;
1424 EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match,
1425 matches[j].allowed_to_be_default_match) << description;
1427 // Ensure that no expected matches are missing.
1428 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1429 EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) <<
1430 "Case # " << i << " " << description;
1434 // Verifies that suggest results with relevance scores are added
1435 // properly when using the keyword fetcher. This is similar to the
1436 // test DefaultFetcherSuggestRelevance above but this uses inputs that
1437 // trigger keyword suggestions (i.e., "k a" rather than "a") and has
1438 // different expectations (because now the results are a mix of
1439 // keyword suggestions and default provider suggestions). When a new
1440 // test is added to this TEST_F, please consider if it would be
1441 // appropriate to add to DefaultFetcherSuggestRelevance as well.
1442 TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
1443 struct KeywordFetcherMatch {
1444 std::string contents;
1445 bool from_keyword;
1446 bool allowed_to_be_default_match;
1448 const KeywordFetcherMatch kEmptyMatch = { kNotApplicable, false, false };
1449 struct {
1450 const std::string json;
1451 const KeywordFetcherMatch matches[6];
1452 const std::string inline_autocompletion;
1453 } cases[] = {
1454 // Ensure that suggest relevance scores reorder matches and that
1455 // the keyword verbatim (lacking a suggested verbatim score) beats
1456 // the default provider verbatim.
1457 { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
1458 { { "a", true, true },
1459 { "k a", false, false },
1460 { "c", true, false },
1461 { "b", true, false },
1462 kEmptyMatch, kEmptyMatch },
1463 std::string() },
1464 // Again, check that relevance scores reorder matches, just this
1465 // time with navigation matches. This also checks that with
1466 // suggested relevance scores we allow multiple navsuggest results.
1467 // Note that navsuggest results that come from a keyword provider
1468 // are marked as not a keyword result. (They don't go to a
1469 // keyword search engine.)
1470 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
1471 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1472 "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
1473 { { "a", true, true },
1474 { "d", true, false },
1475 { "c.com", false, false },
1476 { "b.com", false, false },
1477 { "k a", false, false },
1478 kEmptyMatch },
1479 std::string() },
1481 // Without suggested relevance scores, we should only allow one
1482 // navsuggest result to be be displayed.
1483 { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
1484 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
1485 { { "a", true, true },
1486 { "b.com", false, false },
1487 { "k a", false, false },
1488 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1489 std::string() },
1491 // Ensure that verbatimrelevance scores reorder or suppress verbatim.
1492 // Negative values will have no effect; the calculated value will be used.
1493 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
1494 "\"google:suggestrelevance\":[9998]}]",
1495 { { "a", true, true },
1496 { "a1", true, true },
1497 { "k a", false, false },
1498 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1499 std::string() },
1500 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
1501 "\"google:suggestrelevance\":[9999]}]",
1502 { { "a1", true, true },
1503 { "a", true, true },
1504 { "k a", false, false },
1505 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1506 "1" },
1507 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
1508 "\"google:suggestrelevance\":[9999]}]",
1509 { { "a1", true, true },
1510 { "k a", false, false },
1511 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1512 "1" },
1513 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
1514 "\"google:suggestrelevance\":[9999]}]",
1515 { { "a1", true, true },
1516 { "a", true, true },
1517 { "k a", false, false },
1518 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1519 "1" },
1520 { "[\"a\",[\"http://a.com\"],[],[],"
1521 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1522 "\"google:verbatimrelevance\":9999,"
1523 "\"google:suggestrelevance\":[9998]}]",
1524 { { "a", true, true },
1525 { "a.com", false, false },
1526 { "k a", false, false },
1527 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1528 std::string() },
1530 // Ensure that both types of relevance scores reorder matches together.
1531 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
1532 "\"google:verbatimrelevance\":9998}]",
1533 { { "a1", true, true },
1534 { "a", true, true },
1535 { "a2", true, true },
1536 { "k a", false, false },
1537 kEmptyMatch, kEmptyMatch },
1538 "1" },
1540 // Check that non-inlinable matches may be ranked as the highest result
1541 // if there is at least one inlineable match.
1542 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
1543 { { "b", true, false },
1544 { "a", true, true },
1545 { "k a", false, false },
1546 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1547 std::string() },
1548 { "[\"a\",[\"http://b.com\"],[],[],"
1549 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1550 "\"google:suggestrelevance\":[9999]}]",
1551 { { "b.com", false, false },
1552 { "a", true, true },
1553 { "k a", false, false },
1554 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1555 std::string() },
1556 // On the other hand, if there is no inlineable match, restore
1557 // the keyword verbatim score.
1558 { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
1559 "\"google:verbatimrelevance\":0}]",
1560 { { "b", true, false },
1561 { "a", true, true },
1562 { "k a", false, false },
1563 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1564 std::string() },
1565 { "[\"a\",[\"http://b.com\"],[],[],"
1566 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1567 "\"google:suggestrelevance\":[9999],"
1568 "\"google:verbatimrelevance\":0}]",
1569 { { "b.com", false, false },
1570 { "a", true, true },
1571 { "k a", false, false },
1572 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1573 std::string() },
1575 // The top result does not have to score as highly as calculated
1576 // verbatim. i.e., there are no minimum score restrictions in
1577 // this provider.
1578 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
1579 { { "a1", true, true },
1580 { "k a", false, false },
1581 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1582 "1" },
1583 { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
1584 { { "a1", true, true },
1585 { "k a", false, false },
1586 { "a", true, true },
1587 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1588 "1" },
1589 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
1590 "\"google:verbatimrelevance\":0}]",
1591 { { "k a", false, false },
1592 { "a1", true, true },
1593 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1594 "1" },
1595 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
1596 "\"google:verbatimrelevance\":0}]",
1598 { "k a", false, false },
1599 { "a2", true, true },
1600 { "a1", true, true },
1601 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1602 "2" },
1603 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
1604 "\"google:verbatimrelevance\":2}]",
1605 { { "k a", false, false },
1606 { "a2", true, true },
1607 { "a", true, true },
1608 { "a1", true, true },
1609 kEmptyMatch, kEmptyMatch },
1610 "2" },
1612 // Ensure that all suggestions are considered, regardless of order.
1613 { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
1614 "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1615 { { "a", true, true },
1616 { "k a", false, false },
1617 { "h", true, false },
1618 { "g", true, false },
1619 { "f", true, false },
1620 { "e", true, false } },
1621 std::string() },
1622 { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
1623 "\"http://e.com\", \"http://f.com\", \"http://g.com\","
1624 "\"http://h.com\"],[],[],"
1625 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
1626 "\"NAVIGATION\", \"NAVIGATION\","
1627 "\"NAVIGATION\", \"NAVIGATION\","
1628 "\"NAVIGATION\"],"
1629 "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
1630 { { "a", true, true },
1631 { "k a", false, false },
1632 { "h.com", false, false },
1633 { "g.com", false, false },
1634 { "f.com", false, false },
1635 { "e.com", false, false } },
1636 std::string() },
1638 // Ensure that incorrectly sized suggestion relevance lists are ignored.
1639 // Note that keyword suggestions by default (not in suggested relevance
1640 // mode) score more highly than the default verbatim.
1641 { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
1642 { { "a", true, true },
1643 { "a1", true, true },
1644 { "a2", true, true },
1645 { "k a", false, false },
1646 kEmptyMatch, kEmptyMatch },
1647 std::string() },
1648 { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
1649 { { "a", true, true },
1650 { "a1", true, true },
1651 { "k a", false, false },
1652 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1653 std::string() },
1654 // In this case, ignoring the suggested relevance scores means we keep
1655 // only one navsuggest result.
1656 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1657 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1658 "\"google:suggestrelevance\":[1]}]",
1659 { { "a", true, true },
1660 { "a1.com", false, false },
1661 { "k a", false, false },
1662 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1663 std::string() },
1664 { "[\"a\",[\"http://a1.com\"],[],[],"
1665 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1666 "\"google:suggestrelevance\":[9999, 1]}]",
1667 { { "a", true, true },
1668 { "a1.com", false, false },
1669 { "k a", false, false },
1670 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1671 std::string() },
1673 // Ensure that all 'verbatim' results are merged with their maximum score.
1674 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1675 "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1676 { { "a2", true, true },
1677 { "a", true, true },
1678 { "a1", true, true },
1679 { "k a", false, false },
1680 kEmptyMatch, kEmptyMatch },
1681 "2" },
1682 { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
1683 "{\"google:suggestrelevance\":[9998, 9997, 9999],"
1684 "\"google:verbatimrelevance\":0}]",
1685 { { "a2", true, true },
1686 { "a", true, true },
1687 { "a1", true, true },
1688 { "k a", false, false },
1689 kEmptyMatch, kEmptyMatch },
1690 "2" },
1692 // Ensure that verbatim is always generated without other suggestions.
1693 // TODO(mpearson): Ensure the value of verbatimrelevance is respected
1694 // (except when suggested relevances are ignored).
1695 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
1696 { { "k a", false, false },
1697 { "a", true, true },
1698 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1699 std::string() },
1700 { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
1701 { { "a", true, true },
1702 { "k a", false, false },
1703 kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
1704 std::string() },
1706 // In reorder mode, navsuggestions will not need to be demoted (because
1707 // they are marked as not allowed to be default match and will be
1708 // reordered as necessary).
1709 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1710 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1711 "\"google:verbatimrelevance\":9990,"
1712 "\"google:suggestrelevance\":[9998, 9999]}]",
1713 { { "a2.com", false, false },
1714 { "a1.com", false, false },
1715 { "a", true, true },
1716 { "k a", false, false },
1717 kEmptyMatch, kEmptyMatch },
1718 std::string() },
1719 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1720 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1721 "\"google:verbatimrelevance\":9990,"
1722 "\"google:suggestrelevance\":[9999, 9998]}]",
1723 { { "a1.com", false, false },
1724 { "a2.com", false, false },
1725 { "a", true, true },
1726 { "k a", false, false },
1727 kEmptyMatch, kEmptyMatch },
1728 std::string() },
1729 { "[\"a\",[\"https://a/\"],[],[],"
1730 "{\"google:suggesttype\":[\"NAVIGATION\"],"
1731 "\"google:suggestrelevance\":[9999]}]",
1732 { { "https://a", false, false },
1733 { "a", true, true },
1734 { "k a", false, false },
1735 kEmptyMatch, kEmptyMatch, kEmptyMatch },
1736 std::string() },
1737 // Check when navsuggest scores more than verbatim and there is query
1738 // suggestion but it scores lower.
1739 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1740 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1741 "\"google:verbatimrelevance\":9990,"
1742 "\"google:suggestrelevance\":[9998, 9999, 1300]}]",
1743 { { "a2.com", false, false },
1744 { "a1.com", false, false },
1745 { "a", true, true },
1746 { "a3", true, true },
1747 { "k a", false, false },
1748 kEmptyMatch },
1749 std::string() },
1750 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1751 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1752 "\"google:verbatimrelevance\":9990,"
1753 "\"google:suggestrelevance\":[9999, 9998, 1300]}]",
1754 { { "a1.com", false, false },
1755 { "a2.com", false, false },
1756 { "a", true, true },
1757 { "a3", true, true },
1758 { "k a", false, false },
1759 kEmptyMatch },
1760 std::string() },
1761 // Check when navsuggest scores more than a query suggestion. There is
1762 // a verbatim but it scores lower.
1763 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1764 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1765 "\"google:verbatimrelevance\":9990,"
1766 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1767 { { "a2.com", false, false },
1768 { "a1.com", false, false },
1769 { "a3", true, true },
1770 { "a", true, true },
1771 { "k a", false, false },
1772 kEmptyMatch },
1773 "3" },
1774 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1775 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1776 "\"google:verbatimrelevance\":9990,"
1777 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1778 { { "a1.com", false, false },
1779 { "a2.com", false, false },
1780 { "a3", true, true },
1781 { "a", true, true },
1782 { "k a", false, false },
1783 kEmptyMatch },
1784 "3" },
1785 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1786 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1787 "\"google:verbatimrelevance\":0,"
1788 "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
1789 { { "a2.com", false, false },
1790 { "a1.com", false, false },
1791 { "a3", true, true },
1792 { "k a", false, false },
1793 kEmptyMatch, kEmptyMatch },
1794 "3" },
1795 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1796 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1797 "\"google:verbatimrelevance\":0,"
1798 "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
1799 { { "a1.com", false, false },
1800 { "a2.com", false, false },
1801 { "a3", true, true },
1802 { "k a", false, false },
1803 kEmptyMatch, kEmptyMatch },
1804 "3" },
1805 // Check when there is neither verbatim nor a query suggestion that,
1806 // because we can't demote navsuggestions below a query suggestion,
1807 // we restore the keyword verbatim score.
1808 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1809 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1810 "\"google:verbatimrelevance\":0,"
1811 "\"google:suggestrelevance\":[9998, 9999]}]",
1812 { { "a2.com", false, false },
1813 { "a1.com", false, false },
1814 { "a", true, true },
1815 { "k a", false, false },
1816 kEmptyMatch, kEmptyMatch },
1817 std::string() },
1818 { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
1819 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
1820 "\"google:verbatimrelevance\":0,"
1821 "\"google:suggestrelevance\":[9999, 9998]}]",
1822 { { "a1.com", false, false },
1823 { "a2.com", false, false },
1824 { "a", true, true },
1825 { "k a", false, false },
1826 kEmptyMatch, kEmptyMatch },
1827 std::string() },
1828 // More checks that everything works when it's not necessary to demote.
1829 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1830 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1831 "\"google:verbatimrelevance\":9990,"
1832 "\"google:suggestrelevance\":[9997, 9998, 9999]}]",
1833 { { "a3", true, true },
1834 { "a2.com", false, false },
1835 { "a1.com", false, false },
1836 { "a", true, true },
1837 { "k a", false, false },
1838 kEmptyMatch },
1839 "3" },
1840 { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
1841 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
1842 "\"google:verbatimrelevance\":9990,"
1843 "\"google:suggestrelevance\":[9998, 9997, 9999]}]",
1844 { { "a3", true, true },
1845 { "a1.com", false, false },
1846 { "a2.com", false, false },
1847 { "a", true, true },
1848 { "k a", false, false },
1849 kEmptyMatch },
1850 "3" },
1853 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1854 QueryForInput(ASCIIToUTF16("k a"), false, true);
1856 // Set up a default fetcher with no results.
1857 net::TestURLFetcher* default_fetcher =
1858 test_factory_.GetFetcherByID(
1859 SearchProvider::kDefaultProviderURLFetcherID);
1860 ASSERT_TRUE(default_fetcher);
1861 default_fetcher->set_response_code(200);
1862 default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
1863 default_fetcher = NULL;
1865 // Set up a keyword fetcher with provided results.
1866 net::TestURLFetcher* keyword_fetcher =
1867 test_factory_.GetFetcherByID(
1868 SearchProvider::kKeywordProviderURLFetcherID);
1869 ASSERT_TRUE(keyword_fetcher);
1870 keyword_fetcher->set_response_code(200);
1871 keyword_fetcher->SetResponseString(cases[i].json);
1872 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
1873 keyword_fetcher = NULL;
1874 RunTillProviderDone();
1876 const std::string description = "for input with json=" + cases[i].json;
1877 const ACMatches& matches = provider_->matches();
1878 ASSERT_FALSE(matches.empty());
1879 // Find the first match that's allowed to be the default match and check
1880 // its inline_autocompletion.
1881 ACMatches::const_iterator it = FindDefaultMatch(matches);
1882 ASSERT_NE(matches.end(), it);
1883 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
1884 it->inline_autocompletion) << description;
1886 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
1887 size_t j = 0;
1888 // Ensure that the returned matches equal the expectations.
1889 for (; j < matches.size(); ++j) {
1890 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents),
1891 matches[j].contents) << description;
1892 EXPECT_EQ(cases[i].matches[j].from_keyword,
1893 matches[j].keyword == ASCIIToUTF16("k")) << description;
1894 EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match,
1895 matches[j].allowed_to_be_default_match) << description;
1897 // Ensure that no expected matches are missing.
1898 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1899 EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) <<
1900 "Case # " << i << " " << description;
1904 TEST_F(SearchProviderTest, LocalAndRemoteRelevances) {
1905 // We hardcode the string "term1" below, so ensure that the search term that
1906 // got added to history already is that string.
1907 ASSERT_EQ(ASCIIToUTF16("term1"), term1_);
1908 base::string16 term = term1_.substr(0, term1_.length() - 1);
1910 AddSearchToHistory(default_t_url_, term + ASCIIToUTF16("2"), 2);
1911 profile_.BlockUntilHistoryProcessesPendingRequests();
1913 struct {
1914 const base::string16 input;
1915 const std::string json;
1916 const std::string matches[6];
1917 } cases[] = {
1918 // The history results outscore the default verbatim score. term2 has more
1919 // visits so it outscores term1. The suggestions are still returned since
1920 // they're server-scored.
1921 { term,
1922 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
1923 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
1924 "\"google:suggestrelevance\":[1, 2, 3]}]",
1925 { "term2", "term1", "term", "a3", "a2", "a1" } },
1926 // Because we already have three suggestions by the time we see the history
1927 // results, they don't get returned.
1928 { term,
1929 "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
1930 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
1931 "\"google:verbatimrelevance\":1450,"
1932 "\"google:suggestrelevance\":[1440, 1430, 1420]}]",
1933 { "term", "a1", "a2", "a3", kNotApplicable, kNotApplicable } },
1934 // If we only have two suggestions, we have room for a history result.
1935 { term,
1936 "[\"term\",[\"a1\", \"a2\"],[],[],"
1937 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
1938 "\"google:verbatimrelevance\":1450,"
1939 "\"google:suggestrelevance\":[1430, 1410]}]",
1940 { "term", "a1", "a2", "term2", kNotApplicable, kNotApplicable } },
1941 // If we have more than three suggestions, they should all be returned as
1942 // long as we have enough total space for them.
1943 { term,
1944 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
1945 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
1946 "\"google:verbatimrelevance\":1450,"
1947 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410]}]",
1948 { "term", "a1", "a2", "a3", "a4", kNotApplicable } },
1949 { term,
1950 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\", \"a5\", \"a6\"],[],[],"
1951 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\","
1952 "\"QUERY\", \"QUERY\"],"
1953 "\"google:verbatimrelevance\":1450,"
1954 "\"google:suggestrelevance\":[1440, 1430, 1420, 1410, 1400, 1390]}]",
1955 { "term", "a1", "a2", "a3", "a4", "a5" } },
1956 { term,
1957 "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
1958 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
1959 "\"google:verbatimrelevance\":1450,"
1960 "\"google:suggestrelevance\":[1430, 1410, 1390, 1370]}]",
1961 { "term", "a1", "a2", "term2", "a3", "a4" } }
1964 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1965 QueryForInput(cases[i].input, false, false);
1966 net::TestURLFetcher* fetcher =
1967 test_factory_.GetFetcherByID(
1968 SearchProvider::kDefaultProviderURLFetcherID);
1969 ASSERT_TRUE(fetcher);
1970 fetcher->set_response_code(200);
1971 fetcher->SetResponseString(cases[i].json);
1972 fetcher->delegate()->OnURLFetchComplete(fetcher);
1973 RunTillProviderDone();
1975 const std::string description = "for input with json=" + cases[i].json;
1976 const ACMatches& matches = provider_->matches();
1978 // Ensure no extra matches are present.
1979 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
1981 size_t j = 0;
1982 // Ensure that the returned matches equal the expectations.
1983 for (; j < matches.size(); ++j)
1984 EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]),
1985 matches[j].contents) << description;
1986 // Ensure that no expected matches are missing.
1987 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
1988 EXPECT_EQ(kNotApplicable, cases[i].matches[j]) <<
1989 "Case # " << i << " " << description;
1993 // Verifies suggest relevance behavior for URL input.
1994 TEST_F(SearchProviderTest, DefaultProviderSuggestRelevanceScoringUrlInput) {
1995 struct DefaultFetcherUrlInputMatch {
1996 const std::string match_contents;
1997 AutocompleteMatch::Type match_type;
1998 bool allowed_to_be_default_match;
2000 const DefaultFetcherUrlInputMatch kEmptyMatch =
2001 { kNotApplicable, AutocompleteMatchType::NUM_TYPES, false };
2002 struct {
2003 const std::string input;
2004 const std::string json;
2005 const DefaultFetcherUrlInputMatch output[4];
2006 } cases[] = {
2007 // Ensure NAVIGATION matches are allowed to be listed first for URL
2008 // input regardless of whether the match is inlineable. Note that
2009 // non-inlineable matches should not be allowed to be the default match.
2010 { "a.com", "[\"a.com\",[\"http://b.com/\"],[],[],"
2011 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2012 "\"google:suggestrelevance\":[9999]}]",
2013 { { "b.com", AutocompleteMatchType::NAVSUGGEST, false },
2014 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2015 kEmptyMatch, kEmptyMatch } },
2016 { "a.com", "[\"a.com\",[\"https://b.com\"],[],[],"
2017 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2018 "\"google:suggestrelevance\":[9999]}]",
2019 { { "https://b.com", AutocompleteMatchType::NAVSUGGEST, false },
2020 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2021 kEmptyMatch, kEmptyMatch } },
2022 { "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[],"
2023 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2024 "\"google:suggestrelevance\":[9999]}]",
2025 { { "a.com/a", AutocompleteMatchType::NAVSUGGEST, true },
2026 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2027 kEmptyMatch, kEmptyMatch } },
2028 { "a.com", "[\"a.com\",[\"https://a.com\"],[],[],"
2029 "{\"google:suggesttype\":[\"NAVIGATION\"],"
2030 "\"google:suggestrelevance\":[9999]}]",
2031 { { "https://a.com", AutocompleteMatchType::NAVSUGGEST, true },
2032 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2033 kEmptyMatch, kEmptyMatch } },
2035 // Ensure topmost inlineable SUGGEST matches are NOT allowed for URL
2036 // input. SearchProvider disregards search and verbatim suggested
2037 // relevances.
2038 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2039 "{\"google:suggestrelevance\":[9999]}]",
2040 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2041 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
2042 kEmptyMatch, kEmptyMatch } },
2043 { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
2044 "{\"google:suggestrelevance\":[9999]}]",
2045 { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2046 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
2047 kEmptyMatch, kEmptyMatch } },
2049 // Ensure the fallback mechanism allows inlinable NAVIGATION matches.
2050 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2051 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2052 "\"google:suggestrelevance\":[9999, 9998]}]",
2053 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true },
2054 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2055 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
2056 kEmptyMatch } },
2057 { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
2058 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2059 "\"google:suggestrelevance\":[9998, 9997],"
2060 "\"google:verbatimrelevance\":9999}]",
2061 { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true },
2062 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2063 { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
2064 kEmptyMatch } },
2066 // Ensure topmost non-inlineable SUGGEST matches are allowed for URL
2067 // input assuming the top inlineable match is not a query (i.e., is a
2068 // NAVSUGGEST).
2069 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2070 "{\"google:suggestrelevance\":[9999]}]",
2071 { { "info", AutocompleteMatchType::SEARCH_SUGGEST, false },
2072 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2073 kEmptyMatch, kEmptyMatch } },
2074 { "a.com", "[\"a.com\",[\"info\"],[],[],"
2075 "{\"google:suggestrelevance\":[9999]}]",
2076 { { "info", AutocompleteMatchType::SEARCH_SUGGEST, false },
2077 { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
2078 kEmptyMatch, kEmptyMatch } },
2081 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2082 QueryForInput(ASCIIToUTF16(cases[i].input), false, false);
2083 net::TestURLFetcher* fetcher =
2084 test_factory_.GetFetcherByID(
2085 SearchProvider::kDefaultProviderURLFetcherID);
2086 ASSERT_TRUE(fetcher);
2087 fetcher->set_response_code(200);
2088 fetcher->SetResponseString(cases[i].json);
2089 fetcher->delegate()->OnURLFetchComplete(fetcher);
2090 RunTillProviderDone();
2092 size_t j = 0;
2093 const ACMatches& matches = provider_->matches();
2094 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].output));
2095 // Ensure that the returned matches equal the expectations.
2096 for (; j < matches.size(); ++j) {
2097 EXPECT_EQ(ASCIIToUTF16(cases[i].output[j].match_contents),
2098 matches[j].contents);
2099 EXPECT_EQ(cases[i].output[j].match_type, matches[j].type);
2100 EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match,
2101 matches[j].allowed_to_be_default_match);
2103 // Ensure that no expected matches are missing.
2104 for (; j < ARRAYSIZE_UNSAFE(cases[i].output); ++j) {
2105 EXPECT_EQ(kNotApplicable, cases[i].output[j].match_contents);
2106 EXPECT_EQ(AutocompleteMatchType::NUM_TYPES,
2107 cases[i].output[j].match_type);
2108 EXPECT_FALSE(cases[i].output[j].allowed_to_be_default_match);
2113 // A basic test that verifies the field trial triggered parsing logic.
2114 TEST_F(SearchProviderTest, FieldTrialTriggeredParsing) {
2115 QueryForInput(ASCIIToUTF16("foo"), false, false);
2117 // Make sure the default providers suggest service was queried.
2118 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
2119 SearchProvider::kDefaultProviderURLFetcherID);
2120 ASSERT_TRUE(fetcher);
2122 // Tell the SearchProvider the suggest query is done.
2123 fetcher->set_response_code(200);
2124 fetcher->SetResponseString(
2125 "[\"foo\",[\"foo bar\"],[\"\"],[],"
2126 "{\"google:suggesttype\":[\"QUERY\"],"
2127 "\"google:fieldtrialtriggered\":true}]");
2128 fetcher->delegate()->OnURLFetchComplete(fetcher);
2129 fetcher = NULL;
2131 // Run till the history results complete.
2132 RunTillProviderDone();
2135 // Check for the match and field trial triggered bits.
2136 AutocompleteMatch match;
2137 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("foo bar"), &match));
2138 ProvidersInfo providers_info;
2139 provider_->AddProviderInfo(&providers_info);
2140 ASSERT_EQ(1U, providers_info.size());
2141 EXPECT_EQ(1, providers_info[0].field_trial_triggered_size());
2142 EXPECT_EQ(1, providers_info[0].field_trial_triggered_in_session_size());
2145 // Reset the session and check that bits are reset.
2146 provider_->ResetSession();
2147 ProvidersInfo providers_info;
2148 provider_->AddProviderInfo(&providers_info);
2149 ASSERT_EQ(1U, providers_info.size());
2150 EXPECT_EQ(1, providers_info[0].field_trial_triggered_size());
2151 EXPECT_EQ(0, providers_info[0].field_trial_triggered_in_session_size());
2155 // Verifies inline autocompletion of navigational results.
2156 TEST_F(SearchProviderTest, NavigationInline) {
2157 struct {
2158 const std::string input;
2159 const std::string url;
2160 // Test the expected fill_into_edit, which may drop "http://".
2161 // Some cases do not trim "http://" to match from the start of the scheme.
2162 const std::string fill_into_edit;
2163 const std::string inline_autocompletion;
2164 const bool allowed_to_be_default_match_in_regular_mode;
2165 const bool allowed_to_be_default_match_in_prevent_inline_mode;
2166 } cases[] = {
2167 // Do not inline matches that do not contain the input; trim http as needed.
2168 { "x", "http://www.abc.com",
2169 "www.abc.com", std::string(), false, false },
2170 { "https:", "http://www.abc.com",
2171 "www.abc.com", std::string(), false, false },
2172 { "http://www.abc.com/a", "http://www.abc.com",
2173 "http://www.abc.com", std::string(), false,
2174 false },
2175 { "http://www.abc.com", "https://www.abc.com",
2176 "https://www.abc.com", std::string(), false,
2177 false },
2178 { "http://abc.com", "ftp://abc.com",
2179 "ftp://abc.com", std::string(), false,
2180 false },
2181 { "https://www.abc.com", "http://www.abc.com",
2182 "www.abc.com", std::string(), false,
2183 false },
2184 { "ftp://abc.com", "http://abc.com",
2185 "abc.com", std::string(), false,
2186 false },
2188 // Do not inline matches with invalid input prefixes; trim http as needed.
2189 { "ttp", "http://www.abc.com",
2190 "www.abc.com", std::string(), false, false },
2191 { "://w", "http://www.abc.com",
2192 "www.abc.com", std::string(), false, false },
2193 { "ww.", "http://www.abc.com",
2194 "www.abc.com", std::string(), false, false },
2195 { ".ab", "http://www.abc.com",
2196 "www.abc.com", std::string(), false, false },
2197 { "bc", "http://www.abc.com",
2198 "www.abc.com", std::string(), false, false },
2199 { ".com", "http://www.abc.com",
2200 "www.abc.com", std::string(), false, false },
2202 // Do not inline matches that omit input domain labels; trim http as needed.
2203 { "www.a", "http://a.com",
2204 "a.com", std::string(), false, false },
2205 { "http://www.a", "http://a.com",
2206 "http://a.com", std::string(), false, false },
2207 { "www.a", "ftp://a.com",
2208 "ftp://a.com", std::string(), false, false },
2209 { "ftp://www.a", "ftp://a.com",
2210 "ftp://a.com", std::string(), false, false },
2212 // Input matching but with nothing to inline will not yield an offset, but
2213 // will be allowed to be default.
2214 { "abc.com", "http://www.abc.com",
2215 "www.abc.com", std::string(), true, true },
2216 { "abc.com/", "http://www.abc.com",
2217 "www.abc.com", std::string(), true, true },
2218 { "http://www.abc.com", "http://www.abc.com",
2219 "http://www.abc.com", std::string(), true, true },
2220 { "http://www.abc.com/", "http://www.abc.com",
2221 "http://www.abc.com", std::string(), true, true },
2223 // Inputs with trailing whitespace should inline when possible.
2224 { "abc.com ", "http://www.abc.com",
2225 "www.abc.com", std::string(), true, true },
2226 { "abc.com/ ", "http://www.abc.com",
2227 "www.abc.com", std::string(), true, true },
2228 { "abc.com ", "http://www.abc.com/bar",
2229 "www.abc.com/bar", "/bar", false, false },
2231 // Inline matches when the input is a leading substring of the scheme.
2232 { "h", "http://www.abc.com",
2233 "http://www.abc.com", "ttp://www.abc.com", true, false },
2234 { "http", "http://www.abc.com",
2235 "http://www.abc.com", "://www.abc.com", true, false },
2237 // Inline matches when the input is a leading substring of the full URL.
2238 { "http:", "http://www.abc.com",
2239 "http://www.abc.com", "//www.abc.com", true, false },
2240 { "http://w", "http://www.abc.com",
2241 "http://www.abc.com", "ww.abc.com", true, false },
2242 { "http://www.", "http://www.abc.com",
2243 "http://www.abc.com", "abc.com", true, false },
2244 { "http://www.ab", "http://www.abc.com",
2245 "http://www.abc.com", "c.com", true, false },
2246 { "http://www.abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2247 "http://www.abc.com/path/file.htm?q=x#foo",
2248 "ath/file.htm?q=x#foo",
2249 true, false },
2250 { "http://abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2251 "http://abc.com/path/file.htm?q=x#foo",
2252 "ath/file.htm?q=x#foo",
2253 true, false},
2255 // Inline matches with valid URLPrefixes; only trim "http://".
2256 { "w", "http://www.abc.com",
2257 "www.abc.com", "ww.abc.com", true, false },
2258 { "www.a", "http://www.abc.com",
2259 "www.abc.com", "bc.com", true, false },
2260 { "abc", "http://www.abc.com",
2261 "www.abc.com", ".com", true, false },
2262 { "abc.c", "http://www.abc.com",
2263 "www.abc.com", "om", true, false },
2264 { "abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
2265 "www.abc.com/path/file.htm?q=x#foo",
2266 "ath/file.htm?q=x#foo",
2267 true, false },
2268 { "abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
2269 "abc.com/path/file.htm?q=x#foo",
2270 "ath/file.htm?q=x#foo",
2271 true, false },
2273 // Inline matches using the maximal URLPrefix components.
2274 { "h", "http://help.com",
2275 "help.com", "elp.com", true, false },
2276 { "http", "http://http.com",
2277 "http.com", ".com", true, false },
2278 { "h", "http://www.help.com",
2279 "www.help.com", "elp.com", true, false },
2280 { "http", "http://www.http.com",
2281 "www.http.com", ".com", true, false },
2282 { "w", "http://www.www.com",
2283 "www.www.com", "ww.com", true, false },
2285 // Test similar behavior for the ftp and https schemes.
2286 { "ftp://www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2287 "ftp://www.abc.com/path/file.htm?q=x#foo",
2288 "c.com/path/file.htm?q=x#foo", true, false },
2289 { "www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2290 "ftp://www.abc.com/path/file.htm?q=x#foo",
2291 "c.com/path/file.htm?q=x#foo", true, false },
2292 { "ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
2293 "ftp://www.abc.com/path/file.htm?q=x#foo",
2294 "c.com/path/file.htm?q=x#foo", true, false },
2295 { "ab", "ftp://abc.com/path/file.htm?q=x#foo",
2296 "ftp://abc.com/path/file.htm?q=x#foo",
2297 "c.com/path/file.htm?q=x#foo", true, false },
2298 { "https://www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2299 "https://www.abc.com/path/file.htm?q=x#foo",
2300 "c.com/path/file.htm?q=x#foo",
2301 true, false },
2302 { "www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
2303 "https://www.abc.com/path/file.htm?q=x#foo",
2304 "c.com/path/file.htm?q=x#foo", true, false },
2305 { "ab", "https://www.abc.com/path/file.htm?q=x#foo",
2306 "https://www.abc.com/path/file.htm?q=x#foo",
2307 "c.com/path/file.htm?q=x#foo", true, false },
2308 { "ab", "https://abc.com/path/file.htm?q=x#foo",
2309 "https://abc.com/path/file.htm?q=x#foo",
2310 "c.com/path/file.htm?q=x#foo", true, false },
2312 // Forced query input should inline and retain the "?" prefix.
2313 { "?http://www.ab", "http://www.abc.com",
2314 "?http://www.abc.com", "c.com", true, false },
2315 { "?www.ab", "http://www.abc.com",
2316 "?www.abc.com", "c.com", true, false },
2317 { "?ab", "http://www.abc.com",
2318 "?www.abc.com", "c.com", true, false },
2319 { "?abc.com", "http://www.abc.com",
2320 "?www.abc.com", "", true, true },
2323 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2324 // First test regular mode.
2325 QueryForInput(ASCIIToUTF16(cases[i].input), false, false);
2326 AutocompleteMatch match(
2327 provider_->NavigationToMatch(SearchProvider::NavigationResult(
2328 *provider_.get(), GURL(cases[i].url), base::string16(), false, 0,
2329 false, ASCIIToUTF16(cases[i].input), std::string())));
2330 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
2331 match.inline_autocompletion);
2332 EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit), match.fill_into_edit);
2333 EXPECT_EQ(cases[i].allowed_to_be_default_match_in_regular_mode,
2334 match.allowed_to_be_default_match);
2336 // Then test prevent-inline-autocomplete mode.
2337 QueryForInput(ASCIIToUTF16(cases[i].input), true, false);
2338 AutocompleteMatch match_prevent_inline(
2339 provider_->NavigationToMatch(SearchProvider::NavigationResult(
2340 *provider_.get(), GURL(cases[i].url), base::string16(), false, 0,
2341 false, ASCIIToUTF16(cases[i].input), std::string())));
2342 EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
2343 match_prevent_inline.inline_autocompletion);
2344 EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit),
2345 match_prevent_inline.fill_into_edit);
2346 EXPECT_EQ(cases[i].allowed_to_be_default_match_in_prevent_inline_mode,
2347 match_prevent_inline.allowed_to_be_default_match);
2351 // Verifies that "http://" is not trimmed for input that is a leading substring.
2352 TEST_F(SearchProviderTest, NavigationInlineSchemeSubstring) {
2353 const base::string16 input(ASCIIToUTF16("ht"));
2354 const base::string16 url(ASCIIToUTF16("http://a.com"));
2355 const SearchProvider::NavigationResult result(
2356 *provider_.get(), GURL(url), base::string16(), false, 0, false,
2357 input, std::string());
2359 // Check the offset and strings when inline autocompletion is allowed.
2360 QueryForInput(input, false, false);
2361 AutocompleteMatch match_inline(provider_->NavigationToMatch(result));
2362 EXPECT_EQ(url, match_inline.fill_into_edit);
2363 EXPECT_EQ(url.substr(2), match_inline.inline_autocompletion);
2364 EXPECT_TRUE(match_inline.allowed_to_be_default_match);
2365 EXPECT_EQ(url, match_inline.contents);
2367 // Check the same strings when inline autocompletion is prevented.
2368 QueryForInput(input, true, false);
2369 AutocompleteMatch match_prevent(provider_->NavigationToMatch(result));
2370 EXPECT_EQ(url, match_prevent.fill_into_edit);
2371 EXPECT_FALSE(match_prevent.allowed_to_be_default_match);
2372 EXPECT_EQ(url, match_prevent.contents);
2375 // Verifies that input "w" marks a more significant domain label than "www.".
2376 TEST_F(SearchProviderTest, NavigationInlineDomainClassify) {
2377 QueryForInput(ASCIIToUTF16("w"), false, false);
2378 AutocompleteMatch match(
2379 provider_->NavigationToMatch(SearchProvider::NavigationResult(
2380 *provider_.get(), GURL("http://www.wow.com"), base::string16(), false,
2381 0, false, ASCIIToUTF16("w"), std::string())));
2382 EXPECT_EQ(ASCIIToUTF16("ow.com"), match.inline_autocompletion);
2383 EXPECT_TRUE(match.allowed_to_be_default_match);
2384 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.fill_into_edit);
2385 EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.contents);
2387 // Ensure that the match for input "w" is marked on "wow" and not "www".
2388 ASSERT_EQ(3U, match.contents_class.size());
2389 EXPECT_EQ(0U, match.contents_class[0].offset);
2390 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL,
2391 match.contents_class[0].style);
2392 EXPECT_EQ(4U, match.contents_class[1].offset);
2393 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL |
2394 AutocompleteMatch::ACMatchClassification::MATCH,
2395 match.contents_class[1].style);
2396 EXPECT_EQ(5U, match.contents_class[2].offset);
2397 EXPECT_EQ(AutocompleteMatch::ACMatchClassification::URL,
2398 match.contents_class[2].style);
2401 #if !defined(OS_WIN)
2402 // Verify entity suggestion parsing.
2403 TEST_F(SearchProviderTest, ParseEntitySuggestion) {
2404 struct Match {
2405 std::string contents;
2406 std::string description;
2407 std::string query_params;
2408 std::string fill_into_edit;
2409 AutocompleteMatchType::Type type;
2411 const Match kEmptyMatch = {
2412 kNotApplicable, kNotApplicable, kNotApplicable, kNotApplicable,
2413 AutocompleteMatchType::NUM_TYPES};
2415 struct {
2416 const std::string input_text;
2417 const std::string response_json;
2418 const Match matches[5];
2419 } cases[] = {
2420 // A query and an entity suggestion with different search terms.
2421 { "x",
2422 "[\"x\",[\"xy\", \"yy\"],[\"\",\"\"],[],"
2423 " {\"google:suggestdetail\":[{},"
2424 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2425 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2426 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2427 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST },
2428 { "xy", "A", "p=v", "yy",
2429 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY },
2430 kEmptyMatch,
2431 kEmptyMatch
2434 // A query and an entity suggestion with same search terms.
2435 { "x",
2436 "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
2437 " {\"google:suggestdetail\":[{},"
2438 " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
2439 "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
2440 { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2441 { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST },
2442 { "xy", "A", "p=v", "xy",
2443 AutocompleteMatchType::SEARCH_SUGGEST_ENTITY },
2444 kEmptyMatch,
2445 kEmptyMatch
2449 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2450 QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
2452 // Set up a default fetcher with provided results.
2453 net::TestURLFetcher* fetcher =
2454 test_factory_.GetFetcherByID(
2455 SearchProvider::kDefaultProviderURLFetcherID);
2456 ASSERT_TRUE(fetcher);
2457 fetcher->set_response_code(200);
2458 fetcher->SetResponseString(cases[i].response_json);
2459 fetcher->delegate()->OnURLFetchComplete(fetcher);
2461 RunTillProviderDone();
2463 const ACMatches& matches = provider_->matches();
2464 ASSERT_FALSE(matches.empty());
2466 SCOPED_TRACE("for input with json = " + cases[i].response_json);
2468 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
2469 size_t j = 0;
2470 // Ensure that the returned matches equal the expectations.
2471 for (; j < matches.size(); ++j) {
2472 const Match& match = cases[i].matches[j];
2473 SCOPED_TRACE(" and match index: " + base::IntToString(j));
2474 EXPECT_EQ(match.contents,
2475 base::UTF16ToUTF8(matches[j].contents));
2476 EXPECT_EQ(match.description,
2477 base::UTF16ToUTF8(matches[j].description));
2478 EXPECT_EQ(match.query_params,
2479 matches[j].search_terms_args->suggest_query_params);
2480 EXPECT_EQ(match.fill_into_edit,
2481 base::UTF16ToUTF8(matches[j].fill_into_edit));
2482 EXPECT_EQ(match.type, matches[j].type);
2484 // Ensure that no expected matches are missing.
2485 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
2486 SCOPED_TRACE(" and match index: " + base::IntToString(j));
2487 EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
2488 EXPECT_EQ(cases[i].matches[j].description, kNotApplicable);
2489 EXPECT_EQ(cases[i].matches[j].query_params, kNotApplicable);
2490 EXPECT_EQ(cases[i].matches[j].fill_into_edit, kNotApplicable);
2491 EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
2495 #endif // !defined(OS_WIN)
2498 // A basic test that verifies the prefetch metadata parsing logic.
2499 TEST_F(SearchProviderTest, PrefetchMetadataParsing) {
2500 struct Match {
2501 std::string contents;
2502 bool allowed_to_be_prefetched;
2503 AutocompleteMatchType::Type type;
2504 bool from_keyword;
2506 const Match kEmptyMatch = { kNotApplicable,
2507 false,
2508 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2509 false };
2511 struct {
2512 const std::string input_text;
2513 bool prefer_keyword_provider_results;
2514 const std::string default_provider_response_json;
2515 const std::string keyword_provider_response_json;
2516 const Match matches[5];
2517 } cases[] = {
2518 // Default provider response does not have prefetch details. Ensure that the
2519 // suggestions are not marked as prefetch query.
2520 { "a",
2521 false,
2522 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2523 std::string(),
2524 { { "a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2525 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2526 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2527 kEmptyMatch,
2528 kEmptyMatch
2531 // Ensure that default provider suggest response prefetch details are
2532 // parsed and recorded in AutocompleteMatch.
2533 { "ab",
2534 false,
2535 "[\"ab\",[\"abc\", \"http://b.com\", \"http://c.com\"],[],[],"
2536 "{\"google:clientdata\":{\"phi\": 0},"
2537 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"NAVIGATION\"],"
2538 "\"google:suggestrelevance\":[999, 12, 1]}]",
2539 std::string(),
2540 { { "ab", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2541 { "abc", true, AutocompleteMatchType::SEARCH_SUGGEST, false },
2542 { "b.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2543 { "c.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2544 kEmptyMatch
2547 // Default provider suggest response has prefetch details.
2548 // SEARCH_WHAT_YOU_TYPE suggestion outranks SEARCH_SUGGEST suggestion for
2549 // the same query string. Ensure that the prefetch details from
2550 // SEARCH_SUGGEST match are set onto SEARCH_WHAT_YOU_TYPE match.
2551 { "ab",
2552 false,
2553 "[\"ab\",[\"ab\", \"http://ab.com\"],[],[],"
2554 "{\"google:clientdata\":{\"phi\": 0},"
2555 "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
2556 "\"google:suggestrelevance\":[99, 98]}]",
2557 std::string(),
2558 { {"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2559 {"ab.com", false, AutocompleteMatchType::NAVSUGGEST, false },
2560 kEmptyMatch,
2561 kEmptyMatch,
2562 kEmptyMatch
2565 // Default provider response has prefetch details. We prefer keyword
2566 // provider results. Ensure that prefetch bit for a suggestion from the
2567 // default search provider does not get copied onto a higher-scoring match
2568 // for the same query string from the keyword provider.
2569 { "k a",
2570 true,
2571 "[\"k a\",[\"a\", \"ab\"],[],[], {\"google:clientdata\":{\"phi\": 0},"
2572 "\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
2573 "\"google:suggestrelevance\":[9, 12]}]",
2574 "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
2575 { { "a", false, AutocompleteMatchType::SEARCH_OTHER_ENGINE, true},
2576 { "k a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false },
2577 { "ab", false, AutocompleteMatchType::SEARCH_SUGGEST, false },
2578 { "c", false, AutocompleteMatchType::SEARCH_SUGGEST, true },
2579 { "b", false, AutocompleteMatchType::SEARCH_SUGGEST, true }
2584 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2585 QueryForInput(ASCIIToUTF16(cases[i].input_text), false,
2586 cases[i].prefer_keyword_provider_results);
2588 // Set up a default fetcher with provided results.
2589 net::TestURLFetcher* fetcher =
2590 test_factory_.GetFetcherByID(
2591 SearchProvider::kDefaultProviderURLFetcherID);
2592 ASSERT_TRUE(fetcher);
2593 fetcher->set_response_code(200);
2594 fetcher->SetResponseString(cases[i].default_provider_response_json);
2595 fetcher->delegate()->OnURLFetchComplete(fetcher);
2597 if (cases[i].prefer_keyword_provider_results) {
2598 // Set up a keyword fetcher with provided results.
2599 net::TestURLFetcher* keyword_fetcher =
2600 test_factory_.GetFetcherByID(
2601 SearchProvider::kKeywordProviderURLFetcherID);
2602 ASSERT_TRUE(keyword_fetcher);
2603 keyword_fetcher->set_response_code(200);
2604 keyword_fetcher->SetResponseString(
2605 cases[i].keyword_provider_response_json);
2606 keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
2607 keyword_fetcher = NULL;
2610 RunTillProviderDone();
2612 const std::string description =
2613 "for input with json =" + cases[i].default_provider_response_json;
2614 const ACMatches& matches = provider_->matches();
2615 // The top match must inline and score as highly as calculated verbatim.
2616 ASSERT_FALSE(matches.empty());
2617 EXPECT_GE(matches[0].relevance, 1300);
2619 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
2620 // Ensure that the returned matches equal the expectations.
2621 for (size_t j = 0; j < matches.size(); ++j) {
2622 SCOPED_TRACE(description);
2623 EXPECT_EQ(cases[i].matches[j].contents,
2624 base::UTF16ToUTF8(matches[j].contents));
2625 EXPECT_EQ(cases[i].matches[j].allowed_to_be_prefetched,
2626 SearchProvider::ShouldPrefetch(matches[j]));
2627 EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
2628 EXPECT_EQ(cases[i].matches[j].from_keyword,
2629 matches[j].keyword == ASCIIToUTF16("k"));
2634 TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_InvalidResponse) {
2635 ClearAllResults();
2637 std::string input_str("abc");
2638 QueryForInput(ASCIIToUTF16(input_str), false, false);
2640 // Set up a default fetcher with provided results.
2641 net::TestURLFetcher* fetcher =
2642 test_factory_.GetFetcherByID(
2643 SearchProvider::kDefaultProviderURLFetcherID);
2644 ASSERT_TRUE(fetcher);
2645 fetcher->set_response_code(200);
2646 fetcher->SetResponseString("this is a bad non-json response");
2647 fetcher->delegate()->OnURLFetchComplete(fetcher);
2649 RunTillProviderDone();
2651 const ACMatches& matches = provider_->matches();
2653 // Should have exactly one "search what you typed" match
2654 ASSERT_TRUE(matches.size() == 1);
2655 EXPECT_EQ(input_str, base::UTF16ToUTF8(matches[0].contents));
2656 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2657 matches[0].type);
2660 // A basic test that verifies that the XSSI guarded JSON response is parsed
2661 // correctly.
2662 TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_ValidResponses) {
2663 struct Match {
2664 std::string contents;
2665 AutocompleteMatchType::Type type;
2667 const Match kEmptyMatch = {
2668 kNotApplicable, AutocompleteMatchType::NUM_TYPES
2671 struct {
2672 const std::string input_text;
2673 const std::string default_provider_response_json;
2674 const Match matches[4];
2675 } cases[] = {
2676 // No XSSI guard.
2677 { "a",
2678 "[\"a\",[\"b\", \"c\"],[],[],"
2679 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2680 "\"google:suggestrelevance\":[1, 2]}]",
2681 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2682 { "c", AutocompleteMatchType::SEARCH_SUGGEST },
2683 { "b", AutocompleteMatchType::SEARCH_SUGGEST },
2684 kEmptyMatch,
2687 // Standard XSSI guard - )]}'\n.
2688 { "a",
2689 ")]}'\n[\"a\",[\"b\", \"c\"],[],[],"
2690 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2691 "\"google:suggestrelevance\":[1, 2]}]",
2692 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2693 { "c", AutocompleteMatchType::SEARCH_SUGGEST },
2694 { "b", AutocompleteMatchType::SEARCH_SUGGEST },
2695 kEmptyMatch,
2698 // Modified XSSI guard - contains "[".
2699 { "a",
2700 ")]}'\n[)\"[\"a\",[\"b\", \"c\"],[],[],"
2701 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
2702 "\"google:suggestrelevance\":[1, 2]}]",
2703 { { "a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2704 { "c", AutocompleteMatchType::SEARCH_SUGGEST },
2705 { "b", AutocompleteMatchType::SEARCH_SUGGEST },
2706 kEmptyMatch,
2711 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2712 ClearAllResults();
2713 QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
2715 // Set up a default fetcher with provided results.
2716 net::TestURLFetcher* fetcher =
2717 test_factory_.GetFetcherByID(
2718 SearchProvider::kDefaultProviderURLFetcherID);
2719 ASSERT_TRUE(fetcher);
2720 fetcher->set_response_code(200);
2721 fetcher->SetResponseString(cases[i].default_provider_response_json);
2722 fetcher->delegate()->OnURLFetchComplete(fetcher);
2724 RunTillProviderDone();
2726 const ACMatches& matches = provider_->matches();
2727 // The top match must inline and score as highly as calculated verbatim.
2728 ASSERT_FALSE(matches.empty());
2729 EXPECT_GE(matches[0].relevance, 1300);
2731 SCOPED_TRACE("for case: " + base::IntToString(i));
2732 ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
2733 size_t j = 0;
2734 // Ensure that the returned matches equal the expectations.
2735 for (; j < matches.size(); ++j) {
2736 SCOPED_TRACE("and match: " + base::IntToString(j));
2737 EXPECT_EQ(cases[i].matches[j].contents,
2738 base::UTF16ToUTF8(matches[j].contents));
2739 EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
2741 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
2742 SCOPED_TRACE("and match: " + base::IntToString(j));
2743 EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
2744 EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
2749 // Test that deletion url gets set on an AutocompleteMatch when available for a
2750 // personalized query.
2751 TEST_F(SearchProviderTest, ParseDeletionUrl) {
2752 struct Match {
2753 std::string contents;
2754 std::string deletion_url;
2755 AutocompleteMatchType::Type type;
2758 const Match kEmptyMatch = {
2759 kNotApplicable, "", AutocompleteMatchType::NUM_TYPES
2762 const char url[] = "https://www.google.com/complete/deleteitems"
2763 "?delq=ab&client=chrome&deltok=xsrf123";
2765 struct {
2766 const std::string input_text;
2767 const std::string response_json;
2768 const Match matches[4];
2769 } cases[] = {
2770 // A deletion URL on a personalized query should be reflected in the
2771 // resulting AutocompleteMatch.
2772 { "a",
2773 "[\"a\",[\"ab\", \"ac\"],[],[],"
2774 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\"],"
2775 "\"google:suggestrelevance\":[1, 2],"
2776 "\"google:suggestdetail\":[{\"du\":"
2777 "\"https://www.google.com/complete/deleteitems?delq=ab&client=chrome"
2778 "&deltok=xsrf123\"}, {}]}]",
2779 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2780 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
2781 { "ab", url, AutocompleteMatchType::SEARCH_SUGGEST },
2782 kEmptyMatch,
2785 // Personalized queries without deletion URLs shouldn't cause errors.
2786 { "a",
2787 "[\"a\",[\"ab\", \"ac\"],[],[],"
2788 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\"],"
2789 "\"google:suggestrelevance\":[1, 2],"
2790 "\"google:suggestdetail\":[{}, {}]}]",
2791 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
2792 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
2793 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST },
2794 kEmptyMatch,
2799 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
2800 QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
2802 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
2803 SearchProvider::kDefaultProviderURLFetcherID);
2804 ASSERT_TRUE(fetcher);
2805 fetcher->set_response_code(200);
2806 fetcher->SetResponseString(cases[i].response_json);
2807 fetcher->delegate()->OnURLFetchComplete(fetcher);
2809 RunTillProviderDone();
2811 const ACMatches& matches = provider_->matches();
2812 ASSERT_FALSE(matches.empty());
2814 SCOPED_TRACE("for input with json = " + cases[i].response_json);
2816 for (size_t j = 0; j < matches.size(); ++j) {
2817 const Match& match = cases[i].matches[j];
2818 SCOPED_TRACE(" and match index: " + base::IntToString(j));
2819 EXPECT_EQ(match.contents, base::UTF16ToUTF8(matches[j].contents));
2820 EXPECT_EQ(match.deletion_url, matches[j].GetAdditionalInfo(
2821 "deletion_url"));
2826 TEST_F(SearchProviderTest, ReflectsBookmarkBarState) {
2827 profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, false);
2828 base::string16 term = term1_.substr(0, term1_.length() - 1);
2829 QueryForInput(term, true, false);
2830 ASSERT_FALSE(provider_->matches().empty());
2831 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2832 provider_->matches()[0].type);
2833 ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL);
2834 EXPECT_FALSE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned);
2836 profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, true);
2837 term = term1_.substr(0, term1_.length() - 1);
2838 QueryForInput(term, true, false);
2839 ASSERT_FALSE(provider_->matches().empty());
2840 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
2841 provider_->matches()[0].type);
2842 ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL);
2843 EXPECT_TRUE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned);
2846 TEST_F(SearchProviderTest, CanSendURL) {
2847 TemplateURLData template_url_data;
2848 template_url_data.short_name = ASCIIToUTF16("t");
2849 template_url_data.SetURL("http://www.google.com/{searchTerms}");
2850 template_url_data.suggestions_url = "http://www.google.com/{searchTerms}";
2851 template_url_data.instant_url = "http://does/not/exist?strk=1";
2852 template_url_data.search_terms_replacement_key = "strk";
2853 template_url_data.id = SEARCH_ENGINE_GOOGLE;
2854 TemplateURL google_template_url(&profile_, template_url_data);
2856 // Create field trial.
2857 base::FieldTrial* field_trial = base::FieldTrialList::CreateFieldTrial(
2858 "AutocompleteDynamicTrial_2", "EnableZeroSuggest");
2859 field_trial->group();
2861 // Not signed in.
2862 EXPECT_FALSE(SearchProvider::CanSendURL(
2863 GURL("http://www.google.com/search"),
2864 GURL("https://www.google.com/complete/search"), &google_template_url,
2865 AutocompleteInput::OTHER, &profile_));
2866 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(&profile_);
2867 signin->SetAuthenticatedUsername("test");
2869 // All conditions should be met.
2870 EXPECT_TRUE(SearchProvider::CanSendURL(
2871 GURL("http://www.google.com/search"),
2872 GURL("https://www.google.com/complete/search"), &google_template_url,
2873 AutocompleteInput::OTHER, &profile_));
2875 // Not in field trial.
2876 ResetFieldTrialList();
2877 EXPECT_FALSE(SearchProvider::CanSendURL(
2878 GURL("http://www.google.com/search"),
2879 GURL("https://www.google.com/complete/search"), &google_template_url,
2880 AutocompleteInput::OTHER, &profile_));
2881 field_trial = base::FieldTrialList::CreateFieldTrial(
2882 "AutocompleteDynamicTrial_2", "EnableZeroSuggest");
2883 field_trial->group();
2885 // Invalid page URL.
2886 EXPECT_FALSE(SearchProvider::CanSendURL(
2887 GURL("badpageurl"),
2888 GURL("https://www.google.com/complete/search"), &google_template_url,
2889 AutocompleteInput::OTHER, &profile_));
2891 // Invalid page classification.
2892 EXPECT_FALSE(SearchProvider::CanSendURL(
2893 GURL("http://www.google.com/search"),
2894 GURL("https://www.google.com/complete/search"), &google_template_url,
2895 AutocompleteInput::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS,
2896 &profile_));
2898 // Invalid page classification.
2899 EXPECT_FALSE(SearchProvider::CanSendURL(
2900 GURL("http://www.google.com/search"),
2901 GURL("https://www.google.com/complete/search"), &google_template_url,
2902 AutocompleteInput::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS,
2903 &profile_));
2905 // HTTPS page URL on same domain as provider.
2906 EXPECT_TRUE(SearchProvider::CanSendURL(
2907 GURL("https://www.google.com/search"),
2908 GURL("https://www.google.com/complete/search"),
2909 &google_template_url, AutocompleteInput::OTHER, &profile_));
2911 // Non-HTTP[S] page URL on same domain as provider.
2912 EXPECT_FALSE(SearchProvider::CanSendURL(
2913 GURL("ftp://www.google.com/search"),
2914 GURL("https://www.google.com/complete/search"), &google_template_url,
2915 AutocompleteInput::OTHER, &profile_));
2917 // Non-HTTP page URL on different domain.
2918 EXPECT_FALSE(SearchProvider::CanSendURL(
2919 GURL("https://www.notgoogle.com/search"),
2920 GURL("https://www.google.com/complete/search"), &google_template_url,
2921 AutocompleteInput::OTHER, &profile_));
2923 // Non-HTTPS provider.
2924 EXPECT_FALSE(SearchProvider::CanSendURL(
2925 GURL("http://www.google.com/search"),
2926 GURL("http://www.google.com/complete/search"), &google_template_url,
2927 AutocompleteInput::OTHER, &profile_));
2929 // Suggest disabled.
2930 profile_.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false);
2931 EXPECT_FALSE(SearchProvider::CanSendURL(
2932 GURL("http://www.google.com/search"),
2933 GURL("https://www.google.com/complete/search"), &google_template_url,
2934 AutocompleteInput::OTHER, &profile_));
2935 profile_.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
2937 // Incognito.
2938 EXPECT_FALSE(SearchProvider::CanSendURL(
2939 GURL("http://www.google.com/search"),
2940 GURL("https://www.google.com/complete/search"), &google_template_url,
2941 AutocompleteInput::OTHER, profile_.GetOffTheRecordProfile()));
2943 // Tab sync not enabled.
2944 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncKeepEverythingSynced,
2945 false);
2946 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs, false);
2947 EXPECT_FALSE(SearchProvider::CanSendURL(
2948 GURL("http://www.google.com/search"),
2949 GURL("https://www.google.com/complete/search"), &google_template_url,
2950 AutocompleteInput::OTHER, &profile_));
2951 profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs, true);
2953 // Tab sync is encrypted.
2954 ProfileSyncService* service =
2955 ProfileSyncServiceFactory::GetInstance()->GetForProfile(&profile_);
2956 syncer::ModelTypeSet encrypted_types = service->GetEncryptedDataTypes();
2957 encrypted_types.Put(syncer::SESSIONS);
2958 service->OnEncryptedTypesChanged(encrypted_types, false);
2959 EXPECT_FALSE(SearchProvider::CanSendURL(
2960 GURL("http://www.google.com/search"),
2961 GURL("https://www.google.com/complete/search"), &google_template_url,
2962 AutocompleteInput::OTHER, &profile_));
2963 encrypted_types.Remove(syncer::SESSIONS);
2964 service->OnEncryptedTypesChanged(encrypted_types, false);
2966 // Check that there were no side effects from previous tests.
2967 EXPECT_TRUE(SearchProvider::CanSendURL(
2968 GURL("http://www.google.com/search"),
2969 GURL("https://www.google.com/complete/search"), &google_template_url,
2970 AutocompleteInput::OTHER, &profile_));
2973 TEST_F(SearchProviderTest, TestDeleteMatch) {
2974 AutocompleteMatch match(provider_, 0, true,
2975 AutocompleteMatchType::SEARCH_SUGGEST);
2976 match.RecordAdditionalInfo(
2977 SearchProvider::kDeletionUrlKey,
2978 "https://www.google.com/complete/deleteitem?q=foo");
2980 // Test a successful deletion request.
2981 provider_->matches_.push_back(match);
2982 provider_->DeleteMatch(match);
2983 EXPECT_FALSE(provider_->deletion_handlers_.empty());
2984 EXPECT_TRUE(provider_->matches_.empty());
2985 // Set up a default fetcher with provided results.
2986 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
2987 SearchProvider::kDeletionURLFetcherID);
2988 ASSERT_TRUE(fetcher);
2989 fetcher->set_response_code(200);
2990 fetcher->delegate()->OnURLFetchComplete(fetcher);
2991 EXPECT_TRUE(provider_->deletion_handlers_.empty());
2992 EXPECT_TRUE(provider_->is_success());
2994 // Test a failing deletion request.
2995 provider_->matches_.push_back(match);
2996 provider_->DeleteMatch(match);
2997 EXPECT_FALSE(provider_->deletion_handlers_.empty());
2998 // Set up a default fetcher with provided results.
2999 fetcher = test_factory_.GetFetcherByID(
3000 SearchProvider::kDeletionURLFetcherID);
3001 ASSERT_TRUE(fetcher);
3002 fetcher->set_response_code(500);
3003 fetcher->delegate()->OnURLFetchComplete(fetcher);
3004 EXPECT_TRUE(provider_->deletion_handlers_.empty());
3005 EXPECT_FALSE(provider_->is_success());
3008 TEST_F(SearchProviderTest, TestDeleteHistoryQueryMatch) {
3009 GURL term_url(
3010 AddSearchToHistory(default_t_url_, ASCIIToUTF16("flash games"), 1));
3011 profile_.BlockUntilHistoryProcessesPendingRequests();
3013 AutocompleteMatch games;
3014 QueryForInput(ASCIIToUTF16("fla"), false, false);
3015 profile_.BlockUntilHistoryProcessesPendingRequests();
3016 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3017 ASSERT_TRUE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games));
3019 size_t matches_before = provider_->matches().size();
3020 provider_->DeleteMatch(games);
3021 EXPECT_EQ(matches_before - 1, provider_->matches().size());
3023 // Process history deletions.
3024 profile_.BlockUntilHistoryProcessesPendingRequests();
3026 // Check that the match is gone.
3027 QueryForInput(ASCIIToUTF16("fla"), false, false);
3028 profile_.BlockUntilHistoryProcessesPendingRequests();
3029 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
3030 EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games));
3033 // Verifies that duplicates are preserved in AddMatchToMap().
3034 TEST_F(SearchProviderTest, CheckDuplicateMatchesSaved) {
3035 AddSearchToHistory(default_t_url_, ASCIIToUTF16("a"), 1);
3036 AddSearchToHistory(default_t_url_, ASCIIToUTF16("alpha"), 1);
3037 AddSearchToHistory(default_t_url_, ASCIIToUTF16("avid"), 1);
3039 profile_.BlockUntilHistoryProcessesPendingRequests();
3040 QueryForInput(ASCIIToUTF16("a"), false, false);
3042 // Make sure the default provider's suggest service was queried.
3043 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
3044 SearchProvider::kDefaultProviderURLFetcherID);
3045 ASSERT_TRUE(fetcher);
3047 // Tell the SearchProvider the suggest query is done.
3048 fetcher->set_response_code(200);
3049 fetcher->SetResponseString(
3050 "[\"a\",[\"a\", \"alpha\", \"avid\", \"apricot\"],[],[],"
3051 "{\"google:suggestrelevance\":[1450, 1200, 1150, 1100],"
3052 "\"google:verbatimrelevance\":1350}]");
3053 fetcher->delegate()->OnURLFetchComplete(fetcher);
3054 fetcher = NULL;
3056 // Run till the history results complete.
3057 RunTillProviderDone();
3059 AutocompleteMatch verbatim, match_alpha, match_apricot, match_avid;
3060 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim));
3061 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("alpha"), &match_alpha));
3062 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("apricot"), &match_apricot));
3063 EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("avid"), &match_avid));
3065 // Verbatim match duplicates are added such that each one has a higher
3066 // relevance than the previous one.
3067 EXPECT_EQ(2U, verbatim.duplicate_matches.size());
3069 // Other match duplicates are added in descending relevance order.
3070 EXPECT_EQ(1U, match_alpha.duplicate_matches.size());
3071 EXPECT_EQ(1U, match_avid.duplicate_matches.size());
3073 EXPECT_EQ(0U, match_apricot.duplicate_matches.size());