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 virtual void UpdateAppIconDownloadProgress(
38 content::DownloadItem
* download
) OVERRIDE
{
39 ++notification_count_
;
40 if (acceptable_notification_item_
)
41 EXPECT_EQ(acceptable_notification_item_
, download
);
44 size_t notification_count_
;
45 content::DownloadItem
* acceptable_notification_item_
;
48 class DownloadStatusUpdaterTest
: public testing::Test
{
50 DownloadStatusUpdaterTest()
51 : updater_(new TestDownloadStatusUpdater()),
52 ui_thread_(content::BrowserThread::UI
, &loop_
) {}
54 virtual ~DownloadStatusUpdaterTest() {
55 for (size_t mgr_idx
= 0; mgr_idx
< managers_
.size(); ++mgr_idx
) {
56 EXPECT_CALL(*Manager(mgr_idx
), RemoveObserver(_
));
57 for (size_t item_idx
= 0; item_idx
< manager_items_
[mgr_idx
].size();
59 EXPECT_CALL(*Item(mgr_idx
, item_idx
), RemoveObserver(_
));
65 VerifyAndClearExpectations();
68 for (std::vector
<Items
>::iterator it
= manager_items_
.begin();
69 it
!= manager_items_
.end(); ++it
)
70 STLDeleteContainerPointers(it
->begin(), it
->end());
72 loop_
.RunUntilIdle(); // Allow DownloadManager destruction.
76 // Attach some number of DownloadManagers to the updater.
77 void SetupManagers(int manager_count
) {
78 DCHECK_EQ(0U, managers_
.size());
79 for (int i
= 0; i
< manager_count
; ++i
) {
80 content::MockDownloadManager
* mgr
=
81 new StrictMock
<content::MockDownloadManager
>;
82 managers_
.push_back(mgr
);
86 void SetObserver(content::DownloadManager::Observer
* observer
) {
87 manager_observers_
[manager_observer_index_
] = observer
;
90 // Hook the specified manager into the updater.
91 void LinkManager(int i
) {
92 content::MockDownloadManager
* mgr
= managers_
[i
];
93 manager_observer_index_
= i
;
94 while (manager_observers_
.size() <= static_cast<size_t>(i
)) {
95 manager_observers_
.push_back(NULL
);
97 EXPECT_CALL(*mgr
, AddObserver(_
))
98 .WillOnce(WithArg
<0>(Invoke(
99 this, &DownloadStatusUpdaterTest::SetObserver
)));
100 updater_
->AddManager(mgr
);
103 // Add some number of Download items to a particular manager.
104 void AddItems(int manager_index
, int item_count
, int in_progress_count
) {
105 DCHECK_GT(managers_
.size(), static_cast<size_t>(manager_index
));
106 content::MockDownloadManager
* manager
= managers_
[manager_index
];
108 if (manager_items_
.size() <= static_cast<size_t>(manager_index
))
109 manager_items_
.resize(manager_index
+1);
111 std::vector
<content::DownloadItem
*> item_list
;
112 for (int i
= 0; i
< item_count
; ++i
) {
113 content::MockDownloadItem
* item
=
114 new StrictMock
<content::MockDownloadItem
>;
115 content::DownloadItem::DownloadState state
=
116 i
< in_progress_count
? content::DownloadItem::IN_PROGRESS
117 : content::DownloadItem::CANCELLED
;
118 EXPECT_CALL(*item
, GetState()).WillRepeatedly(Return(state
));
119 EXPECT_CALL(*item
, AddObserver(_
))
121 manager_items_
[manager_index
].push_back(item
);
123 EXPECT_CALL(*manager
, GetAllDownloads(_
))
124 .WillRepeatedly(SetArgPointee
<0>(manager_items_
[manager_index
]));
127 // Return the specified manager.
128 content::MockDownloadManager
* Manager(int manager_index
) {
129 DCHECK_GT(managers_
.size(), static_cast<size_t>(manager_index
));
130 return managers_
[manager_index
];
133 // Return the specified item.
134 content::MockDownloadItem
* Item(int manager_index
, int item_index
) {
135 DCHECK_GT(manager_items_
.size(), static_cast<size_t>(manager_index
));
136 DCHECK_GT(manager_items_
[manager_index
].size(),
137 static_cast<size_t>(item_index
));
138 // All DownloadItems in manager_items_ are MockDownloadItems.
139 return static_cast<content::MockDownloadItem
*>(
140 manager_items_
[manager_index
][item_index
]);
143 // Set return values relevant to |DownloadStatusUpdater::GetProgress()|
144 // for the specified item.
145 void SetItemValues(int manager_index
, int item_index
,
146 int received_bytes
, int total_bytes
, bool notify
) {
147 content::MockDownloadItem
* item(Item(manager_index
, item_index
));
148 EXPECT_CALL(*item
, GetReceivedBytes())
149 .WillRepeatedly(Return(received_bytes
));
150 EXPECT_CALL(*item
, GetTotalBytes())
151 .WillRepeatedly(Return(total_bytes
));
153 updater_
->OnDownloadUpdated(managers_
[manager_index
], item
);
156 // Transition specified item to completed.
157 void CompleteItem(int manager_index
, int item_index
) {
158 content::MockDownloadItem
* item(Item(manager_index
, item_index
));
159 EXPECT_CALL(*item
, GetState())
160 .WillRepeatedly(Return(content::DownloadItem::COMPLETE
));
161 updater_
->OnDownloadUpdated(managers_
[manager_index
], item
);
164 // Verify and clear all mocks expectations.
165 void VerifyAndClearExpectations() {
166 for (ScopedVector
<content::MockDownloadManager
>::iterator it
167 = managers_
.begin(); it
!= managers_
.end(); ++it
)
168 Mock::VerifyAndClearExpectations(*it
);
169 for (std::vector
<Items
>::iterator it
= manager_items_
.begin();
170 it
!= manager_items_
.end(); ++it
)
171 for (Items::iterator sit
= it
->begin(); sit
!= it
->end(); ++sit
)
172 Mock::VerifyAndClearExpectations(*sit
);
175 ScopedVector
<content::MockDownloadManager
> managers_
;
176 // DownloadItem so that it can be assigned to the result of SearchDownloads.
177 typedef std::vector
<content::DownloadItem
*> Items
;
178 std::vector
<Items
> manager_items_
;
179 int manager_observer_index_
;
181 std::vector
<content::DownloadManager::Observer
*> manager_observers_
;
183 // Pointer so we can verify that destruction triggers appropriate
185 TestDownloadStatusUpdater
*updater_
;
187 // Thread so that the DownloadManager (which is a DeleteOnUIThread
188 // object) can be deleted.
189 // TODO(rdsmith): This can be removed when the DownloadManager
190 // is no longer required to be deleted on the UI thread.
191 base::MessageLoop loop_
;
192 content::TestBrowserThread ui_thread_
;
195 // Test null updater.
196 TEST_F(DownloadStatusUpdaterTest
, Basic
) {
198 int download_count
= -1;
199 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
200 EXPECT_FLOAT_EQ(0.0f
, progress
);
201 EXPECT_EQ(0, download_count
);
204 // Test updater with null manager.
205 TEST_F(DownloadStatusUpdaterTest
, OneManagerNoItems
) {
209 VerifyAndClearExpectations();
212 int download_count
= -1;
213 EXPECT_CALL(*managers_
[0], GetAllDownloads(_
))
214 .WillRepeatedly(SetArgPointee
<0>(manager_items_
[0]));
215 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
216 EXPECT_FLOAT_EQ(0.0f
, progress
);
217 EXPECT_EQ(0, download_count
);
220 // Test updater with non-null manager, including transition an item to
221 // |content::DownloadItem::COMPLETE| and adding a new item.
222 TEST_F(DownloadStatusUpdaterTest
, OneManagerManyItems
) {
228 SetItemValues(0, 0, 10, 20, false);
229 SetItemValues(0, 1, 50, 60, false);
230 SetItemValues(0, 2, 90, 90, false);
233 int download_count
= -1;
234 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
235 EXPECT_FLOAT_EQ((10+50)/(20.0f
+60), progress
);
236 EXPECT_EQ(2, download_count
);
238 // Transition one item to completed and confirm progress is updated
241 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
242 EXPECT_FLOAT_EQ(50/60.0f
, progress
);
243 EXPECT_EQ(1, download_count
);
245 // Add a new item to manager and confirm progress is updated properly.
247 SetItemValues(0, 3, 150, 200, false);
248 manager_observers_
[0]->OnDownloadCreated(
249 managers_
[0], manager_items_
[0][manager_items_
[0].size()-1]);
251 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
252 EXPECT_FLOAT_EQ((50+150)/(60+200.0f
), progress
);
253 EXPECT_EQ(2, download_count
);
256 // Test to ensure that the download progress notification is called correctly.
257 TEST_F(DownloadStatusUpdaterTest
, ProgressNotification
) {
258 size_t expected_notifications
= updater_
->NotificationCount();
263 // Expect two notifications, one for each item; which item will come first
264 // isn't defined so it cannot be tested.
265 expected_notifications
+= 2;
266 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
268 // Make progress on the first item.
269 updater_
->SetAcceptableNotificationItem(Item(0, 0));
270 SetItemValues(0, 0, 10, 20, true);
271 ++expected_notifications
;
272 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
274 // Second item completes!
275 updater_
->SetAcceptableNotificationItem(Item(0, 1));
277 ++expected_notifications
;
278 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
280 // First item completes.
281 updater_
->SetAcceptableNotificationItem(Item(0, 0));
283 ++expected_notifications
;
284 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
286 updater_
->SetAcceptableNotificationItem(NULL
);
289 // Confirm we recognize the situation where we have an unknown size.
290 TEST_F(DownloadStatusUpdaterTest
, UnknownSize
) {
296 SetItemValues(0, 0, 10, 20, false);
297 SetItemValues(0, 1, 50, -1, false);
300 int download_count
= -1;
301 EXPECT_FALSE(updater_
->GetProgress(&progress
, &download_count
));
304 // Test many null managers.
305 TEST_F(DownloadStatusUpdaterTest
, ManyManagersNoItems
) {
311 int download_count
= -1;
312 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
313 EXPECT_FLOAT_EQ(0.0f
, progress
);
314 EXPECT_EQ(0, download_count
);
317 // Test many managers with all items complete.
318 TEST_F(DownloadStatusUpdaterTest
, ManyManagersEmptyItems
) {
326 int download_count
= -1;
327 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
328 EXPECT_FLOAT_EQ(0.0f
, progress
);
329 EXPECT_EQ(0, download_count
);
332 // Test many managers with some non-complete items.
333 TEST_F(DownloadStatusUpdaterTest
, ManyManagersMixedItems
) {
340 SetItemValues(0, 0, 10, 20, false);
341 SetItemValues(0, 1, 50, 60, false);
342 SetItemValues(1, 0, 80, 90, false);
345 int download_count
= -1;
346 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
347 EXPECT_FLOAT_EQ((10+50+80)/(20.0f
+60+90), progress
);
348 EXPECT_EQ(3, download_count
);