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 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/macros.h" | 12 #include "base/macros.h" |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
15 #include "base/run_loop.h" | 15 #include "base/run_loop.h" |
16 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
17 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
18 #include "components/ntp_snippets/category_info.h" | 18 #include "components/ntp_snippets/category_info.h" |
19 #include "components/ntp_snippets/category_rankers/constant_category_ranker.h" | 19 #include "components/ntp_snippets/category_rankers/constant_category_ranker.h" |
| 20 #include "components/ntp_snippets/category_rankers/mock_category_ranker.h" |
20 #include "components/ntp_snippets/category_status.h" | 21 #include "components/ntp_snippets/category_status.h" |
21 #include "components/ntp_snippets/content_suggestion.h" | 22 #include "components/ntp_snippets/content_suggestion.h" |
22 #include "components/ntp_snippets/content_suggestions_provider.h" | 23 #include "components/ntp_snippets/content_suggestions_provider.h" |
23 #include "components/ntp_snippets/user_classifier.h" | 24 #include "components/ntp_snippets/user_classifier.h" |
24 #include "components/prefs/testing_pref_service.h" | 25 #include "components/prefs/testing_pref_service.h" |
25 #include "testing/gmock/include/gmock/gmock.h" | 26 #include "testing/gmock/include/gmock/gmock.h" |
26 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
27 #include "ui/gfx/image/image.h" | 28 #include "ui/gfx/image/image.h" |
28 | 29 |
| 30 using testing::_; |
29 using testing::ElementsAre; | 31 using testing::ElementsAre; |
30 using testing::Eq; | 32 using testing::Eq; |
31 using testing::InvokeWithoutArgs; | 33 using testing::InvokeWithoutArgs; |
32 using testing::IsEmpty; | 34 using testing::IsEmpty; |
33 using testing::Mock; | 35 using testing::Mock; |
34 using testing::Property; | 36 using testing::Property; |
35 using testing::_; | 37 using testing::Return; |
| 38 using testing::UnorderedElementsAre; |
36 | 39 |
37 namespace ntp_snippets { | 40 namespace ntp_snippets { |
38 | 41 |
39 namespace { | 42 namespace { |
40 | 43 |
41 class MockProvider : public ContentSuggestionsProvider { | 44 class MockProvider : public ContentSuggestionsProvider { |
42 public: | 45 public: |
43 MockProvider(Observer* observer, | 46 MockProvider(Observer* observer, |
44 const std::vector<Category>& provided_categories) | 47 const std::vector<Category>& provided_categories) |
45 : ContentSuggestionsProvider(observer) { | 48 : ContentSuggestionsProvider(observer) { |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 | 127 |
125 private: | 128 private: |
126 DISALLOW_COPY_AND_ASSIGN(MockServiceObserver); | 129 DISALLOW_COPY_AND_ASSIGN(MockServiceObserver); |
127 }; | 130 }; |
128 | 131 |
129 } // namespace | 132 } // namespace |
130 | 133 |
131 class ContentSuggestionsServiceTest : public testing::Test { | 134 class ContentSuggestionsServiceTest : public testing::Test { |
132 public: | 135 public: |
133 ContentSuggestionsServiceTest() | 136 ContentSuggestionsServiceTest() |
134 : pref_service_(new TestingPrefServiceSimple()) {} | 137 : pref_service_(base::MakeUnique<TestingPrefServiceSimple>()), |
| 138 category_ranker_(base::MakeUnique<ConstantCategoryRanker>()) {} |
135 | 139 |
136 void SetUp() override { | 140 void SetUp() override { |
137 RegisterPrefs(); | 141 RegisterPrefs(); |
138 CreateContentSuggestionsService(ContentSuggestionsService::State::ENABLED); | 142 CreateContentSuggestionsService(ContentSuggestionsService::State::ENABLED); |
139 } | 143 } |
140 | 144 |
141 void TearDown() override { | 145 void TearDown() override { |
142 service_->Shutdown(); | 146 service_->Shutdown(); |
143 service_.reset(); | 147 service_.reset(); |
144 } | 148 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 | 190 |
187 MockProvider* RegisterProvider( | 191 MockProvider* RegisterProvider( |
188 const std::vector<Category>& provided_categories) { | 192 const std::vector<Category>& provided_categories) { |
189 std::unique_ptr<MockProvider> provider = | 193 std::unique_ptr<MockProvider> provider = |
190 base::MakeUnique<MockProvider>(service(), provided_categories); | 194 base::MakeUnique<MockProvider>(service(), provided_categories); |
191 MockProvider* result = provider.get(); | 195 MockProvider* result = provider.get(); |
192 service()->RegisterProvider(std::move(provider)); | 196 service()->RegisterProvider(std::move(provider)); |
193 return result; | 197 return result; |
194 } | 198 } |
195 | 199 |
| 200 void SetCategoryRanker(std::unique_ptr<CategoryRanker> category_ranker) { |
| 201 category_ranker_ = std::move(category_ranker); |
| 202 } |
| 203 |
196 MOCK_METHOD1(OnImageFetched, void(const gfx::Image&)); | 204 MOCK_METHOD1(OnImageFetched, void(const gfx::Image&)); |
197 | 205 |
198 protected: | 206 protected: |
199 void RegisterPrefs() { | 207 void RegisterPrefs() { |
200 ContentSuggestionsService::RegisterProfilePrefs(pref_service_->registry()); | 208 ContentSuggestionsService::RegisterProfilePrefs(pref_service_->registry()); |
201 UserClassifier::RegisterProfilePrefs(pref_service_->registry()); | 209 UserClassifier::RegisterProfilePrefs(pref_service_->registry()); |
202 } | 210 } |
203 | 211 |
204 void CreateContentSuggestionsService( | 212 void CreateContentSuggestionsService( |
205 ContentSuggestionsService::State enabled) { | 213 ContentSuggestionsService::State enabled) { |
206 ASSERT_FALSE(service_); | 214 ASSERT_FALSE(service_); |
207 service_.reset(new ContentSuggestionsService( | 215 service_ = base::MakeUnique<ContentSuggestionsService>( |
208 enabled, /*signin_manager=*/nullptr, /*history_service=*/nullptr, | 216 enabled, /*signin_manager=*/nullptr, /*history_service=*/nullptr, |
209 pref_service_.get(), | 217 pref_service_.get(), std::move(category_ranker_)); |
210 base::MakeUnique<ntp_snippets::ConstantCategoryRanker>())); | |
211 } | 218 } |
212 | 219 |
213 void ResetService() { | 220 void ResetService() { |
214 service_->Shutdown(); | 221 service_->Shutdown(); |
215 service_.reset(); | 222 service_.reset(); |
216 CreateContentSuggestionsService(ContentSuggestionsService::State::ENABLED); | 223 CreateContentSuggestionsService(ContentSuggestionsService::State::ENABLED); |
217 } | 224 } |
218 | 225 |
219 ContentSuggestionsService* service() { return service_.get(); } | 226 ContentSuggestionsService* service() { return service_.get(); } |
220 | 227 |
(...skipping 10 matching lines...) Expand all Loading... |
231 std::vector<ContentSuggestion> result; | 238 std::vector<ContentSuggestion> result; |
232 for (int number : numbers) { | 239 for (int number : numbers) { |
233 result.push_back(CreateSuggestion(category, number)); | 240 result.push_back(CreateSuggestion(category, number)); |
234 } | 241 } |
235 return result; | 242 return result; |
236 } | 243 } |
237 | 244 |
238 private: | 245 private: |
239 std::unique_ptr<ContentSuggestionsService> service_; | 246 std::unique_ptr<ContentSuggestionsService> service_; |
240 std::unique_ptr<TestingPrefServiceSimple> pref_service_; | 247 std::unique_ptr<TestingPrefServiceSimple> pref_service_; |
| 248 std::unique_ptr<CategoryRanker> category_ranker_; |
241 | 249 |
242 DISALLOW_COPY_AND_ASSIGN(ContentSuggestionsServiceTest); | 250 DISALLOW_COPY_AND_ASSIGN(ContentSuggestionsServiceTest); |
243 }; | 251 }; |
244 | 252 |
245 class ContentSuggestionsServiceDisabledTest | 253 class ContentSuggestionsServiceDisabledTest |
246 : public ContentSuggestionsServiceTest { | 254 : public ContentSuggestionsServiceTest { |
247 public: | 255 public: |
248 void SetUp() override { | 256 void SetUp() override { |
249 RegisterPrefs(); | 257 RegisterPrefs(); |
250 CreateContentSuggestionsService(ContentSuggestionsService::State::DISABLED); | 258 CreateContentSuggestionsService(ContentSuggestionsService::State::DISABLED); |
(...skipping 13 matching lines...) Expand all Loading... |
264 Eq(CategoryStatus::NOT_PROVIDED)); | 272 Eq(CategoryStatus::NOT_PROVIDED)); |
265 EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category), | 273 EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category), |
266 Eq(CategoryStatus::NOT_PROVIDED)); | 274 Eq(CategoryStatus::NOT_PROVIDED)); |
267 | 275 |
268 MockProvider* provider1 = RegisterProvider(articles_category); | 276 MockProvider* provider1 = RegisterProvider(articles_category); |
269 provider1->FireCategoryStatusChangedWithCurrentStatus(articles_category); | 277 provider1->FireCategoryStatusChangedWithCurrentStatus(articles_category); |
270 EXPECT_THAT(providers().count(offline_pages_category), Eq(0ul)); | 278 EXPECT_THAT(providers().count(offline_pages_category), Eq(0ul)); |
271 ASSERT_THAT(providers().count(articles_category), Eq(1ul)); | 279 ASSERT_THAT(providers().count(articles_category), Eq(1ul)); |
272 EXPECT_THAT(providers().at(articles_category), Eq(provider1)); | 280 EXPECT_THAT(providers().at(articles_category), Eq(provider1)); |
273 EXPECT_THAT(providers().size(), Eq(1ul)); | 281 EXPECT_THAT(providers().size(), Eq(1ul)); |
274 EXPECT_THAT(service()->GetCategories(), ElementsAre(articles_category)); | 282 EXPECT_THAT(service()->GetCategories(), |
| 283 UnorderedElementsAre(articles_category)); |
275 EXPECT_THAT(service()->GetCategoryStatus(articles_category), | 284 EXPECT_THAT(service()->GetCategoryStatus(articles_category), |
276 Eq(CategoryStatus::AVAILABLE)); | 285 Eq(CategoryStatus::AVAILABLE)); |
277 EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category), | 286 EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category), |
278 Eq(CategoryStatus::NOT_PROVIDED)); | 287 Eq(CategoryStatus::NOT_PROVIDED)); |
279 | 288 |
280 MockProvider* provider2 = RegisterProvider(offline_pages_category); | 289 MockProvider* provider2 = RegisterProvider(offline_pages_category); |
281 provider2->FireCategoryStatusChangedWithCurrentStatus(offline_pages_category); | 290 provider2->FireCategoryStatusChangedWithCurrentStatus(offline_pages_category); |
282 ASSERT_THAT(providers().count(offline_pages_category), Eq(1ul)); | 291 ASSERT_THAT(providers().count(offline_pages_category), Eq(1ul)); |
283 EXPECT_THAT(providers().at(articles_category), Eq(provider1)); | 292 EXPECT_THAT(providers().at(articles_category), Eq(provider1)); |
284 ASSERT_THAT(providers().count(articles_category), Eq(1ul)); | 293 ASSERT_THAT(providers().count(articles_category), Eq(1ul)); |
285 EXPECT_THAT(providers().at(offline_pages_category), Eq(provider2)); | 294 EXPECT_THAT(providers().at(offline_pages_category), Eq(provider2)); |
286 EXPECT_THAT(providers().size(), Eq(2ul)); | 295 EXPECT_THAT(providers().size(), Eq(2ul)); |
287 EXPECT_THAT(service()->GetCategories(), | 296 EXPECT_THAT(service()->GetCategories(), |
288 ElementsAre(offline_pages_category, articles_category)); | 297 UnorderedElementsAre(offline_pages_category, articles_category)); |
289 EXPECT_THAT(service()->GetCategoryStatus(articles_category), | 298 EXPECT_THAT(service()->GetCategoryStatus(articles_category), |
290 Eq(CategoryStatus::AVAILABLE)); | 299 Eq(CategoryStatus::AVAILABLE)); |
291 EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category), | 300 EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category), |
292 Eq(CategoryStatus::AVAILABLE)); | 301 Eq(CategoryStatus::AVAILABLE)); |
293 } | 302 } |
294 | 303 |
295 TEST_F(ContentSuggestionsServiceDisabledTest, ShouldDoNothingWhenDisabled) { | 304 TEST_F(ContentSuggestionsServiceDisabledTest, ShouldDoNothingWhenDisabled) { |
296 Category articles_category = | 305 Category articles_category = |
297 Category::FromKnownCategory(KnownCategories::ARTICLES); | 306 Category::FromKnownCategory(KnownCategories::ARTICLES); |
298 Category offline_pages_category = | 307 Category offline_pages_category = |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 CategoryStatus::INITIALIZING)); | 547 CategoryStatus::INITIALIZING)); |
539 provider->FireCategoryStatusChanged(new_category, | 548 provider->FireCategoryStatusChanged(new_category, |
540 CategoryStatus::INITIALIZING); | 549 CategoryStatus::INITIALIZING); |
541 | 550 |
542 ASSERT_THAT(providers().count(new_category), Eq(1ul)); | 551 ASSERT_THAT(providers().count(new_category), Eq(1ul)); |
543 EXPECT_THAT(providers().at(new_category), Eq(provider)); | 552 EXPECT_THAT(providers().at(new_category), Eq(provider)); |
544 ExpectThatSuggestionsAre(new_category, std::vector<int>()); | 553 ExpectThatSuggestionsAre(new_category, std::vector<int>()); |
545 EXPECT_THAT(service()->GetCategoryStatus(new_category), | 554 EXPECT_THAT(service()->GetCategoryStatus(new_category), |
546 Eq(CategoryStatus::INITIALIZING)); | 555 Eq(CategoryStatus::INITIALIZING)); |
547 EXPECT_THAT(service()->GetCategories(), | 556 EXPECT_THAT(service()->GetCategories(), |
548 Eq(std::vector<Category>({category, new_category}))); | 557 UnorderedElementsAre(category, new_category)); |
549 | 558 |
550 service()->RemoveObserver(&observer); | 559 service()->RemoveObserver(&observer); |
551 } | 560 } |
552 | 561 |
553 TEST_F(ContentSuggestionsServiceTest, ShouldRemoveCategoryWhenNotProvided) { | 562 TEST_F(ContentSuggestionsServiceTest, ShouldRemoveCategoryWhenNotProvided) { |
554 Category category = Category::FromKnownCategory(KnownCategories::DOWNLOADS); | 563 Category category = Category::FromKnownCategory(KnownCategories::DOWNLOADS); |
555 MockProvider* provider = RegisterProvider(category); | 564 MockProvider* provider = RegisterProvider(category); |
556 MockServiceObserver observer; | 565 MockServiceObserver observer; |
557 service()->AddObserver(&observer); | 566 service()->AddObserver(&observer); |
558 | 567 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 service()->Fetch(category, known_suggestions, FetchDoneCallback()); | 600 service()->Fetch(category, known_suggestions, FetchDoneCallback()); |
592 } | 601 } |
593 | 602 |
594 TEST_F(ContentSuggestionsServiceTest, DismissAndRestoreCategory) { | 603 TEST_F(ContentSuggestionsServiceTest, DismissAndRestoreCategory) { |
595 // Register a category with one suggestion. | 604 // Register a category with one suggestion. |
596 Category category = Category::FromKnownCategory(KnownCategories::ARTICLES); | 605 Category category = Category::FromKnownCategory(KnownCategories::ARTICLES); |
597 MockProvider* provider = RegisterProvider(category); | 606 MockProvider* provider = RegisterProvider(category); |
598 provider->FireCategoryStatusChangedWithCurrentStatus(category); | 607 provider->FireCategoryStatusChangedWithCurrentStatus(category); |
599 provider->FireSuggestionsChanged(category, CreateSuggestions(category, {42})); | 608 provider->FireSuggestionsChanged(category, CreateSuggestions(category, {42})); |
600 | 609 |
601 EXPECT_THAT(service()->GetCategories(), ElementsAre(category)); | 610 EXPECT_THAT(service()->GetCategories(), UnorderedElementsAre(category)); |
602 EXPECT_THAT(service()->GetCategoryStatus(category), | 611 EXPECT_THAT(service()->GetCategoryStatus(category), |
603 Eq(CategoryStatus::AVAILABLE)); | 612 Eq(CategoryStatus::AVAILABLE)); |
604 ExpectThatSuggestionsAre(category, {42}); | 613 ExpectThatSuggestionsAre(category, {42}); |
605 EXPECT_THAT(providers().count(category), Eq(1ul)); | 614 EXPECT_THAT(providers().count(category), Eq(1ul)); |
606 EXPECT_THAT(dismissed_providers(), IsEmpty()); | 615 EXPECT_THAT(dismissed_providers(), IsEmpty()); |
607 | 616 |
608 // Dismissing the category clears the suggestions for it. | 617 // Dismissing the category clears the suggestions for it. |
609 service()->DismissCategory(category); | 618 service()->DismissCategory(category); |
610 | 619 |
611 EXPECT_THAT(service()->GetCategories(), IsEmpty()); | 620 EXPECT_THAT(service()->GetCategories(), IsEmpty()); |
612 EXPECT_THAT(service()->GetCategoryStatus(category), | 621 EXPECT_THAT(service()->GetCategoryStatus(category), |
613 Eq(CategoryStatus::NOT_PROVIDED)); | 622 Eq(CategoryStatus::NOT_PROVIDED)); |
614 EXPECT_THAT(service()->GetSuggestionsForCategory(category), IsEmpty()); | 623 EXPECT_THAT(service()->GetSuggestionsForCategory(category), IsEmpty()); |
615 EXPECT_THAT(providers(), IsEmpty()); | 624 EXPECT_THAT(providers(), IsEmpty()); |
616 EXPECT_THAT(dismissed_providers().count(category), Eq(1ul)); | 625 EXPECT_THAT(dismissed_providers().count(category), Eq(1ul)); |
617 | 626 |
618 // Restoring the dismissed category makes it available again but it is still | 627 // Restoring the dismissed category makes it available again but it is still |
619 // empty. | 628 // empty. |
620 service()->RestoreDismissedCategories(); | 629 service()->RestoreDismissedCategories(); |
621 | 630 |
622 EXPECT_THAT(service()->GetCategories(), ElementsAre(category)); | 631 EXPECT_THAT(service()->GetCategories(), UnorderedElementsAre(category)); |
623 EXPECT_THAT(service()->GetCategoryStatus(category), | 632 EXPECT_THAT(service()->GetCategoryStatus(category), |
624 Eq(CategoryStatus::AVAILABLE)); | 633 Eq(CategoryStatus::AVAILABLE)); |
625 EXPECT_THAT(service()->GetSuggestionsForCategory(category), IsEmpty()); | 634 EXPECT_THAT(service()->GetSuggestionsForCategory(category), IsEmpty()); |
626 EXPECT_THAT(providers().count(category), Eq(1ul)); | 635 EXPECT_THAT(providers().count(category), Eq(1ul)); |
627 EXPECT_THAT(dismissed_providers(), IsEmpty()); | 636 EXPECT_THAT(dismissed_providers(), IsEmpty()); |
628 } | 637 } |
629 | 638 |
630 TEST_F(ContentSuggestionsServiceTest, ShouldRestoreDismissedCategories) { | 639 TEST_F(ContentSuggestionsServiceTest, ShouldRestoreDismissedCategories) { |
631 // Create and register provider. | 640 // Create and register provider. |
632 Category category1 = Category::FromIDValue(1); | 641 Category category1 = Category::FromIDValue(1); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
698 // restoration. | 707 // restoration. |
699 provider = RegisterProvider(category); | 708 provider = RegisterProvider(category); |
700 provider->FireCategoryStatusChangedWithCurrentStatus(category); | 709 provider->FireCategoryStatusChangedWithCurrentStatus(category); |
701 EXPECT_TRUE(service()->IsCategoryDismissed(category)); | 710 EXPECT_TRUE(service()->IsCategoryDismissed(category)); |
702 | 711 |
703 service()->RestoreDismissedCategories(); | 712 service()->RestoreDismissedCategories(); |
704 EXPECT_FALSE(service()->IsCategoryDismissed(category)); | 713 EXPECT_FALSE(service()->IsCategoryDismissed(category)); |
705 EXPECT_THAT(providers().find(category)->second, Eq(provider)); | 714 EXPECT_THAT(providers().find(category)->second, Eq(provider)); |
706 } | 715 } |
707 | 716 |
| 717 TEST_F(ContentSuggestionsServiceTest, ShouldReturnCategoriesInOrderToDisplay) { |
| 718 auto mock_ranker = base::MakeUnique<MockCategoryRanker>(); |
| 719 MockCategoryRanker* raw_mock_ranker = mock_ranker.get(); |
| 720 SetCategoryRanker(std::move(mock_ranker)); |
| 721 // The service is recreated to pick up a new ranker. |
| 722 ResetService(); |
| 723 |
| 724 const Category first_category = Category::FromRemoteCategory(1); |
| 725 const Category second_category = Category::FromRemoteCategory(2); |
| 726 |
| 727 MockProvider* provider = RegisterProvider({first_category, second_category}); |
| 728 provider->FireCategoryStatusChangedWithCurrentStatus(first_category); |
| 729 provider->FireCategoryStatusChangedWithCurrentStatus(second_category); |
| 730 |
| 731 EXPECT_CALL(*raw_mock_ranker, Compare(first_category, second_category)) |
| 732 .WillRepeatedly(Return(true)); |
| 733 EXPECT_CALL(*raw_mock_ranker, Compare(second_category, first_category)) |
| 734 .WillRepeatedly(Return(false)); |
| 735 |
| 736 EXPECT_THAT(service()->GetCategories(), |
| 737 ElementsAre(first_category, second_category)); |
| 738 |
| 739 // The order to display (in the ranker) changes. |
| 740 EXPECT_CALL(*raw_mock_ranker, Compare(first_category, second_category)) |
| 741 .WillRepeatedly(Return(false)); |
| 742 EXPECT_CALL(*raw_mock_ranker, Compare(second_category, first_category)) |
| 743 .WillRepeatedly(Return(true)); |
| 744 // Categories order should reflect the new order. |
| 745 EXPECT_THAT(service()->GetCategories(), |
| 746 ElementsAre(second_category, first_category)); |
| 747 } |
| 748 |
708 } // namespace ntp_snippets | 749 } // namespace ntp_snippets |
OLD | NEW |