| 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/offline_pages/recent_tab_suggestions_provider.
h" | 5 #include "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.
h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 } | 72 } |
| 73 | 73 |
| 74 Category recent_tabs_category() { | 74 Category recent_tabs_category() { |
| 75 return category_factory_.FromKnownCategory(KnownCategories::RECENT_TABS); | 75 return category_factory_.FromKnownCategory(KnownCategories::RECENT_TABS); |
| 76 } | 76 } |
| 77 | 77 |
| 78 ContentSuggestion::ID GetDummySuggestionId(int id) { | 78 ContentSuggestion::ID GetDummySuggestionId(int id) { |
| 79 return ContentSuggestion::ID(recent_tabs_category(), base::IntToString(id)); | 79 return ContentSuggestion::ID(recent_tabs_category(), base::IntToString(id)); |
| 80 } | 80 } |
| 81 | 81 |
| 82 void FireOfflinePageModelChanged(const std::vector<OfflinePageItem>& items) { | 82 void AddOfflinePageToModel(const OfflinePageItem item) { |
| 83 *(model_.mutable_items()) = items; | 83 model_.mutable_items()->push_back(item); |
| 84 provider_->OfflinePageModelChanged(&model_); | 84 provider_->OfflinePageAdded(&model_, item); |
| 85 } | 85 } |
| 86 | 86 |
| 87 void FireOfflinePageDeleted(const OfflinePageItem& item) { | 87 void FireOfflinePageDeleted(const OfflinePageItem& item) { |
| 88 auto iter = std::remove(model_.mutable_items()->begin(), |
| 89 model_.mutable_items()->end(), item); |
| 90 auto end = model_.mutable_items()->end(); |
| 91 model_.mutable_items()->erase(iter, end); |
| 92 |
| 88 provider_->OfflinePageDeleted(item.offline_id, item.client_id); | 93 provider_->OfflinePageDeleted(item.offline_id, item.client_id); |
| 89 } | 94 } |
| 90 | 95 |
| 91 std::set<std::string> ReadDismissedIDsFromPrefs() { | 96 std::set<std::string> ReadDismissedIDsFromPrefs() { |
| 92 return provider_->ReadDismissedIDsFromPrefs(); | 97 return provider_->ReadDismissedIDsFromPrefs(); |
| 93 } | 98 } |
| 94 | 99 |
| 95 RecentTabSuggestionsProvider* provider() { return provider_.get(); } | 100 RecentTabSuggestionsProvider* provider() { return provider_.get(); } |
| 96 FakeOfflinePageModel* model() { return &model_; } | 101 FakeOfflinePageModel* model() { return &model_; } |
| 97 MockContentSuggestionsProviderObserver* observer() { return &observer_; } | 102 MockContentSuggestionsProviderObserver* observer() { return &observer_; } |
| 98 TestingPrefServiceSimple* pref_service() { return pref_service_.get(); } | 103 TestingPrefServiceSimple* pref_service() { return pref_service_.get(); } |
| 99 | 104 |
| 100 private: | 105 private: |
| 101 FakeOfflinePageModel model_; | 106 FakeOfflinePageModel model_; |
| 102 MockContentSuggestionsProviderObserver observer_; | 107 MockContentSuggestionsProviderObserver observer_; |
| 103 CategoryFactory category_factory_; | 108 CategoryFactory category_factory_; |
| 104 std::unique_ptr<TestingPrefServiceSimple> pref_service_; | 109 std::unique_ptr<TestingPrefServiceSimple> pref_service_; |
| 105 // Last so that the dependencies are deleted after the provider. | 110 // Last so that the dependencies are deleted after the provider. |
| 106 std::unique_ptr<RecentTabSuggestionsProvider> provider_; | 111 std::unique_ptr<RecentTabSuggestionsProvider> provider_; |
| 107 | 112 |
| 108 DISALLOW_COPY_AND_ASSIGN(RecentTabSuggestionsProviderTest); | 113 DISALLOW_COPY_AND_ASSIGN(RecentTabSuggestionsProviderTest); |
| 109 }; | 114 }; |
| 110 | 115 |
| 111 TEST_F(RecentTabSuggestionsProviderTest, ShouldConvertToSuggestions) { | 116 TEST_F(RecentTabSuggestionsProviderTest, ShouldConvertToSuggestions) { |
| 117 auto recent_tabs_list = CreateDummyRecentTabs({1, 2}); |
| 118 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(2); |
| 119 for (auto& recent_tab : recent_tabs_list) |
| 120 AddOfflinePageToModel(recent_tab); |
| 121 |
| 112 EXPECT_CALL( | 122 EXPECT_CALL( |
| 113 *observer(), | 123 *observer(), |
| 114 OnNewSuggestions(_, recent_tabs_category(), | 124 OnNewSuggestions(_, recent_tabs_category(), |
| 115 UnorderedElementsAre( | 125 UnorderedElementsAre( |
| 116 Property(&ContentSuggestion::url, | 126 Property(&ContentSuggestion::url, |
| 117 GURL("http://dummy.com/1")), | 127 GURL("http://dummy.com/1")), |
| 118 Property(&ContentSuggestion::url, | 128 Property(&ContentSuggestion::url, |
| 119 GURL("http://dummy.com/2")), | 129 GURL("http://dummy.com/2")), |
| 120 Property(&ContentSuggestion::url, | 130 Property(&ContentSuggestion::url, |
| 121 GURL("http://dummy.com/3"))))); | 131 GURL("http://dummy.com/3"))))); |
| 122 FireOfflinePageModelChanged(CreateDummyRecentTabs({1, 2, 3})); | 132 AddOfflinePageToModel(CreateDummyRecentTab(3)); |
| 123 } | 133 } |
| 124 | 134 |
| 125 TEST_F(RecentTabSuggestionsProviderTest, ShouldSortByMostRecentlyVisited) { | 135 TEST_F(RecentTabSuggestionsProviderTest, ShouldSortByMostRecentlyVisited) { |
| 126 base::Time now = base::Time::Now(); | 136 base::Time now = base::Time::Now(); |
| 127 base::Time yesterday = now - base::TimeDelta::FromDays(1); | 137 base::Time yesterday = now - base::TimeDelta::FromDays(1); |
| 128 base::Time tomorrow = now + base::TimeDelta::FromDays(1); | 138 base::Time tomorrow = now + base::TimeDelta::FromDays(1); |
| 129 std::vector<OfflinePageItem> offline_pages = { | |
| 130 CreateDummyRecentTab(1, now), CreateDummyRecentTab(2, yesterday), | |
| 131 CreateDummyRecentTab(3, tomorrow)}; | |
| 132 | 139 |
| 133 EXPECT_CALL( | 140 EXPECT_CALL( |
| 134 *observer(), | 141 *observer(), |
| 142 OnNewSuggestions(_, recent_tabs_category(), |
| 143 ElementsAre(Property(&ContentSuggestion::url, |
| 144 GURL("http://dummy.com/1"))))); |
| 145 AddOfflinePageToModel(CreateDummyRecentTab(1, now)); |
| 146 |
| 147 EXPECT_CALL( |
| 148 *observer(), |
| 149 OnNewSuggestions( |
| 150 _, recent_tabs_category(), |
| 151 ElementsAre( |
| 152 Property(&ContentSuggestion::url, GURL("http://dummy.com/1")), |
| 153 Property(&ContentSuggestion::url, GURL("http://dummy.com/2"))))); |
| 154 AddOfflinePageToModel(CreateDummyRecentTab(2, yesterday)); |
| 155 |
| 156 EXPECT_CALL( |
| 157 *observer(), |
| 135 OnNewSuggestions( | 158 OnNewSuggestions( |
| 136 _, recent_tabs_category(), | 159 _, recent_tabs_category(), |
| 137 ElementsAre(Property(&ContentSuggestion::url, | 160 ElementsAre(Property(&ContentSuggestion::url, |
| 138 GURL("http://dummy.com/3")), | 161 GURL("http://dummy.com/3")), |
| 139 Property(&ContentSuggestion::url, | 162 Property(&ContentSuggestion::url, |
| 140 GURL("http://dummy.com/1")), | 163 GURL("http://dummy.com/1")), |
| 141 Property(&ContentSuggestion::url, | 164 Property(&ContentSuggestion::url, |
| 142 GURL("http://dummy.com/2"))))); | 165 GURL("http://dummy.com/2"))))); |
| 143 FireOfflinePageModelChanged(offline_pages); | 166 AddOfflinePageToModel(CreateDummyRecentTab(3, tomorrow)); |
| 144 } | 167 } |
| 145 | 168 |
| 146 TEST_F(RecentTabSuggestionsProviderTest, ShouldDeliverCorrectCategoryInfo) { | 169 TEST_F(RecentTabSuggestionsProviderTest, ShouldDeliverCorrectCategoryInfo) { |
| 147 EXPECT_FALSE( | 170 EXPECT_FALSE( |
| 148 provider()->GetCategoryInfo(recent_tabs_category()).has_more_action()); | 171 provider()->GetCategoryInfo(recent_tabs_category()).has_more_action()); |
| 149 EXPECT_FALSE( | 172 EXPECT_FALSE( |
| 150 provider()->GetCategoryInfo(recent_tabs_category()).has_reload_action()); | 173 provider()->GetCategoryInfo(recent_tabs_category()).has_reload_action()); |
| 151 EXPECT_FALSE(provider() | 174 EXPECT_FALSE(provider() |
| 152 ->GetCategoryInfo(recent_tabs_category()) | 175 ->GetCategoryInfo(recent_tabs_category()) |
| 153 .has_view_all_action()); | 176 .has_view_all_action()); |
| 154 } | 177 } |
| 155 | 178 |
| 156 TEST_F(RecentTabSuggestionsProviderTest, ShouldDismiss) { | 179 TEST_F(RecentTabSuggestionsProviderTest, ShouldDismiss) { |
| 157 FireOfflinePageModelChanged(CreateDummyRecentTabs({1, 2, 3, 4})); | 180 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(4); |
| 181 auto recent_tabs_list = CreateDummyRecentTabs({1, 2, 3, 4}); |
| 182 for (auto& recent_tab : recent_tabs_list) |
| 183 AddOfflinePageToModel(recent_tab); |
| 158 | 184 |
| 159 // Dismiss 2 and 3. | 185 // Dismiss 2 and 3. |
| 160 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0); | 186 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0); |
| 161 provider()->DismissSuggestion(GetDummySuggestionId(2)); | 187 provider()->DismissSuggestion(GetDummySuggestionId(2)); |
| 162 provider()->DismissSuggestion(GetDummySuggestionId(3)); | 188 provider()->DismissSuggestion(GetDummySuggestionId(3)); |
| 163 Mock::VerifyAndClearExpectations(observer()); | 189 Mock::VerifyAndClearExpectations(observer()); |
| 164 | 190 |
| 165 // They should disappear from the reported suggestions. | 191 // They should disappear from the reported suggestions. |
| 166 EXPECT_CALL( | 192 EXPECT_CALL( |
| 167 *observer(), | 193 *observer(), |
| 168 OnNewSuggestions(_, recent_tabs_category(), | 194 OnNewSuggestions(_, recent_tabs_category(), |
| 169 UnorderedElementsAre( | 195 UnorderedElementsAre( |
| 170 Property(&ContentSuggestion::url, | 196 Property(&ContentSuggestion::url, |
| 171 GURL("http://dummy.com/1")), | 197 GURL("http://dummy.com/1")), |
| 172 Property(&ContentSuggestion::url, | 198 Property(&ContentSuggestion::url, |
| 173 GURL("http://dummy.com/4"))))); | 199 GURL("http://dummy.com/4"))))); |
| 174 | 200 |
| 175 FireOfflinePageModelChanged(model()->items()); | 201 AddOfflinePageToModel(ntp_snippets::test::CreateDummyOfflinePageItem( |
| 202 4, offline_pages::kDefaultNamespace)); |
| 176 Mock::VerifyAndClearExpectations(observer()); | 203 Mock::VerifyAndClearExpectations(observer()); |
| 177 | 204 |
| 178 // And appear in the dismissed suggestions. | 205 // And appear in the dismissed suggestions. |
| 179 std::vector<ContentSuggestion> dismissed_suggestions; | 206 std::vector<ContentSuggestion> dismissed_suggestions; |
| 180 provider()->GetDismissedSuggestionsForDebugging( | 207 provider()->GetDismissedSuggestionsForDebugging( |
| 181 recent_tabs_category(), | 208 recent_tabs_category(), |
| 182 base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions)); | 209 base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions)); |
| 183 EXPECT_THAT( | 210 EXPECT_THAT( |
| 184 dismissed_suggestions, | 211 dismissed_suggestions, |
| 185 UnorderedElementsAre(Property(&ContentSuggestion::url, | 212 UnorderedElementsAre(Property(&ContentSuggestion::url, |
| 186 GURL("http://dummy.com/2")), | 213 GURL("http://dummy.com/2")), |
| 187 Property(&ContentSuggestion::url, | 214 Property(&ContentSuggestion::url, |
| 188 GURL("http://dummy.com/3")))); | 215 GURL("http://dummy.com/3")))); |
| 189 | 216 |
| 190 // Clear dismissed suggestions. | 217 // Clear dismissed suggestions. |
| 191 provider()->ClearDismissedSuggestionsForDebugging(recent_tabs_category()); | 218 provider()->ClearDismissedSuggestionsForDebugging(recent_tabs_category()); |
| 192 | 219 |
| 193 // They should be gone from the dismissed suggestions. | 220 // They should be gone from the dismissed suggestions. |
| 194 dismissed_suggestions.clear(); | 221 dismissed_suggestions.clear(); |
| 195 provider()->GetDismissedSuggestionsForDebugging( | 222 provider()->GetDismissedSuggestionsForDebugging( |
| 196 recent_tabs_category(), | 223 recent_tabs_category(), |
| 197 base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions)); | 224 base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions)); |
| 198 EXPECT_THAT(dismissed_suggestions, IsEmpty()); | 225 EXPECT_THAT(dismissed_suggestions, IsEmpty()); |
| 199 | 226 |
| 200 // And appear in the reported suggestions for the category again. | 227 // And appear in the reported suggestions for the category again. |
| 201 EXPECT_CALL(*observer(), | 228 EXPECT_CALL(*observer(), |
| 202 OnNewSuggestions(_, recent_tabs_category(), SizeIs(4))); | 229 OnNewSuggestions(_, recent_tabs_category(), SizeIs(4))); |
| 203 FireOfflinePageModelChanged(model()->items()); | 230 AddOfflinePageToModel(ntp_snippets::test::CreateDummyOfflinePageItem( |
| 231 5, offline_pages::kDefaultNamespace)); |
| 204 Mock::VerifyAndClearExpectations(observer()); | 232 Mock::VerifyAndClearExpectations(observer()); |
| 205 } | 233 } |
| 206 | 234 |
| 207 TEST_F(RecentTabSuggestionsProviderTest, | 235 TEST_F(RecentTabSuggestionsProviderTest, |
| 208 ShouldInvalidateWhenOfflinePageDeleted) { | 236 ShouldInvalidateWhenOfflinePageDeleted) { |
| 237 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3); |
| 209 std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3}); | 238 std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3}); |
| 210 FireOfflinePageModelChanged(offline_pages); | 239 for (auto& recent_tab : offline_pages) |
| 240 AddOfflinePageToModel(recent_tab); |
| 211 | 241 |
| 212 // Invalidation of suggestion 2 should be forwarded. | 242 // Invalidation of suggestion 2 should be forwarded. |
| 213 EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, GetDummySuggestionId(2))); | 243 EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, GetDummySuggestionId(2))); |
| 214 FireOfflinePageDeleted(offline_pages[1]); | 244 FireOfflinePageDeleted(offline_pages[1]); |
| 215 } | 245 } |
| 216 | 246 |
| 217 TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnInvalidate) { | 247 TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnInvalidate) { |
| 248 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3); |
| 218 std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3}); | 249 std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3}); |
| 219 FireOfflinePageModelChanged(offline_pages); | 250 for (auto& recent_tab : offline_pages) |
| 251 AddOfflinePageToModel(recent_tab); |
| 220 EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty()); | 252 EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty()); |
| 221 | 253 |
| 222 provider()->DismissSuggestion(GetDummySuggestionId(2)); | 254 provider()->DismissSuggestion(GetDummySuggestionId(2)); |
| 223 EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(1)); | 255 EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(1)); |
| 224 | 256 |
| 225 FireOfflinePageDeleted(offline_pages[1]); | 257 FireOfflinePageDeleted(offline_pages[1]); |
| 226 EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty()); | 258 EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty()); |
| 227 } | 259 } |
| 228 | 260 |
| 229 TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnFetch) { | 261 TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnFetch) { |
| 230 FireOfflinePageModelChanged(CreateDummyRecentTabs({1, 2, 3})); | 262 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3); |
| 263 std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3}); |
| 264 for (auto& recent_tab : offline_pages) |
| 265 AddOfflinePageToModel(recent_tab); |
| 231 | 266 |
| 232 provider()->DismissSuggestion(GetDummySuggestionId(2)); | 267 provider()->DismissSuggestion(GetDummySuggestionId(2)); |
| 233 provider()->DismissSuggestion(GetDummySuggestionId(3)); | 268 provider()->DismissSuggestion(GetDummySuggestionId(3)); |
| 234 EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(2)); | 269 EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(2)); |
| 235 | 270 |
| 236 FireOfflinePageModelChanged(CreateDummyRecentTabs({2})); | 271 FireOfflinePageDeleted(offline_pages[0]); |
| 272 FireOfflinePageDeleted(offline_pages[2]); |
| 237 EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(1)); | 273 EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(1)); |
| 238 | 274 |
| 239 FireOfflinePageModelChanged(std::vector<OfflinePageItem>()); | 275 FireOfflinePageDeleted(offline_pages[1]); |
| 240 EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty()); | 276 EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty()); |
| 241 } | 277 } |
| 242 | 278 |
| 243 } // namespace ntp_snippets | 279 } // namespace ntp_snippets |
| OLD | NEW |