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

Side by Side Diff: chrome/browser/ntp_snippets/download_suggestions_provider_unittest.cc

Issue 2360263002: [NTPSnippets] Show all downloads on the NTP (3/3): Downloads provider. (Closed)
Patch Set: Marc's comments + tests + some corrections. Created 4 years, 2 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
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 "chrome/browser/ntp_snippets/download_suggestions_provider.h"
6
7 #include "base/bind.h"
8 #include "base/observer_list.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "components/ntp_snippets/category.h"
11 #include "components/ntp_snippets/category_factory.h"
12 #include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
13 #include "components/ntp_snippets/offline_pages/offline_pages_test_utils.h"
14 #include "components/offline_pages/client_namespace_constants.h"
15 #include "components/prefs/testing_pref_service.h"
16 #include "content/public/test/mock_download_item.h"
17 #include "content/public/test/mock_download_manager.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using content::DownloadItem;
21 using content::MockDownloadItem;
22 using content::MockDownloadManager;
23 using ntp_snippets::Category;
24 using ntp_snippets::CategoryFactory;
25 using ntp_snippets::ContentSuggestion;
26 using ntp_snippets::ContentSuggestionsProvider;
27 using ntp_snippets::MockContentSuggestionsProviderObserver;
28 using ntp_snippets::OfflinePageProxy;
29 using ntp_snippets::test::CaptureDismissedSuggestions;
30 using ntp_snippets::test::FakeOfflinePageModel;
31 using offline_pages::ClientId;
32 using offline_pages::OfflinePageItem;
33 using testing::_;
34 using testing::AnyNumber;
35 using testing::ElementsAre;
36 using testing::IsEmpty;
37 using testing::Mock;
38 using testing::Return;
39 using testing::SizeIs;
40 using testing::UnorderedElementsAre;
41
42 namespace ntp_snippets {
43
44 void PrintTo(const ContentSuggestion& value, std::ostream* os) {
Marc Treib 2016/10/13 12:11:26 Is this used anywhere?
vitaliii 2016/10/15 18:36:31 Yes, the testing framework uses this when printing
Marc Treib 2016/10/17 10:18:40 I think defining an "operator<<" also does the tri
vitaliii 2016/10/26 00:07:54 Done.
45 *os << "{ url: " << value.url() << ", publish_date: " << value.publish_date()
46 << "}";
47 }
48
49 } // namespace ntp_snippets
50
51 namespace {
52
53 // TODO(vitaliii): Move this and |PrintTo| above to common file and replace
54 // remaining |Property(&ContentSuggestion::url, GURL("some_url"))|.
55 // See crbug.com/655513.
56 MATCHER_P(HasUrl, url, "") {
57 *result_listener << "expected URL: " << url
58 << "has URL: " << arg.url().spec();
59 return arg.url().spec() == url;
60 }
61
62 OfflinePageItem CreateDummyOfflinePage(int id) {
63 return ntp_snippets::test::CreateDummyOfflinePageItem(
64 id, offline_pages::kAsyncNamespace);
65 }
66
67 std::vector<OfflinePageItem> CreateDummyOfflinePages(
68 const std::vector<int>& ids) {
69 std::vector<OfflinePageItem> result;
70 for (int id : ids) {
71 result.push_back(CreateDummyOfflinePage(id));
72 }
73 return result;
74 }
75
76 OfflinePageItem CreateDummyOfflinePage(int id, base::Time time) {
77 OfflinePageItem item = CreateDummyOfflinePage(id);
78 item.creation_time = time;
79 return item;
80 }
81
82 class FakeDownloadItem : public DownloadItem {
Marc Treib 2016/10/13 12:11:26 Since this is so huge, maybe worth putting it into
vitaliii 2016/10/15 18:36:31 Done.
83 public:
84 FakeDownloadItem() {}
85 ~FakeDownloadItem() override {
86 NotifyOnDownloadRemoved();
87 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this));
88 }
89
90 void AddObserver(Observer* observer) override {
91 observers_.AddObserver(observer);
92 }
93
94 void RemoveObserver(Observer* observer) override {
95 observers_.RemoveObserver(observer);
96 }
97
98 void NotifyOnDownloadRemoved() {
99 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadRemoved(this));
100 }
101
102 void NotifyOnDownloadUpdated() { UpdateObservers(); }
103
104 void UpdateObservers() override {
105 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
106 }
107
108 void SetId(uint32_t id) { id_ = id; }
109 uint32_t GetId() const override { return id_; }
110
111 void SetURL(GURL url) { url_ = url; }
112 const GURL& GetURL() const override { return url_; }
113
114 void SetTargetFilePath(const base::FilePath& file_path) {
115 file_path_ = file_path;
116 }
117 const base::FilePath& GetTargetFilePath() const override {
118 return file_path_;
119 }
120
121 void SetFileExternallyRemoved(bool is_file_externally_removed) {
122 is_file_externally_removed_ = is_file_externally_removed;
123 }
124 bool GetFileExternallyRemoved() const override {
125 return is_file_externally_removed_;
126 }
127
128 void SetEndTime(const base::Time& end_time) { end_time_ = end_time; }
129 base::Time GetEndTime() const override { return end_time_; }
130
131 void SetState(const DownloadState& state) { download_state_ = state; }
132 DownloadState GetState() const override { return download_state_; }
133
134 // The methods below are not supported and are not expected to be called.
135 void ValidateDangerousDownload() override { NOTREACHED(); }
136 void StealDangerousDownload(const AcquireFileCallback& callback) override {
137 NOTREACHED();
138 callback.Run(base::FilePath());
139 }
140 void Pause() override { NOTREACHED(); }
141 void Resume() override { NOTREACHED(); }
142 void Cancel(bool user_cancel) override { NOTREACHED(); }
143 void Remove() override { NOTREACHED(); }
144 void OpenDownload() override { NOTREACHED(); }
145 void ShowDownloadInShell() override { NOTREACHED(); }
146 const std::string& GetGuid() const override {
147 NOTREACHED();
148 return dummy_string;
149 }
150 content::DownloadInterruptReason GetLastReason() const override {
151 NOTREACHED();
152 return content::DownloadInterruptReason();
153 }
154 bool IsPaused() const override {
155 NOTREACHED();
156 return false;
157 }
158 bool IsTemporary() const override {
159 NOTREACHED();
160 return false;
161 }
162 bool CanResume() const override {
163 NOTREACHED();
164 return false;
165 }
166 bool IsDone() const override {
167 NOTREACHED();
168 return true;
169 }
170 const std::vector<GURL>& GetUrlChain() const override {
171 NOTREACHED();
172 return dummy_url_vector;
173 }
174 const GURL& GetOriginalUrl() const override {
175 NOTREACHED();
176 return dummy_url;
177 }
178 const GURL& GetReferrerUrl() const override {
179 NOTREACHED();
180 return dummy_url;
181 }
182 const GURL& GetSiteUrl() const override {
183 NOTREACHED();
184 return dummy_url;
185 }
186 const GURL& GetTabUrl() const override {
187 NOTREACHED();
188 return dummy_url;
189 }
190 const GURL& GetTabReferrerUrl() const override {
191 NOTREACHED();
192 return dummy_url;
193 }
194 std::string GetSuggestedFilename() const override {
195 NOTREACHED();
196 return std::string();
197 }
198 std::string GetContentDisposition() const override {
199 NOTREACHED();
200 return std::string();
201 }
202 std::string GetMimeType() const override {
203 NOTREACHED();
204 return std::string();
205 }
206 std::string GetOriginalMimeType() const override {
207 NOTREACHED();
208 return std::string();
209 }
210 std::string GetRemoteAddress() const override {
211 NOTREACHED();
212 return std::string();
213 }
214 bool HasUserGesture() const override {
215 NOTREACHED();
216 return false;
217 }
218 ui::PageTransition GetTransitionType() const override {
219 NOTREACHED();
220 return ui::PageTransition();
221 }
222 const std::string& GetLastModifiedTime() const override {
223 NOTREACHED();
224 return dummy_string;
225 }
226 const std::string& GetETag() const override {
227 NOTREACHED();
228 return dummy_string;
229 }
230 bool IsSavePackageDownload() const override {
231 NOTREACHED();
232 return false;
233 }
234 const base::FilePath& GetFullPath() const override {
235 NOTREACHED();
236 return dummy_file_path;
237 }
238 const base::FilePath& GetForcedFilePath() const override {
239 NOTREACHED();
240 return dummy_file_path;
241 }
242 base::FilePath GetFileNameToReportUser() const override {
243 NOTREACHED();
244 return base::FilePath();
245 }
246 TargetDisposition GetTargetDisposition() const override {
247 NOTREACHED();
248 return TargetDisposition();
249 }
250 const std::string& GetHash() const override {
251 NOTREACHED();
252 return dummy_string;
253 }
254 void DeleteFile(const base::Callback<void(bool)>& callback) override {
255 NOTREACHED();
256 callback.Run(false);
257 }
258 bool IsDangerous() const override {
259 NOTREACHED();
260 return false;
261 }
262 content::DownloadDangerType GetDangerType() const override {
263 NOTREACHED();
264 return content::DownloadDangerType();
265 }
266 bool TimeRemaining(base::TimeDelta* remaining) const override {
267 NOTREACHED();
268 return false;
269 }
270 int64_t CurrentSpeed() const override {
271 NOTREACHED();
272 return 1;
273 }
274 int PercentComplete() const override {
275 NOTREACHED();
276 return 1;
277 }
278 bool AllDataSaved() const override {
279 NOTREACHED();
280 return true;
281 }
282 int64_t GetTotalBytes() const override {
283 NOTREACHED();
284 return 1;
285 }
286 int64_t GetReceivedBytes() const override {
287 NOTREACHED();
288 return 1;
289 }
290 base::Time GetStartTime() const override {
291 NOTREACHED();
292 return base::Time();
293 }
294 bool CanShowInFolder() override {
295 NOTREACHED();
296 return true;
297 }
298 bool CanOpenDownload() override {
299 NOTREACHED();
300 return true;
301 }
302 bool ShouldOpenFileBasedOnExtension() override {
303 NOTREACHED();
304 return true;
305 }
306 bool GetOpenWhenComplete() const override {
307 NOTREACHED();
308 return false;
309 }
310 bool GetAutoOpened() override {
311 NOTREACHED();
312 return false;
313 }
314 bool GetOpened() const override {
315 NOTREACHED();
316 return false;
317 }
318 content::BrowserContext* GetBrowserContext() const override {
319 NOTREACHED();
320 return nullptr;
321 }
322 content::WebContents* GetWebContents() const override {
323 NOTREACHED();
324 return nullptr;
325 }
326 void OnContentCheckCompleted(
327 content::DownloadDangerType danger_type) override {
328 NOTREACHED();
329 }
330 void SetOpenWhenComplete(bool open) override { NOTREACHED(); }
331 void SetOpened(bool opened) override { NOTREACHED(); }
332 void SetDisplayName(const base::FilePath& name) override { NOTREACHED(); }
333 std::string DebugString(bool verbose) const override {
334 NOTREACHED();
335 return std::string();
336 }
337
338 private:
339 base::ObserverList<Observer> observers_;
340 uint32_t id_;
341 GURL url_;
342 base::FilePath file_path_;
343 bool is_file_externally_removed_;
344 base::Time end_time_;
345 DownloadState download_state_;
346
347 // The members bellow are to be returned by methods, which return links.
Marc Treib 2016/10/13 12:11:26 s/bellow/below/ s/links/pointers/ ? I assume that'
vitaliii 2016/10/15 18:36:31 First - yes. Second - no, I meant by reference.
348 std::string dummy_string;
349 std::vector<GURL> dummy_url_vector;
350 GURL dummy_url;
351 base::FilePath dummy_file_path;
352 };
353
354 std::unique_ptr<FakeDownloadItem> CreateDummyAssetDownload(int id) {
Marc Treib 2016/10/13 12:11:26 nit: Please move this down to the other CreateDumm
vitaliii 2016/10/15 18:36:31 Done.
355 std::unique_ptr<FakeDownloadItem> item = base::MakeUnique<FakeDownloadItem>();
356 item->SetId(id);
357 std::string id_string = base::IntToString(id);
358 item->SetTargetFilePath(
359 base::FilePath::FromUTF8Unsafe("folder/file" + id_string + ".mhtml"));
360 item->SetURL(GURL("http://dummy_file.com/" + id_string));
361 item->SetEndTime(base::Time::Now());
362 item->SetFileExternallyRemoved(false);
363 item->SetState(DownloadItem::DownloadState::COMPLETE);
364 return item;
365 }
366
367 class ObservedMockDownloadManager : public MockDownloadManager {
368 public:
369 ObservedMockDownloadManager() {}
370 ~ObservedMockDownloadManager() override {
371 FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown(this));
372 }
373
374 // Observer accessors.
375 void AddObserver(Observer* observer) override {
376 observers_.AddObserver(observer);
377 }
378
379 void RemoveObserver(Observer* observer) override {
380 observers_.RemoveObserver(observer);
381 }
382
383 void NotifyOnDownloadCreated(DownloadItem* item) {
384 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, item));
385 }
386
387 std::vector<std::unique_ptr<FakeDownloadItem>>* mutable_items() {
388 return &items_;
389 }
390
391 const std::vector<std::unique_ptr<FakeDownloadItem>>& items() const {
392 return items_;
393 }
394
395 void GetAllDownloads(std::vector<DownloadItem*>* all_downloads) override {
396 all_downloads->clear();
397 for (const auto& item : items_)
398 all_downloads->push_back(item.get());
399 }
400
401 private:
402 base::ObserverList<Observer> observers_;
403 std::vector<std::unique_ptr<FakeDownloadItem>> items_;
404 };
405
406 std::unique_ptr<FakeDownloadItem> CreateDummyAssetDownload(
407 int id,
408 const base::Time end_time) {
409 std::unique_ptr<FakeDownloadItem> item = CreateDummyAssetDownload(id);
410 item->SetEndTime(end_time);
411 return item;
412 }
413
414 std::vector<std::unique_ptr<FakeDownloadItem>> CreateDummyAssetDownloads(
415 const std::vector<int>& ids) {
416 std::vector<std::unique_ptr<FakeDownloadItem>> result;
417 for (int id : ids) {
418 result.push_back(CreateDummyAssetDownload(id));
419 }
420 return result;
421 }
422
423 } // namespace
424
425 class DownloadSuggestionsProviderTest : public testing::Test {
426 public:
427 DownloadSuggestionsProviderTest()
428 : pref_service_(new TestingPrefServiceSimple()) {
429 DownloadSuggestionsProvider::RegisterProfilePrefs(
430 pref_service()->registry());
431
432 scoped_refptr<OfflinePageProxy> proxy(
433 new OfflinePageProxy(&offline_pages_model_));
434
435 provider_.reset(
436 new DownloadSuggestionsProvider(&observer_, &category_factory_, proxy,
437 &downloads_manager_, pref_service(),
438 /*download_manager_ui_enabled=*/false));
439 }
440
441 Category downloads_category() {
442 return category_factory_.FromKnownCategory(
443 ntp_snippets::KnownCategories::DOWNLOADS);
444 }
445
446 void FireOfflinePageModelChanged(const std::vector<OfflinePageItem>& items) {
447 provider_->OfflinePageModelChanged(items);
448 }
449
450 void FireOfflinePageDeleted(const OfflinePageItem& item) {
451 provider_->OfflinePageDeleted(item.offline_id, item.client_id);
452 }
453
454 void FireOnDownloadCreated(DownloadItem* item) {
455 downloads_manager_.NotifyOnDownloadCreated(item);
456 }
457
458 void FireDownloadRemoved(FakeDownloadItem* item) {
Marc Treib 2016/10/13 12:11:26 nit: either FireOnDownloadRemoved (add "On"), or r
vitaliii 2016/10/15 18:36:30 Done.
459 item->NotifyOnDownloadRemoved();
460 }
461
462 void FireOnDownloadsCreated(
463 const std::vector<std::unique_ptr<FakeDownloadItem>>& items) {
464 for (const auto& item : items)
465 FireOnDownloadCreated(item.get());
466 }
467
468 ContentSuggestion::ID GetDummySuggestionId(int id, bool is_offline_page) {
469 return ContentSuggestion::ID(
470 downloads_category(),
471 (is_offline_page ? "O" : "D") + base::IntToString(id));
472 }
473
474 std::set<std::string> ReadDismissedIDsFromPrefs(bool for_offline_pages) {
475 return provider_->ReadDismissedIDsFromPrefs(for_offline_pages);
476 }
477
478 ContentSuggestionsProvider* provider() { return provider_.get(); }
479 ObservedMockDownloadManager* downloads_manager() {
480 return &downloads_manager_;
481 }
482 FakeOfflinePageModel* offline_pages_model() { return &offline_pages_model_; }
483 MockContentSuggestionsProviderObserver* observer() { return &observer_; }
484 TestingPrefServiceSimple* pref_service() { return pref_service_.get(); }
485
486 private:
487 ObservedMockDownloadManager downloads_manager_;
488 FakeOfflinePageModel offline_pages_model_;
489 MockContentSuggestionsProviderObserver observer_;
490 CategoryFactory category_factory_;
491 std::unique_ptr<TestingPrefServiceSimple> pref_service_;
492 // Last so that the dependencies are deleted after the provider.
493 std::unique_ptr<DownloadSuggestionsProvider> provider_;
494
495 DISALLOW_COPY_AND_ASSIGN(DownloadSuggestionsProviderTest);
496 };
497
498 TEST_F(DownloadSuggestionsProviderTest,
499 ShouldConvertOfflinePagesToSuggestions) {
500 std::vector<OfflinePageItem> offline_pages = CreateDummyOfflinePages({1, 2});
501
502 EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(),
503 UnorderedElementsAre(
504 HasUrl("http://dummy.com/1"),
505 HasUrl("http://dummy.com/2"))));
506 FireOfflinePageModelChanged(offline_pages);
507 }
508
509 TEST_F(DownloadSuggestionsProviderTest,
510 ShouldConvertDownloadItemsToSuggestions) {
511 std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads =
512 CreateDummyAssetDownloads({1, 2});
513
514 FireOnDownloadCreated(asset_downloads[0].get());
Marc Treib 2016/10/13 12:11:26 Shouldn't the observer already get a call from thi
vitaliii 2016/10/15 18:36:31 Yes, it should. I use a StrictMock now.
515
516 EXPECT_CALL(*observer(),
517 OnNewSuggestions(
518 _, downloads_category(),
519 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"),
520 HasUrl("file:///folder/file2.mhtml"))));
521
522 FireOnDownloadCreated(asset_downloads[1].get());
523 }
524
525 TEST_F(DownloadSuggestionsProviderTest, ShouldMixInBothSources) {
526 std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads =
527 CreateDummyAssetDownloads({1, 2});
528 std::vector<OfflinePageItem> offline_pages = CreateDummyOfflinePages({1, 2});
529
530 FireOnDownloadCreated(asset_downloads[0].get());
531 FireOnDownloadCreated(asset_downloads[1].get());
532
533 EXPECT_CALL(*observer(),
534 OnNewSuggestions(
535 _, downloads_category(),
536 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"),
537 HasUrl("file:///folder/file2.mhtml"),
538 HasUrl("http://dummy.com/1"),
539 HasUrl("http://dummy.com/2"))));
540
541 FireOfflinePageModelChanged(offline_pages);
542 }
543
544 TEST_F(DownloadSuggestionsProviderTest, ShouldSortSuggestions) {
545 base::Time now = base::Time::Now();
546 base::Time yesterday = now - base::TimeDelta::FromDays(1);
547 base::Time tomorrow = now + base::TimeDelta::FromDays(1);
548 base::Time next_week = now + base::TimeDelta::FromDays(7);
549
550 std::vector<OfflinePageItem> offline_pages;
551 offline_pages.push_back(CreateDummyOfflinePage(1, yesterday));
552 offline_pages.push_back(CreateDummyOfflinePage(2, tomorrow));
553 std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads;
554 asset_downloads.push_back(CreateDummyAssetDownload(3, next_week));
555 asset_downloads.push_back(CreateDummyAssetDownload(4, now));
556
557 FireOnDownloadCreated(asset_downloads[0].get());
558 FireOnDownloadCreated(asset_downloads[1].get());
559
560 EXPECT_CALL(*observer(),
561 OnNewSuggestions(_, downloads_category(),
562 ElementsAre(HasUrl("file:///folder/file3.mhtml"),
563 HasUrl("http://dummy.com/2"),
564 HasUrl("file:///folder/file4.mhtml"),
565 HasUrl("http://dummy.com/1"))));
566
567 FireOfflinePageModelChanged(offline_pages);
568 }
569
570 TEST_F(DownloadSuggestionsProviderTest, ShouldDismiss) {
571 // OfflinePageModel is initialised here because
572 // |GetDismissedSuggestionsForDebugging| may need to call |GetAllPages|
573 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
574 FireOfflinePageModelChanged(offline_pages_model()->items());
575
576 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({3, 4});
577 FireOnDownloadsCreated(downloads_manager()->items());
578
579 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
580 provider()->DismissSuggestion(
581 GetDummySuggestionId(1, /*is_offline_page=*/true));
582 provider()->DismissSuggestion(
583 GetDummySuggestionId(3, /*is_offline_page=*/false));
584 Mock::VerifyAndClearExpectations(observer());
585
586 // The dismissed suggestions should not be in the reported suggestions.
587 EXPECT_CALL(*observer(),
588 OnNewSuggestions(
589 _, downloads_category(),
590 UnorderedElementsAre(HasUrl("http://dummy.com/2"),
591 HasUrl("file:///folder/file4.mhtml"))));
592 FireOfflinePageModelChanged(offline_pages_model()->items());
593 Mock::VerifyAndClearExpectations(observer());
594
595 // Instead they should be reported as dismissed.
596 std::vector<ContentSuggestion> dismissed_suggestions;
597 provider()->GetDismissedSuggestionsForDebugging(
598 downloads_category(),
599 base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
600 EXPECT_THAT(dismissed_suggestions,
601 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
602 HasUrl("file:///folder/file3.mhtml")));
603
604 provider()->ClearDismissedSuggestionsForDebugging(downloads_category());
605
606 // No more dismissed suggestions.
607 dismissed_suggestions.clear();
608 provider()->GetDismissedSuggestionsForDebugging(
609 downloads_category(),
610 base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
611 EXPECT_THAT(dismissed_suggestions, IsEmpty());
612
613 // And they should be reported now.
614 EXPECT_CALL(*observer(),
615 OnNewSuggestions(_, downloads_category(), SizeIs(4)));
616 FireOfflinePageModelChanged(offline_pages_model()->items());
617 Mock::VerifyAndClearExpectations(observer());
Marc Treib 2016/10/13 12:11:26 Not needed
vitaliii 2016/10/15 18:36:31 Done.
618 }
619
620 TEST_F(DownloadSuggestionsProviderTest,
621 ShouldNotDismissOtherTypeWithTheSameID) {
622 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
623 FireOfflinePageModelChanged(offline_pages_model()->items());
624
625 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
626 FireOnDownloadsCreated(downloads_manager()->items());
627
628 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
629 provider()->DismissSuggestion(
630 GetDummySuggestionId(1, /*is_offline_page=*/true));
631 Mock::VerifyAndClearExpectations(observer());
Marc Treib 2016/10/13 12:11:26 nit: This and the EXPECT_CALL above aren't really
vitaliii 2016/10/15 18:36:31 Done.
632
633 EXPECT_CALL(*observer(),
634 OnNewSuggestions(
635 _, downloads_category(),
636 UnorderedElementsAre(HasUrl("http://dummy.com/2"),
637 HasUrl("file:///folder/file1.mhtml"),
638 HasUrl("file:///folder/file2.mhtml"))));
639 FireOfflinePageModelChanged(offline_pages_model()->items());
640 }
641
642 TEST_F(DownloadSuggestionsProviderTest, ShouldReplaceDismissedItemWithNewData) {
643 *(downloads_manager()->mutable_items()) =
644 CreateDummyAssetDownloads({1, 2, 3, 4, 5, 6});
Marc Treib 2016/10/13 12:11:26 Took me a while to see why you need 6 :D Maybe add
vitaliii 2016/10/15 18:36:31 Done.
645 FireOnDownloadsCreated(downloads_manager()->items());
646
647 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
648 provider()->DismissSuggestion(
649 GetDummySuggestionId(1, /*is_offline_page=*/true));
Marc Treib 2016/10/13 12:11:26 Wait, this dismisses an offline page - does the te
vitaliii 2016/10/15 18:36:30 {2, 3, 4, 5, 6} were shown by the provider. I cha
650 Mock::VerifyAndClearExpectations(observer());
Marc Treib 2016/10/13 12:11:26 Also here. Generally, it's better to avoid VerifyA
vitaliii 2016/10/15 18:36:30 Done. Why?
Marc Treib 2016/10/17 10:18:40 It's a hint that the test is testing more than one
vitaliii 2016/10/26 00:07:54 I see, good point!
651
652 // The provider is not notified about the 6th item for the second time,
653 // however, it must report it.
654 EXPECT_CALL(*observer(),
655 OnNewSuggestions(
656 _, downloads_category(),
657 UnorderedElementsAre(HasUrl("file:///folder/file2.mhtml"),
658 HasUrl("file:///folder/file3.mhtml"),
659 HasUrl("file:///folder/file4.mhtml"),
660 HasUrl("file:///folder/file5.mhtml"),
661 HasUrl("file:///folder/file6.mhtml"))));
Marc Treib 2016/10/13 12:11:26 Maybe also verify before dismissing that items 1-5
vitaliii 2016/10/15 18:36:31 Done.
662 FireOfflinePageModelChanged(offline_pages_model()->items());
663 }
664
665 TEST_F(DownloadSuggestionsProviderTest,
666 ShouldInvalidateWhenUnderlyingItemDeleted) {
667 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
668 FireOfflinePageModelChanged(offline_pages_model()->items());
669
670 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({3, 4});
671 FireOnDownloadsCreated(downloads_manager()->items());
672
673 EXPECT_CALL(*observer(),
674 OnSuggestionInvalidated(
675 _, GetDummySuggestionId(1, /*is_offline_page=*/true)));
676 FireOfflinePageDeleted(offline_pages_model()->items()[0]);
677 EXPECT_CALL(*observer(),
678 OnSuggestionInvalidated(
679 _, GetDummySuggestionId(3, /*is_offline_page=*/false)));
680 FireDownloadRemoved(downloads_manager()->items()[0].get());
681 }
682
683 TEST_F(DownloadSuggestionsProviderTest, ShouldReplaceRemovedItemWithNewData) {
684 *(downloads_manager()->mutable_items()) =
685 CreateDummyAssetDownloads({1, 2, 3, 4, 5, 6});
686 FireOnDownloadsCreated(downloads_manager()->items());
Marc Treib 2016/10/13 12:11:26 Also here: Verify that actually items 1-5 get repo
vitaliii 2016/10/15 18:36:31 Done.
687
688 EXPECT_CALL(*observer(),
689 OnSuggestionInvalidated(
690 _, GetDummySuggestionId(1, /*is_offline_page=*/false)));
691 // |OnDownloadRemoved| notification is done in |DownloadItem|'s destructor.
692 downloads_manager()->mutable_items()->erase(
693 downloads_manager()->mutable_items()->begin());
694
695 EXPECT_CALL(*observer(),
696 OnNewSuggestions(
697 _, downloads_category(),
698 UnorderedElementsAre(HasUrl("file:///folder/file2.mhtml"),
699 HasUrl("file:///folder/file3.mhtml"),
700 HasUrl("file:///folder/file4.mhtml"),
701 HasUrl("file:///folder/file5.mhtml"),
702 HasUrl("file:///folder/file6.mhtml"))));
703 FireOfflinePageModelChanged(offline_pages_model()->items());
704 }
705
706 TEST_F(DownloadSuggestionsProviderTest, ShouldPruneOfflinePagesDismissedIDs) {
707 *(offline_pages_model()->mutable_items()) =
708 CreateDummyOfflinePages({1, 2, 3});
709 FireOfflinePageModelChanged(offline_pages_model()->items());
710
711 provider()->DismissSuggestion(
712 GetDummySuggestionId(1, /*is_offline_page=*/true));
713 provider()->DismissSuggestion(
714 GetDummySuggestionId(2, /*is_offline_page=*/true));
715 provider()->DismissSuggestion(
716 GetDummySuggestionId(3, /*is_offline_page=*/true));
717 EXPECT_THAT(ReadDismissedIDsFromPrefs(/*for_offline_pages=*/true), SizeIs(3));
Marc Treib 2016/10/13 12:11:26 IMO the prefs are an implementation detail that do
vitaliii 2016/10/15 18:36:30 I use GetDismissedSuggestions now. However, this m
718
719 // Prune on getting all offline pages.
720 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({2, 3});
721 FireOfflinePageModelChanged(offline_pages_model()->items());
722 EXPECT_THAT(ReadDismissedIDsFromPrefs(/*for_offline_pages=*/true), SizeIs(2));
723
724 // Prune when offline page is deleted.
725 FireOfflinePageDeleted(offline_pages_model()->items()[0]);
726 EXPECT_THAT(ReadDismissedIDsFromPrefs(/*for_offline_pages=*/true), SizeIs(1));
727
728 // Clear when explicitly requested.
729 provider()->ClearDismissedSuggestionsForDebugging(downloads_category());
730 EXPECT_THAT(ReadDismissedIDsFromPrefs(/*for_offline_pages=*/true), SizeIs(0));
731 }
732
733 TEST_F(DownloadSuggestionsProviderTest, ShouldPruneAssetDownloadsDismissedIDs) {
734 *(downloads_manager()->mutable_items()) =
735 CreateDummyAssetDownloads({4, 5, 6, 7, 8, 9});
736 FireOnDownloadsCreated(downloads_manager()->items());
737
738 provider()->DismissSuggestion(
739 GetDummySuggestionId(4, /*is_offline_page=*/false));
740 provider()->DismissSuggestion(
741 GetDummySuggestionId(5, /*is_offline_page=*/false));
742 EXPECT_THAT(ReadDismissedIDsFromPrefs(/*for_offline_pages=*/false),
743 SizeIs(2));
744
745 // Prune when item is deleted.
746 FireDownloadRemoved(downloads_manager()->items()[0].get());
747 EXPECT_THAT(ReadDismissedIDsFromPrefs(/*for_offline_pages=*/false),
748 SizeIs(1));
749
750 // Clear when explicitly requested.
751 provider()->ClearDismissedSuggestionsForDebugging(downloads_category());
752 EXPECT_THAT(ReadDismissedIDsFromPrefs(/*for_offline_pages=*/false),
753 SizeIs(0));
754
755 // Simulate that we miss |OnDownloadRemoved|. The pruning should occur when
756 // all pages are fetched.
757 std::unique_ptr<FakeDownloadItem> missed_item = CreateDummyAssetDownload(100);
758 FireOnDownloadCreated(missed_item.get());
759
760 provider()->DismissSuggestion(
761 GetDummySuggestionId(100, /*is_offline_page=*/false));
762 FireOfflinePageModelChanged(offline_pages_model()->items());
763 // After OfflinePage model change all download items request must have
764 // occurred. Note that |missed_item| is not in |downloads_manager| and so the
765 // provider does not receive it.
766 EXPECT_THAT(ReadDismissedIDsFromPrefs(/*for_offline_pages=*/false),
767 SizeIs(0));
768 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698