| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/autocomplete/search_provider.h" | 5 #include "chrome/browser/autocomplete/search_provider.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/metrics/field_trial.h" | 10 #include "base/metrics/field_trial.h" |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 | 49 |
| 50 // Returns the first match in |matches| with |allowed_to_be_default_match| | 50 // Returns the first match in |matches| with |allowed_to_be_default_match| |
| 51 // set to true. | 51 // set to true. |
| 52 ACMatches::const_iterator FindDefaultMatch(const ACMatches& matches) { | 52 ACMatches::const_iterator FindDefaultMatch(const ACMatches& matches) { |
| 53 ACMatches::const_iterator it = matches.begin(); | 53 ACMatches::const_iterator it = matches.begin(); |
| 54 while ((it != matches.end()) && !it->allowed_to_be_default_match) | 54 while ((it != matches.end()) && !it->allowed_to_be_default_match) |
| 55 ++it; | 55 ++it; |
| 56 return it; | 56 return it; |
| 57 } | 57 } |
| 58 | 58 |
| 59 class SuggestionDeletionHandler; |
| 60 class SearchProviderForTest : public SearchProvider { |
| 61 public: |
| 62 SearchProviderForTest( |
| 63 AutocompleteProviderListener* listener, |
| 64 Profile* profile); |
| 65 bool is_success() { return is_success_; }; |
| 66 |
| 67 protected: |
| 68 virtual ~SearchProviderForTest(); |
| 69 |
| 70 private: |
| 71 virtual void RecordDeletionResult(bool success) OVERRIDE; |
| 72 bool is_success_; |
| 73 DISALLOW_COPY_AND_ASSIGN(SearchProviderForTest); |
| 74 }; |
| 75 |
| 76 SearchProviderForTest::SearchProviderForTest( |
| 77 AutocompleteProviderListener* listener, |
| 78 Profile* profile) |
| 79 : SearchProvider(listener, profile), is_success_(false) { |
| 80 } |
| 81 |
| 82 SearchProviderForTest::~SearchProviderForTest() { |
| 83 } |
| 84 |
| 85 void SearchProviderForTest::RecordDeletionResult(bool success) { |
| 86 is_success_ = success; |
| 87 } |
| 88 |
| 59 } // namespace | 89 } // namespace |
| 60 | 90 |
| 61 // SearchProviderTest --------------------------------------------------------- | 91 // SearchProviderTest --------------------------------------------------------- |
| 62 | 92 |
| 63 // The following environment is configured for these tests: | 93 // The following environment is configured for these tests: |
| 64 // . The TemplateURL default_t_url_ is set as the default provider. | 94 // . The TemplateURL default_t_url_ is set as the default provider. |
| 65 // . The TemplateURL keyword_t_url_ is added to the TemplateURLService. This | 95 // . The TemplateURL keyword_t_url_ is added to the TemplateURLService. This |
| 66 // TemplateURL has a valid suggest and search URL. | 96 // TemplateURL has a valid suggest and search URL. |
| 67 // . The URL created by using the search term term1_ with default_t_url_ is | 97 // . The URL created by using the search term term1_ with default_t_url_ is |
| 68 // added to history. | 98 // added to history. |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 | 210 |
| 181 content::TestBrowserThreadBundle thread_bundle_; | 211 content::TestBrowserThreadBundle thread_bundle_; |
| 182 | 212 |
| 183 // URLFetcherFactory implementation registered. | 213 // URLFetcherFactory implementation registered. |
| 184 net::TestURLFetcherFactory test_factory_; | 214 net::TestURLFetcherFactory test_factory_; |
| 185 | 215 |
| 186 // Profile we use. | 216 // Profile we use. |
| 187 TestingProfile profile_; | 217 TestingProfile profile_; |
| 188 | 218 |
| 189 // The provider. | 219 // The provider. |
| 190 scoped_refptr<SearchProvider> provider_; | 220 scoped_refptr<SearchProviderForTest> provider_; |
| 191 | 221 |
| 192 // If non-NULL, OnProviderUpdate quits the current |run_loop_|. | 222 // If non-NULL, OnProviderUpdate quits the current |run_loop_|. |
| 193 base::RunLoop* run_loop_; | 223 base::RunLoop* run_loop_; |
| 194 | 224 |
| 195 DISALLOW_COPY_AND_ASSIGN(SearchProviderTest); | 225 DISALLOW_COPY_AND_ASSIGN(SearchProviderTest); |
| 196 }; | 226 }; |
| 197 | 227 |
| 198 // static | 228 // static |
| 199 const std::string SearchProviderTest::kNotApplicable = "Not Applicable"; | 229 const std::string SearchProviderTest::kNotApplicable = "Not Applicable"; |
| 200 | 230 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 ASSERT_NE(0, keyword_t_url_->id()); | 268 ASSERT_NE(0, keyword_t_url_->id()); |
| 239 | 269 |
| 240 // Add a page and search term for keyword_t_url_. | 270 // Add a page and search term for keyword_t_url_. |
| 241 keyword_url_ = AddSearchToHistory(keyword_t_url_, keyword_term_, 1); | 271 keyword_url_ = AddSearchToHistory(keyword_t_url_, keyword_term_, 1); |
| 242 | 272 |
| 243 // Keywords are updated by the InMemoryHistoryBackend only after the message | 273 // Keywords are updated by the InMemoryHistoryBackend only after the message |
| 244 // has been processed on the history thread. Block until history processes all | 274 // has been processed on the history thread. Block until history processes all |
| 245 // requests to ensure the InMemoryDatabase is the state we expect it. | 275 // requests to ensure the InMemoryDatabase is the state we expect it. |
| 246 profile_.BlockUntilHistoryProcessesPendingRequests(); | 276 profile_.BlockUntilHistoryProcessesPendingRequests(); |
| 247 | 277 |
| 248 provider_ = new SearchProvider(this, &profile_); | 278 provider_ = new SearchProviderForTest(this, &profile_); |
| 249 provider_->kMinimumTimeBetweenSuggestQueriesMs = 0; | 279 provider_->kMinimumTimeBetweenSuggestQueriesMs = 0; |
| 250 } | 280 } |
| 251 | 281 |
| 252 void SearchProviderTest::TearDown() { | 282 void SearchProviderTest::TearDown() { |
| 253 base::RunLoop().RunUntilIdle(); | 283 base::RunLoop().RunUntilIdle(); |
| 254 | 284 |
| 255 // Shutdown the provider before the profile. | 285 // Shutdown the provider before the profile. |
| 256 provider_ = NULL; | 286 provider_ = NULL; |
| 257 } | 287 } |
| 258 | 288 |
| (...skipping 3088 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3347 if (suggestion == kNotApplicable) | 3377 if (suggestion == kNotApplicable) |
| 3348 break; | 3378 break; |
| 3349 if (cases[i].results[j].is_navigation_result) { | 3379 if (cases[i].results[j].is_navigation_result) { |
| 3350 provider_->default_results_.navigation_results.push_back( | 3380 provider_->default_results_.navigation_results.push_back( |
| 3351 SearchProvider::NavigationResult( | 3381 SearchProvider::NavigationResult( |
| 3352 *provider_.get(), GURL(suggestion), string16(), false, | 3382 *provider_.get(), GURL(suggestion), string16(), false, |
| 3353 cases[i].results[j].relevance, false)); | 3383 cases[i].results[j].relevance, false)); |
| 3354 } else { | 3384 } else { |
| 3355 provider_->default_results_.suggest_results.push_back( | 3385 provider_->default_results_.suggest_results.push_back( |
| 3356 SearchProvider::SuggestResult(ASCIIToUTF16(suggestion), string16(), | 3386 SearchProvider::SuggestResult(ASCIIToUTF16(suggestion), string16(), |
| 3357 string16(), std::string(), false, | 3387 string16(), std::string(), |
| 3388 std::string(), false, |
| 3358 cases[i].results[j].relevance, | 3389 cases[i].results[j].relevance, |
| 3359 false, false)); | 3390 false, false)); |
| 3360 } | 3391 } |
| 3361 } | 3392 } |
| 3362 | 3393 |
| 3363 provider_->input_ = AutocompleteInput( | 3394 provider_->input_ = AutocompleteInput( |
| 3364 ASCIIToUTF16(cases[i].omnibox_input), string16::npos, string16(), | 3395 ASCIIToUTF16(cases[i].omnibox_input), string16::npos, string16(), |
| 3365 GURL(), AutocompleteInput::INVALID_SPEC, false, false, true, | 3396 GURL(), AutocompleteInput::INVALID_SPEC, false, false, true, |
| 3366 AutocompleteInput::ALL_MATCHES); | 3397 AutocompleteInput::ALL_MATCHES); |
| 3367 provider_->RemoveAllStaleResults(); | 3398 provider_->RemoveAllStaleResults(); |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3748 } | 3779 } |
| 3749 } | 3780 } |
| 3750 | 3781 |
| 3751 // A basic test that verifies that the XSSI guarded JSON response is parsed | 3782 // A basic test that verifies that the XSSI guarded JSON response is parsed |
| 3752 // correctly. | 3783 // correctly. |
| 3753 TEST_F(SearchProviderTest, XSSIGuardedJSONParsing) { | 3784 TEST_F(SearchProviderTest, XSSIGuardedJSONParsing) { |
| 3754 struct Match { | 3785 struct Match { |
| 3755 std::string contents; | 3786 std::string contents; |
| 3756 AutocompleteMatchType::Type type; | 3787 AutocompleteMatchType::Type type; |
| 3757 }; | 3788 }; |
| 3758 const Match kEmptyMatch = { kNotApplicable, | 3789 const Match kEmptyMatch = { |
| 3759 AutocompleteMatchType::NUM_TYPES}; | 3790 kNotApplicable, AutocompleteMatchType::NUM_TYPES |
| 3791 }; |
| 3760 | 3792 |
| 3761 struct { | 3793 struct { |
| 3762 const std::string input_text; | 3794 const std::string input_text; |
| 3763 const std::string default_provider_response_json; | 3795 const std::string default_provider_response_json; |
| 3764 const Match matches[4]; | 3796 const Match matches[4]; |
| 3765 } cases[] = { | 3797 } cases[] = { |
| 3766 // No XSSI guard. | 3798 // No XSSI guard. |
| 3767 { "a", | 3799 { "a", |
| 3768 "[\"a\",[\"b\", \"c\"],[],[]," | 3800 "[\"a\",[\"b\", \"c\"],[],[]," |
| 3769 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"]," | 3801 "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"]," |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3828 EXPECT_EQ(cases[i].matches[j].type, matches[j].type); | 3860 EXPECT_EQ(cases[i].matches[j].type, matches[j].type); |
| 3829 } | 3861 } |
| 3830 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) { | 3862 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) { |
| 3831 SCOPED_TRACE("and match: " + base::IntToString(j)); | 3863 SCOPED_TRACE("and match: " + base::IntToString(j)); |
| 3832 EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable); | 3864 EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable); |
| 3833 EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES); | 3865 EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES); |
| 3834 } | 3866 } |
| 3835 } | 3867 } |
| 3836 } | 3868 } |
| 3837 | 3869 |
| 3870 // Test that deletion url gets set on an AutocompleteMatch when available for a |
| 3871 // personalized query. |
| 3872 TEST_F(SearchProviderTest, ParseDeletionUrl) { |
| 3873 struct Match { |
| 3874 std::string contents; |
| 3875 std::string deletion_url; |
| 3876 AutocompleteMatchType::Type type; |
| 3877 }; |
| 3878 |
| 3879 const Match kEmptyMatch = { |
| 3880 kNotApplicable, "", AutocompleteMatchType::NUM_TYPES |
| 3881 }; |
| 3882 |
| 3883 const char url[] = "https://www.google.com/complete/deleteitems" |
| 3884 "?delq=ab&client=chrome&deltok=xsrf123"; |
| 3885 |
| 3886 struct { |
| 3887 const std::string input_text; |
| 3888 const std::string response_json; |
| 3889 const Match matches[4]; |
| 3890 } cases[] = { |
| 3891 // A deletion URL on a personalized query should be reflected in the |
| 3892 // resulting AutocompleteMatch. |
| 3893 { "a", |
| 3894 "[\"a\",[\"ab\", \"ac\"],[],[]," |
| 3895 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\"]," |
| 3896 "\"google:suggestrelevance\":[1, 2]," |
| 3897 "\"google:suggestdetail\":[{\"du\":" |
| 3898 "\"https://www.google.com/complete/deleteitems?delq=ab&client=chrome" |
| 3899 "&deltok=xsrf123\"}, {}]}]", |
| 3900 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED }, |
| 3901 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST }, |
| 3902 { "ab", url, AutocompleteMatchType::SEARCH_SUGGEST }, |
| 3903 kEmptyMatch, |
| 3904 }, |
| 3905 }, |
| 3906 // Personalized queries without deletion URLs shouldn't cause errors. |
| 3907 { "a", |
| 3908 "[\"a\",[\"ab\", \"ac\"],[],[]," |
| 3909 "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\"]," |
| 3910 "\"google:suggestrelevance\":[1, 2]," |
| 3911 "\"google:suggestdetail\":[{}, {}]}]", |
| 3912 { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED }, |
| 3913 { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST }, |
| 3914 { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST }, |
| 3915 kEmptyMatch, |
| 3916 }, |
| 3917 }, |
| 3918 }; |
| 3919 |
| 3920 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { |
| 3921 QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false); |
| 3922 |
| 3923 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID( |
| 3924 SearchProvider::kDefaultProviderURLFetcherID); |
| 3925 ASSERT_TRUE(fetcher); |
| 3926 fetcher->set_response_code(200); |
| 3927 fetcher->SetResponseString(cases[i].response_json); |
| 3928 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 3929 |
| 3930 RunTillProviderDone(); |
| 3931 |
| 3932 const ACMatches& matches = provider_->matches(); |
| 3933 ASSERT_FALSE(matches.empty()); |
| 3934 |
| 3935 SCOPED_TRACE("for input with json = " + cases[i].response_json); |
| 3936 |
| 3937 for (size_t j = 0; j < matches.size(); ++j) { |
| 3938 const Match& match = cases[i].matches[j]; |
| 3939 SCOPED_TRACE(" and match index: " + base::IntToString(j)); |
| 3940 EXPECT_EQ(match.contents, UTF16ToUTF8(matches[j].contents)); |
| 3941 EXPECT_EQ(match.deletion_url, matches[j].GetAdditionalInfo( |
| 3942 "deletion_url")); |
| 3943 } |
| 3944 } |
| 3945 } |
| 3838 | 3946 |
| 3839 TEST_F(SearchProviderTest, ReflectsBookmarkBarState) { | 3947 TEST_F(SearchProviderTest, ReflectsBookmarkBarState) { |
| 3840 profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, false); | 3948 profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, false); |
| 3841 string16 term = term1_.substr(0, term1_.length() - 1); | 3949 string16 term = term1_.substr(0, term1_.length() - 1); |
| 3842 QueryForInput(term, true, false); | 3950 QueryForInput(term, true, false); |
| 3843 ASSERT_FALSE(provider_->matches().empty()); | 3951 ASSERT_FALSE(provider_->matches().empty()); |
| 3844 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, | 3952 EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, |
| 3845 provider_->matches()[0].type); | 3953 provider_->matches()[0].type); |
| 3846 ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL); | 3954 ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL); |
| 3847 EXPECT_FALSE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned); | 3955 EXPECT_FALSE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3974 AutocompleteInput::OTHER, &profile_)); | 4082 AutocompleteInput::OTHER, &profile_)); |
| 3975 encrypted_types.Remove(syncer::SESSIONS); | 4083 encrypted_types.Remove(syncer::SESSIONS); |
| 3976 service->OnEncryptedTypesChanged(encrypted_types, false); | 4084 service->OnEncryptedTypesChanged(encrypted_types, false); |
| 3977 | 4085 |
| 3978 // Check that there were no side effects from previous tests. | 4086 // Check that there were no side effects from previous tests. |
| 3979 EXPECT_TRUE(SearchProvider::CanSendURL( | 4087 EXPECT_TRUE(SearchProvider::CanSendURL( |
| 3980 GURL("http://www.google.com/search"), | 4088 GURL("http://www.google.com/search"), |
| 3981 GURL("https://www.google.com/complete/search"), &google_template_url, | 4089 GURL("https://www.google.com/complete/search"), &google_template_url, |
| 3982 AutocompleteInput::OTHER, &profile_)); | 4090 AutocompleteInput::OTHER, &profile_)); |
| 3983 } | 4091 } |
| 4092 |
| 4093 TEST_F(SearchProviderTest, TestDeleteMatch) { |
| 4094 AutocompleteMatch match(provider_, 0, true, |
| 4095 AutocompleteMatchType::SEARCH_SUGGEST); |
| 4096 match.RecordAdditionalInfo( |
| 4097 SearchProvider::kDeletionUrlKey, |
| 4098 "https://www.google.com/complete/deleteitem?q=foo"); |
| 4099 |
| 4100 // Test a successful deletion request. |
| 4101 provider_->matches_.push_back(match); |
| 4102 provider_->DeleteMatch(match); |
| 4103 EXPECT_FALSE(provider_->deletion_handlers_.empty()); |
| 4104 EXPECT_TRUE(provider_->matches_.empty()); |
| 4105 // Set up a default fetcher with provided results. |
| 4106 net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID( |
| 4107 SearchProvider::kDeletionURLFetcherID); |
| 4108 ASSERT_TRUE(fetcher); |
| 4109 fetcher->set_response_code(200); |
| 4110 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 4111 EXPECT_TRUE(provider_->deletion_handlers_.empty()); |
| 4112 EXPECT_TRUE(provider_->is_success()); |
| 4113 |
| 4114 // Test a failing deletion request. |
| 4115 provider_->matches_.push_back(match); |
| 4116 provider_->DeleteMatch(match); |
| 4117 EXPECT_FALSE(provider_->deletion_handlers_.empty()); |
| 4118 // Set up a default fetcher with provided results. |
| 4119 fetcher = test_factory_.GetFetcherByID( |
| 4120 SearchProvider::kDeletionURLFetcherID); |
| 4121 ASSERT_TRUE(fetcher); |
| 4122 fetcher->set_response_code(500); |
| 4123 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 4124 EXPECT_TRUE(provider_->deletion_handlers_.empty()); |
| 4125 EXPECT_FALSE(provider_->is_success()); |
| 4126 } |
| OLD | NEW |