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.
4
5 #include "chrome/browser/download/download_item_model.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <vector>
11
12 #include "base/check_op.h"
13 #include "base/i18n/rtl.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string16.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "build/build_config.h"
19 #include "components/download/public/common/mock_download_item.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "ui/base/text/bytes_formatting.h"
23
24 using download::DownloadItem;
25 using safe_browsing::DownloadFileType;
26 using ::testing::Mock;
27 using ::testing::NiceMock;
28 using ::testing::Return;
29 using ::testing::ReturnRef;
30 using ::testing::ReturnRefOfCopy;
31 using ::testing::SetArgPointee;
32 using ::testing::_;
33
34 namespace {
35
36 // Create a char array that has as many elements as there are download
37 // interrupt reasons. We can then use that in a static_assert to make sure
38 // that all the interrupt reason codes are accounted for. The reason codes are
39 // unfortunately sparse, making this necessary.
40 char kInterruptReasonCounter[] = {
41 0, // download::DOWNLOAD_INTERRUPT_REASON_NONE
42 #define INTERRUPT_REASON(name,value) 0,
43 #include "components/download/public/common/download_interrupt_reason_values.h"
44 #undef INTERRUPT_REASON
45 };
46 const size_t kInterruptReasonCount = base::size(kInterruptReasonCounter);
47
48 // Default target path for a mock download item in DownloadItemModelTest.
49 const base::FilePath::CharType kDefaultTargetFilePath[] =
50 FILE_PATH_LITERAL("/foo/bar/foo.bar");
51
52 const base::FilePath::CharType kDefaultDisplayFileName[] =
53 FILE_PATH_LITERAL("foo.bar");
54
55 // Default URL for a mock download item in DownloadItemModelTest.
56 const char kDefaultURL[] = "http://example.com/foo.bar";
57
58 class DownloadItemModelTest : public testing::Test {
59 public:
DownloadItemModelTest()60 DownloadItemModelTest()
61 : model_(&item_) {}
62
~DownloadItemModelTest()63 ~DownloadItemModelTest() override {}
64
65 protected:
66 // Sets up defaults for the download item and sets |model_| to a new
67 // DownloadItemModel that uses the mock download item.
SetupDownloadItemDefaults()68 void SetupDownloadItemDefaults() {
69 ON_CALL(item_, GetReceivedBytes()).WillByDefault(Return(1));
70 ON_CALL(item_, GetTotalBytes()).WillByDefault(Return(2));
71 ON_CALL(item_, TimeRemaining(_)).WillByDefault(Return(false));
72 ON_CALL(item_, GetMimeType()).WillByDefault(Return("text/html"));
73 ON_CALL(item_, AllDataSaved()).WillByDefault(Return(false));
74 ON_CALL(item_, GetOpenWhenComplete()).WillByDefault(Return(false));
75 ON_CALL(item_, GetFileExternallyRemoved()).WillByDefault(Return(false));
76 ON_CALL(item_, GetState())
77 .WillByDefault(Return(DownloadItem::IN_PROGRESS));
78 ON_CALL(item_, GetURL())
79 .WillByDefault(ReturnRefOfCopy(GURL(kDefaultURL)));
80 ON_CALL(item_, GetFileNameToReportUser())
81 .WillByDefault(Return(base::FilePath(kDefaultDisplayFileName)));
82 ON_CALL(item_, GetTargetFilePath())
83 .WillByDefault(ReturnRefOfCopy(base::FilePath(kDefaultTargetFilePath)));
84 ON_CALL(item_, GetTargetDisposition())
85 .WillByDefault(
86 Return(DownloadItem::TARGET_DISPOSITION_OVERWRITE));
87 ON_CALL(item_, IsPaused()).WillByDefault(Return(false));
88 }
89
SetupInterruptedDownloadItem(download::DownloadInterruptReason reason)90 void SetupInterruptedDownloadItem(download::DownloadInterruptReason reason) {
91 EXPECT_CALL(item_, GetLastReason()).WillRepeatedly(Return(reason));
92 EXPECT_CALL(item_, GetState())
93 .WillRepeatedly(
94 Return((reason == download::DOWNLOAD_INTERRUPT_REASON_NONE)
95 ? DownloadItem::IN_PROGRESS
96 : DownloadItem::INTERRUPTED));
97 }
98
item()99 download::MockDownloadItem& item() { return item_; }
100
model()101 DownloadItemModel& model() {
102 return model_;
103 }
104
105 private:
106 NiceMock<download::MockDownloadItem> item_;
107 DownloadItemModel model_;
108 };
109
110 } // namespace
111
TEST_F(DownloadItemModelTest,InterruptedStatus)112 TEST_F(DownloadItemModelTest, InterruptedStatus) {
113 // Test that we have the correct interrupt status message for downloads that
114 // are in the INTERRUPTED state.
115 const struct TestCase {
116 // The reason.
117 download::DownloadInterruptReason reason;
118
119 // Expected status string. This will include the progress as well.
120 const char* expected_status;
121 } kTestCases[] = {
122 {download::DOWNLOAD_INTERRUPT_REASON_NONE, "1/2 B"},
123 {download::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
124 "Failed - Download error"},
125 {download::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
126 "Failed - Insufficient permissions"},
127 {download::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, "Failed - Disk full"},
128 {download::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG,
129 "Failed - Path too long"},
130 {download::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE,
131 "Failed - File too large"},
132 {download::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED,
133 "Failed - Virus detected"},
134 {download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED, "Failed - Blocked"},
135 {download::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED,
136 "Failed - Virus scan failed"},
137 {download::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT,
138 "Failed - File truncated"},
139 {download::DOWNLOAD_INTERRUPT_REASON_FILE_SAME_AS_SOURCE,
140 "Failed - Already downloaded"},
141 {download::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR,
142 "Failed - System busy"},
143 {download::DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH,
144 "Failed - Download error"},
145 {download::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
146 "Failed - Network error"},
147 {download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT,
148 "Failed - Network timeout"},
149 {download::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED,
150 "Failed - Network disconnected"},
151 {download::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN,
152 "Failed - Server unavailable"},
153 {download::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST,
154 "Failed - Network error"},
155 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED,
156 "Failed - Server problem"},
157 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE,
158 "Failed - Download error"},
159 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
160 "Failed - No file"},
161 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED,
162 "Failed - Needs authorization"},
163 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM,
164 "Failed - Bad certificate"},
165 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN,
166 "Failed - Forbidden"},
167 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE,
168 "Failed - Server unreachable"},
169 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_CONTENT_LENGTH_MISMATCH,
170 "Failed - File incomplete"},
171 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT,
172 "Failed - Download error"},
173 {download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED, "Canceled"},
174 {download::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN, "Failed - Shutdown"},
175 {download::DOWNLOAD_INTERRUPT_REASON_CRASH, "Failed - Crash"},
176 };
177 static_assert(kInterruptReasonCount == base::size(kTestCases),
178 "interrupt reason mismatch");
179
180 SetupDownloadItemDefaults();
181 for (const auto& test_case : kTestCases) {
182 SetupInterruptedDownloadItem(test_case.reason);
183 EXPECT_EQ(test_case.expected_status,
184 base::UTF16ToUTF8(model().GetStatusText()));
185 }
186 }
187
TEST_F(DownloadItemModelTest,InterruptTooltip)188 TEST_F(DownloadItemModelTest, InterruptTooltip) {
189 // Test that we have the correct interrupt tooltip for downloads that are in
190 // the INTERRUPTED state.
191 const struct TestCase {
192 // The reason.
193 download::DownloadInterruptReason reason;
194
195 // Expected tooltip text. The tooltip text for interrupted downloads
196 // typically consist of two lines. One for the filename and one for the
197 // interrupt reason. The returned string contains a newline.
198 const char* expected_tooltip;
199 } kTestCases[] = {
200 {download::DOWNLOAD_INTERRUPT_REASON_NONE, "foo.bar"},
201 {download::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
202 "foo.bar\nDownload error"},
203 {download::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
204 "foo.bar\nInsufficient permissions"},
205 {download::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, "foo.bar\nDisk full"},
206 {download::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG,
207 "foo.bar\nPath too long"},
208 {download::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE,
209 "foo.bar\nFile too large"},
210 {download::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED,
211 "foo.bar\nVirus detected"},
212 {download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED, "foo.bar\nBlocked"},
213 {download::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED,
214 "foo.bar\nVirus scan failed"},
215 {download::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT,
216 "foo.bar\nFile truncated"},
217 {download::DOWNLOAD_INTERRUPT_REASON_FILE_SAME_AS_SOURCE,
218 "foo.bar\nAlready downloaded"},
219 {download::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR,
220 "foo.bar\nSystem busy"},
221 {download::DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH,
222 "foo.bar\nDownload error"},
223 {download::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
224 "foo.bar\nNetwork error"},
225 {download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT,
226 "foo.bar\nNetwork timeout"},
227 {download::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED,
228 "foo.bar\nNetwork disconnected"},
229 {download::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN,
230 "foo.bar\nServer unavailable"},
231 {download::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST,
232 "foo.bar\nNetwork error"},
233 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED,
234 "foo.bar\nServer problem"},
235 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE,
236 "foo.bar\nDownload error"},
237 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
238 "foo.bar\nNo file"},
239 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED,
240 "foo.bar\nNeeds authorization"},
241 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM,
242 "foo.bar\nBad certificate"},
243 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN,
244 "foo.bar\nForbidden"},
245 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE,
246 "foo.bar\nServer unreachable"},
247 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_CONTENT_LENGTH_MISMATCH,
248 "foo.bar\nFile incomplete"},
249 {download::DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT,
250 "foo.bar\nDownload error"},
251 {download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED, "foo.bar"},
252 {download::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN, "foo.bar\nShutdown"},
253 {download::DOWNLOAD_INTERRUPT_REASON_CRASH, "foo.bar\nCrash"},
254 };
255 static_assert(kInterruptReasonCount == base::size(kTestCases),
256 "interrupt reason mismatch");
257
258 SetupDownloadItemDefaults();
259 for (const auto& test_case : kTestCases) {
260 SetupInterruptedDownloadItem(test_case.reason);
261 EXPECT_EQ(test_case.expected_tooltip,
262 base::UTF16ToUTF8(model().GetTooltipText()));
263 }
264 }
265
TEST_F(DownloadItemModelTest,InProgressStatus)266 TEST_F(DownloadItemModelTest, InProgressStatus) {
267 const struct TestCase {
268 int64_t received_bytes; // Return value of GetReceivedBytes().
269 int64_t total_bytes; // Return value of GetTotalBytes().
270 bool time_remaining_known; // If TimeRemaining() is known.
271 bool open_when_complete; // GetOpenWhenComplete().
272 bool is_paused; // IsPaused().
273 const char* expected_status; // Expected status text.
274 } kTestCases[] = {
275 // These are all the valid combinations of the above fields for a download
276 // that is in IN_PROGRESS state. Go through all of them and check the return
277 // value of DownloadItemModel::GetStatusText(). The point isn't to lock down
278 // the status strings, but to make sure we end up with something sane for
279 // all the circumstances we care about.
280 //
281 // For GetReceivedBytes()/GetTotalBytes(), we only check whether each is
282 // non-zero. In addition, if |total_bytes| is zero, then
283 // |time_remaining_known| is also false.
284 //
285 // .-- .TimeRemaining() is known.
286 // | .-- .GetOpenWhenComplete()
287 // | | .---- .IsPaused()
288 { 0, 0, false, false, false, "Starting\xE2\x80\xA6" },
289 { 1, 0, false, false, false, "1 B" },
290 { 0, 2, false, false, false, "Starting\xE2\x80\xA6"},
291 { 1, 2, false, false, false, "1/2 B" },
292 { 0, 2, true, false, false, "0/2 B, 10 secs left" },
293 { 1, 2, true, false, false, "1/2 B, 10 secs left" },
294 { 0, 0, false, true, false, "Opening when complete" },
295 { 1, 0, false, true, false, "Opening when complete" },
296 { 0, 2, false, true, false, "Opening when complete" },
297 { 1, 2, false, true, false, "Opening when complete" },
298 { 0, 2, true, true, false, "Opening in 10 secs\xE2\x80\xA6"},
299 { 1, 2, true, true, false, "Opening in 10 secs\xE2\x80\xA6"},
300 { 0, 0, false, false, true, "0 B, Paused" },
301 { 1, 0, false, false, true, "1 B, Paused" },
302 { 0, 2, false, false, true, "0/2 B, Paused" },
303 { 1, 2, false, false, true, "1/2 B, Paused" },
304 { 0, 2, true, false, true, "0/2 B, Paused" },
305 { 1, 2, true, false, true, "1/2 B, Paused" },
306 { 0, 0, false, true, true, "0 B, Paused" },
307 { 1, 0, false, true, true, "1 B, Paused" },
308 { 0, 2, false, true, true, "0/2 B, Paused" },
309 { 1, 2, false, true, true, "1/2 B, Paused" },
310 { 0, 2, true, true, true, "0/2 B, Paused" },
311 { 1, 2, true, true, true, "1/2 B, Paused" },
312 };
313
314 SetupDownloadItemDefaults();
315
316 for (const auto& test_case : kTestCases) {
317 Mock::VerifyAndClearExpectations(&item());
318 Mock::VerifyAndClearExpectations(&model());
319 EXPECT_CALL(item(), GetReceivedBytes())
320 .WillRepeatedly(Return(test_case.received_bytes));
321 EXPECT_CALL(item(), GetTotalBytes())
322 .WillRepeatedly(Return(test_case.total_bytes));
323 EXPECT_CALL(item(), TimeRemaining(_))
324 .WillRepeatedly(testing::DoAll(
325 testing::SetArgPointee<0>(base::TimeDelta::FromSeconds(10)),
326 Return(test_case.time_remaining_known)));
327 EXPECT_CALL(item(), GetOpenWhenComplete())
328 .WillRepeatedly(Return(test_case.open_when_complete));
329 EXPECT_CALL(item(), IsPaused())
330 .WillRepeatedly(Return(test_case.is_paused));
331
332 EXPECT_EQ(test_case.expected_status,
333 base::UTF16ToUTF8(model().GetStatusText()));
334 }
335 }
336
TEST_F(DownloadItemModelTest,ShouldShowInShelf)337 TEST_F(DownloadItemModelTest, ShouldShowInShelf) {
338 SetupDownloadItemDefaults();
339
340 // By default the download item should be displayable on the shelf when it is
341 // not a transient download.
342 EXPECT_CALL(item(), IsTransient()).WillOnce(Return(false));
343 EXPECT_TRUE(model().ShouldShowInShelf());
344
345 EXPECT_CALL(item(), IsTransient()).WillOnce(Return(true));
346 EXPECT_FALSE(model().ShouldShowInShelf());
347
348 // Once explicitly set, ShouldShowInShelf() should return the explicit value
349 // regardless of whether it's a transient download, which should no longer
350 // be considered by the model after initializing it.
351 EXPECT_CALL(item(), IsTransient()).Times(1);
352
353 model().SetShouldShowInShelf(true);
354 EXPECT_TRUE(model().ShouldShowInShelf());
355
356 model().SetShouldShowInShelf(false);
357 EXPECT_FALSE(model().ShouldShowInShelf());
358 }
359
TEST_F(DownloadItemModelTest,DangerLevel)360 TEST_F(DownloadItemModelTest, DangerLevel) {
361 SetupDownloadItemDefaults();
362
363 // Default danger level is NOT_DANGEROUS.
364 EXPECT_EQ(DownloadFileType::NOT_DANGEROUS, model().GetDangerLevel());
365
366 model().SetDangerLevel(DownloadFileType::ALLOW_ON_USER_GESTURE);
367 EXPECT_EQ(DownloadFileType::ALLOW_ON_USER_GESTURE, model().GetDangerLevel());
368 }
369
TEST_F(DownloadItemModelTest,HasSupportedImageMimeType)370 TEST_F(DownloadItemModelTest, HasSupportedImageMimeType) {
371 SetupDownloadItemDefaults();
372
373 // When the item has a supported image MIME type, true should be returned.
374 ON_CALL(item(), GetMimeType()).WillByDefault(Return("image/png"));
375 EXPECT_TRUE(model().HasSupportedImageMimeType());
376
377 // An unsupported MIME type should result in false being returned...
378 ON_CALL(item(), GetMimeType()).WillByDefault(Return("image/unsupported"));
379 EXPECT_FALSE(model().HasSupportedImageMimeType());
380
381 // ... unless the target path has a well-known image extension.
382 const base::FilePath kImagePath(FILE_PATH_LITERAL("/foo/image.png"));
383 ON_CALL(item(), GetTargetFilePath()).WillByDefault(ReturnRef(kImagePath));
384 EXPECT_TRUE(model().HasSupportedImageMimeType());
385
386 // .txt and missing extensions should also result in false being returned.
387 const base::FilePath kTextPath(FILE_PATH_LITERAL("/foo/image.txt"));
388 ON_CALL(item(), GetTargetFilePath()).WillByDefault(ReturnRef(kTextPath));
389 EXPECT_FALSE(model().HasSupportedImageMimeType());
390
391 const base::FilePath kNoExtensionPath(FILE_PATH_LITERAL("/foo/image."));
392 ON_CALL(item(), GetTargetFilePath())
393 .WillByDefault(ReturnRef(kNoExtensionPath));
394 EXPECT_FALSE(model().HasSupportedImageMimeType());
395 }
396
TEST_F(DownloadItemModelTest,ShouldRemoveFromShelfWhenComplete)397 TEST_F(DownloadItemModelTest, ShouldRemoveFromShelfWhenComplete) {
398 const struct TestCase {
399 DownloadItem::DownloadState state;
400 bool is_dangerous; // Expectation for IsDangerous().
401 bool is_auto_open; // Expectation for GetOpenWhenComplete().
402 bool auto_opened; // Whether the download was successfully
403 // auto-opened. Expecation for GetAutoOpened().
404 bool expected_result;
405 } kTestCases[] = {
406 // All the valid combinations of state, is_dangerous, is_auto_open and
407 // auto_opened.
408 //
409 // .--- Is dangerous.
410 // | .--- Auto open or temporary.
411 // | | .--- Auto opened.
412 // | | | .--- Expected result.
413 { DownloadItem::IN_PROGRESS, false, false, false, false},
414 { DownloadItem::IN_PROGRESS, false, true , false, true },
415 { DownloadItem::IN_PROGRESS, true , false, false, false},
416 { DownloadItem::IN_PROGRESS, true , true , false, false},
417 { DownloadItem::COMPLETE, false, false, false, false},
418 { DownloadItem::COMPLETE, false, true , false, false},
419 { DownloadItem::COMPLETE, false, false, true , true },
420 { DownloadItem::COMPLETE, false, true , true , true },
421 { DownloadItem::CANCELLED, false, false, false, false},
422 { DownloadItem::CANCELLED, false, true , false, false},
423 { DownloadItem::CANCELLED, true , false, false, false},
424 { DownloadItem::CANCELLED, true , true , false, false},
425 { DownloadItem::INTERRUPTED, false, false, false, false},
426 { DownloadItem::INTERRUPTED, false, true , false, false},
427 { DownloadItem::INTERRUPTED, true , false, false, false},
428 { DownloadItem::INTERRUPTED, true , true , false, false}
429 };
430
431 SetupDownloadItemDefaults();
432
433 for (const auto& test_case : kTestCases) {
434 EXPECT_CALL(item(), GetOpenWhenComplete())
435 .WillRepeatedly(Return(test_case.is_auto_open));
436 EXPECT_CALL(item(), GetState())
437 .WillRepeatedly(Return(test_case.state));
438 EXPECT_CALL(item(), IsDangerous())
439 .WillRepeatedly(Return(test_case.is_dangerous));
440 EXPECT_CALL(item(), GetAutoOpened())
441 .WillRepeatedly(Return(test_case.auto_opened));
442
443 EXPECT_EQ(test_case.expected_result,
444 model().ShouldRemoveFromShelfWhenComplete());
445 Mock::VerifyAndClearExpectations(&item());
446 Mock::VerifyAndClearExpectations(&model());
447 }
448 }
449
TEST_F(DownloadItemModelTest,ShouldShowDropdown)450 TEST_F(DownloadItemModelTest, ShouldShowDropdown) {
451 // A few aliases for DownloadDangerTypes since the full names are fairly
452 // verbose.
453 download::DownloadDangerType safe =
454 download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
455 download::DownloadDangerType dangerous_file =
456 download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE;
457 download::DownloadDangerType dangerous_content =
458 download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT;
459 download::DownloadDangerType blocked_encrypted =
460 download::DOWNLOAD_DANGER_TYPE_BLOCKED_PASSWORD_PROTECTED;
461 download::DownloadDangerType blocked_too_large =
462 download::DOWNLOAD_DANGER_TYPE_BLOCKED_TOO_LARGE;
463 download::DownloadDangerType blocked_sensitive =
464 download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_BLOCK;
465 download::DownloadDangerType blocked_filetype =
466 download::DOWNLOAD_DANGER_TYPE_BLOCKED_UNSUPPORTED_FILETYPE;
467
468 const struct TestCase {
469 DownloadItem::DownloadState state; // Expectation for GetState()
470 download::DownloadDangerType danger_type; // Expectation for GetDangerType()
471 bool is_dangerous; // Expectation for IsDangerous()
472 bool expected_result;
473 } kTestCases[] = {
474 // .--- Is dangerous.
475 // Download state Danger type | .--- Expected result.
476 {DownloadItem::COMPLETE, safe, false, true},
477 {DownloadItem::COMPLETE, dangerous_file, true, false},
478 {DownloadItem::CANCELLED, dangerous_file, true, true},
479 {DownloadItem::COMPLETE, dangerous_content, true, true},
480 {DownloadItem::COMPLETE, blocked_encrypted, true, false},
481 {DownloadItem::COMPLETE, blocked_too_large, true, false},
482 {DownloadItem::COMPLETE, blocked_sensitive, true, false},
483 {DownloadItem::COMPLETE, blocked_filetype, true, false},
484 };
485
486 SetupDownloadItemDefaults();
487
488 for (const auto& test_case : kTestCases) {
489 EXPECT_CALL(item(), GetState()).WillRepeatedly(Return(test_case.state));
490 EXPECT_CALL(item(), GetDangerType())
491 .WillRepeatedly(Return(test_case.danger_type));
492 EXPECT_CALL(item(), IsDangerous())
493 .WillRepeatedly(Return(test_case.is_dangerous));
494
495 EXPECT_EQ(test_case.expected_result, model().ShouldShowDropdown());
496 Mock::VerifyAndClearExpectations(&item());
497 Mock::VerifyAndClearExpectations(&model());
498 }
499 }
500