// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/omnibox/browser/base_search_provider.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/autocomplete_match_type.h" #include "components/omnibox/browser/autocomplete_scheme_classifier.h" #include "components/omnibox/browser/mock_autocomplete_provider_client.h" #include "components/omnibox/browser/search_suggestion_parser.h" #include "components/omnibox/browser/suggestion_answer.h" #include "components/search_engines/search_terms_data.h" #include "components/search_engines/template_url_service.h" #include "components/search_engines/template_url_service_client.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using testing::NiceMock; using testing::Return; using testing::_; class TestBaseSearchProvider : public BaseSearchProvider { public: typedef BaseSearchProvider::MatchMap MatchMap; TestBaseSearchProvider(AutocompleteProvider::Type type, AutocompleteProviderClient* client) : BaseSearchProvider(type, client) {} MOCK_METHOD1(DeleteMatch, void(const AutocompleteMatch& match)); MOCK_CONST_METHOD1(AddProviderInfo, void(ProvidersInfo* provider_info)); MOCK_CONST_METHOD1(GetTemplateURL, const TemplateURL*(bool is_keyword)); MOCK_CONST_METHOD1(GetInput, const AutocompleteInput(bool is_keyword)); MOCK_CONST_METHOD1(ShouldAppendExtraParams, bool(const SearchSuggestionParser::SuggestResult& result)); MOCK_METHOD1(RecordDeletionResult, void(bool success)); MOCK_METHOD2(Start, void(const AutocompleteInput& input, bool minimal_changes)); void AddMatchToMap(const SearchSuggestionParser::SuggestResult& result, const std::string& metadata, int accepted_suggestion, bool mark_as_deletable, bool in_keyword_mode, MatchMap* map) { BaseSearchProvider::AddMatchToMap(result, metadata, accepted_suggestion, mark_as_deletable, in_keyword_mode, map); } protected: virtual ~TestBaseSearchProvider() {} private: DISALLOW_COPY_AND_ASSIGN(TestBaseSearchProvider); }; class BaseSearchProviderTest : public testing::Test { public: ~BaseSearchProviderTest() override {} protected: void SetUp() override { scoped_ptr template_url_service(new TemplateURLService( nullptr, scoped_ptr(new SearchTermsData), nullptr, scoped_ptr(), nullptr, nullptr, base::Closure())); client_.reset(new NiceMock()); client_->set_template_url_service(template_url_service.Pass()); provider_ = new NiceMock( AutocompleteProvider::TYPE_SEARCH, client_.get()); } scoped_refptr > provider_; scoped_ptr> client_; }; TEST_F(BaseSearchProviderTest, PreserveAnswersWhenDeduplicating) { TemplateURLData data; data.SetURL("http://foo.com/url?bar={searchTerms}"); scoped_ptr template_url(new TemplateURL(data)); TestBaseSearchProvider::MatchMap map; base::string16 query = base::ASCIIToUTF16("weather los angeles"); base::string16 answer_contents = base::ASCIIToUTF16("some answer content"); base::string16 answer_type = base::ASCIIToUTF16("2334"); scoped_ptr answer(new SuggestionAnswer()); answer->set_type(2334); EXPECT_CALL(*provider_, GetInput(_)) .WillRepeatedly(Return(AutocompleteInput())); EXPECT_CALL(*provider_, GetTemplateURL(_)) .WillRepeatedly(Return(template_url.get())); SearchSuggestionParser::SuggestResult more_relevant( query, AutocompleteMatchType::SEARCH_HISTORY, query, base::string16(), base::string16(), base::string16(), base::string16(), nullptr, std::string(), std::string(), false, 1300, true, false, query); provider_->AddMatchToMap( more_relevant, std::string(), TemplateURLRef::NO_SUGGESTION_CHOSEN, false, false, &map); SearchSuggestionParser::SuggestResult less_relevant( query, AutocompleteMatchType::SEARCH_SUGGEST, query, base::string16(), base::string16(), answer_contents, answer_type, SuggestionAnswer::copy(answer.get()), std::string(), std::string(), false, 850, true, false, query); provider_->AddMatchToMap( less_relevant, std::string(), TemplateURLRef::NO_SUGGESTION_CHOSEN, false, false, &map); ASSERT_EQ(1U, map.size()); AutocompleteMatch match = map.begin()->second; ASSERT_EQ(1U, match.duplicate_matches.size()); AutocompleteMatch duplicate = match.duplicate_matches[0]; EXPECT_EQ(answer_contents, match.answer_contents); EXPECT_EQ(answer_type, match.answer_type); EXPECT_TRUE(answer->Equals(*match.answer)); EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY, match.type); EXPECT_EQ(1300, match.relevance); EXPECT_EQ(answer_contents, duplicate.answer_contents); EXPECT_EQ(answer_type, duplicate.answer_type); EXPECT_TRUE(answer->Equals(*duplicate.answer)); EXPECT_EQ(AutocompleteMatchType::SEARCH_SUGGEST, duplicate.type); EXPECT_EQ(850, duplicate.relevance); // Ensure answers are not copied over existing answers. map.clear(); base::string16 answer_contents2 = base::ASCIIToUTF16("different answer"); base::string16 answer_type2 = base::ASCIIToUTF16("8242"); scoped_ptr answer2(new SuggestionAnswer()); answer2->set_type(8242); more_relevant = SearchSuggestionParser::SuggestResult( query, AutocompleteMatchType::SEARCH_HISTORY, query, base::string16(), base::string16(), answer_contents2, answer_type2, SuggestionAnswer::copy(answer2.get()), std::string(), std::string(), false, 1300, true, false, query); provider_->AddMatchToMap( more_relevant, std::string(), TemplateURLRef::NO_SUGGESTION_CHOSEN, false, false, &map); provider_->AddMatchToMap( less_relevant, std::string(), TemplateURLRef::NO_SUGGESTION_CHOSEN, false, false, &map); ASSERT_EQ(1U, map.size()); match = map.begin()->second; ASSERT_EQ(1U, match.duplicate_matches.size()); duplicate = match.duplicate_matches[0]; EXPECT_EQ(answer_contents2, match.answer_contents); EXPECT_EQ(answer_type2, match.answer_type); EXPECT_TRUE(answer2->Equals(*match.answer)); EXPECT_EQ(AutocompleteMatchType::SEARCH_HISTORY, match.type); EXPECT_EQ(1300, match.relevance); EXPECT_EQ(answer_contents, duplicate.answer_contents); EXPECT_EQ(answer_type, duplicate.answer_type); EXPECT_TRUE(answer->Equals(*duplicate.answer)); EXPECT_EQ(AutocompleteMatchType::SEARCH_SUGGEST, duplicate.type); EXPECT_EQ(850, duplicate.relevance); }