Give names to all utility processes.
[chromium-blink-merge.git] / chrome / browser / download / download_item_model_unittest.cc
blobec13f652971ab78abef8db14d2c109e2024844ec
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 "chrome/browser/download/download_item_model.h"
7 #include <vector>
9 #include "base/i18n/rtl.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "content/public/test/mock_download_item.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "ui/base/resource/resource_bundle.h"
19 #include "ui/base/text/bytes_formatting.h"
20 #include "ui/gfx/font_list.h"
21 #include "ui/gfx/text_utils.h"
23 using content::DownloadItem;
24 using ::testing::Mock;
25 using ::testing::NiceMock;
26 using ::testing::Return;
27 using ::testing::ReturnRefOfCopy;
28 using ::testing::SetArgPointee;
29 using ::testing::_;
31 namespace {
33 // Create a char array that has as many elements as there are download
34 // interrupt reasons. We can then use that in a static_assert to make sure
35 // that all the interrupt reason codes are accounted for. The reason codes are
36 // unfortunately sparse, making this necessary.
37 char kInterruptReasonCounter[] = {
38 0, // content::DOWNLOAD_INTERRUPT_REASON_NONE
39 #define INTERRUPT_REASON(name,value) 0,
40 #include "content/public/browser/download_interrupt_reason_values.h"
41 #undef INTERRUPT_REASON
43 const size_t kInterruptReasonCount = arraysize(kInterruptReasonCounter);
45 // Default target path for a mock download item in DownloadItemModelTest.
46 const base::FilePath::CharType kDefaultTargetFilePath[] =
47 FILE_PATH_LITERAL("/foo/bar/foo.bar");
49 const base::FilePath::CharType kDefaultDisplayFileName[] =
50 FILE_PATH_LITERAL("foo.bar");
52 // Default URL for a mock download item in DownloadItemModelTest.
53 const char kDefaultURL[] = "http://example.com/foo.bar";
55 class DownloadItemModelTest : public testing::Test {
56 public:
57 DownloadItemModelTest()
58 : model_(&item_) {}
60 virtual ~DownloadItemModelTest() {
63 protected:
64 // Sets up defaults for the download item and sets |model_| to a new
65 // DownloadItemModel that uses the mock download item.
66 void SetupDownloadItemDefaults() {
67 ON_CALL(item_, GetReceivedBytes()).WillByDefault(Return(1));
68 ON_CALL(item_, GetTotalBytes()).WillByDefault(Return(2));
69 ON_CALL(item_, TimeRemaining(_)).WillByDefault(Return(false));
70 ON_CALL(item_, GetMimeType()).WillByDefault(Return("text/html"));
71 ON_CALL(item_, AllDataSaved()).WillByDefault(Return(false));
72 ON_CALL(item_, GetOpenWhenComplete()).WillByDefault(Return(false));
73 ON_CALL(item_, GetFileExternallyRemoved()).WillByDefault(Return(false));
74 ON_CALL(item_, GetState())
75 .WillByDefault(Return(DownloadItem::IN_PROGRESS));
76 ON_CALL(item_, GetURL())
77 .WillByDefault(ReturnRefOfCopy(GURL(kDefaultURL)));
78 ON_CALL(item_, GetFileNameToReportUser())
79 .WillByDefault(Return(base::FilePath(kDefaultDisplayFileName)));
80 ON_CALL(item_, GetTargetFilePath())
81 .WillByDefault(ReturnRefOfCopy(base::FilePath(kDefaultTargetFilePath)));
82 ON_CALL(item_, GetTargetDisposition())
83 .WillByDefault(
84 Return(DownloadItem::TARGET_DISPOSITION_OVERWRITE));
85 ON_CALL(item_, IsPaused()).WillByDefault(Return(false));
88 void SetupInterruptedDownloadItem(content::DownloadInterruptReason reason) {
89 EXPECT_CALL(item_, GetLastReason()).WillRepeatedly(Return(reason));
90 EXPECT_CALL(item_, GetState())
91 .WillRepeatedly(Return(
92 (reason == content::DOWNLOAD_INTERRUPT_REASON_NONE) ?
93 DownloadItem::IN_PROGRESS :
94 DownloadItem::INTERRUPTED));
97 content::MockDownloadItem& item() {
98 return item_;
101 DownloadItemModel& model() {
102 return model_;
105 private:
106 NiceMock<content::MockDownloadItem> item_;
107 DownloadItemModel model_;
110 } // namespace
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 content::DownloadInterruptReason reason;
119 // Expected status string. This will include the progress as well.
120 const char* expected_status;
121 } kTestCases[] = {
122 { content::DOWNLOAD_INTERRUPT_REASON_NONE,
123 "1/2 B" },
124 { content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
125 "Failed - Download error" },
126 { content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
127 "Failed - Insufficient permissions" },
128 { content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
129 "Failed - Disk full" },
130 { content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG,
131 "Failed - Path too long" },
132 { content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE,
133 "Failed - File too large" },
134 { content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED,
135 "Failed - Virus detected" },
136 { content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED,
137 "Failed - Blocked" },
138 { content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED,
139 "Failed - Virus scan failed" },
140 { content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT,
141 "Failed - File truncated" },
142 { content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR,
143 "Failed - System busy" },
144 { content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
145 "Failed - Network error" },
146 { content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT,
147 "Failed - Network timeout" },
148 { content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED,
149 "Failed - Network disconnected" },
150 { content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN,
151 "Failed - Server unavailable" },
152 { content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST,
153 "Failed - Network error" },
154 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED,
155 "Failed - Server problem" },
156 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE,
157 "Failed - Download error" },
158 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION,
159 "Failed - Download error" },
160 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
161 "Failed - No file" },
162 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED,
163 "Failed - Needs authorization" },
164 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM,
165 "Failed - Bad certificate" },
166 { content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED,
167 "Canceled" },
168 { content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN,
169 "Failed - Shutdown" },
170 { content::DOWNLOAD_INTERRUPT_REASON_CRASH,
171 "Failed - Crash" },
173 static_assert(kInterruptReasonCount == arraysize(kTestCases),
174 "interrupt reason mismatch");
176 SetupDownloadItemDefaults();
177 for (unsigned i = 0; i < arraysize(kTestCases); ++i) {
178 const TestCase& test_case = kTestCases[i];
179 SetupInterruptedDownloadItem(test_case.reason);
180 EXPECT_STREQ(test_case.expected_status,
181 base::UTF16ToUTF8(model().GetStatusText()).c_str());
185 // Note: This test is currently skipped on Android. See http://crbug.com/139398
186 TEST_F(DownloadItemModelTest, InterruptTooltip) {
187 // Test that we have the correct interrupt tooltip for downloads that are in
188 // the INTERRUPTED state.
189 const struct TestCase {
190 // The reason.
191 content::DownloadInterruptReason reason;
193 // Expected tooltip text. The tooltip text for interrupted downloads
194 // typically consist of two lines. One for the filename and one for the
195 // interrupt reason. The returned string contains a newline.
196 const char* expected_tooltip;
197 } kTestCases[] = {
198 { content::DOWNLOAD_INTERRUPT_REASON_NONE,
199 "foo.bar" },
200 { content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
201 "foo.bar\nDownload error" },
202 { content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
203 "foo.bar\nInsufficient permissions" },
204 { content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
205 "foo.bar\nDisk full" },
206 { content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG,
207 "foo.bar\nPath too long" },
208 { content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE,
209 "foo.bar\nFile too large" },
210 { content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED,
211 "foo.bar\nVirus detected" },
212 { content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED,
213 "foo.bar\nBlocked" },
214 { content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED,
215 "foo.bar\nVirus scan failed" },
216 { content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT,
217 "foo.bar\nFile truncated" },
218 { content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR,
219 "foo.bar\nSystem busy" },
220 { content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
221 "foo.bar\nNetwork error" },
222 { content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT,
223 "foo.bar\nNetwork timeout" },
224 { content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED,
225 "foo.bar\nNetwork disconnected" },
226 { content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN,
227 "foo.bar\nServer unavailable" },
228 { content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST,
229 "foo.bar\nNetwork error" },
230 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED,
231 "foo.bar\nServer problem" },
232 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE,
233 "foo.bar\nDownload error" },
234 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION,
235 "foo.bar\nDownload error" },
236 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
237 "foo.bar\nNo file" },
238 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED,
239 "foo.bar\nNeeds authorization" },
240 { content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM,
241 "foo.bar\nBad certificate" },
242 { content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED,
243 "foo.bar" },
244 { content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN,
245 "foo.bar\nShutdown" },
246 { content::DOWNLOAD_INTERRUPT_REASON_CRASH,
247 "foo.bar\nCrash" },
249 static_assert(kInterruptReasonCount == arraysize(kTestCases),
250 "interrupt reason mismatch");
252 // Large tooltip width. Should be large enough to accommodate the entire
253 // tooltip without truncation.
254 const int kLargeTooltipWidth = 1000;
256 // Small tooltip width. Small enough to require truncation of most
257 // tooltips. Used to test eliding logic.
258 const int kSmallTooltipWidth = 40;
260 const gfx::FontList& font_list =
261 ui::ResourceBundle::GetSharedInstance().GetFontList(
262 ui::ResourceBundle::BaseFont);
263 SetupDownloadItemDefaults();
264 for (unsigned i = 0; i < arraysize(kTestCases); ++i) {
265 const TestCase& test_case = kTestCases[i];
266 SetupInterruptedDownloadItem(test_case.reason);
268 // GetTooltipText() elides the tooltip so that the text would fit within a
269 // given width. The following test would fail if kLargeTooltipWidth isn't
270 // large enough to accomodate all the strings.
271 EXPECT_STREQ(
272 test_case.expected_tooltip,
273 base::UTF16ToUTF8(model().GetTooltipText(font_list,
274 kLargeTooltipWidth)).c_str());
276 // Check that if the width is small, the returned tooltip only contains
277 // lines of the given width or smaller.
278 std::vector<base::string16> lines;
279 base::string16 truncated_tooltip =
280 model().GetTooltipText(font_list, kSmallTooltipWidth);
281 Tokenize(truncated_tooltip, base::ASCIIToUTF16("\n"), &lines);
282 for (unsigned i = 0; i < lines.size(); ++i)
283 EXPECT_GE(kSmallTooltipWidth, gfx::GetStringWidth(lines[i], font_list));
287 TEST_F(DownloadItemModelTest, InProgressStatus) {
288 const struct TestCase {
289 int64 received_bytes; // Return value of GetReceivedBytes().
290 int64 total_bytes; // Return value of GetTotalBytes().
291 bool time_remaining_known; // If TimeRemaining() is known.
292 bool open_when_complete; // GetOpenWhenComplete().
293 bool is_paused; // IsPaused().
294 const char* expected_status; // Expected status text.
295 } kTestCases[] = {
296 // These are all the valid combinations of the above fields for a download
297 // that is in IN_PROGRESS state. Go through all of them and check the return
298 // value of DownloadItemModel::GetStatusText(). The point isn't to lock down
299 // the status strings, but to make sure we end up with something sane for
300 // all the circumstances we care about.
302 // For GetReceivedBytes()/GetTotalBytes(), we only check whether each is
303 // non-zero. In addition, if |total_bytes| is zero, then
304 // |time_remaining_known| is also false.
306 // .-- .TimeRemaining() is known.
307 // | .-- .GetOpenWhenComplete()
308 // | | .---- .IsPaused()
309 { 0, 0, false, false, false, "Starting..." },
310 { 1, 0, false, false, false, "1 B" },
311 { 0, 2, false, false, false, "Starting..." },
312 { 1, 2, false, false, false, "1/2 B" },
313 { 0, 2, true, false, false, "0/2 B, 10 secs left" },
314 { 1, 2, true, false, false, "1/2 B, 10 secs left" },
315 { 0, 0, false, true, false, "Opening when complete" },
316 { 1, 0, false, true, false, "Opening when complete" },
317 { 0, 2, false, true, false, "Opening when complete" },
318 { 1, 2, false, true, false, "Opening when complete" },
319 { 0, 2, true, true, false, "Opening in 10 secs..." },
320 { 1, 2, true, true, false, "Opening in 10 secs..." },
321 { 0, 0, false, false, true, "0 B, Paused" },
322 { 1, 0, false, false, true, "1 B, Paused" },
323 { 0, 2, false, false, true, "0/2 B, Paused" },
324 { 1, 2, false, false, true, "1/2 B, Paused" },
325 { 0, 2, true, false, true, "0/2 B, Paused" },
326 { 1, 2, true, false, true, "1/2 B, Paused" },
327 { 0, 0, false, true, true, "0 B, Paused" },
328 { 1, 0, false, true, true, "1 B, Paused" },
329 { 0, 2, false, true, true, "0/2 B, Paused" },
330 { 1, 2, false, true, true, "1/2 B, Paused" },
331 { 0, 2, true, true, true, "0/2 B, Paused" },
332 { 1, 2, true, true, true, "1/2 B, Paused" },
335 SetupDownloadItemDefaults();
337 for (unsigned i = 0; i < arraysize(kTestCases); i++) {
338 const TestCase& test_case = kTestCases[i];
339 Mock::VerifyAndClearExpectations(&item());
340 Mock::VerifyAndClearExpectations(&model());
341 EXPECT_CALL(item(), GetReceivedBytes())
342 .WillRepeatedly(Return(test_case.received_bytes));
343 EXPECT_CALL(item(), GetTotalBytes())
344 .WillRepeatedly(Return(test_case.total_bytes));
345 EXPECT_CALL(item(), TimeRemaining(_))
346 .WillRepeatedly(testing::DoAll(
347 testing::SetArgPointee<0>(base::TimeDelta::FromSeconds(10)),
348 Return(test_case.time_remaining_known)));
349 EXPECT_CALL(item(), GetOpenWhenComplete())
350 .WillRepeatedly(Return(test_case.open_when_complete));
351 EXPECT_CALL(item(), IsPaused())
352 .WillRepeatedly(Return(test_case.is_paused));
354 EXPECT_STREQ(test_case.expected_status,
355 base::UTF16ToUTF8(model().GetStatusText()).c_str());
359 TEST_F(DownloadItemModelTest, ShouldShowInShelf) {
360 SetupDownloadItemDefaults();
362 // By default the download item should be displayable on the shelf.
363 EXPECT_TRUE(model().ShouldShowInShelf());
365 // Once explicitly set, ShouldShowInShelf() should return the explicit value.
366 model().SetShouldShowInShelf(false);
367 EXPECT_FALSE(model().ShouldShowInShelf());
369 model().SetShouldShowInShelf(true);
370 EXPECT_TRUE(model().ShouldShowInShelf());
373 TEST_F(DownloadItemModelTest, ShouldRemoveFromShelfWhenComplete) {
374 const struct TestCase {
375 DownloadItem::DownloadState state;
376 bool is_dangerous; // Expectation for IsDangerous().
377 bool is_auto_open; // Expectation for GetOpenWhenComplete().
378 bool auto_opened; // Whether the download was successfully
379 // auto-opened. Expecation for GetAutoOpened().
380 bool expected_result;
381 } kTestCases[] = {
382 // All the valid combinations of state, is_dangerous, is_auto_open and
383 // auto_opened.
385 // .--- Is dangerous.
386 // | .--- Auto open or temporary.
387 // | | .--- Auto opened.
388 // | | | .--- Expected result.
389 { DownloadItem::IN_PROGRESS, false, false, false, false},
390 { DownloadItem::IN_PROGRESS, false, true , false, true },
391 { DownloadItem::IN_PROGRESS, true , false, false, false},
392 { DownloadItem::IN_PROGRESS, true , true , false, false},
393 { DownloadItem::COMPLETE, false, false, false, false},
394 { DownloadItem::COMPLETE, false, true , false, false},
395 { DownloadItem::COMPLETE, false, false, true , true },
396 { DownloadItem::COMPLETE, false, true , true , true },
397 { DownloadItem::CANCELLED, false, false, false, false},
398 { DownloadItem::CANCELLED, false, true , false, false},
399 { DownloadItem::CANCELLED, true , false, false, false},
400 { DownloadItem::CANCELLED, true , true , false, false},
401 { DownloadItem::INTERRUPTED, false, false, false, false},
402 { DownloadItem::INTERRUPTED, false, true , false, false},
403 { DownloadItem::INTERRUPTED, true , false, false, false},
404 { DownloadItem::INTERRUPTED, true , true , false, false}
407 SetupDownloadItemDefaults();
409 for (unsigned i = 0; i < arraysize(kTestCases); i++) {
410 const TestCase& test_case = kTestCases[i];
411 EXPECT_CALL(item(), GetOpenWhenComplete())
412 .WillRepeatedly(Return(test_case.is_auto_open));
413 EXPECT_CALL(item(), GetState())
414 .WillRepeatedly(Return(test_case.state));
415 EXPECT_CALL(item(), IsDangerous())
416 .WillRepeatedly(Return(test_case.is_dangerous));
417 EXPECT_CALL(item(), GetAutoOpened())
418 .WillRepeatedly(Return(test_case.auto_opened));
420 EXPECT_EQ(test_case.expected_result,
421 model().ShouldRemoveFromShelfWhenComplete())
422 << "Test case: " << i;
423 Mock::VerifyAndClearExpectations(&item());
424 Mock::VerifyAndClearExpectations(&model());