Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1095)

Side by Side Diff: components/ntp_snippets/offline_pages/offline_page_suggestions_provider_unittest.cc

Issue 2279223002: Add OfflinePageSuggestionsProviderTest (Closed)
Patch Set: Marc's comments Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "components/ntp_snippets/offline_pages/offline_page_suggestions_provide r.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/files/file_path.h"
12 #include "base/guid.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "components/ntp_snippets/category.h"
17 #include "components/ntp_snippets/category_factory.h"
18 #include "components/ntp_snippets/content_suggestions_provider.h"
19 #include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
20 #include "components/offline_pages/client_namespace_constants.h"
21 #include "components/offline_pages/offline_page_item.h"
22 #include "components/offline_pages/stub_offline_page_model.h"
23 #include "components/prefs/testing_pref_service.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 using offline_pages::ClientId;
28 using offline_pages::MultipleOfflinePageItemCallback;
29 using offline_pages::OfflinePageItem;
30 using offline_pages::StubOfflinePageModel;
31 using testing::AllOf;
32 using testing::Eq;
33 using testing::Invoke;
34 using testing::IsEmpty;
35 using testing::Property;
36 using testing::ElementsAre;
37 using testing::Mock;
38 using testing::UnorderedElementsAre;
39 using testing::UnorderedElementsAreArray;
40 using testing::SizeIs;
41 using testing::WhenSortedBy;
42 using testing::_;
43
44 namespace ntp_snippets {
45
46 namespace {
47
48 struct OrderByMostRecentlyVisited {
49 bool operator()(const OfflinePageItem* left,
50 const OfflinePageItem* right) const {
51 return left->last_access_time > right->last_access_time;
52 }
53 };
54
55 OfflinePageItem CreateDummyItem(std::string name_space, int id) {
56 std::string strid = base::IntToString(id);
57 return OfflinePageItem(GURL("http://dummy.com/" + strid), id,
58 ClientId(name_space, base::GenerateGUID()),
59 base::FilePath("some/folder/test" + strid + ".mhtml"),
60 0, base::Time::Now());
61 }
62
63 OfflinePageItem CreateDummyRecentTab(int id) {
64 return CreateDummyItem(offline_pages::kLastNNamespace, id);
65 }
66
67 OfflinePageItem CreateDummyRecentTab(int id, base::Time time) {
68 OfflinePageItem item = CreateDummyRecentTab(id);
69 item.last_access_time = time;
70 return item;
71 }
72
73 OfflinePageItem CreateDummyDownload(int id) {
74 return CreateDummyItem(offline_pages::kAsyncNamespace, id);
75 }
76
77 } // namespace
78
79 class MockOfflinePageModel : public StubOfflinePageModel {
80 public:
81 MockOfflinePageModel() {}
82
83 void GetAllPages(const MultipleOfflinePageItemCallback& callback) override {
84 callback.Run(items_);
85 }
86
87 std::vector<OfflinePageItem>* items() { return &items_; }
88
89 private:
90 std::vector<OfflinePageItem> items_;
91 };
92
93 class OfflinePageSuggestionsProviderTest : public testing::Test {
94 public:
95 OfflinePageSuggestionsProviderTest()
96 : pref_service_(new TestingPrefServiceSimple()) {
97 OfflinePageSuggestionsProvider::RegisterProfilePrefs(
98 pref_service()->registry());
99 CreateProvider(true, true, true);
100 }
101
102 void RecreateProvider(bool recent_tabs_enabled,
103 bool downloads_enabled,
104 bool download_manager_ui_enabled) {
105 provider_.reset();
106 CreateProvider(recent_tabs_enabled, downloads_enabled,
107 download_manager_ui_enabled);
108 }
109
110 void CreateProvider(bool recent_tabs_enabled,
111 bool downloads_enabled,
112 bool download_manager_ui_enabled) {
113 DCHECK(!provider_);
114
115 provider_.reset(new OfflinePageSuggestionsProvider(
116 recent_tabs_enabled, downloads_enabled, download_manager_ui_enabled,
117 &observer_, &category_factory_, &model_, pref_service()));
118 }
119
120 Category recent_tabs_category() {
121 return category_factory_.FromKnownCategory(KnownCategories::RECENT_TABS);
122 }
123
124 Category downloads_category() {
125 return category_factory_.FromKnownCategory(KnownCategories::DOWNLOADS);
126 }
127
128 void AddItem(OfflinePageItem item) { model()->items()->push_back(item); }
129
130 std::string GetDummySuggestionId(Category category, int id) {
131 return provider_->MakeUniqueID(category, base::IntToString(id));
132 }
133
134 ContentSuggestion CreateDummySuggestion(Category category, int id) {
135 std::string strid = base::IntToString(id);
136 ContentSuggestion result(
137 GetDummySuggestionId(category, id),
138 GURL("file:///some/folder/test" + strid + ".mhtml"));
139 result.set_title(base::UTF8ToUTF16("http://dummy.com/" + strid));
140 return result;
141 }
142
143 void FireOfflinePageModelChanged() {
144 provider_->OfflinePageModelChanged(model());
145 }
146
147 void FireOfflinePageDeleted(const OfflinePageItem& item) {
148 provider_->OfflinePageDeleted(item.offline_id, item.client_id);
149 }
150
151 std::set<std::string> ReadDismissedIDsFromPrefs(Category category) {
152 return provider_->ReadDismissedIDsFromPrefs(category);
153 }
154
155 void ReceiveDismissedSuggestions(
156 std::vector<ContentSuggestion> dismissed_suggestions) {
157 ReceivedDismissedSuggestions(dismissed_suggestions);
158 }
159 MOCK_METHOD1(
Marc Treib 2016/08/26 12:52:03 nit: Add a comment explaining the workaround? It m
Philipp Keck 2016/08/26 17:19:55 Done.
Marc Treib 2016/08/29 09:28:48 No better ideas, no... One suggestion Tim had in a
Philipp Keck 2016/08/29 11:32:42 I tried, but this std::list workaround is not poss
tschumann 2016/08/29 12:45:14 in this particular case, I wouldn't use the MOCK m
Marc Treib 2016/08/29 13:01:51 I disagree: I find a mock method and EXPECT_CALLs
Philipp Keck 2016/08/29 13:35:06 @Tim: Yes, currently, there are no other methods m
tschumann 2016/08/29 14:13:32 IMO, adding MOCK methods on a test is abusing the
160 ReceivedDismissedSuggestions,
161 void(const std::vector<ContentSuggestion>& dismissed_suggestions));
162
163 ContentSuggestionsProvider* provider() { return provider_.get(); }
164 MockOfflinePageModel* model() { return &model_; }
165 MockContentSuggestionsProviderObserver* observer() { return &observer_; }
166 TestingPrefServiceSimple* pref_service() { return pref_service_.get(); }
167
168 private:
169 MockOfflinePageModel model_;
170 MockContentSuggestionsProviderObserver observer_;
171 CategoryFactory category_factory_;
172 std::unique_ptr<TestingPrefServiceSimple> pref_service_;
173 std::unique_ptr<OfflinePageSuggestionsProvider> provider_;
174
175 DISALLOW_COPY_AND_ASSIGN(OfflinePageSuggestionsProviderTest);
176 };
177
178 TEST_F(OfflinePageSuggestionsProviderTest, ShouldSplitAndConvertToSuggestions) {
179 AddItem(CreateDummyRecentTab(1));
180 AddItem(CreateDummyRecentTab(2));
181 AddItem(CreateDummyRecentTab(3));
182 AddItem(CreateDummyDownload(101));
183
184 EXPECT_CALL(
185 *observer(),
186 OnNewSuggestions(_, recent_tabs_category(),
187 UnorderedElementsAre(
188 Property(&ContentSuggestion::url,
189 GURL("file:///some/folder/test1.mhtml")),
190 Property(&ContentSuggestion::url,
191 GURL("file:///some/folder/test2.mhtml")),
192 Property(&ContentSuggestion::url,
193 GURL("file:///some/folder/test3.mhtml")))));
194
195 EXPECT_CALL(*observer(),
196 OnNewSuggestions(
197 _, downloads_category(),
198 UnorderedElementsAre(AllOf(
199 Property(&ContentSuggestion::url,
200 GURL("file:///some/folder/test101.mhtml")),
201 Property(&ContentSuggestion::title,
202 base::UTF8ToUTF16("http://dummy.com/101"))))));
203
204 FireOfflinePageModelChanged();
205 }
206
207 TEST_F(OfflinePageSuggestionsProviderTest, ShouldIgnoreDisabledCategories) {
208 AddItem(CreateDummyRecentTab(1));
209 AddItem(CreateDummyRecentTab(2));
210 AddItem(CreateDummyRecentTab(3));
211 AddItem(CreateDummyDownload(101));
212
213 // Disable recent tabs, enable downloads.
214 EXPECT_CALL(*observer(), OnNewSuggestions(_, recent_tabs_category(), _))
215 .Times(0);
216 EXPECT_CALL(
217 *observer(),
218 OnNewSuggestions(_, downloads_category(),
219 UnorderedElementsAre(Property(
220 &ContentSuggestion::url,
221 GURL("file:///some/folder/test101.mhtml")))));
222 RecreateProvider(false, true, true);
223 Mock::VerifyAndClearExpectations(observer());
224
225 // Enable recent tabs, disable downloads.
226 EXPECT_CALL(
227 *observer(),
228 OnNewSuggestions(_, recent_tabs_category(),
229 UnorderedElementsAre(
230 Property(&ContentSuggestion::url,
231 GURL("file:///some/folder/test1.mhtml")),
232 Property(&ContentSuggestion::url,
233 GURL("file:///some/folder/test2.mhtml")),
234 Property(&ContentSuggestion::url,
235 GURL("file:///some/folder/test3.mhtml")))));
236 EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(), _))
237 .Times(0);
238 RecreateProvider(true, false, true);
239 Mock::VerifyAndClearExpectations(observer());
240 }
241
242 TEST_F(OfflinePageSuggestionsProviderTest, ShouldSortByMostRecentlyVisited) {
243 base::Time now = base::Time::Now();
244 base::Time yesterday = now - base::TimeDelta::FromDays(1);
245 base::Time tomorrow = now + base::TimeDelta::FromDays(1);
246 AddItem(CreateDummyRecentTab(1, now));
247 AddItem(CreateDummyRecentTab(2, yesterday));
248 AddItem(CreateDummyRecentTab(3, tomorrow));
249
250 EXPECT_CALL(
251 *observer(),
252 OnNewSuggestions(
253 _, recent_tabs_category(),
254 ElementsAre(Property(&ContentSuggestion::url,
255 GURL("file:///some/folder/test3.mhtml")),
256 Property(&ContentSuggestion::url,
257 GURL("file:///some/folder/test1.mhtml")),
258 Property(&ContentSuggestion::url,
259 GURL("file:///some/folder/test2.mhtml")))));
260 EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(), _));
261 FireOfflinePageModelChanged();
262 }
263
264 TEST_F(OfflinePageSuggestionsProviderTest, ShouldDeliverCorrectCategoryInfo) {
265 EXPECT_FALSE(
266 provider()->GetCategoryInfo(recent_tabs_category()).has_more_button());
267 EXPECT_TRUE(
268 provider()->GetCategoryInfo(downloads_category()).has_more_button());
269 RecreateProvider(true, true, false);
270 EXPECT_FALSE(
271 provider()->GetCategoryInfo(recent_tabs_category()).has_more_button());
272 EXPECT_FALSE(
273 provider()->GetCategoryInfo(downloads_category()).has_more_button());
274 }
275
276 TEST_F(OfflinePageSuggestionsProviderTest, ShouldDismiss) {
277 AddItem(CreateDummyRecentTab(1));
278 AddItem(CreateDummyRecentTab(2));
279 AddItem(CreateDummyRecentTab(3));
280 AddItem(CreateDummyRecentTab(4));
281 FireOfflinePageModelChanged();
282
283 // Dismiss 2 and 3.
284 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
285 provider()->DismissSuggestion(
286 GetDummySuggestionId(recent_tabs_category(), 2));
287 provider()->DismissSuggestion(
288 GetDummySuggestionId(recent_tabs_category(), 3));
289 Mock::VerifyAndClearExpectations(observer());
290
291 // They should disappear from the reported suggestions.
292 EXPECT_CALL(
293 *observer(),
294 OnNewSuggestions(_, recent_tabs_category(),
295 UnorderedElementsAre(
296 Property(&ContentSuggestion::url,
297 GURL("file:///some/folder/test1.mhtml")),
298 Property(&ContentSuggestion::url,
299 GURL("file:///some/folder/test4.mhtml")))));
300 EXPECT_CALL(*observer(),
301 OnNewSuggestions(_, downloads_category(), IsEmpty()));
302 FireOfflinePageModelChanged();
303 Mock::VerifyAndClearExpectations(observer());
304
305 // And appear in the dismissed suggestions for the right category.
306 EXPECT_CALL(*this, ReceivedDismissedSuggestions(UnorderedElementsAre(
307 Property(&ContentSuggestion::url,
308 GURL("file:///some/folder/test2.mhtml")),
309 Property(&ContentSuggestion::url,
310 GURL("file:///some/folder/test3.mhtml")))));
311 provider()->GetDismissedSuggestionsForDebugging(
312 recent_tabs_category(),
313 base::Bind(
314 &OfflinePageSuggestionsProviderTest::ReceiveDismissedSuggestions,
315 base::Unretained(this)));
316 Mock::VerifyAndClearExpectations(this);
317
318 // The other category should have no dismissed suggestions.
319 EXPECT_CALL(*this, ReceivedDismissedSuggestions(IsEmpty()));
320 provider()->GetDismissedSuggestionsForDebugging(
321 downloads_category(),
322 base::Bind(
323 &OfflinePageSuggestionsProviderTest::ReceiveDismissedSuggestions,
324 base::Unretained(this)));
325 Mock::VerifyAndClearExpectations(this);
326
327 // Clear dismissed suggestions.
328 provider()->ClearDismissedSuggestionsForDebugging(recent_tabs_category());
329
330 // They should be gone from the dismissed suggestions.
331 EXPECT_CALL(*this, ReceivedDismissedSuggestions(IsEmpty()));
332 provider()->GetDismissedSuggestionsForDebugging(
333 recent_tabs_category(),
334 base::Bind(
335 &OfflinePageSuggestionsProviderTest::ReceiveDismissedSuggestions,
336 base::Unretained(this)));
337 Mock::VerifyAndClearExpectations(this);
338
339 // And appear in the reported suggestions for the category again.
340 EXPECT_CALL(*observer(),
341 OnNewSuggestions(_, recent_tabs_category(), SizeIs(4)));
342 EXPECT_CALL(*observer(),
343 OnNewSuggestions(_, downloads_category(), IsEmpty()));
344 FireOfflinePageModelChanged();
345 Mock::VerifyAndClearExpectations(observer());
346 }
347
348 TEST_F(OfflinePageSuggestionsProviderTest,
349 ShouldInvalidateWhenOfflinePageDeleted) {
350 AddItem(CreateDummyRecentTab(1));
351 AddItem(CreateDummyRecentTab(2));
352 AddItem(CreateDummyRecentTab(3));
353 FireOfflinePageModelChanged();
354
355 // Invalidation of suggestion 2 should be forwarded.
356 EXPECT_CALL(
357 *observer(),
358 OnSuggestionInvalidated(_, recent_tabs_category(),
359 GetDummySuggestionId(recent_tabs_category(), 2)));
360 FireOfflinePageDeleted(model()->items()->at(1));
361 }
362
363 TEST_F(OfflinePageSuggestionsProviderTest, ShouldClearDismissedOnInvalidate) {
364 AddItem(CreateDummyRecentTab(1));
365 AddItem(CreateDummyRecentTab(2));
366 AddItem(CreateDummyRecentTab(3));
367 FireOfflinePageModelChanged();
368 EXPECT_THAT(ReadDismissedIDsFromPrefs(recent_tabs_category()), IsEmpty());
369 EXPECT_THAT(ReadDismissedIDsFromPrefs(downloads_category()), IsEmpty());
370
371 provider()->DismissSuggestion(
372 GetDummySuggestionId(recent_tabs_category(), 2));
373 EXPECT_THAT(ReadDismissedIDsFromPrefs(recent_tabs_category()), SizeIs(1));
374 EXPECT_THAT(ReadDismissedIDsFromPrefs(downloads_category()), IsEmpty());
375
376 FireOfflinePageDeleted(model()->items()->at(1));
377 EXPECT_THAT(ReadDismissedIDsFromPrefs(recent_tabs_category()), IsEmpty());
378 EXPECT_THAT(ReadDismissedIDsFromPrefs(downloads_category()), IsEmpty());
379 }
380
381 TEST_F(OfflinePageSuggestionsProviderTest, ShouldClearDismissedOnFetch) {
382 AddItem(CreateDummyDownload(1));
383 AddItem(CreateDummyDownload(2));
384 AddItem(CreateDummyDownload(3));
385 FireOfflinePageModelChanged();
386
387 provider()->DismissSuggestion(GetDummySuggestionId(downloads_category(), 2));
388 provider()->DismissSuggestion(GetDummySuggestionId(downloads_category(), 3));
389 EXPECT_THAT(ReadDismissedIDsFromPrefs(recent_tabs_category()), IsEmpty());
390 EXPECT_THAT(ReadDismissedIDsFromPrefs(downloads_category()), SizeIs(2));
391
392 model()->items()->clear();
393 AddItem(CreateDummyDownload(2));
394 FireOfflinePageModelChanged();
395 EXPECT_THAT(ReadDismissedIDsFromPrefs(recent_tabs_category()), IsEmpty());
396 EXPECT_THAT(ReadDismissedIDsFromPrefs(downloads_category()), SizeIs(1));
397
398 model()->items()->clear();
399 FireOfflinePageModelChanged();
400 EXPECT_THAT(ReadDismissedIDsFromPrefs(recent_tabs_category()), IsEmpty());
401 EXPECT_THAT(ReadDismissedIDsFromPrefs(downloads_category()), IsEmpty());
402 }
403
404 } // namespace ntp_snippets
OLDNEW
« no previous file with comments | « components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698