1 // Copyright (c) 2012 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.
5 #include "base/memory/scoped_vector.h"
6 #include "base/memory/weak_ptr.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/stl_util.h"
9 #include "chrome/browser/download/download_status_updater.h"
10 #include "content/public/test/mock_download_item.h"
11 #include "content/public/test/mock_download_manager.h"
12 #include "content/public/test/test_browser_thread.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 using testing::AtLeast
;
17 using testing::Invoke
;
19 using testing::Return
;
20 using testing::SetArgPointee
;
21 using testing::StrictMock
;
22 using testing::WithArg
;
25 class TestDownloadStatusUpdater
: public DownloadStatusUpdater
{
27 TestDownloadStatusUpdater() : notification_count_(0),
28 acceptable_notification_item_(NULL
) {
30 void SetAcceptableNotificationItem(content::DownloadItem
* item
) {
31 acceptable_notification_item_
= item
;
33 size_t NotificationCount() {
34 return notification_count_
;
37 void UpdateAppIconDownloadProgress(content::DownloadItem
* download
) override
{
38 ++notification_count_
;
39 if (acceptable_notification_item_
)
40 EXPECT_EQ(acceptable_notification_item_
, download
);
43 size_t notification_count_
;
44 content::DownloadItem
* acceptable_notification_item_
;
47 class DownloadStatusUpdaterTest
: public testing::Test
{
49 DownloadStatusUpdaterTest()
50 : updater_(new TestDownloadStatusUpdater()),
51 ui_thread_(content::BrowserThread::UI
, &loop_
) {}
53 ~DownloadStatusUpdaterTest() override
{
54 for (size_t mgr_idx
= 0; mgr_idx
< managers_
.size(); ++mgr_idx
) {
55 EXPECT_CALL(*Manager(mgr_idx
), RemoveObserver(_
));
60 VerifyAndClearExpectations();
63 for (std::vector
<Items
>::iterator it
= manager_items_
.begin();
64 it
!= manager_items_
.end(); ++it
)
65 STLDeleteContainerPointers(it
->begin(), it
->end());
67 loop_
.RunUntilIdle(); // Allow DownloadManager destruction.
71 // Attach some number of DownloadManagers to the updater.
72 void SetupManagers(int manager_count
) {
73 DCHECK_EQ(0U, managers_
.size());
74 for (int i
= 0; i
< manager_count
; ++i
) {
75 content::MockDownloadManager
* mgr
=
76 new StrictMock
<content::MockDownloadManager
>;
77 managers_
.push_back(mgr
);
81 void SetObserver(content::DownloadManager::Observer
* observer
) {
82 manager_observers_
[manager_observer_index_
] = observer
;
85 // Hook the specified manager into the updater.
86 void LinkManager(int i
) {
87 content::MockDownloadManager
* mgr
= managers_
[i
];
88 manager_observer_index_
= i
;
89 while (manager_observers_
.size() <= static_cast<size_t>(i
)) {
90 manager_observers_
.push_back(NULL
);
92 EXPECT_CALL(*mgr
, AddObserver(_
))
93 .WillOnce(WithArg
<0>(Invoke(
94 this, &DownloadStatusUpdaterTest::SetObserver
)));
95 updater_
->AddManager(mgr
);
98 // Add some number of Download items to a particular manager.
99 void AddItems(int manager_index
, int item_count
, int in_progress_count
) {
100 DCHECK_GT(managers_
.size(), static_cast<size_t>(manager_index
));
101 content::MockDownloadManager
* manager
= managers_
[manager_index
];
103 if (manager_items_
.size() <= static_cast<size_t>(manager_index
))
104 manager_items_
.resize(manager_index
+1);
106 std::vector
<content::DownloadItem
*> item_list
;
107 for (int i
= 0; i
< item_count
; ++i
) {
108 content::MockDownloadItem
* item
=
109 new StrictMock
<content::MockDownloadItem
>;
110 content::DownloadItem::DownloadState state
=
111 i
< in_progress_count
? content::DownloadItem::IN_PROGRESS
112 : content::DownloadItem::CANCELLED
;
113 EXPECT_CALL(*item
, GetState()).WillRepeatedly(Return(state
));
114 manager_items_
[manager_index
].push_back(item
);
116 EXPECT_CALL(*manager
, GetAllDownloads(_
))
117 .WillRepeatedly(SetArgPointee
<0>(manager_items_
[manager_index
]));
120 // Return the specified manager.
121 content::MockDownloadManager
* Manager(int manager_index
) {
122 DCHECK_GT(managers_
.size(), static_cast<size_t>(manager_index
));
123 return managers_
[manager_index
];
126 // Return the specified item.
127 content::MockDownloadItem
* Item(int manager_index
, int item_index
) {
128 DCHECK_GT(manager_items_
.size(), static_cast<size_t>(manager_index
));
129 DCHECK_GT(manager_items_
[manager_index
].size(),
130 static_cast<size_t>(item_index
));
131 // All DownloadItems in manager_items_ are MockDownloadItems.
132 return static_cast<content::MockDownloadItem
*>(
133 manager_items_
[manager_index
][item_index
]);
136 // Set return values relevant to |DownloadStatusUpdater::GetProgress()|
137 // for the specified item.
138 void SetItemValues(int manager_index
, int item_index
,
139 int received_bytes
, int total_bytes
, bool notify
) {
140 content::MockDownloadItem
* item(Item(manager_index
, item_index
));
141 EXPECT_CALL(*item
, GetReceivedBytes())
142 .WillRepeatedly(Return(received_bytes
));
143 EXPECT_CALL(*item
, GetTotalBytes())
144 .WillRepeatedly(Return(total_bytes
));
146 updater_
->OnDownloadUpdated(managers_
[manager_index
], item
);
149 // Transition specified item to completed.
150 void CompleteItem(int manager_index
, int item_index
) {
151 content::MockDownloadItem
* item(Item(manager_index
, item_index
));
152 EXPECT_CALL(*item
, GetState())
153 .WillRepeatedly(Return(content::DownloadItem::COMPLETE
));
154 updater_
->OnDownloadUpdated(managers_
[manager_index
], item
);
157 // Verify and clear all mocks expectations.
158 void VerifyAndClearExpectations() {
159 for (ScopedVector
<content::MockDownloadManager
>::iterator it
160 = managers_
.begin(); it
!= managers_
.end(); ++it
)
161 Mock::VerifyAndClearExpectations(*it
);
162 for (std::vector
<Items
>::iterator it
= manager_items_
.begin();
163 it
!= manager_items_
.end(); ++it
)
164 for (Items::iterator sit
= it
->begin(); sit
!= it
->end(); ++sit
)
165 Mock::VerifyAndClearExpectations(*sit
);
168 ScopedVector
<content::MockDownloadManager
> managers_
;
169 // DownloadItem so that it can be assigned to the result of SearchDownloads.
170 typedef std::vector
<content::DownloadItem
*> Items
;
171 std::vector
<Items
> manager_items_
;
172 int manager_observer_index_
;
174 std::vector
<content::DownloadManager::Observer
*> manager_observers_
;
176 // Pointer so we can verify that destruction triggers appropriate
178 TestDownloadStatusUpdater
*updater_
;
180 // Thread so that the DownloadManager (which is a DeleteOnUIThread
181 // object) can be deleted.
182 // TODO(rdsmith): This can be removed when the DownloadManager
183 // is no longer required to be deleted on the UI thread.
184 base::MessageLoop loop_
;
185 content::TestBrowserThread ui_thread_
;
188 // Test null updater.
189 TEST_F(DownloadStatusUpdaterTest
, Basic
) {
191 int download_count
= -1;
192 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
193 EXPECT_FLOAT_EQ(0.0f
, progress
);
194 EXPECT_EQ(0, download_count
);
197 // Test updater with null manager.
198 TEST_F(DownloadStatusUpdaterTest
, OneManagerNoItems
) {
202 VerifyAndClearExpectations();
205 int download_count
= -1;
206 EXPECT_CALL(*managers_
[0], GetAllDownloads(_
))
207 .WillRepeatedly(SetArgPointee
<0>(manager_items_
[0]));
208 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
209 EXPECT_FLOAT_EQ(0.0f
, progress
);
210 EXPECT_EQ(0, download_count
);
213 // Test updater with non-null manager, including transition an item to
214 // |content::DownloadItem::COMPLETE| and adding a new item.
215 TEST_F(DownloadStatusUpdaterTest
, OneManagerManyItems
) {
221 SetItemValues(0, 0, 10, 20, false);
222 SetItemValues(0, 1, 50, 60, false);
223 SetItemValues(0, 2, 90, 90, false);
226 int download_count
= -1;
227 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
228 EXPECT_FLOAT_EQ((10+50)/(20.0f
+60), progress
);
229 EXPECT_EQ(2, download_count
);
231 // Transition one item to completed and confirm progress is updated
234 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
235 EXPECT_FLOAT_EQ(50/60.0f
, progress
);
236 EXPECT_EQ(1, download_count
);
238 // Add a new item to manager and confirm progress is updated properly.
240 SetItemValues(0, 3, 150, 200, false);
241 manager_observers_
[0]->OnDownloadCreated(
242 managers_
[0], manager_items_
[0][manager_items_
[0].size()-1]);
244 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
245 EXPECT_FLOAT_EQ((50+150)/(60+200.0f
), progress
);
246 EXPECT_EQ(2, download_count
);
249 // Test to ensure that the download progress notification is called correctly.
250 TEST_F(DownloadStatusUpdaterTest
, ProgressNotification
) {
251 size_t expected_notifications
= updater_
->NotificationCount();
256 // Expect two notifications, one for each item; which item will come first
257 // isn't defined so it cannot be tested.
258 expected_notifications
+= 2;
259 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
261 // Make progress on the first item.
262 updater_
->SetAcceptableNotificationItem(Item(0, 0));
263 SetItemValues(0, 0, 10, 20, true);
264 ++expected_notifications
;
265 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
267 // Second item completes!
268 updater_
->SetAcceptableNotificationItem(Item(0, 1));
270 ++expected_notifications
;
271 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
273 // First item completes.
274 updater_
->SetAcceptableNotificationItem(Item(0, 0));
276 ++expected_notifications
;
277 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
279 updater_
->SetAcceptableNotificationItem(NULL
);
282 // Confirm we recognize the situation where we have an unknown size.
283 TEST_F(DownloadStatusUpdaterTest
, UnknownSize
) {
289 SetItemValues(0, 0, 10, 20, false);
290 SetItemValues(0, 1, 50, -1, false);
293 int download_count
= -1;
294 EXPECT_FALSE(updater_
->GetProgress(&progress
, &download_count
));
297 // Test many null managers.
298 TEST_F(DownloadStatusUpdaterTest
, ManyManagersNoItems
) {
304 int download_count
= -1;
305 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
306 EXPECT_FLOAT_EQ(0.0f
, progress
);
307 EXPECT_EQ(0, download_count
);
310 // Test many managers with all items complete.
311 TEST_F(DownloadStatusUpdaterTest
, ManyManagersEmptyItems
) {
319 int download_count
= -1;
320 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
321 EXPECT_FLOAT_EQ(0.0f
, progress
);
322 EXPECT_EQ(0, download_count
);
325 // Test many managers with some non-complete items.
326 TEST_F(DownloadStatusUpdaterTest
, ManyManagersMixedItems
) {
333 SetItemValues(0, 0, 10, 20, false);
334 SetItemValues(0, 1, 50, 60, false);
335 SetItemValues(1, 0, 80, 90, false);
338 int download_count
= -1;
339 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
340 EXPECT_FLOAT_EQ((10+50+80)/(20.0f
+60+90), progress
);
341 EXPECT_EQ(3, download_count
);