Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / download / download_target_determiner_unittest.cc
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 "base/at_exit.h"
6 #include "base/files/file_path.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/observer_list.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/run_loop.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "base/value_conversions.h"
15 #include "chrome/browser/download/chrome_download_manager_delegate.h"
16 #include "chrome/browser/download/download_extensions.h"
17 #include "chrome/browser/download/download_prefs.h"
18 #include "chrome/browser/download/download_target_determiner.h"
19 #include "chrome/browser/download/download_target_info.h"
20 #include "chrome/browser/history/history_service.h"
21 #include "chrome/browser/history/history_service_factory.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
24 #include "chrome/test/base/testing_pref_service_syncable.h"
25 #include "chrome/test/base/testing_profile.h"
26 #include "components/history/core/browser/history_types.h"
27 #include "content/public/browser/download_interrupt_reasons.h"
28 #include "content/public/browser/render_process_host.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/browser/web_contents_delegate.h"
31 #include "content/public/test/mock_download_item.h"
32 #include "content/public/test/test_renderer_host.h"
33 #include "content/public/test/web_contents_tester.h"
34 #include "net/base/mime_util.h"
35 #include "testing/gmock/include/gmock/gmock.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37
38 #if defined(ENABLE_PLUGINS)
39 #include "content/public/browser/plugin_service.h"
40 #include "content/public/browser/plugin_service_filter.h"
41 #include "content/public/common/webplugininfo.h"
42 #endif
43
44 #if defined(ENABLE_EXTENSIONS)
45 #include "extensions/common/extension.h"
46 #endif
47
48 using ::testing::AnyNumber;
49 using ::testing::Invoke;
50 using ::testing::Ref;
51 using ::testing::Return;
52 using ::testing::ReturnRef;
53 using ::testing::ReturnRefOfCopy;
54 using ::testing::Truly;
55 using ::testing::WithArg;
56 using ::testing::_;
57 using content::DownloadItem;
58
59 namespace {
60
61 // No-op delegate.
62 class NullWebContentsDelegate : public content::WebContentsDelegate {
63  public:
64   NullWebContentsDelegate() {}
65   ~NullWebContentsDelegate() override {}
66 };
67
68 // Google Mock action that posts a task to the current message loop that invokes
69 // the first argument of the mocked method as a callback. Said argument must be
70 // a base::Callback<void(ParamType)>. |result| must be of |ParamType| and is
71 // bound as that parameter.
72 // Example:
73 //   class FooClass {
74 //    public:
75 //     virtual void Foo(base::Callback<void(bool)> callback);
76 //   };
77 //   ...
78 //   EXPECT_CALL(mock_fooclass_instance, Foo(callback))
79 //     .WillOnce(ScheduleCallback(false));
80 ACTION_P(ScheduleCallback, result0) {
81   base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(arg0, result0));
82 }
83
84 // Similar to ScheduleCallback, but binds 2 arguments.
85 ACTION_P2(ScheduleCallback2, result0, result1) {
86   base::MessageLoop::current()->PostTask(
87       FROM_HERE, base::Bind(arg0, result0, result1));
88 }
89
90 // Used with DownloadTestCase. Indicates the type of test case. The expectations
91 // for the test is set based on the type.
92 enum TestCaseType {
93   SAVE_AS,
94   AUTOMATIC,
95   FORCED  // Requires that forced_file_path be non-empty.
96 };
97
98 // Used with DownloadTestCase. Type of intermediate filename to expect.
99 enum TestCaseExpectIntermediate {
100   EXPECT_CRDOWNLOAD,   // Expect path/to/target.crdownload.
101   EXPECT_UNCONFIRMED,  // Expect path/to/Unconfirmed xxx.crdownload.
102   EXPECT_LOCAL_PATH,   // Expect target path.
103 };
104
105 // Typical download test case. Used with
106 // DownloadTargetDeterminerTest::RunTestCase().
107 struct DownloadTestCase {
108   // Type of test.
109   TestCaseType test_type;
110
111   // Expected danger type. Verified at the end of target determination.
112   content::DownloadDangerType expected_danger_type;
113
114   // Value of DownloadItem::GetURL()
115   const char* url;
116
117   // Value of DownloadItem::GetMimeType()
118   const char* mime_type;
119
120   // Should be non-empty if |test_type| == FORCED. Value of GetForcedFilePath().
121   const base::FilePath::CharType* forced_file_path;
122
123   // Expected local path. Specified relative to the test download path.
124   const base::FilePath::CharType* expected_local_path;
125
126   // Expected target disposition. If this is TARGET_DISPOSITION_PROMPT, then the
127   // test run will expect ChromeDownloadManagerDelegate to prompt the user for a
128   // download location.
129   DownloadItem::TargetDisposition expected_disposition;
130
131   // Type of intermediate path to expect.
132   TestCaseExpectIntermediate expected_intermediate;
133 };
134
135 class MockDownloadTargetDeterminerDelegate
136     : public DownloadTargetDeterminerDelegate {
137  public:
138   MOCK_METHOD3(CheckDownloadUrl,
139                void(content::DownloadItem*, const base::FilePath&,
140                     const CheckDownloadUrlCallback&));
141   MOCK_METHOD3(NotifyExtensions,
142                void(content::DownloadItem*, const base::FilePath&,
143                     const NotifyExtensionsCallback&));
144   MOCK_METHOD3(PromptUserForDownloadPath,
145                void(content::DownloadItem*, const base::FilePath&,
146                     const FileSelectedCallback&));
147   MOCK_METHOD3(DetermineLocalPath,
148                void(DownloadItem*, const base::FilePath&,
149                     const LocalPathCallback&));
150   MOCK_METHOD5(ReserveVirtualPath,
151                void(DownloadItem*, const base::FilePath&, bool,
152                     DownloadPathReservationTracker::FilenameConflictAction,
153                     const ReservedPathCallback&));
154   MOCK_METHOD2(GetFileMimeType,
155                void(const base::FilePath&,
156                     const GetFileMimeTypeCallback&));
157
158   void SetupDefaults() {
159     ON_CALL(*this, CheckDownloadUrl(_, _, _))
160         .WillByDefault(WithArg<2>(
161             ScheduleCallback(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)));
162     ON_CALL(*this, NotifyExtensions(_, _, _))
163         .WillByDefault(WithArg<2>(
164             ScheduleCallback2(base::FilePath(),
165                               DownloadPathReservationTracker::UNIQUIFY)));
166     ON_CALL(*this, ReserveVirtualPath(_, _, _, _, _))
167         .WillByDefault(Invoke(
168             &MockDownloadTargetDeterminerDelegate::NullReserveVirtualPath));
169     ON_CALL(*this, PromptUserForDownloadPath(_, _, _))
170         .WillByDefault(Invoke(
171             &MockDownloadTargetDeterminerDelegate::NullPromptUser));
172     ON_CALL(*this, DetermineLocalPath(_, _, _))
173         .WillByDefault(Invoke(
174             &MockDownloadTargetDeterminerDelegate::NullDetermineLocalPath));
175     ON_CALL(*this, GetFileMimeType(_, _))
176         .WillByDefault(WithArg<1>(
177             ScheduleCallback("")));
178   }
179  private:
180   static void NullReserveVirtualPath(
181       DownloadItem* download,
182       const base::FilePath& virtual_path,
183       bool create_directory,
184       DownloadPathReservationTracker::FilenameConflictAction conflict_action,
185       const DownloadTargetDeterminerDelegate::ReservedPathCallback& callback);
186   static void NullPromptUser(
187       DownloadItem* download, const base::FilePath& suggested_path,
188       const FileSelectedCallback& callback);
189   static void NullDetermineLocalPath(
190       DownloadItem* download, const base::FilePath& virtual_path,
191       const LocalPathCallback& callback);
192 };
193
194 class DownloadTargetDeterminerTest : public ChromeRenderViewHostTestHarness {
195  public:
196   // ::testing::Test
197   virtual void SetUp() override;
198   virtual void TearDown() override;
199
200   // Creates MockDownloadItem and sets up default expectations.
201   content::MockDownloadItem* CreateActiveDownloadItem(
202       int32 id,
203       const DownloadTestCase& test_case);
204
205   // Sets the AutoOpenBasedOnExtension user preference for |path|.
206   void EnableAutoOpenBasedOnExtension(const base::FilePath& path);
207
208   // Set the kDownloadDefaultDirectory managed preference to |path|.
209   void SetManagedDownloadPath(const base::FilePath& path);
210
211   // Set the kPromptForDownload user preference to |prompt|.
212   void SetPromptForDownload(bool prompt);
213
214   // Given the relative path |path|, returns the full path under the temporary
215   // downloads directory.
216   base::FilePath GetPathInDownloadDir(const base::FilePath::StringType& path);
217
218   // Run |test_case| using |item|.
219   void RunTestCase(const DownloadTestCase& test_case,
220                    const base::FilePath& initial_virtual_path,
221                    content::MockDownloadItem* item);
222
223   // Runs |test_case| with |item|. When the DownloadTargetDeterminer is done,
224   // returns the resulting DownloadTargetInfo.
225   scoped_ptr<DownloadTargetInfo> RunDownloadTargetDeterminer(
226       const base::FilePath& initial_virtual_path,
227       content::MockDownloadItem* item);
228
229   // Run through |test_case_count| tests in |test_cases|. A new MockDownloadItem
230   // will be created for each test case and destroyed when the test case is
231   // complete.
232   void RunTestCasesWithActiveItem(const DownloadTestCase test_cases[],
233                                   size_t test_case_count);
234
235   // Verifies that |target_path|, |disposition|, |expected_danger_type| and
236   // |intermediate_path| matches the expectations of |test_case|. Posts
237   // |closure| to the current message loop when done.
238   void VerifyDownloadTarget(const DownloadTestCase& test_case,
239                             const DownloadTargetInfo* target_info);
240
241   const base::FilePath& test_download_dir() const {
242     return test_download_dir_.path();
243   }
244
245   const base::FilePath& test_virtual_dir() const {
246     return test_virtual_dir_;
247   }
248
249   MockDownloadTargetDeterminerDelegate* delegate() {
250     return &delegate_;
251   }
252
253   DownloadPrefs* download_prefs() {
254     return download_prefs_.get();
255   }
256
257  private:
258   scoped_ptr<DownloadPrefs> download_prefs_;
259   ::testing::NiceMock<MockDownloadTargetDeterminerDelegate> delegate_;
260   NullWebContentsDelegate web_contents_delegate_;
261   base::ScopedTempDir test_download_dir_;
262   base::FilePath test_virtual_dir_;
263 };
264
265 void DownloadTargetDeterminerTest::SetUp() {
266   ChromeRenderViewHostTestHarness::SetUp();
267   CHECK(profile());
268   download_prefs_.reset(new DownloadPrefs(profile()));
269   web_contents()->SetDelegate(&web_contents_delegate_);
270   ASSERT_TRUE(test_download_dir_.CreateUniqueTempDir());
271   test_virtual_dir_ = test_download_dir().Append(FILE_PATH_LITERAL("virtual"));
272   download_prefs_->SetDownloadPath(test_download_dir());
273   delegate_.SetupDefaults();
274 }
275
276 void DownloadTargetDeterminerTest::TearDown() {
277   download_prefs_.reset();
278   ChromeRenderViewHostTestHarness::TearDown();
279 }
280
281 content::MockDownloadItem*
282 DownloadTargetDeterminerTest::CreateActiveDownloadItem(
283     int32 id,
284     const DownloadTestCase& test_case) {
285   content::MockDownloadItem* item =
286       new ::testing::NiceMock<content::MockDownloadItem>();
287   GURL download_url(test_case.url);
288   std::vector<GURL> url_chain;
289   url_chain.push_back(download_url);
290   base::FilePath forced_file_path =
291       GetPathInDownloadDir(test_case.forced_file_path);
292   DownloadItem::TargetDisposition initial_disposition =
293       (test_case.test_type == SAVE_AS) ?
294       DownloadItem::TARGET_DISPOSITION_PROMPT :
295       DownloadItem::TARGET_DISPOSITION_OVERWRITE;
296   EXPECT_EQ(test_case.test_type == FORCED,
297             !forced_file_path.empty());
298
299   ON_CALL(*item, GetBrowserContext())
300       .WillByDefault(Return(profile()));
301   ON_CALL(*item, GetDangerType())
302       .WillByDefault(Return(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS));
303   ON_CALL(*item, GetForcedFilePath())
304       .WillByDefault(ReturnRefOfCopy(forced_file_path));
305   ON_CALL(*item, GetFullPath())
306       .WillByDefault(ReturnRefOfCopy(base::FilePath()));
307   ON_CALL(*item, GetHash())
308       .WillByDefault(ReturnRefOfCopy(std::string()));
309   ON_CALL(*item, GetId())
310       .WillByDefault(Return(id));
311   ON_CALL(*item, GetLastReason())
312       .WillByDefault(Return(content::DOWNLOAD_INTERRUPT_REASON_NONE));
313   ON_CALL(*item, GetMimeType())
314       .WillByDefault(Return(test_case.mime_type));
315   ON_CALL(*item, GetReferrerUrl())
316       .WillByDefault(ReturnRefOfCopy(download_url));
317   ON_CALL(*item, GetState())
318       .WillByDefault(Return(DownloadItem::IN_PROGRESS));
319   ON_CALL(*item, GetTargetDisposition())
320       .WillByDefault(Return(initial_disposition));
321   ON_CALL(*item, GetTargetFilePath())
322       .WillByDefault(ReturnRefOfCopy(base::FilePath()));
323   ON_CALL(*item, GetTransitionType())
324       .WillByDefault(Return(ui::PAGE_TRANSITION_LINK));
325   ON_CALL(*item, GetURL())
326       .WillByDefault(ReturnRefOfCopy(download_url));
327   ON_CALL(*item, GetUrlChain())
328       .WillByDefault(ReturnRefOfCopy(url_chain));
329   ON_CALL(*item, GetWebContents())
330       .WillByDefault(Return(web_contents()));
331   ON_CALL(*item, HasUserGesture())
332       .WillByDefault(Return(true));
333   ON_CALL(*item, IsDangerous())
334       .WillByDefault(Return(false));
335   ON_CALL(*item, IsTemporary())
336       .WillByDefault(Return(false));
337   return item;
338 }
339
340 void DownloadTargetDeterminerTest::EnableAutoOpenBasedOnExtension(
341     const base::FilePath& path) {
342   EXPECT_TRUE(download_prefs_->EnableAutoOpenBasedOnExtension(path));
343 }
344
345 void DownloadTargetDeterminerTest::SetManagedDownloadPath(
346     const base::FilePath& path) {
347   profile()->GetTestingPrefService()->
348       SetManagedPref(prefs::kDownloadDefaultDirectory,
349                      base::CreateFilePathValue(path));
350 }
351
352 void DownloadTargetDeterminerTest::SetPromptForDownload(bool prompt) {
353   profile()->GetTestingPrefService()->
354       SetBoolean(prefs::kPromptForDownload, prompt);
355 }
356
357 base::FilePath DownloadTargetDeterminerTest::GetPathInDownloadDir(
358     const base::FilePath::StringType& relative_path) {
359   if (relative_path.empty())
360     return base::FilePath();
361   base::FilePath full_path(test_download_dir().Append(relative_path));
362   return full_path.NormalizePathSeparators();
363 }
364
365 void DownloadTargetDeterminerTest::RunTestCase(
366     const DownloadTestCase& test_case,
367     const base::FilePath& initial_virtual_path,
368     content::MockDownloadItem* item) {
369   scoped_ptr<DownloadTargetInfo> target_info =
370       RunDownloadTargetDeterminer(initial_virtual_path, item);
371   VerifyDownloadTarget(test_case, target_info.get());
372 }
373
374 void CompletionCallbackWrapper(
375     const base::Closure& closure,
376     scoped_ptr<DownloadTargetInfo>* target_info_receiver,
377     scoped_ptr<DownloadTargetInfo> target_info) {
378   target_info_receiver->swap(target_info);
379   base::MessageLoop::current()->PostTask(FROM_HERE, closure);
380 }
381
382 scoped_ptr<DownloadTargetInfo>
383 DownloadTargetDeterminerTest::RunDownloadTargetDeterminer(
384     const base::FilePath& initial_virtual_path,
385     content::MockDownloadItem* item) {
386   scoped_ptr<DownloadTargetInfo> target_info;
387   base::RunLoop run_loop;
388   DownloadTargetDeterminer::Start(
389       item, initial_virtual_path, download_prefs_.get(), delegate(),
390       base::Bind(&CompletionCallbackWrapper,
391                  run_loop.QuitClosure(),
392                  &target_info));
393   run_loop.Run();
394   ::testing::Mock::VerifyAndClearExpectations(delegate());
395   return target_info.Pass();
396 }
397
398 void DownloadTargetDeterminerTest::RunTestCasesWithActiveItem(
399     const DownloadTestCase test_cases[],
400     size_t test_case_count) {
401   for (size_t i = 0; i < test_case_count; ++i) {
402     scoped_ptr<content::MockDownloadItem> item(
403         CreateActiveDownloadItem(i, test_cases[i]));
404     SCOPED_TRACE(testing::Message() << "Running test case " << i);
405     RunTestCase(test_cases[i], base::FilePath(), item.get());
406   }
407 }
408
409 void DownloadTargetDeterminerTest::VerifyDownloadTarget(
410     const DownloadTestCase& test_case,
411     const DownloadTargetInfo* target_info) {
412   base::FilePath expected_local_path(
413       GetPathInDownloadDir(test_case.expected_local_path));
414   EXPECT_EQ(expected_local_path.value(), target_info->target_path.value());
415   EXPECT_EQ(test_case.expected_disposition, target_info->target_disposition);
416   EXPECT_EQ(test_case.expected_danger_type, target_info->danger_type);
417
418   switch (test_case.expected_intermediate) {
419     case EXPECT_CRDOWNLOAD:
420       EXPECT_EQ(DownloadTargetDeterminer::GetCrDownloadPath(
421                     target_info->target_path).value(),
422                 target_info->intermediate_path.value());
423       break;
424
425     case EXPECT_UNCONFIRMED:
426       // The paths (in English) look like: /path/Unconfirmed xxx.crdownload.
427       // Of this, we only check that the path is:
428       // 1. Not "/path/target.crdownload",
429       // 2. Points to the same directory as the target.
430       // 3. Has extension ".crdownload".
431       // 4. Basename starts with "Unconfirmed ".
432       EXPECT_NE(DownloadTargetDeterminer::GetCrDownloadPath(expected_local_path)
433                     .value(),
434                 target_info->intermediate_path.value());
435       EXPECT_EQ(expected_local_path.DirName().value(),
436                 target_info->intermediate_path.DirName().value());
437       EXPECT_TRUE(target_info->intermediate_path.MatchesExtension(
438           FILE_PATH_LITERAL(".crdownload")));
439       EXPECT_EQ(0u,
440                 target_info->intermediate_path.BaseName().value().find(
441                     FILE_PATH_LITERAL("Unconfirmed ")));
442       break;
443
444     case EXPECT_LOCAL_PATH:
445       EXPECT_EQ(expected_local_path.value(),
446                 target_info->intermediate_path.value());
447       break;
448   }
449 }
450
451 // static
452 void MockDownloadTargetDeterminerDelegate::NullReserveVirtualPath(
453     DownloadItem* download,
454     const base::FilePath& virtual_path,
455     bool create_directory,
456     DownloadPathReservationTracker::FilenameConflictAction conflict_action,
457     const DownloadTargetDeterminerDelegate::ReservedPathCallback& callback) {
458   callback.Run(virtual_path, true);
459 }
460
461 // static
462 void MockDownloadTargetDeterminerDelegate::NullPromptUser(
463     DownloadItem* download, const base::FilePath& suggested_path,
464     const FileSelectedCallback& callback) {
465   callback.Run(suggested_path);
466 }
467
468 // static
469 void MockDownloadTargetDeterminerDelegate::NullDetermineLocalPath(
470     DownloadItem* download, const base::FilePath& virtual_path,
471     const LocalPathCallback& callback) {
472   callback.Run(virtual_path);
473 }
474
475 // NotifyExtensions implementation that overrides the path so that the target
476 // file is in a subdirectory called 'overridden'. If the extension is '.remove',
477 // the extension is removed.
478 void NotifyExtensionsOverridePath(
479     content::DownloadItem* download,
480     const base::FilePath& path,
481     const DownloadTargetDeterminerDelegate::NotifyExtensionsCallback&
482         callback) {
483   base::FilePath new_path =
484       base::FilePath()
485       .AppendASCII("overridden")
486       .Append(path.BaseName());
487   if (new_path.MatchesExtension(FILE_PATH_LITERAL(".remove")))
488     new_path = new_path.RemoveExtension();
489   callback.Run(new_path, DownloadPathReservationTracker::UNIQUIFY);
490 }
491
492 void CheckDownloadUrlCheckExes(
493     content::DownloadItem* download,
494     const base::FilePath& path,
495     const DownloadTargetDeterminerDelegate::CheckDownloadUrlCallback&
496         callback) {
497   if (path.MatchesExtension(FILE_PATH_LITERAL(".exe")))
498     callback.Run(content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT);
499   else
500     callback.Run(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
501 }
502
503 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_Basic) {
504   const DownloadTestCase kBasicTestCases[] = {
505     {
506       // 0: Automatic Safe
507       AUTOMATIC,
508       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
509       "http://example.com/foo.txt", "text/plain",
510       FILE_PATH_LITERAL(""),
511
512       FILE_PATH_LITERAL("foo.txt"),
513       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
514
515       EXPECT_CRDOWNLOAD
516     },
517
518     {
519       // 1: Save_As Safe
520       SAVE_AS,
521       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
522       "http://example.com/foo.txt", "text/plain",
523       FILE_PATH_LITERAL(""),
524
525       FILE_PATH_LITERAL("foo.txt"),
526       DownloadItem::TARGET_DISPOSITION_PROMPT,
527
528       EXPECT_CRDOWNLOAD
529     },
530
531     {
532       // 2: Automatic Dangerous
533       AUTOMATIC,
534       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
535       "http://example.com/foo.crx", "",
536       FILE_PATH_LITERAL(""),
537
538       FILE_PATH_LITERAL("foo.crx"),
539       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
540
541       EXPECT_UNCONFIRMED
542     },
543
544     {
545       // 3: Forced Safe
546       FORCED,
547       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
548       "http://example.com/foo.txt", "",
549       FILE_PATH_LITERAL("forced-foo.txt"),
550
551       FILE_PATH_LITERAL("forced-foo.txt"),
552       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
553
554       EXPECT_LOCAL_PATH
555     },
556   };
557
558   // The test assumes that .crx files have a danger level of
559   // ALLOW_ON_USER_GESTURE.
560   ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE,
561             download_util::GetFileDangerLevel(
562                 base::FilePath(FILE_PATH_LITERAL("foo.crx"))));
563   RunTestCasesWithActiveItem(kBasicTestCases, arraysize(kBasicTestCases));
564 }
565
566 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_CancelSaveAs) {
567   const DownloadTestCase kCancelSaveAsTestCases[] = {
568     {
569       // 0: Save_As Safe, Cancelled.
570       SAVE_AS,
571       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
572       "http://example.com/foo.txt", "text/plain",
573       FILE_PATH_LITERAL(""),
574
575       FILE_PATH_LITERAL(""),
576       DownloadItem::TARGET_DISPOSITION_PROMPT,
577
578       EXPECT_LOCAL_PATH
579     }
580   };
581   ON_CALL(*delegate(), PromptUserForDownloadPath(_, _, _))
582       .WillByDefault(WithArg<2>(ScheduleCallback(base::FilePath())));
583   RunTestCasesWithActiveItem(kCancelSaveAsTestCases,
584                              arraysize(kCancelSaveAsTestCases));
585 }
586
587 // The SafeBrowsing check is performed early. Make sure that a download item
588 // that has been marked as DANGEROUS_URL behaves correctly.
589 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_DangerousUrl) {
590   const DownloadTestCase kSafeBrowsingTestCases[] = {
591     {
592       // 0: Automatic Dangerous URL
593       AUTOMATIC,
594       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
595       "http://phishing.example.com/foo.txt", "",
596       FILE_PATH_LITERAL(""),
597
598       FILE_PATH_LITERAL("foo.txt"),
599       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
600
601       EXPECT_UNCONFIRMED
602     },
603
604     {
605       // 1: Save As Dangerous URL
606       SAVE_AS,
607       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
608       "http://phishing.example.com/foo.txt", "",
609       FILE_PATH_LITERAL(""),
610
611       FILE_PATH_LITERAL("foo.txt"),
612       DownloadItem::TARGET_DISPOSITION_PROMPT,
613
614       EXPECT_UNCONFIRMED
615     },
616
617     {
618       // 2: Forced Dangerous URL
619       FORCED,
620       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
621       "http://phishing.example.com/foo.txt", "",
622       FILE_PATH_LITERAL("forced-foo.txt"),
623
624       FILE_PATH_LITERAL("forced-foo.txt"),
625       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
626
627       EXPECT_UNCONFIRMED
628     },
629
630     {
631       // 3: Automatic Dangerous URL + Dangerous file. Dangerous URL takes
632       // precedence.
633       AUTOMATIC,
634       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
635       "http://phishing.example.com/foo.html", "",
636       FILE_PATH_LITERAL(""),
637
638       FILE_PATH_LITERAL("foo.html"),
639       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
640
641       EXPECT_UNCONFIRMED
642     },
643
644     {
645       // 4: Save As Dangerous URL + Dangerous file
646       SAVE_AS,
647       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
648       "http://phishing.example.com/foo.html", "",
649       FILE_PATH_LITERAL(""),
650
651       FILE_PATH_LITERAL("foo.html"),
652       DownloadItem::TARGET_DISPOSITION_PROMPT,
653
654       EXPECT_UNCONFIRMED
655     },
656
657     {
658       // 5: Forced Dangerous URL + Dangerous file
659       FORCED,
660       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
661       "http://phishing.example.com/foo.html", "",
662       FILE_PATH_LITERAL("forced-foo.html"),
663
664       FILE_PATH_LITERAL("forced-foo.html"),
665       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
666
667       EXPECT_UNCONFIRMED
668     },
669   };
670
671   ON_CALL(*delegate(), CheckDownloadUrl(_, _, _))
672       .WillByDefault(WithArg<2>(ScheduleCallback(
673           content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL)));
674   RunTestCasesWithActiveItem(kSafeBrowsingTestCases,
675                              arraysize(kSafeBrowsingTestCases));
676 }
677
678 // The SafeBrowsing check is performed early. Make sure that a download item
679 // that has been marked as MAYBE_DANGEROUS_CONTENT behaves correctly.
680 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_MaybeDangerousContent) {
681   const DownloadTestCase kSafeBrowsingTestCases[] = {
682     {
683       // 0: Automatic Maybe dangerous content
684       AUTOMATIC,
685       content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT,
686       "http://phishing.example.com/foo.exe", "",
687       FILE_PATH_LITERAL(""),
688
689       FILE_PATH_LITERAL("foo.exe"),
690       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
691
692       EXPECT_UNCONFIRMED
693     },
694
695     {
696       // 1: Save As Maybe dangerous content
697       SAVE_AS,
698       content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT,
699       "http://phishing.example.com/foo.exe", "",
700       FILE_PATH_LITERAL(""),
701
702       FILE_PATH_LITERAL("foo.exe"),
703       DownloadItem::TARGET_DISPOSITION_PROMPT,
704
705       EXPECT_UNCONFIRMED
706     },
707
708     {
709       // 2: Forced Maybe dangerous content
710       FORCED,
711       content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT,
712       "http://phishing.example.com/foo.exe", "",
713       FILE_PATH_LITERAL("forced-foo.exe"),
714
715       FILE_PATH_LITERAL("forced-foo.exe"),
716       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
717
718       EXPECT_UNCONFIRMED
719     },
720   };
721
722   ON_CALL(*delegate(), CheckDownloadUrl(_, _, _))
723       .WillByDefault(WithArg<2>(ScheduleCallback(
724           content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT)));
725   RunTestCasesWithActiveItem(kSafeBrowsingTestCases,
726                              arraysize(kSafeBrowsingTestCases));
727 }
728
729 // Test whether the last saved directory is used for 'Save As' downloads.
730 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_LastSavePath) {
731   const DownloadTestCase kLastSavePathTestCasesPre[] = {
732     {
733       // 0: If the last save path is empty, then the default download directory
734       //    should be used.
735       SAVE_AS,
736       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
737       "http://example.com/foo.txt", "text/plain",
738       FILE_PATH_LITERAL(""),
739
740       FILE_PATH_LITERAL("foo.txt"),
741       DownloadItem::TARGET_DISPOSITION_PROMPT,
742
743       EXPECT_CRDOWNLOAD
744     }
745   };
746
747   // These test cases are run with a last save path set to a non-emtpy local
748   // download directory.
749   const DownloadTestCase kLastSavePathTestCasesPost[] = {
750     {
751       // 0: This test case is run with the last download directory set to
752       //    '<test_download_dir()>/foo'.
753       SAVE_AS,
754       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
755       "http://example.com/foo.txt", "text/plain",
756       FILE_PATH_LITERAL(""),
757
758       FILE_PATH_LITERAL("foo/foo.txt"),
759       DownloadItem::TARGET_DISPOSITION_PROMPT,
760
761       EXPECT_CRDOWNLOAD
762     },
763
764     {
765       // 1: Start an automatic download. This should be saved to the user's
766       //    default download directory and not the last used Save As directory.
767       AUTOMATIC,
768       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
769       "http://example.com/foo.txt", "text/plain",
770       FILE_PATH_LITERAL(""),
771
772       FILE_PATH_LITERAL("foo.txt"),
773       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
774
775       EXPECT_CRDOWNLOAD
776     },
777   };
778
779   // This test case is run with the last save path set to a non-empty virtual
780   // directory.
781   const DownloadTestCase kLastSavePathTestCasesVirtual[] = {
782     {
783       SAVE_AS,
784       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
785       "http://example.com/foo.txt", "text/plain",
786       FILE_PATH_LITERAL(""),
787
788       FILE_PATH_LITERAL("bar.txt"),
789       DownloadItem::TARGET_DISPOSITION_PROMPT,
790
791       EXPECT_LOCAL_PATH
792     },
793   };
794
795   {
796     SCOPED_TRACE(testing::Message()
797                  << "Running with default download path");
798     base::FilePath prompt_path =
799         GetPathInDownloadDir(FILE_PATH_LITERAL("foo.txt"));
800     EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, prompt_path, _));
801     RunTestCasesWithActiveItem(kLastSavePathTestCasesPre,
802                                arraysize(kLastSavePathTestCasesPre));
803   }
804
805   // Try with a non-empty last save path.
806   {
807     SCOPED_TRACE(testing::Message()
808                  << "Running with local last_selected_directory");
809     download_prefs()->SetSaveFilePath(test_download_dir().AppendASCII("foo"));
810     base::FilePath prompt_path =
811         GetPathInDownloadDir(FILE_PATH_LITERAL("foo/foo.txt"));
812     EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, prompt_path, _));
813     RunTestCasesWithActiveItem(kLastSavePathTestCasesPost,
814                                arraysize(kLastSavePathTestCasesPost));
815   }
816
817   // And again, but this time use a virtual directory.
818   {
819     SCOPED_TRACE(testing::Message()
820                  << "Running with virtual last_selected_directory");
821     base::FilePath last_selected_dir = test_virtual_dir().AppendASCII("foo");
822     base::FilePath virtual_path = last_selected_dir.AppendASCII("foo.txt");
823     download_prefs()->SetSaveFilePath(last_selected_dir);
824     EXPECT_CALL(*delegate(), PromptUserForDownloadPath(
825         _, last_selected_dir.AppendASCII("foo.txt"), _));
826     EXPECT_CALL(*delegate(), DetermineLocalPath(_, virtual_path, _))
827         .WillOnce(WithArg<2>(ScheduleCallback(
828             GetPathInDownloadDir(FILE_PATH_LITERAL("bar.txt")))));
829     RunTestCasesWithActiveItem(kLastSavePathTestCasesVirtual,
830                                arraysize(kLastSavePathTestCasesVirtual));
831   }
832 }
833
834 // These tests are run with the default downloads folder set to a virtual
835 // directory.
836 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_DefaultVirtual) {
837   // The default download directory is the virutal path.
838   download_prefs()->SetDownloadPath(test_virtual_dir());
839
840   {
841     SCOPED_TRACE(testing::Message() << "Automatic Safe Download");
842     const DownloadTestCase kAutomaticDownloadToVirtualDir = {
843       AUTOMATIC,
844       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
845       "http://example.com/foo.txt", "text/plain",
846       FILE_PATH_LITERAL(""),
847
848       FILE_PATH_LITERAL("foo-local.txt"),
849       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
850
851       EXPECT_LOCAL_PATH
852     };
853     EXPECT_CALL(*delegate(), DetermineLocalPath(_, _, _))
854         .WillOnce(WithArg<2>(ScheduleCallback(
855             GetPathInDownloadDir(FILE_PATH_LITERAL("foo-local.txt")))));
856     RunTestCasesWithActiveItem(&kAutomaticDownloadToVirtualDir, 1);
857   }
858
859   {
860     SCOPED_TRACE(testing::Message() << "Save As to virtual directory");
861     const DownloadTestCase kSaveAsToVirtualDir = {
862       SAVE_AS,
863       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
864       "http://example.com/bar.txt", "text/plain",
865       FILE_PATH_LITERAL(""),
866
867       FILE_PATH_LITERAL("foo-local.txt"),
868       DownloadItem::TARGET_DISPOSITION_PROMPT,
869
870       EXPECT_LOCAL_PATH
871     };
872     EXPECT_CALL(*delegate(), DetermineLocalPath(_, _, _))
873         .WillOnce(WithArg<2>(ScheduleCallback(
874             GetPathInDownloadDir(FILE_PATH_LITERAL("foo-local.txt")))));
875     EXPECT_CALL(*delegate(), PromptUserForDownloadPath(
876         _, test_virtual_dir().AppendASCII("bar.txt"), _))
877         .WillOnce(WithArg<2>(ScheduleCallback(
878             test_virtual_dir().AppendASCII("prompted.txt"))));
879     RunTestCasesWithActiveItem(&kSaveAsToVirtualDir, 1);
880   }
881
882   {
883     SCOPED_TRACE(testing::Message() << "Save As to local directory");
884     const DownloadTestCase kSaveAsToLocalDir = {
885       SAVE_AS,
886       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
887       "http://example.com/bar.txt", "text/plain",
888       FILE_PATH_LITERAL(""),
889
890       FILE_PATH_LITERAL("foo-x.txt"),
891       DownloadItem::TARGET_DISPOSITION_PROMPT,
892
893       EXPECT_CRDOWNLOAD
894     };
895     EXPECT_CALL(*delegate(), PromptUserForDownloadPath(
896         _, test_virtual_dir().AppendASCII("bar.txt"), _))
897         .WillOnce(WithArg<2>(ScheduleCallback(
898             GetPathInDownloadDir(FILE_PATH_LITERAL("foo-x.txt")))));
899     RunTestCasesWithActiveItem(&kSaveAsToLocalDir, 1);
900   }
901
902   {
903     SCOPED_TRACE(testing::Message() << "Forced safe download");
904     const DownloadTestCase kForcedSafe = {
905       FORCED,
906       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
907       "http://example.com/foo.txt", "",
908       FILE_PATH_LITERAL("forced-foo.txt"),
909
910       FILE_PATH_LITERAL("forced-foo.txt"),
911       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
912
913       EXPECT_LOCAL_PATH
914     };
915     RunTestCasesWithActiveItem(&kForcedSafe, 1);
916   }
917 }
918
919 // Test that an inactive download will still get a virtual or local download
920 // path.
921 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_InactiveDownload) {
922   const DownloadTestCase kInactiveTestCases[] = {
923     {
924       AUTOMATIC,
925       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
926       "http://example.com/foo.txt", "text/plain",
927       FILE_PATH_LITERAL(""),
928
929       FILE_PATH_LITERAL(""),
930       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
931
932       EXPECT_LOCAL_PATH
933     },
934
935     {
936       SAVE_AS,
937       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
938       "http://example.com/foo.txt", "text/plain",
939       FILE_PATH_LITERAL(""),
940
941       FILE_PATH_LITERAL(""),
942       DownloadItem::TARGET_DISPOSITION_PROMPT,
943
944       EXPECT_LOCAL_PATH
945     }
946   };
947
948   for (size_t i = 0; i < arraysize(kInactiveTestCases); ++i) {
949     SCOPED_TRACE(testing::Message() << "Running test case " << i);
950     const DownloadTestCase& test_case = kInactiveTestCases[i];
951     scoped_ptr<content::MockDownloadItem> item(
952         CreateActiveDownloadItem(i, test_case));
953     EXPECT_CALL(*item.get(), GetState())
954         .WillRepeatedly(Return(content::DownloadItem::CANCELLED));
955     // Even though one is a SAVE_AS download, no prompt will be displayed to
956     // the user because the download is inactive.
957     EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, _, _))
958         .Times(0);
959     RunTestCase(test_case, base::FilePath(), item.get());
960   }
961 }
962
963 // If the reserved path could not be verified, then the user should see a
964 // prompt.
965 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ReservationFailed) {
966   const DownloadTestCase kReservationFailedCases[] = {
967     {
968       // 0: Automatic download. Since the reservation fails, the disposition of
969       // the target is to prompt, but the returned path is used.
970       AUTOMATIC,
971       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
972       "http://example.com/foo.txt", "text/plain",
973       FILE_PATH_LITERAL(""),
974
975       FILE_PATH_LITERAL("bar.txt"),
976       DownloadItem::TARGET_DISPOSITION_PROMPT,
977
978       EXPECT_CRDOWNLOAD
979     },
980   };
981
982   // Setup ReserveVirtualPath() to fail.
983   ON_CALL(*delegate(), ReserveVirtualPath(_, _, _, _, _))
984       .WillByDefault(WithArg<4>(ScheduleCallback2(
985           GetPathInDownloadDir(FILE_PATH_LITERAL("bar.txt")), false)));
986   RunTestCasesWithActiveItem(kReservationFailedCases,
987                              arraysize(kReservationFailedCases));
988 }
989
990 // If the local path could not be determined, the download should be cancelled.
991 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_LocalPathFailed) {
992   const DownloadTestCase kLocalPathFailedCases[] = {
993     {
994       // 0: Automatic download.
995       AUTOMATIC,
996       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
997       "http://example.com/foo.txt", "text/plain",
998       FILE_PATH_LITERAL(""),
999
1000       FILE_PATH_LITERAL(""),
1001       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1002
1003       EXPECT_LOCAL_PATH
1004     },
1005   };
1006
1007   // The default download directory is the virtual path.
1008   download_prefs()->SetDownloadPath(test_virtual_dir());
1009   // Simulate failed call to DetermineLocalPath.
1010   EXPECT_CALL(*delegate(), DetermineLocalPath(
1011       _, GetPathInDownloadDir(FILE_PATH_LITERAL("virtual/foo.txt")), _))
1012       .WillOnce(WithArg<2>(ScheduleCallback(base::FilePath())));
1013   RunTestCasesWithActiveItem(kLocalPathFailedCases,
1014                              arraysize(kLocalPathFailedCases));
1015 }
1016
1017 // Downloads that have a danger level of ALLOW_ON_USER_GESTURE should be marked
1018 // as safe depending on whether there was a user gesture associated with the
1019 // download and whether the referrer was visited prior to today.
1020 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_VisitedReferrer) {
1021   const DownloadTestCase kVisitedReferrerCases[] = {
1022     // http://visited.example.com/ is added to the history as a visit that
1023     // happened prior to today.
1024     {
1025       // 0: Safe download due to visiting referrer before.
1026       AUTOMATIC,
1027       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1028       "http://visited.example.com/foo.crx", "application/xml",
1029       FILE_PATH_LITERAL(""),
1030
1031       FILE_PATH_LITERAL("foo.crx"),
1032       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1033
1034       EXPECT_CRDOWNLOAD
1035     },
1036
1037     {
1038       // 1: Dangerous due to not having visited referrer before.
1039       AUTOMATIC,
1040       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1041       "http://not-visited.example.com/foo.crx", "application/xml",
1042       FILE_PATH_LITERAL(""),
1043
1044       FILE_PATH_LITERAL("foo.crx"),
1045       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1046
1047       EXPECT_UNCONFIRMED
1048     },
1049
1050     {
1051       // 2: Safe because the user is being prompted.
1052       SAVE_AS,
1053       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1054       "http://not-visited.example.com/foo.crx", "application/xml",
1055       FILE_PATH_LITERAL(""),
1056
1057       FILE_PATH_LITERAL("foo.crx"),
1058       DownloadItem::TARGET_DISPOSITION_PROMPT,
1059
1060       EXPECT_CRDOWNLOAD
1061     },
1062
1063     {
1064       // 3: Safe because of forced path.
1065       FORCED,
1066       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1067       "http://not-visited.example.com/foo.crx", "application/xml",
1068       FILE_PATH_LITERAL("foo.crx"),
1069
1070       FILE_PATH_LITERAL("foo.crx"),
1071       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1072
1073       EXPECT_LOCAL_PATH
1074     },
1075   };
1076
1077   // This test assumes that the danger level of .crx files is
1078   // ALLOW_ON_USER_GESTURE.
1079   ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE,
1080             download_util::GetFileDangerLevel(
1081                 base::FilePath(FILE_PATH_LITERAL("foo.crx"))));
1082
1083   // First the history service must exist.
1084   ASSERT_TRUE(profile()->CreateHistoryService(false, false));
1085
1086   GURL url("http://visited.example.com/visited-link.html");
1087   // The time of visit is picked to be several seconds prior to the most recent
1088   // midnight.
1089   base::Time time_of_visit(
1090       base::Time::Now().LocalMidnight() - base::TimeDelta::FromSeconds(10));
1091   HistoryService* history_service =
1092       HistoryServiceFactory::GetForProfile(profile(), Profile::EXPLICIT_ACCESS);
1093   ASSERT_TRUE(history_service);
1094   history_service->AddPage(url, time_of_visit, history::SOURCE_BROWSED);
1095
1096   RunTestCasesWithActiveItem(kVisitedReferrerCases,
1097                              arraysize(kVisitedReferrerCases));
1098 }
1099
1100 // These test cases are run with "Prompt for download" user preference set to
1101 // true.
1102 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_PromptAlways) {
1103   const DownloadTestCase kPromptingTestCases[] = {
1104     {
1105       // 0: Safe Automatic - Should prompt because of "Prompt for download"
1106       //    preference setting.
1107       AUTOMATIC,
1108       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1109       "http://example.com/foo.txt", "text/plain",
1110       FILE_PATH_LITERAL(""),
1111
1112       FILE_PATH_LITERAL("foo.txt"),
1113       DownloadItem::TARGET_DISPOSITION_PROMPT,
1114
1115       EXPECT_CRDOWNLOAD
1116     },
1117
1118     {
1119       // 1: Safe Forced - Shouldn't prompt.
1120       FORCED,
1121       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1122       "http://example.com/foo.txt", "text/plain",
1123       FILE_PATH_LITERAL("foo.txt"),
1124
1125       FILE_PATH_LITERAL("foo.txt"),
1126       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1127
1128       EXPECT_LOCAL_PATH
1129     },
1130
1131     {
1132       // 2: Automatic - The filename extension is marked as one that we will
1133       //    open automatically. Shouldn't prompt.
1134       AUTOMATIC,
1135       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1136       "http://example.com/foo.dummy", "",
1137       FILE_PATH_LITERAL(""),
1138
1139       FILE_PATH_LITERAL("foo.dummy"),
1140       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1141
1142       EXPECT_CRDOWNLOAD
1143     },
1144   };
1145
1146   SetPromptForDownload(true);
1147   EnableAutoOpenBasedOnExtension(
1148       base::FilePath(FILE_PATH_LITERAL("dummy.dummy")));
1149   RunTestCasesWithActiveItem(kPromptingTestCases,
1150                              arraysize(kPromptingTestCases));
1151 }
1152
1153 #if defined(ENABLE_EXTENSIONS)
1154 // These test cases are run with "Prompt for download" user preference set to
1155 // true. Automatic extension downloads shouldn't cause prompting.
1156 // Android doesn't support extensions.
1157 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_PromptAlways_Extension) {
1158   const DownloadTestCase kPromptingTestCases[] = {
1159     {
1160       // 0: Automatic Browser Extension download. - Shouldn't prompt for browser
1161       //    extension downloads even if "Prompt for download" preference is set.
1162       AUTOMATIC,
1163       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1164       "http://example.com/foo.crx",
1165       extensions::Extension::kMimeType,
1166       FILE_PATH_LITERAL(""),
1167
1168       FILE_PATH_LITERAL("foo.crx"),
1169       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1170
1171       EXPECT_UNCONFIRMED
1172     },
1173
1174 #if defined(OS_WIN)
1175     {
1176       // 1: Automatic User Script - Shouldn't prompt for user script downloads
1177       //    even if "Prompt for download" preference is set. ".js" files are
1178       //    considered dangerous on Windows.
1179       AUTOMATIC,
1180       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1181       "http://example.com/foo.user.js", "",
1182       FILE_PATH_LITERAL(""),
1183
1184       FILE_PATH_LITERAL("foo.user.js"),
1185       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1186
1187       EXPECT_UNCONFIRMED
1188     },
1189 #else
1190     {
1191       // 1: Automatic User Script - Shouldn't prompt for user script downloads
1192       //    even if "Prompt for download" preference is set.
1193       AUTOMATIC,
1194       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1195       "http://example.com/foo.user.js", "",
1196       FILE_PATH_LITERAL(""),
1197
1198       FILE_PATH_LITERAL("foo.user.js"),
1199       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1200
1201       EXPECT_CRDOWNLOAD
1202     },
1203 #endif
1204   };
1205
1206   SetPromptForDownload(true);
1207   RunTestCasesWithActiveItem(kPromptingTestCases,
1208                              arraysize(kPromptingTestCases));
1209 }
1210 #endif  // defined(ENABLE_EXTENSIONS)
1211
1212 // If the download path is managed, then we don't show any prompts.
1213 // Note that if the download path is managed, then PromptForDownload() is false.
1214 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ManagedPath) {
1215   const DownloadTestCase kManagedPathTestCases[] = {
1216     {
1217       // 0: Automatic Safe
1218       AUTOMATIC,
1219       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1220       "http://example.com/foo.txt", "text/plain",
1221       FILE_PATH_LITERAL(""),
1222
1223       FILE_PATH_LITERAL("foo.txt"),
1224       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1225
1226       EXPECT_CRDOWNLOAD
1227     },
1228
1229     {
1230       // 1: Save_As Safe
1231       SAVE_AS,
1232       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1233       "http://example.com/foo.txt", "text/plain",
1234       FILE_PATH_LITERAL(""),
1235
1236       FILE_PATH_LITERAL("foo.txt"),
1237       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1238
1239       EXPECT_CRDOWNLOAD
1240     },
1241   };
1242
1243   SetManagedDownloadPath(test_download_dir());
1244   ASSERT_TRUE(download_prefs()->IsDownloadPathManaged());
1245   RunTestCasesWithActiveItem(kManagedPathTestCases,
1246                              arraysize(kManagedPathTestCases));
1247 }
1248
1249 // Test basic functionality supporting extensions that want to override download
1250 // filenames.
1251 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_NotifyExtensionsSafe) {
1252   const DownloadTestCase kNotifyExtensionsTestCases[] = {
1253     {
1254       // 0: Automatic Safe
1255       AUTOMATIC,
1256       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1257       "http://example.com/foo.txt", "text/plain",
1258       FILE_PATH_LITERAL(""),
1259
1260       FILE_PATH_LITERAL("overridden/foo.txt"),
1261       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1262
1263       EXPECT_CRDOWNLOAD
1264     },
1265
1266     {
1267       // 1: Save_As Safe
1268       SAVE_AS,
1269       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1270       "http://example.com/foo.txt", "text/plain",
1271       FILE_PATH_LITERAL(""),
1272
1273       FILE_PATH_LITERAL("overridden/foo.txt"),
1274       DownloadItem::TARGET_DISPOSITION_PROMPT,
1275
1276       EXPECT_CRDOWNLOAD
1277     },
1278
1279     {
1280       // 2: Automatic Dangerous
1281       AUTOMATIC,
1282       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1283       "http://example.com/foo.crx", "",
1284       FILE_PATH_LITERAL(""),
1285
1286       FILE_PATH_LITERAL("overridden/foo.crx"),
1287       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1288
1289       EXPECT_UNCONFIRMED
1290     },
1291
1292     {
1293       // 3: Forced Safe
1294       FORCED,
1295       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1296       "http://example.com/foo.txt", "",
1297       FILE_PATH_LITERAL("forced-foo.txt"),
1298
1299       FILE_PATH_LITERAL("forced-foo.txt"),
1300       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1301
1302       EXPECT_LOCAL_PATH
1303     },
1304   };
1305
1306   ON_CALL(*delegate(), NotifyExtensions(_, _, _))
1307       .WillByDefault(Invoke(&NotifyExtensionsOverridePath));
1308   RunTestCasesWithActiveItem(kNotifyExtensionsTestCases,
1309                              arraysize(kNotifyExtensionsTestCases));
1310 }
1311
1312 // Test that filenames provided by extensions are passed into SafeBrowsing
1313 // checks and dangerous download checks.
1314 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_NotifyExtensionsUnsafe) {
1315   const DownloadTestCase kNotifyExtensionsTestCases[] = {
1316     {
1317       // 0: Automatic Safe : Later overridden by a dangerous filetype.
1318       AUTOMATIC,
1319       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1320       "http://example.com/foo.crx.remove", "text/plain",
1321       FILE_PATH_LITERAL(""),
1322
1323       FILE_PATH_LITERAL("overridden/foo.crx"),
1324       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1325
1326       EXPECT_UNCONFIRMED
1327     },
1328
1329     {
1330       // 1: Automatic Safe : Later overridden by a potentially dangerous
1331       // filetype.
1332       AUTOMATIC,
1333       content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT,
1334       "http://example.com/foo.exe.remove", "text/plain",
1335       FILE_PATH_LITERAL(""),
1336
1337       FILE_PATH_LITERAL("overridden/foo.exe"),
1338       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1339
1340       EXPECT_UNCONFIRMED
1341     },
1342   };
1343
1344   ON_CALL(*delegate(), NotifyExtensions(_, _, _))
1345       .WillByDefault(Invoke(&NotifyExtensionsOverridePath));
1346   ON_CALL(*delegate(), CheckDownloadUrl(_, _, _))
1347       .WillByDefault(Invoke(&CheckDownloadUrlCheckExes));
1348   RunTestCasesWithActiveItem(kNotifyExtensionsTestCases,
1349                              arraysize(kNotifyExtensionsTestCases));
1350 }
1351
1352 // Test that conflict actions set by extensions are passed correctly into
1353 // ReserveVirtualPath.
1354 TEST_F(DownloadTargetDeterminerTest,
1355        TargetDeterminer_NotifyExtensionsConflict) {
1356   const DownloadTestCase kNotifyExtensionsTestCase = {
1357     AUTOMATIC,
1358     content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1359     "http://example.com/foo.txt", "text/plain",
1360     FILE_PATH_LITERAL(""),
1361
1362     FILE_PATH_LITERAL("overridden/foo.txt"),
1363     DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1364
1365     EXPECT_CRDOWNLOAD
1366   };
1367
1368   const DownloadTestCase& test_case = kNotifyExtensionsTestCase;
1369   scoped_ptr<content::MockDownloadItem> item(
1370       CreateActiveDownloadItem(0, test_case));
1371   base::FilePath overridden_path(FILE_PATH_LITERAL("overridden/foo.txt"));
1372   base::FilePath full_overridden_path =
1373       GetPathInDownloadDir(overridden_path.value());
1374
1375   // First case: An extension sets the conflict_action to OVERWRITE.
1376   EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1377       .WillOnce(WithArg<2>(
1378           ScheduleCallback2(overridden_path,
1379                             DownloadPathReservationTracker::OVERWRITE)));
1380   EXPECT_CALL(*delegate(), ReserveVirtualPath(
1381       _, full_overridden_path, true, DownloadPathReservationTracker::OVERWRITE,
1382       _)).WillOnce(WithArg<4>(
1383           ScheduleCallback2(full_overridden_path, true)));
1384
1385   RunTestCase(test_case, base::FilePath(), item.get());
1386
1387   // Second case: An extension sets the conflict_action to PROMPT.
1388   EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1389       .WillOnce(WithArg<2>(
1390           ScheduleCallback2(overridden_path,
1391                             DownloadPathReservationTracker::PROMPT)));
1392   EXPECT_CALL(*delegate(), ReserveVirtualPath(
1393       _, full_overridden_path, true, DownloadPathReservationTracker::PROMPT, _))
1394       .WillOnce(WithArg<4>(
1395           ScheduleCallback2(full_overridden_path, true)));
1396   RunTestCase(test_case, base::FilePath(), item.get());
1397 }
1398
1399 // Test that relative paths returned by extensions are always relative to the
1400 // default downloads path.
1401 TEST_F(DownloadTargetDeterminerTest,
1402        TargetDeterminer_NotifyExtensionsDefaultPath) {
1403   const DownloadTestCase kNotifyExtensionsTestCase = {
1404     SAVE_AS,
1405     content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1406     "http://example.com/foo.txt", "text/plain",
1407     FILE_PATH_LITERAL(""),
1408
1409     FILE_PATH_LITERAL("overridden/foo.txt"),
1410     DownloadItem::TARGET_DISPOSITION_PROMPT,
1411
1412     EXPECT_CRDOWNLOAD
1413   };
1414
1415   const DownloadTestCase& test_case = kNotifyExtensionsTestCase;
1416   scoped_ptr<content::MockDownloadItem> item(
1417       CreateActiveDownloadItem(0, test_case));
1418   base::FilePath overridden_path(FILE_PATH_LITERAL("overridden/foo.txt"));
1419   base::FilePath full_overridden_path =
1420       GetPathInDownloadDir(overridden_path.value());
1421
1422   download_prefs()->SetSaveFilePath(GetPathInDownloadDir(
1423       FILE_PATH_LITERAL("last_selected")));
1424
1425   EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1426       .WillOnce(WithArg<2>(
1427           ScheduleCallback2(overridden_path,
1428                             DownloadPathReservationTracker::UNIQUIFY)));
1429   EXPECT_CALL(*delegate(),
1430               PromptUserForDownloadPath(_, full_overridden_path, _))
1431       .WillOnce(WithArg<2>(
1432           ScheduleCallback(full_overridden_path)));
1433   RunTestCase(test_case, base::FilePath(), item.get());
1434 }
1435
1436 TEST_F(DownloadTargetDeterminerTest,
1437        TargetDeterminer_InitialVirtualPathUnsafe) {
1438   const base::FilePath::CharType* kInitialPath =
1439       FILE_PATH_LITERAL("some_path/bar.html");
1440
1441   const DownloadTestCase kInitialPathTestCase = {
1442     // 0: Save As Save. The path generated based on the DownloadItem is safe,
1443     // but the initial path is unsafe. However, the download is not considered
1444     // dangerous since the user has been prompted.
1445     SAVE_AS,
1446     content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1447     "http://example.com/foo.txt", "text/plain",
1448     FILE_PATH_LITERAL(""),
1449
1450     kInitialPath,
1451     DownloadItem::TARGET_DISPOSITION_PROMPT,
1452
1453     EXPECT_CRDOWNLOAD
1454   };
1455
1456   const DownloadTestCase& test_case = kInitialPathTestCase;
1457   scoped_ptr<content::MockDownloadItem> item(
1458       CreateActiveDownloadItem(1, test_case));
1459   EXPECT_CALL(*item, GetLastReason())
1460       .WillRepeatedly(Return(
1461           content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED));
1462   EXPECT_CALL(*item, GetTargetDisposition())
1463       .WillRepeatedly(Return(DownloadItem::TARGET_DISPOSITION_PROMPT));
1464   RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get());
1465 }
1466
1467 // Prompting behavior for resumed downloads is based on the last interrupt
1468 // reason. If the reason indicates that the target path may not be suitable for
1469 // the download (ACCESS_DENIED, NO_SPACE, etc..), then the user should be
1470 // prompted, and not otherwise. These test cases shouldn't result in prompting
1471 // since the error is set to NETWORK_FAILED.
1472 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ResumedNoPrompt) {
1473   // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
1474   // path.
1475   const base::FilePath::CharType* kInitialPath =
1476       FILE_PATH_LITERAL("some_path/bar.txt");
1477
1478   const DownloadTestCase kResumedTestCases[] = {
1479     {
1480       // 0: Automatic Safe: Initial path is ignored since the user has not been
1481       // prompted before.
1482       AUTOMATIC,
1483       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1484       "http://example.com/foo.txt", "text/plain",
1485       FILE_PATH_LITERAL(""),
1486
1487       FILE_PATH_LITERAL("foo.txt"),
1488       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1489
1490       EXPECT_CRDOWNLOAD
1491     },
1492
1493     {
1494       // 1: Save_As Safe: Initial path used.
1495       SAVE_AS,
1496       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1497       "http://example.com/foo.txt", "text/plain",
1498       FILE_PATH_LITERAL(""),
1499
1500       kInitialPath,
1501       DownloadItem::TARGET_DISPOSITION_PROMPT,
1502
1503       EXPECT_CRDOWNLOAD
1504     },
1505
1506     {
1507       // 2: Automatic Dangerous: Initial path is ignored since the user hasn't
1508       // been prompted before.
1509       AUTOMATIC,
1510       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1511       "http://example.com/foo.crx", "",
1512       FILE_PATH_LITERAL(""),
1513
1514       FILE_PATH_LITERAL("foo.crx"),
1515       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1516
1517       EXPECT_UNCONFIRMED
1518     },
1519
1520     {
1521       // 3: Forced Safe: Initial path is ignored due to the forced path.
1522       FORCED,
1523       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1524       "http://example.com/foo.txt", "",
1525       FILE_PATH_LITERAL("forced-foo.txt"),
1526
1527       FILE_PATH_LITERAL("forced-foo.txt"),
1528       DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1529
1530       EXPECT_LOCAL_PATH
1531     },
1532   };
1533
1534   // The test assumes that .crx files have a danger level of
1535   // ALLOW_ON_USER_GESTURE.
1536   ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE,
1537             download_util::GetFileDangerLevel(
1538                 base::FilePath(FILE_PATH_LITERAL("foo.crx"))));
1539   for (size_t i = 0; i < arraysize(kResumedTestCases); ++i) {
1540     SCOPED_TRACE(testing::Message() << "Running test case " << i);
1541     const DownloadTestCase& test_case = kResumedTestCases[i];
1542     scoped_ptr<content::MockDownloadItem> item(
1543         CreateActiveDownloadItem(i, test_case));
1544     base::FilePath expected_path =
1545         GetPathInDownloadDir(test_case.expected_local_path);
1546     ON_CALL(*item.get(), GetLastReason())
1547         .WillByDefault(Return(
1548             content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED));
1549     // Extensions should be notified if a new path is being generated and there
1550     // is no forced path. In the test cases above, this is true for tests with
1551     // type == AUTOMATIC.
1552     EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1553         .Times(test_case.test_type == AUTOMATIC ? 1 : 0);
1554     EXPECT_CALL(*delegate(), ReserveVirtualPath(_, expected_path, false, _, _));
1555     EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, expected_path, _))
1556         .Times(0);
1557     EXPECT_CALL(*delegate(), DetermineLocalPath(_, expected_path, _));
1558     EXPECT_CALL(*delegate(), CheckDownloadUrl(_, expected_path, _));
1559     RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get());
1560   }
1561 }
1562
1563 // Test that a forced download doesn't prompt, even if the interrupt reason
1564 // suggests that the target path may not be suitable for downloads.
1565 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ResumedForcedDownload) {
1566   const base::FilePath::CharType* kInitialPath =
1567       FILE_PATH_LITERAL("some_path/bar.txt");
1568   const DownloadTestCase kResumedForcedDownload = {
1569     // 3: Forced Safe
1570     FORCED,
1571     content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1572     "http://example.com/foo.txt", "",
1573     FILE_PATH_LITERAL("forced-foo.txt"),
1574
1575     FILE_PATH_LITERAL("forced-foo.txt"),
1576     DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1577
1578     EXPECT_LOCAL_PATH
1579   };
1580
1581   const DownloadTestCase& test_case = kResumedForcedDownload;
1582   base::FilePath expected_path =
1583       GetPathInDownloadDir(test_case.expected_local_path);
1584   scoped_ptr<content::MockDownloadItem> item(
1585       CreateActiveDownloadItem(0, test_case));
1586   ON_CALL(*item.get(), GetLastReason())
1587       .WillByDefault(Return(content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE));
1588   EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1589       .Times(test_case.test_type == AUTOMATIC ? 1 : 0);
1590   EXPECT_CALL(*delegate(), ReserveVirtualPath(_, expected_path, false, _, _));
1591   EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, _, _))
1592       .Times(0);
1593   EXPECT_CALL(*delegate(), DetermineLocalPath(_, expected_path, _));
1594   EXPECT_CALL(*delegate(), CheckDownloadUrl(_, expected_path, _));
1595   RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get());
1596 }
1597
1598 // Prompting behavior for resumed downloads is based on the last interrupt
1599 // reason. If the reason indicates that the target path may not be suitable for
1600 // the download (ACCESS_DENIED, NO_SPACE, etc..), then the user should be
1601 // prompted, and not otherwise. These test cases result in prompting since the
1602 // error is set to NO_SPACE.
1603 TEST_F(DownloadTargetDeterminerTest, TargetDeterminer_ResumedWithPrompt) {
1604   // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
1605   // path.
1606   const base::FilePath::CharType* kInitialPath =
1607       FILE_PATH_LITERAL("some_path/bar.txt");
1608
1609   const DownloadTestCase kResumedTestCases[] = {
1610     {
1611       // 0: Automatic Safe
1612       AUTOMATIC,
1613       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1614       "http://example.com/foo.txt", "text/plain",
1615       FILE_PATH_LITERAL(""),
1616
1617       FILE_PATH_LITERAL("foo.txt"),
1618       DownloadItem::TARGET_DISPOSITION_PROMPT,
1619
1620       EXPECT_CRDOWNLOAD
1621     },
1622
1623     {
1624       // 1: Save_As Safe
1625       SAVE_AS,
1626       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1627       "http://example.com/foo.txt", "text/plain",
1628       FILE_PATH_LITERAL(""),
1629
1630       kInitialPath,
1631       DownloadItem::TARGET_DISPOSITION_PROMPT,
1632
1633       EXPECT_CRDOWNLOAD
1634     },
1635
1636     {
1637       // 2: Automatic Dangerous
1638       AUTOMATIC,
1639       content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1640       "http://example.com/foo.crx", "",
1641       FILE_PATH_LITERAL(""),
1642
1643       FILE_PATH_LITERAL("foo.crx"),
1644       DownloadItem::TARGET_DISPOSITION_PROMPT,
1645
1646       EXPECT_CRDOWNLOAD
1647     },
1648   };
1649
1650   // The test assumes that .xml files have a danger level of
1651   // ALLOW_ON_USER_GESTURE.
1652   ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE,
1653             download_util::GetFileDangerLevel(
1654                 base::FilePath(FILE_PATH_LITERAL("foo.crx"))));
1655   for (size_t i = 0; i < arraysize(kResumedTestCases); ++i) {
1656     SCOPED_TRACE(testing::Message() << "Running test case " << i);
1657     download_prefs()->SetSaveFilePath(test_download_dir());
1658     const DownloadTestCase& test_case = kResumedTestCases[i];
1659     base::FilePath expected_path =
1660         GetPathInDownloadDir(test_case.expected_local_path);
1661     scoped_ptr<content::MockDownloadItem> item(
1662         CreateActiveDownloadItem(i, test_case));
1663     ON_CALL(*item.get(), GetLastReason())
1664         .WillByDefault(Return(
1665             content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE));
1666     EXPECT_CALL(*delegate(), NotifyExtensions(_, _, _))
1667         .Times(test_case.test_type == AUTOMATIC ? 1 : 0);
1668     EXPECT_CALL(*delegate(), ReserveVirtualPath(_, expected_path, false, _, _));
1669     EXPECT_CALL(*delegate(), PromptUserForDownloadPath(_, expected_path, _));
1670     EXPECT_CALL(*delegate(), DetermineLocalPath(_, expected_path, _));
1671     EXPECT_CALL(*delegate(), CheckDownloadUrl(_, expected_path, _));
1672     RunTestCase(test_case, GetPathInDownloadDir(kInitialPath), item.get());
1673   }
1674 }
1675
1676 // Test intermediate filename generation for resumed downloads.
1677 TEST_F(DownloadTargetDeterminerTest,
1678        TargetDeterminer_IntermediateNameForResumed) {
1679   // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
1680   // path.
1681   const base::FilePath::CharType kInitialPath[] =
1682       FILE_PATH_LITERAL("some_path/bar.txt");
1683
1684   struct IntermediateNameTestCase {
1685     // General test case settings.
1686     DownloadTestCase general;
1687
1688     // Value of DownloadItem::GetFullPath() during test run, relative
1689     // to test download path.
1690     const base::FilePath::CharType* initial_intermediate_path;
1691
1692     // Expected intermediate path relatvie to the test download path. An exact
1693     // match is performed if this string is non-empty. Ignored otherwise.
1694     const base::FilePath::CharType* expected_intermediate_path;
1695   } kIntermediateNameTestCases[] = {
1696     {
1697       {
1698         // 0: Automatic Safe
1699         AUTOMATIC,
1700         content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1701         "http://example.com/foo.txt", "text/plain",
1702         FILE_PATH_LITERAL(""),
1703
1704         FILE_PATH_LITERAL("foo.txt"),
1705         DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1706
1707         EXPECT_CRDOWNLOAD
1708       },
1709       FILE_PATH_LITERAL("bar.txt.crdownload"),
1710       FILE_PATH_LITERAL("foo.txt.crdownload")
1711     },
1712
1713     {
1714       {
1715         // 1: Save_As Safe
1716         SAVE_AS,
1717         content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1718         "http://example.com/foo.txt", "text/plain",
1719         FILE_PATH_LITERAL(""),
1720
1721         kInitialPath,
1722         DownloadItem::TARGET_DISPOSITION_PROMPT,
1723
1724         EXPECT_CRDOWNLOAD
1725       },
1726       FILE_PATH_LITERAL("foo.txt.crdownload"),
1727       FILE_PATH_LITERAL("some_path/bar.txt.crdownload")
1728     },
1729
1730     {
1731       {
1732         // 2: Automatic Dangerous
1733         AUTOMATIC,
1734         content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1735         "http://example.com/foo.crx", "",
1736         FILE_PATH_LITERAL(""),
1737
1738         FILE_PATH_LITERAL("foo.crx"),
1739         DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1740
1741         EXPECT_UNCONFIRMED
1742       },
1743       FILE_PATH_LITERAL("Unconfirmed abcd.crdownload"),
1744       FILE_PATH_LITERAL("Unconfirmed abcd.crdownload")
1745     },
1746
1747     {
1748       {
1749         // 3: Automatic Dangerous
1750         AUTOMATIC,
1751         content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
1752         "http://example.com/foo.crx", "",
1753         FILE_PATH_LITERAL(""),
1754
1755         FILE_PATH_LITERAL("foo.crx"),
1756         DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1757
1758         EXPECT_UNCONFIRMED
1759       },
1760       FILE_PATH_LITERAL("other_path/Unconfirmed abcd.crdownload"),
1761       // Rely on the EXPECT_UNCONFIRMED check in the general test settings. A
1762       // new intermediate path of the form "Unconfirmed <number>.crdownload"
1763       // should be generated for this case since the initial intermediate path
1764       // is in the wrong directory.
1765       FILE_PATH_LITERAL("")
1766     },
1767
1768     {
1769       {
1770         // 3: Forced Safe: Initial path is ignored due to the forced path.
1771         FORCED,
1772         content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1773         "http://example.com/foo.txt", "",
1774         FILE_PATH_LITERAL("forced-foo.txt"),
1775
1776         FILE_PATH_LITERAL("forced-foo.txt"),
1777         DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1778
1779         EXPECT_LOCAL_PATH
1780       },
1781       FILE_PATH_LITERAL("forced-foo.txt"),
1782       FILE_PATH_LITERAL("forced-foo.txt")
1783     },
1784   };
1785
1786   // The test assumes that .crx files have a danger level of
1787   // ALLOW_ON_USER_GESTURE.
1788   ASSERT_EQ(download_util::ALLOW_ON_USER_GESTURE,
1789             download_util::GetFileDangerLevel(
1790                 base::FilePath(FILE_PATH_LITERAL("foo.crx"))));
1791
1792   for (size_t i = 0; i < arraysize(kIntermediateNameTestCases); ++i) {
1793     SCOPED_TRACE(testing::Message() << "Running test case " << i);
1794     const IntermediateNameTestCase& test_case = kIntermediateNameTestCases[i];
1795     scoped_ptr<content::MockDownloadItem> item(
1796         CreateActiveDownloadItem(i, test_case.general));
1797
1798     ON_CALL(*item.get(), GetLastReason())
1799         .WillByDefault(Return(
1800             content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED));
1801     ON_CALL(*item.get(), GetFullPath())
1802         .WillByDefault(ReturnRefOfCopy(
1803             GetPathInDownloadDir(test_case.initial_intermediate_path)));
1804     ON_CALL(*item.get(), GetDangerType())
1805         .WillByDefault(Return(test_case.general.expected_danger_type));
1806
1807     scoped_ptr<DownloadTargetInfo> target_info =
1808         RunDownloadTargetDeterminer(GetPathInDownloadDir(kInitialPath),
1809                                     item.get());
1810     VerifyDownloadTarget(test_case.general, target_info.get());
1811     base::FilePath expected_intermediate_path =
1812         GetPathInDownloadDir(test_case.expected_intermediate_path);
1813     if (!expected_intermediate_path.empty())
1814       EXPECT_EQ(expected_intermediate_path, target_info->intermediate_path);
1815   }
1816 }
1817
1818 // Test MIME type determination based on the target filename.
1819 TEST_F(DownloadTargetDeterminerTest,
1820        TargetDeterminer_MIMETypeDetermination) {
1821   // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
1822   // path.
1823   const base::FilePath::CharType kInitialPath[] =
1824       FILE_PATH_LITERAL("some_path/bar.txt");
1825
1826   struct MIMETypeTestCase {
1827     // General test case settings.
1828     DownloadTestCase general;
1829
1830     // Expected MIME type for test case.
1831     const char* expected_mime_type;
1832   } kMIMETypeTestCases[] = {
1833     {
1834       {
1835         // 0:
1836         AUTOMATIC,
1837         content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1838         "http://example.com/foo.png", "image/png",
1839         FILE_PATH_LITERAL(""),
1840
1841         FILE_PATH_LITERAL("foo.png"),
1842         DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1843
1844         EXPECT_CRDOWNLOAD
1845       },
1846       "image/png"
1847     },
1848     {
1849       {
1850         // 1: Empty MIME type in response.
1851         AUTOMATIC,
1852         content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1853         "http://example.com/foo.png", "",
1854         FILE_PATH_LITERAL(""),
1855
1856         FILE_PATH_LITERAL("foo.png"),
1857         DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1858
1859         EXPECT_CRDOWNLOAD
1860       },
1861       "image/png"
1862     },
1863     {
1864       {
1865         // 2: Forced path.
1866         FORCED,
1867         content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1868         "http://example.com/foo.abc", "",
1869         FILE_PATH_LITERAL("foo.png"),
1870
1871         FILE_PATH_LITERAL("foo.png"),
1872         DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1873
1874         EXPECT_CRDOWNLOAD
1875       },
1876       "image/png"
1877     },
1878     {
1879       {
1880         // 3: Unknown file type.
1881         AUTOMATIC,
1882         content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1883         "http://example.com/foo.notarealext", "",
1884         FILE_PATH_LITERAL(""),
1885
1886         FILE_PATH_LITERAL("foo.notarealext"),
1887         DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1888
1889         EXPECT_CRDOWNLOAD
1890       },
1891       ""
1892     },
1893     {
1894       {
1895         // 4: Unknown file type.
1896         AUTOMATIC,
1897         content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
1898         "http://example.com/foo.notarealext", "image/png",
1899         FILE_PATH_LITERAL(""),
1900
1901         FILE_PATH_LITERAL("foo.notarealext"),
1902         DownloadItem::TARGET_DISPOSITION_OVERWRITE,
1903
1904         EXPECT_CRDOWNLOAD
1905       },
1906       ""
1907     },
1908   };
1909
1910   ON_CALL(*delegate(), GetFileMimeType(
1911       GetPathInDownloadDir(FILE_PATH_LITERAL("foo.png")), _))
1912       .WillByDefault(WithArg<1>(
1913           ScheduleCallback("image/png")));
1914
1915   for (size_t i = 0; i < arraysize(kMIMETypeTestCases); ++i) {
1916     SCOPED_TRACE(testing::Message() << "Running test case " << i);
1917     const MIMETypeTestCase& test_case = kMIMETypeTestCases[i];
1918     scoped_ptr<content::MockDownloadItem> item(
1919         CreateActiveDownloadItem(i, test_case.general));
1920     scoped_ptr<DownloadTargetInfo> target_info =
1921         RunDownloadTargetDeterminer(GetPathInDownloadDir(kInitialPath),
1922                                     item.get());
1923     EXPECT_EQ(test_case.expected_mime_type, target_info->mime_type);
1924   }
1925 }
1926
1927 #if defined(ENABLE_PLUGINS)
1928
1929 void DummyGetPluginsCallback(
1930     const base::Closure& closure,
1931     const std::vector<content::WebPluginInfo>& plugins) {
1932   closure.Run();
1933 }
1934
1935 void ForceRefreshOfPlugins() {
1936 #if !defined(OS_WIN)
1937   // Prevent creation of a utility process for loading plugins. Doing so breaks
1938   // unit_tests since /proc/self/exe can't be run as a utility process.
1939   content::RenderProcessHost::SetRunRendererInProcess(true);
1940 #endif
1941   base::RunLoop run_loop;
1942   content::PluginService::GetInstance()->GetPlugins(
1943       base::Bind(&DummyGetPluginsCallback, run_loop.QuitClosure()));
1944   run_loop.Run();
1945 #if !defined(OS_WIN)
1946   content::RenderProcessHost::SetRunRendererInProcess(false);
1947 #endif
1948 }
1949
1950 class MockPluginServiceFilter : public content::PluginServiceFilter {
1951  public:
1952   MOCK_METHOD1(MockPluginAvailable, bool(const base::FilePath&));
1953
1954   virtual bool IsPluginAvailable(int render_process_id,
1955                                  int render_view_id,
1956                                  const void* context,
1957                                  const GURL& url,
1958                                  const GURL& policy_url,
1959                                  content::WebPluginInfo* plugin) override {
1960     return MockPluginAvailable(plugin->path);
1961   }
1962
1963   virtual bool CanLoadPlugin(int render_process_id,
1964                              const base::FilePath& path) override {
1965     return true;
1966   }
1967 };
1968
1969 class ScopedRegisterInternalPlugin {
1970  public:
1971   ScopedRegisterInternalPlugin(content::PluginService* plugin_service,
1972                                content::WebPluginInfo::PluginType type,
1973                                const base::FilePath& path,
1974                                const char* mime_type,
1975                                const char* extension)
1976       : plugin_service_(plugin_service),
1977         plugin_path_(path) {
1978     content::WebPluginMimeType plugin_mime_type(mime_type,
1979                                                 extension,
1980                                                 "Test file");
1981     content::WebPluginInfo plugin_info(base::string16(),
1982                                        path,
1983                                        base::string16(),
1984                                        base::string16());
1985     plugin_info.mime_types.push_back(plugin_mime_type);
1986     plugin_info.type = type;
1987
1988     plugin_service->RegisterInternalPlugin(plugin_info, true);
1989     plugin_service->RefreshPlugins();
1990     ForceRefreshOfPlugins();
1991   }
1992
1993   ~ScopedRegisterInternalPlugin() {
1994     plugin_service_->UnregisterInternalPlugin(plugin_path_);
1995     plugin_service_->RefreshPlugins();
1996     ForceRefreshOfPlugins();
1997   }
1998
1999   const base::FilePath& path() { return plugin_path_; }
2000
2001  private:
2002   content::PluginService* plugin_service_;
2003   base::FilePath plugin_path_;
2004 };
2005
2006 // We use a slightly different test fixture for tests that touch plugins. SetUp
2007 // needs to disable plugin discovery and we need to use a
2008 // ShadowingAtExitManager to discard the tainted PluginService. Unfortunately,
2009 // PluginService carries global state.
2010 class DownloadTargetDeterminerTestWithPlugin
2011     : public DownloadTargetDeterminerTest {
2012  public:
2013   DownloadTargetDeterminerTestWithPlugin()
2014       : old_plugin_service_filter_(NULL) {}
2015
2016   virtual void SetUp() override {
2017     content::PluginService* plugin_service =
2018         content::PluginService::GetInstance();
2019     plugin_service->Init();
2020     plugin_service->DisablePluginsDiscoveryForTesting();
2021     old_plugin_service_filter_ = plugin_service->GetFilter();
2022     plugin_service->SetFilter(&mock_plugin_filter_);
2023     DownloadTargetDeterminerTest::SetUp();
2024   }
2025
2026   virtual void TearDown() override {
2027     content::PluginService::GetInstance()->SetFilter(
2028         old_plugin_service_filter_);
2029     DownloadTargetDeterminerTest::TearDown();
2030   }
2031
2032  protected:
2033   content::PluginServiceFilter* old_plugin_service_filter_;
2034   testing::StrictMock<MockPluginServiceFilter> mock_plugin_filter_;
2035   // The ShadowingAtExitManager destroys the tainted PluginService instance.
2036   base::ShadowingAtExitManager at_exit_manager_;
2037 };
2038
2039 // Check if secure handling of filetypes is determined correctly for PPAPI
2040 // plugins.
2041 TEST_F(DownloadTargetDeterminerTestWithPlugin,
2042        TargetDeterminer_CheckForSecureHandling_PPAPI) {
2043   // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
2044   // path.
2045   const base::FilePath::CharType kInitialPath[] =
2046       FILE_PATH_LITERAL("some_path/bar.txt");
2047   const char kTestMIMEType[] = "application/x-example-should-not-exist";
2048
2049   DownloadTestCase kSecureHandlingTestCase = {
2050     AUTOMATIC,
2051     content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
2052     "http://example.com/foo.fakeext", "",
2053     FILE_PATH_LITERAL(""),
2054
2055     FILE_PATH_LITERAL("foo.fakeext"),
2056     DownloadItem::TARGET_DISPOSITION_OVERWRITE,
2057
2058     EXPECT_CRDOWNLOAD
2059   };
2060
2061   content::PluginService* plugin_service =
2062       content::PluginService::GetInstance();
2063
2064   // Verify our test assumptions.
2065   {
2066     ForceRefreshOfPlugins();
2067     std::vector<content::WebPluginInfo> info;
2068     ASSERT_FALSE(plugin_service->GetPluginInfoArray(
2069         GURL(), kTestMIMEType, false, &info, NULL));
2070     ASSERT_EQ(0u, info.size())
2071         << "Name: " << info[0].name << ", Path: " << info[0].path.value();
2072   }
2073
2074   ON_CALL(*delegate(), GetFileMimeType(
2075       GetPathInDownloadDir(FILE_PATH_LITERAL("foo.fakeext")), _))
2076       .WillByDefault(WithArg<1>(
2077           ScheduleCallback(kTestMIMEType)));
2078   scoped_ptr<content::MockDownloadItem> item(
2079       CreateActiveDownloadItem(1, kSecureHandlingTestCase));
2080   scoped_ptr<DownloadTargetInfo> target_info =
2081       RunDownloadTargetDeterminer(GetPathInDownloadDir(kInitialPath),
2082                                   item.get());
2083   EXPECT_FALSE(target_info->is_filetype_handled_safely);
2084
2085   // Register a PPAPI plugin. This should count as handling the filetype
2086   // securely.
2087   ScopedRegisterInternalPlugin ppapi_plugin(
2088       plugin_service,
2089       content::WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS,
2090       test_download_dir().AppendASCII("ppapi"),
2091       kTestMIMEType,
2092       "fakeext");
2093   EXPECT_CALL(mock_plugin_filter_, MockPluginAvailable(ppapi_plugin.path()))
2094       .WillRepeatedly(Return(true));
2095
2096   target_info = RunDownloadTargetDeterminer(
2097       GetPathInDownloadDir(kInitialPath), item.get());
2098   EXPECT_TRUE(target_info->is_filetype_handled_safely);
2099
2100   // Try disabling the plugin. Handling should no longer be considered secure.
2101   EXPECT_CALL(mock_plugin_filter_, MockPluginAvailable(ppapi_plugin.path()))
2102       .WillRepeatedly(Return(false));
2103   target_info = RunDownloadTargetDeterminer(
2104       GetPathInDownloadDir(kInitialPath), item.get());
2105   EXPECT_FALSE(target_info->is_filetype_handled_safely);
2106
2107   // Now register an unsandboxed PPAPI plug-in. This plugin should not be
2108   // considered secure.
2109   ScopedRegisterInternalPlugin ppapi_unsandboxed_plugin(
2110       plugin_service,
2111       content::WebPluginInfo::PLUGIN_TYPE_PEPPER_UNSANDBOXED,
2112       test_download_dir().AppendASCII("ppapi-nosandbox"),
2113       kTestMIMEType,
2114       "fakeext");
2115   EXPECT_CALL(mock_plugin_filter_,
2116               MockPluginAvailable(ppapi_unsandboxed_plugin.path()))
2117       .WillRepeatedly(Return(true));
2118
2119   target_info = RunDownloadTargetDeterminer(
2120       GetPathInDownloadDir(kInitialPath), item.get());
2121   EXPECT_FALSE(target_info->is_filetype_handled_safely);
2122 }
2123
2124 // Check if secure handling of filetypes is determined correctly for NPAPI
2125 // plugins.
2126 TEST_F(DownloadTargetDeterminerTestWithPlugin,
2127        TargetDeterminer_CheckForSecureHandling_NPAPI) {
2128   // All test cases run with GetPathInDownloadDir(kInitialPath) as the inital
2129   // path.
2130   const base::FilePath::CharType kInitialPath[] =
2131       FILE_PATH_LITERAL("some_path/bar.txt");
2132   const char kTestMIMEType[] = "application/x-example-should-not-exist";
2133
2134   DownloadTestCase kSecureHandlingTestCase = {
2135     AUTOMATIC,
2136     content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
2137     "http://example.com/foo.fakeext", "",
2138     FILE_PATH_LITERAL(""),
2139
2140     FILE_PATH_LITERAL("foo.fakeext"),
2141     DownloadItem::TARGET_DISPOSITION_OVERWRITE,
2142
2143     EXPECT_CRDOWNLOAD
2144   };
2145
2146   content::PluginService* plugin_service =
2147       content::PluginService::GetInstance();
2148
2149   // Can't run this test if NPAPI isn't supported.
2150   if (!plugin_service->NPAPIPluginsSupported())
2151     return;
2152
2153   // Verify our test assumptions.
2154   {
2155     ForceRefreshOfPlugins();
2156     std::vector<content::WebPluginInfo> info;
2157     ASSERT_FALSE(plugin_service->GetPluginInfoArray(
2158         GURL(), kTestMIMEType, false, &info, NULL));
2159     ASSERT_EQ(0u, info.size())
2160         << "Name: " << info[0].name << ", Path: " << info[0].path.value();
2161   }
2162
2163   ON_CALL(*delegate(), GetFileMimeType(
2164       GetPathInDownloadDir(FILE_PATH_LITERAL("foo.fakeext")), _))
2165       .WillByDefault(WithArg<1>(
2166           ScheduleCallback(kTestMIMEType)));
2167   scoped_ptr<content::MockDownloadItem> item(
2168       CreateActiveDownloadItem(1, kSecureHandlingTestCase));
2169   scoped_ptr<DownloadTargetInfo> target_info =
2170       RunDownloadTargetDeterminer(GetPathInDownloadDir(kInitialPath),
2171                                   item.get());
2172   EXPECT_FALSE(target_info->is_filetype_handled_safely);
2173
2174   // Register a NPAPI plugin. This should not count as handling the filetype
2175   // securely.
2176   ScopedRegisterInternalPlugin npapi_plugin(
2177       plugin_service,
2178       content::WebPluginInfo::PLUGIN_TYPE_NPAPI,
2179       test_download_dir().AppendASCII("npapi"),
2180       kTestMIMEType,
2181       "fakeext");
2182   EXPECT_CALL(mock_plugin_filter_, MockPluginAvailable(npapi_plugin.path()))
2183       .WillRepeatedly(Return(true));
2184
2185   target_info = RunDownloadTargetDeterminer(
2186       GetPathInDownloadDir(kInitialPath), item.get());
2187   EXPECT_FALSE(target_info->is_filetype_handled_safely);
2188 }
2189 #endif  // defined(ENABLE_PLUGINS)
2190
2191 }  // namespace