| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "components/ntp_snippets/content_suggestions_service.h" | 5 #include "components/ntp_snippets/content_suggestions_service.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 void FireCategoryStatusChanged(Category category, CategoryStatus new_status) { | 70 void FireCategoryStatusChanged(Category category, CategoryStatus new_status) { |
| 71 statuses_[category.id()] = new_status; | 71 statuses_[category.id()] = new_status; |
| 72 observer()->OnCategoryStatusChanged(this, category, new_status); | 72 observer()->OnCategoryStatusChanged(this, category, new_status); |
| 73 } | 73 } |
| 74 | 74 |
| 75 void FireCategoryStatusChangedWithCurrentStatus(Category category) { | 75 void FireCategoryStatusChangedWithCurrentStatus(Category category) { |
| 76 observer()->OnCategoryStatusChanged(this, category, | 76 observer()->OnCategoryStatusChanged(this, category, |
| 77 statuses_[category.id()]); | 77 statuses_[category.id()]); |
| 78 } | 78 } |
| 79 | 79 |
| 80 void FireSuggestionInvalidated(Category category, | 80 void FireSuggestionInvalidated(const ContentSuggestion::ID& suggestion_id) { |
| 81 const std::string& suggestion_id) { | 81 observer()->OnSuggestionInvalidated(this, suggestion_id); |
| 82 observer()->OnSuggestionInvalidated(this, category, suggestion_id); | |
| 83 } | 82 } |
| 84 | 83 |
| 85 MOCK_METHOD3(ClearHistory, | 84 MOCK_METHOD3(ClearHistory, |
| 86 void(base::Time begin, | 85 void(base::Time begin, |
| 87 base::Time end, | 86 base::Time end, |
| 88 const base::Callback<bool(const GURL& url)>& filter)); | 87 const base::Callback<bool(const GURL& url)>& filter)); |
| 89 MOCK_METHOD1(ClearCachedSuggestions, void(Category category)); | 88 MOCK_METHOD1(ClearCachedSuggestions, void(Category category)); |
| 90 MOCK_METHOD2(GetDismissedSuggestionsForDebugging, | 89 MOCK_METHOD2(GetDismissedSuggestionsForDebugging, |
| 91 void(Category category, | 90 void(Category category, |
| 92 const DismissedSuggestionsCallback& callback)); | 91 const DismissedSuggestionsCallback& callback)); |
| 93 MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category category)); | 92 MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category category)); |
| 94 MOCK_METHOD1(DismissSuggestion, void(const std::string& suggestion_id)); | 93 MOCK_METHOD1(DismissSuggestion, |
| 94 void(const ContentSuggestion::ID& suggestion_id)); |
| 95 MOCK_METHOD2(FetchSuggestionImage, | 95 MOCK_METHOD2(FetchSuggestionImage, |
| 96 void(const std::string& suggestion_id, | 96 void(const ContentSuggestion::ID& suggestion_id, |
| 97 const ImageFetchedCallback& callback)); | 97 const ImageFetchedCallback& callback)); |
| 98 | 98 |
| 99 private: | 99 private: |
| 100 std::vector<Category> provided_categories_; | 100 std::vector<Category> provided_categories_; |
| 101 std::map<int, CategoryStatus> statuses_; | 101 std::map<int, CategoryStatus> statuses_; |
| 102 }; | 102 }; |
| 103 | 103 |
| 104 class MockServiceObserver : public ContentSuggestionsService::Observer { | 104 class MockServiceObserver : public ContentSuggestionsService::Observer { |
| 105 public: | 105 public: |
| 106 MockServiceObserver() = default; | 106 MockServiceObserver() = default; |
| 107 ~MockServiceObserver() override = default; | 107 ~MockServiceObserver() override = default; |
| 108 | 108 |
| 109 MOCK_METHOD1(OnNewSuggestions, void(Category category)); | 109 MOCK_METHOD1(OnNewSuggestions, void(Category category)); |
| 110 MOCK_METHOD2(OnCategoryStatusChanged, | 110 MOCK_METHOD2(OnCategoryStatusChanged, |
| 111 void(Category changed_category, CategoryStatus new_status)); | 111 void(Category changed_category, CategoryStatus new_status)); |
| 112 MOCK_METHOD2(OnSuggestionInvalidated, | 112 MOCK_METHOD1(OnSuggestionInvalidated, |
| 113 void(Category category, const std::string& suggestion_id)); | 113 void(const ContentSuggestion::ID& suggestion_id)); |
| 114 MOCK_METHOD0(ContentSuggestionsServiceShutdown, void()); | 114 MOCK_METHOD0(ContentSuggestionsServiceShutdown, void()); |
| 115 | 115 |
| 116 private: | 116 private: |
| 117 DISALLOW_COPY_AND_ASSIGN(MockServiceObserver); | 117 DISALLOW_COPY_AND_ASSIGN(MockServiceObserver); |
| 118 }; | 118 }; |
| 119 | 119 |
| 120 } // namespace | 120 } // namespace |
| 121 | 121 |
| 122 class ContentSuggestionsServiceTest : public testing::Test { | 122 class ContentSuggestionsServiceTest : public testing::Test { |
| 123 public: | 123 public: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 136 // returned by the service for the given |category|. | 136 // returned by the service for the given |category|. |
| 137 void ExpectThatSuggestionsAre(Category category, std::vector<int> numbers) { | 137 void ExpectThatSuggestionsAre(Category category, std::vector<int> numbers) { |
| 138 std::vector<Category> categories = service()->GetCategories(); | 138 std::vector<Category> categories = service()->GetCategories(); |
| 139 auto position = std::find(categories.begin(), categories.end(), category); | 139 auto position = std::find(categories.begin(), categories.end(), category); |
| 140 if (!numbers.empty()) { | 140 if (!numbers.empty()) { |
| 141 EXPECT_NE(categories.end(), position); | 141 EXPECT_NE(categories.end(), position); |
| 142 } | 142 } |
| 143 | 143 |
| 144 for (const auto& suggestion : | 144 for (const auto& suggestion : |
| 145 service()->GetSuggestionsForCategory(category)) { | 145 service()->GetSuggestionsForCategory(category)) { |
| 146 std::string within_category_id = | 146 std::string within_category_id = suggestion.id().within_category_id(); |
| 147 service()->category_factory()->GetWithinCategoryIDFromUniqueID( | |
| 148 suggestion.id()); | |
| 149 int id; | 147 int id; |
| 150 ASSERT_TRUE(base::StringToInt(within_category_id, &id)); | 148 ASSERT_TRUE(base::StringToInt(within_category_id, &id)); |
| 151 auto position = std::find(numbers.begin(), numbers.end(), id); | 149 auto position = std::find(numbers.begin(), numbers.end(), id); |
| 152 if (position == numbers.end()) { | 150 if (position == numbers.end()) { |
| 153 ADD_FAILURE() << "Unexpected suggestion with ID " << id; | 151 ADD_FAILURE() << "Unexpected suggestion with ID " << id; |
| 154 } else { | 152 } else { |
| 155 numbers.erase(position); | 153 numbers.erase(position); |
| 156 } | 154 } |
| 157 } | 155 } |
| 158 for (int number : numbers) { | 156 for (int number : numbers) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 service_.reset(new ContentSuggestionsService(enabled, | 196 service_.reset(new ContentSuggestionsService(enabled, |
| 199 nullptr /* history_service */, | 197 nullptr /* history_service */, |
| 200 nullptr /* pref_service */)); | 198 nullptr /* pref_service */)); |
| 201 } | 199 } |
| 202 | 200 |
| 203 ContentSuggestionsService* service() { return service_.get(); } | 201 ContentSuggestionsService* service() { return service_.get(); } |
| 204 | 202 |
| 205 // Returns a suggestion instance for testing. | 203 // Returns a suggestion instance for testing. |
| 206 ContentSuggestion CreateSuggestion(Category category, int number) { | 204 ContentSuggestion CreateSuggestion(Category category, int number) { |
| 207 return ContentSuggestion( | 205 return ContentSuggestion( |
| 208 service()->category_factory()->MakeUniqueID(category, | 206 category, base::IntToString(number), |
| 209 base::IntToString(number)), | |
| 210 GURL("http://testsuggestion/" + base::IntToString(number))); | 207 GURL("http://testsuggestion/" + base::IntToString(number))); |
| 211 } | 208 } |
| 212 | 209 |
| 213 std::vector<ContentSuggestion> CreateSuggestions( | 210 std::vector<ContentSuggestion> CreateSuggestions( |
| 214 Category category, | 211 Category category, |
| 215 const std::vector<int>& numbers) { | 212 const std::vector<int>& numbers) { |
| 216 std::vector<ContentSuggestion> result; | 213 std::vector<ContentSuggestion> result; |
| 217 for (int number : numbers) { | 214 for (int number : numbers) { |
| 218 result.push_back(CreateSuggestion(category, number)); | 215 result.push_back(CreateSuggestion(category, number)); |
| 219 } | 216 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 | 289 |
| 293 TEST_F(ContentSuggestionsServiceTest, ShouldRedirectFetchSuggestionImage) { | 290 TEST_F(ContentSuggestionsServiceTest, ShouldRedirectFetchSuggestionImage) { |
| 294 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); | 291 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); |
| 295 Category offline_pages_category = | 292 Category offline_pages_category = |
| 296 FromKnownCategory(KnownCategories::DOWNLOADS); | 293 FromKnownCategory(KnownCategories::DOWNLOADS); |
| 297 MockProvider* provider1 = RegisterProvider(articles_category); | 294 MockProvider* provider1 = RegisterProvider(articles_category); |
| 298 MockProvider* provider2 = RegisterProvider(offline_pages_category); | 295 MockProvider* provider2 = RegisterProvider(offline_pages_category); |
| 299 | 296 |
| 300 provider1->FireSuggestionsChanged(articles_category, | 297 provider1->FireSuggestionsChanged(articles_category, |
| 301 CreateSuggestions(articles_category, {1})); | 298 CreateSuggestions(articles_category, {1})); |
| 302 std::string suggestion_id = CreateSuggestion(articles_category, 1).id(); | 299 ContentSuggestion::ID suggestion_id(articles_category, "1"); |
| 303 | 300 |
| 304 EXPECT_CALL(*provider1, FetchSuggestionImage(suggestion_id, _)); | 301 EXPECT_CALL(*provider1, FetchSuggestionImage(suggestion_id, _)); |
| 305 EXPECT_CALL(*provider2, FetchSuggestionImage(_, _)).Times(0); | 302 EXPECT_CALL(*provider2, FetchSuggestionImage(_, _)).Times(0); |
| 306 service()->FetchSuggestionImage( | 303 service()->FetchSuggestionImage( |
| 307 suggestion_id, base::Bind(&ContentSuggestionsServiceTest::OnImageFetched, | 304 suggestion_id, base::Bind(&ContentSuggestionsServiceTest::OnImageFetched, |
| 308 base::Unretained(this))); | 305 base::Unretained(this))); |
| 309 } | 306 } |
| 310 | 307 |
| 311 TEST_F(ContentSuggestionsServiceTest, | 308 TEST_F(ContentSuggestionsServiceTest, |
| 312 ShouldCallbackEmptyImageForUnavailableProvider) { | 309 ShouldCallbackEmptyImageForUnavailableProvider) { |
| 313 // Setup the current thread's MessageLoop. | 310 // Setup the current thread's MessageLoop. |
| 314 base::MessageLoop message_loop; | 311 base::MessageLoop message_loop; |
| 315 | 312 |
| 316 base::RunLoop run_loop; | 313 base::RunLoop run_loop; |
| 317 // Assuming there will never be a category with the id below. | 314 // Assuming there will never be a category with the id below. |
| 318 std::string suggestion_id = "21563|TestID"; | 315 ContentSuggestion::ID suggestion_id(category_factory()->FromIDValue(21563), |
| 316 "TestID"); |
| 319 EXPECT_CALL(*this, OnImageFetched(Property(&gfx::Image::IsEmpty, Eq(true)))) | 317 EXPECT_CALL(*this, OnImageFetched(Property(&gfx::Image::IsEmpty, Eq(true)))) |
| 320 .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); | 318 .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); |
| 321 service()->FetchSuggestionImage( | 319 service()->FetchSuggestionImage( |
| 322 suggestion_id, base::Bind(&ContentSuggestionsServiceTest::OnImageFetched, | 320 suggestion_id, base::Bind(&ContentSuggestionsServiceTest::OnImageFetched, |
| 323 base::Unretained(this))); | 321 base::Unretained(this))); |
| 324 run_loop.Run(); | 322 run_loop.Run(); |
| 325 } | 323 } |
| 326 | 324 |
| 327 TEST_F(ContentSuggestionsServiceTest, ShouldRedirectDismissSuggestion) { | 325 TEST_F(ContentSuggestionsServiceTest, ShouldRedirectDismissSuggestion) { |
| 328 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); | 326 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); |
| 329 Category offline_pages_category = | 327 Category offline_pages_category = |
| 330 FromKnownCategory(KnownCategories::DOWNLOADS); | 328 FromKnownCategory(KnownCategories::DOWNLOADS); |
| 331 MockProvider* provider1 = RegisterProvider(articles_category); | 329 MockProvider* provider1 = RegisterProvider(articles_category); |
| 332 MockProvider* provider2 = RegisterProvider(offline_pages_category); | 330 MockProvider* provider2 = RegisterProvider(offline_pages_category); |
| 333 | 331 |
| 334 provider2->FireSuggestionsChanged( | 332 provider2->FireSuggestionsChanged( |
| 335 offline_pages_category, CreateSuggestions(offline_pages_category, {11})); | 333 offline_pages_category, CreateSuggestions(offline_pages_category, {11})); |
| 336 std::string suggestion_id = CreateSuggestion(offline_pages_category, 11).id(); | 334 ContentSuggestion::ID suggestion_id(offline_pages_category, "11"); |
| 337 | 335 |
| 338 EXPECT_CALL(*provider1, DismissSuggestion(_)).Times(0); | 336 EXPECT_CALL(*provider1, DismissSuggestion(_)).Times(0); |
| 339 EXPECT_CALL(*provider2, DismissSuggestion(suggestion_id)); | 337 EXPECT_CALL(*provider2, DismissSuggestion(suggestion_id)); |
| 340 service()->DismissSuggestion(suggestion_id); | 338 service()->DismissSuggestion(suggestion_id); |
| 341 } | 339 } |
| 342 | 340 |
| 343 TEST_F(ContentSuggestionsServiceTest, ShouldRedirectSuggestionInvalidated) { | 341 TEST_F(ContentSuggestionsServiceTest, ShouldRedirectSuggestionInvalidated) { |
| 344 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); | 342 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); |
| 345 | 343 |
| 346 MockProvider* provider = RegisterProvider(articles_category); | 344 MockProvider* provider = RegisterProvider(articles_category); |
| 347 MockServiceObserver observer; | 345 MockServiceObserver observer; |
| 348 service()->AddObserver(&observer); | 346 service()->AddObserver(&observer); |
| 349 | 347 |
| 350 provider->FireSuggestionsChanged( | 348 provider->FireSuggestionsChanged( |
| 351 articles_category, CreateSuggestions(articles_category, {11, 12, 13})); | 349 articles_category, CreateSuggestions(articles_category, {11, 12, 13})); |
| 352 ExpectThatSuggestionsAre(articles_category, {11, 12, 13}); | 350 ExpectThatSuggestionsAre(articles_category, {11, 12, 13}); |
| 353 | 351 |
| 354 std::string suggestion_id = CreateSuggestion(articles_category, 12).id(); | 352 ContentSuggestion::ID suggestion_id(articles_category, "12"); |
| 355 EXPECT_CALL(observer, | 353 EXPECT_CALL(observer, OnSuggestionInvalidated(suggestion_id)); |
| 356 OnSuggestionInvalidated(articles_category, suggestion_id)); | 354 provider->FireSuggestionInvalidated(suggestion_id); |
| 357 provider->FireSuggestionInvalidated(articles_category, suggestion_id); | |
| 358 ExpectThatSuggestionsAre(articles_category, {11, 13}); | 355 ExpectThatSuggestionsAre(articles_category, {11, 13}); |
| 359 Mock::VerifyAndClearExpectations(&observer); | 356 Mock::VerifyAndClearExpectations(&observer); |
| 360 | 357 |
| 361 // Unknown IDs must be forwarded (though no change happens to the service's | 358 // Unknown IDs must be forwarded (though no change happens to the service's |
| 362 // internal data structures) because previously opened UIs, which can still | 359 // internal data structures) because previously opened UIs, which can still |
| 363 // show the invalidated suggestion, must be notified. | 360 // show the invalidated suggestion, must be notified. |
| 364 std::string unknown_id = CreateSuggestion(articles_category, 1234).id(); | 361 ContentSuggestion::ID unknown_id(articles_category, "1234"); |
| 365 EXPECT_CALL(observer, OnSuggestionInvalidated(articles_category, unknown_id)); | 362 EXPECT_CALL(observer, OnSuggestionInvalidated(unknown_id)); |
| 366 provider->FireSuggestionInvalidated(articles_category, unknown_id); | 363 provider->FireSuggestionInvalidated(unknown_id); |
| 367 ExpectThatSuggestionsAre(articles_category, {11, 13}); | 364 ExpectThatSuggestionsAre(articles_category, {11, 13}); |
| 368 Mock::VerifyAndClearExpectations(&observer); | 365 Mock::VerifyAndClearExpectations(&observer); |
| 369 | 366 |
| 370 service()->RemoveObserver(&observer); | 367 service()->RemoveObserver(&observer); |
| 371 } | 368 } |
| 372 | 369 |
| 373 TEST_F(ContentSuggestionsServiceTest, ShouldForwardSuggestions) { | 370 TEST_F(ContentSuggestionsServiceTest, ShouldForwardSuggestions) { |
| 374 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); | 371 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); |
| 375 Category offline_pages_category = | 372 Category offline_pages_category = |
| 376 FromKnownCategory(KnownCategories::DOWNLOADS); | 373 FromKnownCategory(KnownCategories::DOWNLOADS); |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 569 EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote)); | 566 EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote)); |
| 570 // Dismiss the second suggestion; now bookmarks should go back to the end. | 567 // Dismiss the second suggestion; now bookmarks should go back to the end. |
| 571 service()->DismissSuggestion(CreateSuggestion(bookmarks, 2).id()); | 568 service()->DismissSuggestion(CreateSuggestion(bookmarks, 2).id()); |
| 572 EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks)); | 569 EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks)); |
| 573 | 570 |
| 574 // Same thing, but invalidate instead of dismissing. | 571 // Same thing, but invalidate instead of dismissing. |
| 575 bookmarks_provider->FireSuggestionsChanged( | 572 bookmarks_provider->FireSuggestionsChanged( |
| 576 bookmarks, CreateSuggestions(bookmarks, {1, 2})); | 573 bookmarks, CreateSuggestions(bookmarks, {1, 2})); |
| 577 EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote)); | 574 EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote)); |
| 578 bookmarks_provider->FireSuggestionInvalidated( | 575 bookmarks_provider->FireSuggestionInvalidated( |
| 579 bookmarks, CreateSuggestion(bookmarks, 1).id()); | 576 ContentSuggestion::ID(bookmarks, "1")); |
| 580 EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote)); | 577 EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote)); |
| 581 bookmarks_provider->FireSuggestionInvalidated( | 578 bookmarks_provider->FireSuggestionInvalidated( |
| 582 bookmarks, CreateSuggestion(bookmarks, 2).id()); | 579 ContentSuggestion::ID(bookmarks, "2")); |
| 583 EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks)); | 580 EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks)); |
| 584 | 581 |
| 585 // Same thing, but now the bookmarks category updates "naturally". | 582 // Same thing, but now the bookmarks category updates "naturally". |
| 586 bookmarks_provider->FireSuggestionsChanged( | 583 bookmarks_provider->FireSuggestionsChanged( |
| 587 bookmarks, CreateSuggestions(bookmarks, {1, 2})); | 584 bookmarks, CreateSuggestions(bookmarks, {1, 2})); |
| 588 EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote)); | 585 EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote)); |
| 589 bookmarks_provider->FireSuggestionsChanged(bookmarks, | 586 bookmarks_provider->FireSuggestionsChanged(bookmarks, |
| 590 CreateSuggestions(bookmarks, {1})); | 587 CreateSuggestions(bookmarks, {1})); |
| 591 EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote)); | 588 EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote)); |
| 592 bookmarks_provider->FireSuggestionsChanged( | 589 bookmarks_provider->FireSuggestionsChanged( |
| 593 bookmarks, CreateSuggestions(bookmarks, std::vector<int>())); | 590 bookmarks, CreateSuggestions(bookmarks, std::vector<int>())); |
| 594 EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks)); | 591 EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks)); |
| 595 } | 592 } |
| 596 | 593 |
| 597 TEST_F(ContentSuggestionsServiceTest, ShouldForwardClearHistory) { | 594 TEST_F(ContentSuggestionsServiceTest, ShouldForwardClearHistory) { |
| 598 Category category = FromKnownCategory(KnownCategories::DOWNLOADS); | 595 Category category = FromKnownCategory(KnownCategories::DOWNLOADS); |
| 599 MockProvider* provider = RegisterProvider(category); | 596 MockProvider* provider = RegisterProvider(category); |
| 600 base::Time begin = base::Time::FromTimeT(123), | 597 base::Time begin = base::Time::FromTimeT(123), |
| 601 end = base::Time::FromTimeT(456); | 598 end = base::Time::FromTimeT(456); |
| 602 EXPECT_CALL(*provider, ClearHistory(begin, end, _)); | 599 EXPECT_CALL(*provider, ClearHistory(begin, end, _)); |
| 603 base::Callback<bool(const GURL& url)> filter; | 600 base::Callback<bool(const GURL& url)> filter; |
| 604 service()->ClearHistory(begin, end, filter); | 601 service()->ClearHistory(begin, end, filter); |
| 605 } | 602 } |
| 606 | 603 |
| 607 } // namespace ntp_snippets | 604 } // namespace ntp_snippets |
| OLD | NEW |