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