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(_
));
61 VerifyAndClearExpectations();
64 for (std::vector
<Items
>::iterator it
= manager_items_
.begin();
65 it
!= manager_items_
.end(); ++it
)
66 STLDeleteContainerPointers(it
->begin(), it
->end());
68 loop_
.RunUntilIdle(); // Allow DownloadManager destruction.
72 // Attach some number of DownloadManagers to the updater.
73 void SetupManagers(int manager_count
) {
74 DCHECK_EQ(0U, managers_
.size());
75 for (int i
= 0; i
< manager_count
; ++i
) {
76 content::MockDownloadManager
* mgr
=
77 new StrictMock
<content::MockDownloadManager
>;
78 managers_
.push_back(mgr
);
82 void SetObserver(content::DownloadManager::Observer
* observer
) {
83 manager_observers_
[manager_observer_index_
] = observer
;
86 // Hook the specified manager into the updater.
87 void LinkManager(int i
) {
88 content::MockDownloadManager
* mgr
= managers_
[i
];
89 manager_observer_index_
= i
;
90 while (manager_observers_
.size() <= static_cast<size_t>(i
)) {
91 manager_observers_
.push_back(NULL
);
93 EXPECT_CALL(*mgr
, AddObserver(_
))
94 .WillOnce(WithArg
<0>(Invoke(
95 this, &DownloadStatusUpdaterTest::SetObserver
)));
96 updater_
->AddManager(mgr
);
99 // Add some number of Download items to a particular manager.
100 void AddItems(int manager_index
, int item_count
, int in_progress_count
) {
101 DCHECK_GT(managers_
.size(), static_cast<size_t>(manager_index
));
102 content::MockDownloadManager
* manager
= managers_
[manager_index
];
104 if (manager_items_
.size() <= static_cast<size_t>(manager_index
))
105 manager_items_
.resize(manager_index
+1);
107 std::vector
<content::DownloadItem
*> item_list
;
108 for (int i
= 0; i
< item_count
; ++i
) {
109 content::MockDownloadItem
* item
=
110 new StrictMock
<content::MockDownloadItem
>;
111 content::DownloadItem::DownloadState state
=
112 i
< in_progress_count
? content::DownloadItem::IN_PROGRESS
113 : content::DownloadItem::CANCELLED
;
114 EXPECT_CALL(*item
, GetState()).WillRepeatedly(Return(state
));
115 manager_items_
[manager_index
].push_back(item
);
117 EXPECT_CALL(*manager
, GetAllDownloads(_
))
118 .WillRepeatedly(SetArgPointee
<0>(manager_items_
[manager_index
]));
121 // Return the specified manager.
122 content::MockDownloadManager
* Manager(int manager_index
) {
123 DCHECK_GT(managers_
.size(), static_cast<size_t>(manager_index
));
124 return managers_
[manager_index
];
127 // Return the specified item.
128 content::MockDownloadItem
* Item(int manager_index
, int item_index
) {
129 DCHECK_GT(manager_items_
.size(), static_cast<size_t>(manager_index
));
130 DCHECK_GT(manager_items_
[manager_index
].size(),
131 static_cast<size_t>(item_index
));
132 // All DownloadItems in manager_items_ are MockDownloadItems.
133 return static_cast<content::MockDownloadItem
*>(
134 manager_items_
[manager_index
][item_index
]);
137 // Set return values relevant to |DownloadStatusUpdater::GetProgress()|
138 // for the specified item.
139 void SetItemValues(int manager_index
, int item_index
,
140 int received_bytes
, int total_bytes
, bool notify
) {
141 content::MockDownloadItem
* item(Item(manager_index
, item_index
));
142 EXPECT_CALL(*item
, GetReceivedBytes())
143 .WillRepeatedly(Return(received_bytes
));
144 EXPECT_CALL(*item
, GetTotalBytes())
145 .WillRepeatedly(Return(total_bytes
));
147 updater_
->OnDownloadUpdated(managers_
[manager_index
], item
);
150 // Transition specified item to completed.
151 void CompleteItem(int manager_index
, int item_index
) {
152 content::MockDownloadItem
* item(Item(manager_index
, item_index
));
153 EXPECT_CALL(*item
, GetState())
154 .WillRepeatedly(Return(content::DownloadItem::COMPLETE
));
155 updater_
->OnDownloadUpdated(managers_
[manager_index
], item
);
158 // Verify and clear all mocks expectations.
159 void VerifyAndClearExpectations() {
160 for (ScopedVector
<content::MockDownloadManager
>::iterator it
161 = managers_
.begin(); it
!= managers_
.end(); ++it
)
162 Mock::VerifyAndClearExpectations(*it
);
163 for (std::vector
<Items
>::iterator it
= manager_items_
.begin();
164 it
!= manager_items_
.end(); ++it
)
165 for (Items::iterator sit
= it
->begin(); sit
!= it
->end(); ++sit
)
166 Mock::VerifyAndClearExpectations(*sit
);
169 ScopedVector
<content::MockDownloadManager
> managers_
;
170 // DownloadItem so that it can be assigned to the result of SearchDownloads.
171 typedef std::vector
<content::DownloadItem
*> Items
;
172 std::vector
<Items
> manager_items_
;
173 int manager_observer_index_
;
175 std::vector
<content::DownloadManager::Observer
*> manager_observers_
;
177 // Pointer so we can verify that destruction triggers appropriate
179 TestDownloadStatusUpdater
*updater_
;
181 // Thread so that the DownloadManager (which is a DeleteOnUIThread
182 // object) can be deleted.
183 // TODO(rdsmith): This can be removed when the DownloadManager
184 // is no longer required to be deleted on the UI thread.
185 base::MessageLoop loop_
;
186 content::TestBrowserThread ui_thread_
;
189 // Test null updater.
190 TEST_F(DownloadStatusUpdaterTest
, Basic
) {
192 int download_count
= -1;
193 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
194 EXPECT_FLOAT_EQ(0.0f
, progress
);
195 EXPECT_EQ(0, download_count
);
198 // Test updater with null manager.
199 TEST_F(DownloadStatusUpdaterTest
, OneManagerNoItems
) {
203 VerifyAndClearExpectations();
206 int download_count
= -1;
207 EXPECT_CALL(*managers_
[0], GetAllDownloads(_
))
208 .WillRepeatedly(SetArgPointee
<0>(manager_items_
[0]));
209 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
210 EXPECT_FLOAT_EQ(0.0f
, progress
);
211 EXPECT_EQ(0, download_count
);
214 // Test updater with non-null manager, including transition an item to
215 // |content::DownloadItem::COMPLETE| and adding a new item.
216 TEST_F(DownloadStatusUpdaterTest
, OneManagerManyItems
) {
222 SetItemValues(0, 0, 10, 20, false);
223 SetItemValues(0, 1, 50, 60, false);
224 SetItemValues(0, 2, 90, 90, false);
227 int download_count
= -1;
228 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
229 EXPECT_FLOAT_EQ((10+50)/(20.0f
+60), progress
);
230 EXPECT_EQ(2, download_count
);
232 // Transition one item to completed and confirm progress is updated
235 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
236 EXPECT_FLOAT_EQ(50/60.0f
, progress
);
237 EXPECT_EQ(1, download_count
);
239 // Add a new item to manager and confirm progress is updated properly.
241 SetItemValues(0, 3, 150, 200, false);
242 manager_observers_
[0]->OnDownloadCreated(
243 managers_
[0], manager_items_
[0][manager_items_
[0].size()-1]);
245 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
246 EXPECT_FLOAT_EQ((50+150)/(60+200.0f
), progress
);
247 EXPECT_EQ(2, download_count
);
250 // Test to ensure that the download progress notification is called correctly.
251 TEST_F(DownloadStatusUpdaterTest
, ProgressNotification
) {
252 size_t expected_notifications
= updater_
->NotificationCount();
257 // Expect two notifications, one for each item; which item will come first
258 // isn't defined so it cannot be tested.
259 expected_notifications
+= 2;
260 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
262 // Make progress on the first item.
263 updater_
->SetAcceptableNotificationItem(Item(0, 0));
264 SetItemValues(0, 0, 10, 20, true);
265 ++expected_notifications
;
266 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
268 // Second item completes!
269 updater_
->SetAcceptableNotificationItem(Item(0, 1));
271 ++expected_notifications
;
272 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
274 // First item completes.
275 updater_
->SetAcceptableNotificationItem(Item(0, 0));
277 ++expected_notifications
;
278 ASSERT_EQ(expected_notifications
, updater_
->NotificationCount());
280 updater_
->SetAcceptableNotificationItem(NULL
);
283 // Confirm we recognize the situation where we have an unknown size.
284 TEST_F(DownloadStatusUpdaterTest
, UnknownSize
) {
290 SetItemValues(0, 0, 10, 20, false);
291 SetItemValues(0, 1, 50, -1, false);
294 int download_count
= -1;
295 EXPECT_FALSE(updater_
->GetProgress(&progress
, &download_count
));
298 // Test many null managers.
299 TEST_F(DownloadStatusUpdaterTest
, ManyManagersNoItems
) {
305 int download_count
= -1;
306 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
307 EXPECT_FLOAT_EQ(0.0f
, progress
);
308 EXPECT_EQ(0, download_count
);
311 // Test many managers with all items complete.
312 TEST_F(DownloadStatusUpdaterTest
, ManyManagersEmptyItems
) {
320 int download_count
= -1;
321 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
322 EXPECT_FLOAT_EQ(0.0f
, progress
);
323 EXPECT_EQ(0, download_count
);
326 // Test many managers with some non-complete items.
327 TEST_F(DownloadStatusUpdaterTest
, ManyManagersMixedItems
) {
334 SetItemValues(0, 0, 10, 20, false);
335 SetItemValues(0, 1, 50, 60, false);
336 SetItemValues(1, 0, 80, 90, false);
339 int download_count
= -1;
340 EXPECT_TRUE(updater_
->GetProgress(&progress
, &download_count
));
341 EXPECT_FLOAT_EQ((10+50+80)/(20.0f
+60+90), progress
);
342 EXPECT_EQ(3, download_count
);