Home | History | Annotate | Download | only in omnibox
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/omnibox/base_search_provider.h"
      6 
      7 #include "base/strings/string16.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "components/omnibox/autocomplete_match.h"
     10 #include "components/omnibox/autocomplete_match_type.h"
     11 #include "components/omnibox/autocomplete_provider_client.h"
     12 #include "components/omnibox/autocomplete_scheme_classifier.h"
     13 #include "components/omnibox/search_suggestion_parser.h"
     14 #include "components/search_engines/search_terms_data.h"
     15 #include "components/search_engines/template_url_service.h"
     16 #include "components/search_engines/template_url_service_client.h"
     17 #include "testing/gmock/include/gmock/gmock.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 
     20 using testing::NiceMock;
     21 using testing::Return;
     22 using testing::_;
     23 
     24 class MockAutocompleteProviderClient : public AutocompleteProviderClient {
     25  public:
     26   MockAutocompleteProviderClient() {}
     27   MOCK_METHOD0(RequestContext, net::URLRequestContextGetter*());
     28   MOCK_METHOD0(IsOffTheRecord, bool());
     29   MOCK_METHOD0(AcceptLanguages, std::string());
     30   MOCK_METHOD0(SearchSuggestEnabled, bool());
     31   MOCK_METHOD0(ShowBookmarkBar, bool());
     32   MOCK_METHOD0(SchemeClassifier, const AutocompleteSchemeClassifier&());
     33   MOCK_METHOD6(
     34       Classify,
     35       void(const base::string16& text,
     36            bool prefer_keyword,
     37            bool allow_exact_keyword_match,
     38            metrics::OmniboxEventProto::PageClassification page_classification,
     39            AutocompleteMatch* match,
     40            GURL* alternate_nav_url));
     41   MOCK_METHOD0(InMemoryDatabase, history::URLDatabase*());
     42   MOCK_METHOD2(DeleteMatchingURLsForKeywordFromHistory,
     43                void(history::KeywordID keyword_id, const base::string16& term));
     44   MOCK_METHOD0(TabSyncEnabledAndUnencrypted, bool());
     45   MOCK_METHOD1(PrefetchImage, void(const GURL& url));
     46 
     47  private:
     48   DISALLOW_COPY_AND_ASSIGN(MockAutocompleteProviderClient);
     49 };
     50 
     51 class TestBaseSearchProvider : public BaseSearchProvider {
     52  public:
     53   typedef BaseSearchProvider::MatchMap MatchMap;
     54 
     55   // Note: Takes ownership of client. scoped_ptr<> would be the right way to
     56   // express that, but NiceMock<> can't forward a scoped_ptr.
     57   TestBaseSearchProvider(TemplateURLService* template_url_service,
     58                          AutocompleteProviderClient* client,
     59                          AutocompleteProvider::Type type)
     60       : BaseSearchProvider(template_url_service,
     61                            scoped_ptr<AutocompleteProviderClient>(client),
     62                            type) {}
     63   MOCK_METHOD1(DeleteMatch, void(const AutocompleteMatch& match));
     64   MOCK_CONST_METHOD1(AddProviderInfo, void(ProvidersInfo* provider_info));
     65   MOCK_CONST_METHOD1(GetTemplateURL, const TemplateURL*(bool is_keyword));
     66   MOCK_CONST_METHOD1(GetInput, const AutocompleteInput(bool is_keyword));
     67   MOCK_CONST_METHOD1(ShouldAppendExtraParams,
     68                      bool(const SearchSuggestionParser::SuggestResult& result));
     69   MOCK_METHOD1(RecordDeletionResult, void(bool success));
     70 
     71   MOCK_METHOD2(Start,
     72                void(const AutocompleteInput& input, bool minimal_changes));
     73   void AddMatchToMap(const SearchSuggestionParser::SuggestResult& result,
     74                      const std::string& metadata,
     75                      int accepted_suggestion,
     76                      bool mark_as_deletable,
     77                      bool in_keyword_mode,
     78                      MatchMap* map) {
     79     BaseSearchProvider::AddMatchToMap(result,
     80                                       metadata,
     81                                       accepted_suggestion,
     82                                       mark_as_deletable,
     83                                       in_keyword_mode,
     84                                       map);
     85   }
     86 
     87  protected:
     88   virtual ~TestBaseSearchProvider() {}
     89 
     90  private:
     91   DISALLOW_COPY_AND_ASSIGN(TestBaseSearchProvider);
     92 };
     93 
     94 class BaseSearchProviderTest : public testing::Test {
     95  public:
     96   virtual ~BaseSearchProviderTest() {}
     97 
     98  protected:
     99   virtual void SetUp() {
    100     service_.reset(
    101         new TemplateURLService(NULL,
    102                                scoped_ptr<SearchTermsData>(new SearchTermsData),
    103                                NULL,
    104                                scoped_ptr<TemplateURLServiceClient>(),
    105                                NULL,
    106                                NULL,
    107                                base::Closure()));
    108     provider_ = new NiceMock<TestBaseSearchProvider>(
    109         service_.get(),
    110         new NiceMock<MockAutocompleteProviderClient>,
    111         AutocompleteProvider::TYPE_SEARCH);
    112   }
    113 
    114   scoped_refptr<NiceMock<TestBaseSearchProvider> > provider_;
    115   scoped_ptr<TemplateURLService> service_;
    116 };
    117 
    118 TEST_F(BaseSearchProviderTest, PreserveAnswersWhenDeduplicating) {
    119   TemplateURLData data;
    120   data.SetURL("http://foo.com/url?bar={searchTerms}");
    121   scoped_ptr<TemplateURL> template_url(new TemplateURL(data));
    122 
    123   TestBaseSearchProvider::MatchMap map;
    124   base::string16 query = base::ASCIIToUTF16("weather los angeles");
    125   base::string16 answer_contents = base::ASCIIToUTF16("some answer content");
    126   base::string16 answer_type = base::ASCIIToUTF16("2334");
    127 
    128   EXPECT_CALL(*provider_, GetInput(_))
    129       .WillRepeatedly(Return(AutocompleteInput()));
    130   EXPECT_CALL(*provider_, GetTemplateURL(_))
    131       .WillRepeatedly(Return(template_url.get()));
    132 
    133   SearchSuggestionParser::SuggestResult more_relevant(
    134       query, AutocompleteMatchType::SEARCH_HISTORY, query, base::string16(),
    135       base::string16(), base::string16(), base::string16(), std::string(),
    136       std::string(), false, 1300, true, false, query);
    137   provider_->AddMatchToMap(
    138       more_relevant, std::string(), TemplateURLRef::NO_SUGGESTION_CHOSEN,
    139       false, false, &map);
    140 
    141   SearchSuggestionParser::SuggestResult less_relevant(
    142       query, AutocompleteMatchType::SEARCH_SUGGEST, query, base::string16(),
    143       base::string16(), answer_contents, answer_type, std::string(),
    144       std::string(), false, 850, true, false, query);
    145   provider_->AddMatchToMap(
    146       less_relevant, std::string(), TemplateURLRef::NO_SUGGESTION_CHOSEN,
    147       false, false, &map);
    148 
    149   ASSERT_EQ(1U, map.size());
    150   AutocompleteMatch match = map.begin()->second;
    151   ASSERT_EQ(1U, match.duplicate_matches.size());
    152   AutocompleteMatch duplicate = match.duplicate_matches[0];
    153 
    154   EXPECT_EQ(answer_contents, match.answer_contents);
    155   EXPECT_EQ(answer_type, match.answer_type);
    156   EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY, match.type);
    157   EXPECT_EQ(1300, match.relevance);
    158 
    159   EXPECT_EQ(answer_contents, duplicate.answer_contents);
    160   EXPECT_EQ(answer_type, duplicate.answer_type);
    161   EXPECT_EQ(AutocompleteMatchType::SEARCH_SUGGEST, duplicate.type);
    162   EXPECT_EQ(850, duplicate.relevance);
    163 
    164   // Ensure answers are not copied over existing answers.
    165   map.clear();
    166   base::string16 answer_contents2 = base::ASCIIToUTF16("different answer");
    167   more_relevant = SearchSuggestionParser::SuggestResult(
    168       query, AutocompleteMatchType::SEARCH_HISTORY, query, base::string16(),
    169       base::string16(), answer_contents2, answer_type, std::string(),
    170       std::string(), false, 1300, true, false, query);
    171   provider_->AddMatchToMap(
    172       more_relevant, std::string(), TemplateURLRef::NO_SUGGESTION_CHOSEN,
    173       false, false, &map);
    174   provider_->AddMatchToMap(
    175       less_relevant, std::string(), TemplateURLRef::NO_SUGGESTION_CHOSEN,
    176       false, false, &map);
    177   ASSERT_EQ(1U, map.size());
    178   match = map.begin()->second;
    179   ASSERT_EQ(1U, match.duplicate_matches.size());
    180   duplicate = match.duplicate_matches[0];
    181 
    182   EXPECT_EQ(answer_contents2, match.answer_contents);
    183   EXPECT_EQ(answer_type, match.answer_type);
    184   EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY, match.type);
    185   EXPECT_EQ(1300, match.relevance);
    186 
    187   EXPECT_EQ(answer_contents, duplicate.answer_contents);
    188   EXPECT_EQ(answer_type, duplicate.answer_type);
    189   EXPECT_EQ(AutocompleteMatchType::SEARCH_SUGGEST, duplicate.type);
    190   EXPECT_EQ(850, duplicate.relevance);
    191 
    192 }
    193