1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/files/file_path.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/run_loop.h"
10 #include "chrome/browser/download/chrome_download_manager_delegate.h"
11 #include "chrome/browser/download/download_prefs.h"
12 #include "chrome/common/pref_names.h"
13 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
14 #include "chrome/test/base/testing_pref_service_syncable.h"
15 #include "chrome/test/base/testing_profile.h"
16 #include "content/public/browser/download_interrupt_reasons.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/browser/web_contents_delegate.h"
19 #include "content/public/test/mock_download_item.h"
20 #include "content/public/test/mock_download_manager.h"
21 #include "content/public/test/test_browser_thread.h"
22 #include "content/public/test/test_renderer_host.h"
23 #include "content/public/test/web_contents_tester.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 using ::testing::AtMost;
28 using ::testing::Invoke;
30 using ::testing::Return;
31 using ::testing::ReturnPointee;
32 using ::testing::ReturnRef;
33 using ::testing::ReturnRefOfCopy;
34 using ::testing::SetArgPointee;
35 using ::testing::WithArg;
37 using content::DownloadItem;
41 class MockWebContentsDelegate : public content::WebContentsDelegate {
43 virtual ~MockWebContentsDelegate() {}
46 // Google Mock action that posts a task to the current message loop that invokes
47 // the first argument of the mocked method as a callback. Said argument must be
48 // a base::Callback<void(ParamType)>. |result| must be of |ParamType| and is
49 // bound as that parameter.
53 // virtual void Foo(base::Callback<void(bool)> callback);
56 // EXPECT_CALL(mock_fooclass_instance, Foo(callback))
57 // .WillOnce(ScheduleCallback(false));
58 ACTION_P(ScheduleCallback, result) {
59 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(arg0, result));
62 // Similar to ScheduleCallback, but binds 2 arguments.
63 ACTION_P2(ScheduleCallback2, result0, result1) {
64 base::MessageLoop::current()->PostTask(
65 FROM_HERE, base::Bind(arg0, result0, result1));
68 struct DownloadTarget {
69 base::FilePath target_path;
70 base::FilePath intermediate_path;
71 DownloadItem::TargetDisposition target_disposition;
72 content::DownloadDangerType danger_type;
75 // Subclass of the ChromeDownloadManagerDelegate that uses a mock
76 // DownloadProtectionService.
77 class TestChromeDownloadManagerDelegate : public ChromeDownloadManagerDelegate {
79 explicit TestChromeDownloadManagerDelegate(Profile* profile)
80 : ChromeDownloadManagerDelegate(profile) {
83 virtual safe_browsing::DownloadProtectionService*
84 GetDownloadProtectionService() OVERRIDE {
88 virtual void NotifyExtensions(
89 content::DownloadItem* download,
90 const base::FilePath& suggested_virtual_path,
91 const NotifyExtensionsCallback& callback) OVERRIDE {
92 callback.Run(base::FilePath(),
93 DownloadPathReservationTracker::UNIQUIFY);
96 virtual void ReserveVirtualPath(
97 content::DownloadItem* download,
98 const base::FilePath& virtual_path,
99 bool create_directory,
100 DownloadPathReservationTracker::FilenameConflictAction conflict_action,
101 const DownloadPathReservationTracker::ReservedPathCallback& callback)
103 // Pretend the path reservation succeeded without any change to
105 base::MessageLoop::current()->PostTask(
106 FROM_HERE, base::Bind(callback, virtual_path, true));
109 virtual void PromptUserForDownloadPath(
110 DownloadItem* download,
111 const base::FilePath& suggested_path,
112 const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback)
114 base::FilePath return_path = MockPromptUserForDownloadPath(download,
117 callback.Run(return_path);
121 MockPromptUserForDownloadPath,
123 content::DownloadItem*,
124 const base::FilePath&,
125 const DownloadTargetDeterminerDelegate::FileSelectedCallback&));
128 ~TestChromeDownloadManagerDelegate() {}
131 class ChromeDownloadManagerDelegateTest :
132 public ChromeRenderViewHostTestHarness {
134 ChromeDownloadManagerDelegateTest();
137 virtual void SetUp() OVERRIDE;
138 virtual void TearDown() OVERRIDE;
140 // Verifies and clears test expectations for |delegate_| and
141 // |download_manager_|.
142 void VerifyAndClearExpectations();
144 // Creates MockDownloadItem and sets up default expectations.
145 content::MockDownloadItem* CreateActiveDownloadItem(int32 id);
147 // Given the relative path |path|, returns the full path under the temporary
148 // downloads directory.
149 base::FilePath GetPathInDownloadDir(const char* path);
151 // Set the kDownloadDefaultDirectory user preference to |path|.
152 void SetDefaultDownloadPath(const base::FilePath& path);
154 void DetermineDownloadTarget(DownloadItem* download,
155 DownloadTarget* result);
157 const base::FilePath& default_download_path() const;
158 TestChromeDownloadManagerDelegate* delegate();
159 content::MockDownloadManager* download_manager();
160 DownloadPrefs* download_prefs();
163 void OnDownloadTargetDone(DownloadTarget* result,
164 const base::FilePath& target_path,
165 DownloadItem::TargetDisposition disposition,
166 content::DownloadDangerType danger_type,
167 const base::FilePath& intermediate_path);
169 TestingPrefServiceSyncable* pref_service_;
170 base::ScopedTempDir test_download_dir_;
171 scoped_ptr<content::MockDownloadManager> download_manager_;
172 scoped_refptr<TestChromeDownloadManagerDelegate> delegate_;
173 MockWebContentsDelegate web_contents_delegate_;
176 ChromeDownloadManagerDelegateTest::ChromeDownloadManagerDelegateTest()
177 : download_manager_(new ::testing::NiceMock<content::MockDownloadManager>) {
180 void ChromeDownloadManagerDelegateTest::SetUp() {
181 ChromeRenderViewHostTestHarness::SetUp();
184 delegate_ = new TestChromeDownloadManagerDelegate(profile());
185 delegate_->SetDownloadManager(download_manager_.get());
186 pref_service_ = profile()->GetTestingPrefService();
187 web_contents()->SetDelegate(&web_contents_delegate_);
189 ASSERT_TRUE(test_download_dir_.CreateUniqueTempDir());
190 SetDefaultDownloadPath(test_download_dir_.path());
193 void ChromeDownloadManagerDelegateTest::TearDown() {
194 base::RunLoop().RunUntilIdle();
195 delegate_->Shutdown();
196 ChromeRenderViewHostTestHarness::TearDown();
199 void ChromeDownloadManagerDelegateTest::VerifyAndClearExpectations() {
200 ::testing::Mock::VerifyAndClearExpectations(delegate_.get());
203 content::MockDownloadItem*
204 ChromeDownloadManagerDelegateTest::CreateActiveDownloadItem(int32 id) {
205 content::MockDownloadItem* item =
206 new ::testing::NiceMock<content::MockDownloadItem>();
207 ON_CALL(*item, GetBrowserContext())
208 .WillByDefault(Return(profile()));
209 ON_CALL(*item, GetDangerType())
210 .WillByDefault(Return(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS));
211 ON_CALL(*item, GetForcedFilePath())
212 .WillByDefault(ReturnRefOfCopy(base::FilePath()));
213 ON_CALL(*item, GetFullPath())
214 .WillByDefault(ReturnRefOfCopy(base::FilePath()));
215 ON_CALL(*item, GetHash())
216 .WillByDefault(ReturnRefOfCopy(std::string()));
217 ON_CALL(*item, GetId())
218 .WillByDefault(Return(id));
219 ON_CALL(*item, GetLastReason())
220 .WillByDefault(Return(content::DOWNLOAD_INTERRUPT_REASON_NONE));
221 ON_CALL(*item, GetReferrerUrl())
222 .WillByDefault(ReturnRefOfCopy(GURL()));
223 ON_CALL(*item, GetState())
224 .WillByDefault(Return(DownloadItem::IN_PROGRESS));
225 ON_CALL(*item, GetTargetFilePath())
226 .WillByDefault(ReturnRefOfCopy(base::FilePath()));
227 ON_CALL(*item, GetTransitionType())
228 .WillByDefault(Return(content::PAGE_TRANSITION_LINK));
229 ON_CALL(*item, GetWebContents())
230 .WillByDefault(Return(web_contents()));
231 ON_CALL(*item, HasUserGesture())
232 .WillByDefault(Return(false));
233 ON_CALL(*item, IsDangerous())
234 .WillByDefault(Return(false));
235 ON_CALL(*item, IsTemporary())
236 .WillByDefault(Return(false));
237 EXPECT_CALL(*download_manager_, GetDownload(id))
238 .WillRepeatedly(Return(item));
242 base::FilePath ChromeDownloadManagerDelegateTest::GetPathInDownloadDir(
243 const char* relative_path) {
244 base::FilePath full_path =
245 test_download_dir_.path().AppendASCII(relative_path);
246 return full_path.NormalizePathSeparators();
249 void ChromeDownloadManagerDelegateTest::SetDefaultDownloadPath(
250 const base::FilePath& path) {
251 pref_service_->SetFilePath(prefs::kDownloadDefaultDirectory, path);
252 pref_service_->SetFilePath(prefs::kSaveFileDefaultDirectory, path);
255 void ChromeDownloadManagerDelegateTest::DetermineDownloadTarget(
256 DownloadItem* download_item,
257 DownloadTarget* result) {
258 base::WeakPtrFactory<ChromeDownloadManagerDelegateTest> factory(this);
259 delegate()->DetermineDownloadTarget(
261 base::Bind(&ChromeDownloadManagerDelegateTest::OnDownloadTargetDone,
262 factory.GetWeakPtr(), base::Unretained(result)));
263 base::RunLoop loop_runner;
264 loop_runner.RunUntilIdle();
267 void ChromeDownloadManagerDelegateTest::OnDownloadTargetDone(
268 DownloadTarget* result,
269 const base::FilePath& target_path,
270 DownloadItem::TargetDisposition target_disposition,
271 content::DownloadDangerType danger_type,
272 const base::FilePath& intermediate_path) {
273 result->target_path = target_path;
274 result->intermediate_path = intermediate_path;
275 result->target_disposition = target_disposition;
276 result->danger_type = danger_type;
279 const base::FilePath& ChromeDownloadManagerDelegateTest::default_download_path()
281 return test_download_dir_.path();
284 TestChromeDownloadManagerDelegate*
285 ChromeDownloadManagerDelegateTest::delegate() {
286 return delegate_.get();
289 content::MockDownloadManager*
290 ChromeDownloadManagerDelegateTest::download_manager() {
291 return download_manager_.get();
294 DownloadPrefs* ChromeDownloadManagerDelegateTest::download_prefs() {
295 return delegate_->download_prefs();
300 TEST_F(ChromeDownloadManagerDelegateTest, StartDownload_LastSavePath) {
301 GURL download_url("http://example.com/foo.txt");
303 scoped_ptr<content::MockDownloadItem> save_as_download(
304 CreateActiveDownloadItem(0));
305 EXPECT_CALL(*save_as_download, GetURL())
306 .Times(::testing::AnyNumber())
307 .WillRepeatedly(ReturnRef(download_url));
308 EXPECT_CALL(*save_as_download, GetTargetDisposition())
309 .Times(::testing::AnyNumber())
310 .WillRepeatedly(Return(DownloadItem::TARGET_DISPOSITION_PROMPT));
312 scoped_ptr<content::MockDownloadItem> automatic_download(
313 CreateActiveDownloadItem(1));
314 EXPECT_CALL(*automatic_download, GetURL())
315 .Times(::testing::AnyNumber())
316 .WillRepeatedly(ReturnRef(download_url));
317 EXPECT_CALL(*automatic_download, GetTargetDisposition())
318 .Times(::testing::AnyNumber())
319 .WillRepeatedly(Return(DownloadItem::TARGET_DISPOSITION_OVERWRITE));
322 // When the prompt is displayed for the first download, the user selects a
323 // path in a different directory.
324 DownloadTarget result;
325 base::FilePath expected_prompt_path(GetPathInDownloadDir("foo.txt"));
326 base::FilePath user_selected_path(GetPathInDownloadDir("bar/baz.txt"));
327 EXPECT_CALL(*delegate(),
328 MockPromptUserForDownloadPath(save_as_download.get(),
329 expected_prompt_path, _))
330 .WillOnce(Return(user_selected_path));
331 DetermineDownloadTarget(save_as_download.get(), &result);
332 EXPECT_EQ(user_selected_path, result.target_path);
333 VerifyAndClearExpectations();
337 // The prompt path for the second download is the user selected directroy
338 // from the previous download.
339 DownloadTarget result;
340 base::FilePath expected_prompt_path(GetPathInDownloadDir("bar/foo.txt"));
341 EXPECT_CALL(*delegate(),
342 MockPromptUserForDownloadPath(save_as_download.get(),
343 expected_prompt_path, _))
344 .WillOnce(Return(base::FilePath()));
345 DetermineDownloadTarget(save_as_download.get(), &result);
346 VerifyAndClearExpectations();
350 // Start an automatic download. This one should get the default download
351 // path since the last download path only affects Save As downloads.
352 DownloadTarget result;
353 base::FilePath expected_path(GetPathInDownloadDir("foo.txt"));
354 DetermineDownloadTarget(automatic_download.get(), &result);
355 EXPECT_EQ(expected_path, result.target_path);
356 VerifyAndClearExpectations();
360 // The prompt path for the next download should be the default.
361 download_prefs()->SetSaveFilePath(download_prefs()->DownloadPath());
362 DownloadTarget result;
363 base::FilePath expected_prompt_path(GetPathInDownloadDir("foo.txt"));
364 EXPECT_CALL(*delegate(),
365 MockPromptUserForDownloadPath(save_as_download.get(),
366 expected_prompt_path, _))
367 .WillOnce(Return(base::FilePath()));
368 DetermineDownloadTarget(save_as_download.get(), &result);
369 VerifyAndClearExpectations();