OLD | NEW |
---|---|
(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 } | |
OLD | NEW |