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