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