- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / download / download_path_reservation_tracker_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/file_util.h"
6 #include "base/files/file_path.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/observer_list.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/test/test_file_util.h"
13 #include "chrome/browser/download/download_path_reservation_tracker.h"
14 #include "chrome/browser/download/download_target_determiner.h"
15 #include "content/public/test/mock_download_item.h"
16 #include "content/public/test/test_browser_thread.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using content::BrowserThread;
21 using content::DownloadItem;
22 using content::MockDownloadItem;
23 using testing::AnyNumber;
24 using testing::Return;
25 using testing::ReturnRef;
26 using testing::ReturnRefOfCopy;
27
28 namespace {
29
30 // MockDownloadItem with real observers and state.
31 class FakeDownloadItem : public MockDownloadItem {
32  public:
33   explicit FakeDownloadItem()
34       : state_(IN_PROGRESS) {
35   }
36   virtual ~FakeDownloadItem() {
37     FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this));
38     EXPECT_FALSE(observers_.might_have_observers());
39   }
40   virtual void AddObserver(Observer* observer) OVERRIDE {
41     observers_.AddObserver(observer);
42   }
43   virtual void RemoveObserver(Observer* observer) OVERRIDE {
44     observers_.RemoveObserver(observer);
45   }
46   virtual void UpdateObservers() OVERRIDE {
47     FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
48   }
49
50   virtual DownloadState GetState() const OVERRIDE {
51     return state_;
52   }
53
54   void SetState(DownloadState state) {
55     state_ = state;
56     UpdateObservers();
57   }
58
59  private:
60   DownloadState state_;
61   ObserverList<Observer> observers_;
62 };
63
64 class DownloadPathReservationTrackerTest : public testing::Test {
65  public:
66   DownloadPathReservationTrackerTest();
67
68   // testing::Test
69   virtual void SetUp() OVERRIDE;
70   virtual void TearDown() OVERRIDE;
71
72   FakeDownloadItem* CreateDownloadItem(int32 id);
73   base::FilePath GetPathInDownloadsDirectory(
74       const base::FilePath::CharType* suffix);
75   bool IsPathInUse(const base::FilePath& path);
76   void CallGetReservedPath(
77       DownloadItem* download_item,
78       const base::FilePath& target_path,
79       bool create_directory,
80       DownloadPathReservationTracker::FilenameConflictAction conflict_action,
81       base::FilePath* return_path,
82       bool* return_verified);
83
84   const base::FilePath& default_download_path() const {
85     return default_download_path_;
86   }
87   void set_default_download_path(const base::FilePath& path) {
88     default_download_path_ = path;
89   }
90   // Creates a name of form 'a'*repeat + suffix
91   base::FilePath GetLongNamePathInDownloadsDirectory(
92       size_t repeat, const base::FilePath::CharType* suffix);
93
94  protected:
95   base::ScopedTempDir test_download_dir_;
96   base::FilePath default_download_path_;
97   base::MessageLoopForUI message_loop_;
98   content::TestBrowserThread ui_thread_;
99   content::TestBrowserThread file_thread_;
100
101  private:
102   void TestReservedPathCallback(base::FilePath* return_path,
103                                 bool* return_verified, bool* did_run_callback,
104                                 const base::FilePath& path, bool verified);
105 };
106
107 DownloadPathReservationTrackerTest::DownloadPathReservationTrackerTest()
108     : ui_thread_(BrowserThread::UI, &message_loop_),
109       file_thread_(BrowserThread::FILE, &message_loop_) {
110 }
111
112 void DownloadPathReservationTrackerTest::SetUp() {
113   ASSERT_TRUE(test_download_dir_.CreateUniqueTempDir());
114   set_default_download_path(test_download_dir_.path());
115 }
116
117 void DownloadPathReservationTrackerTest::TearDown() {
118   message_loop_.RunUntilIdle();
119 }
120
121 FakeDownloadItem* DownloadPathReservationTrackerTest::CreateDownloadItem(
122     int32 id) {
123   FakeDownloadItem* item = new ::testing::StrictMock<FakeDownloadItem>;
124   EXPECT_CALL(*item, GetId())
125       .WillRepeatedly(Return(id));
126   EXPECT_CALL(*item, GetTargetFilePath())
127       .WillRepeatedly(ReturnRefOfCopy(base::FilePath()));
128   return item;
129 }
130
131 base::FilePath DownloadPathReservationTrackerTest::GetPathInDownloadsDirectory(
132     const base::FilePath::CharType* suffix) {
133   return default_download_path().Append(suffix).NormalizePathSeparators();
134 }
135
136 bool DownloadPathReservationTrackerTest::IsPathInUse(
137     const base::FilePath& path) {
138   return DownloadPathReservationTracker::IsPathInUseForTesting(path);
139 }
140
141 void DownloadPathReservationTrackerTest::CallGetReservedPath(
142     DownloadItem* download_item,
143     const base::FilePath& target_path,
144     bool create_directory,
145     DownloadPathReservationTracker::FilenameConflictAction conflict_action,
146     base::FilePath* return_path,
147     bool* return_verified) {
148   // Weak pointer factory to prevent the callback from running after this
149   // function has returned.
150   base::WeakPtrFactory<DownloadPathReservationTrackerTest> weak_ptr_factory(
151       this);
152   bool did_run_callback = false;
153   DownloadPathReservationTracker::GetReservedPath(
154       download_item,
155       target_path,
156       default_download_path(),
157       create_directory,
158       conflict_action,
159       base::Bind(&DownloadPathReservationTrackerTest::TestReservedPathCallback,
160                  weak_ptr_factory.GetWeakPtr(), return_path, return_verified,
161                  &did_run_callback));
162   message_loop_.RunUntilIdle();
163   EXPECT_TRUE(did_run_callback);
164 }
165
166 void DownloadPathReservationTrackerTest::TestReservedPathCallback(
167     base::FilePath* return_path, bool* return_verified, bool* did_run_callback,
168     const base::FilePath& path, bool verified) {
169   *did_run_callback = true;
170   *return_path = path;
171   *return_verified = verified;
172 }
173
174 base::FilePath
175 DownloadPathReservationTrackerTest::GetLongNamePathInDownloadsDirectory(
176     size_t repeat, const base::FilePath::CharType* suffix) {
177   return GetPathInDownloadsDirectory(
178       (base::FilePath::StringType(repeat, FILE_PATH_LITERAL('a'))
179           + suffix).c_str());
180 }
181
182 }  // namespace
183
184 // A basic reservation is acquired and committed.
185 TEST_F(DownloadPathReservationTrackerTest, BasicReservation) {
186   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
187   base::FilePath path(
188       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
189   ASSERT_FALSE(IsPathInUse(path));
190
191   base::FilePath reserved_path;
192   bool verified = false;
193   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
194     DownloadPathReservationTracker::OVERWRITE;
195   bool create_directory = false;
196   CallGetReservedPath(
197       item.get(),
198       path,
199       create_directory,
200       conflict_action,
201       &reserved_path,
202       &verified);
203   EXPECT_TRUE(IsPathInUse(path));
204   EXPECT_TRUE(verified);
205   EXPECT_EQ(path.value(), reserved_path.value());
206
207   // Destroying the item should release the reservation.
208   item->SetState(DownloadItem::COMPLETE);
209   item.reset();
210   message_loop_.RunUntilIdle();
211   EXPECT_FALSE(IsPathInUse(path));
212 }
213
214 // A download that is interrupted should lose its reservation.
215 TEST_F(DownloadPathReservationTrackerTest, InterruptedDownload) {
216   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
217   base::FilePath path(
218       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
219   ASSERT_FALSE(IsPathInUse(path));
220
221   base::FilePath reserved_path;
222   bool verified = false;
223   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
224     DownloadPathReservationTracker::OVERWRITE;
225   bool create_directory = false;
226   CallGetReservedPath(
227       item.get(),
228       path,
229       create_directory,
230       conflict_action,
231       &reserved_path,
232       &verified);
233   EXPECT_TRUE(IsPathInUse(path));
234   EXPECT_TRUE(verified);
235   EXPECT_EQ(path.value(), reserved_path.value());
236
237   // Once the download is interrupted, the path should become available again.
238   item->SetState(DownloadItem::INTERRUPTED);
239   message_loop_.RunUntilIdle();
240   EXPECT_FALSE(IsPathInUse(path));
241 }
242
243 // A completed download should also lose its reservation.
244 TEST_F(DownloadPathReservationTrackerTest, CompleteDownload) {
245   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
246   base::FilePath path(
247       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
248   ASSERT_FALSE(IsPathInUse(path));
249
250   base::FilePath reserved_path;
251   bool verified = false;
252   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
253     DownloadPathReservationTracker::OVERWRITE;
254   bool create_directory = false;
255   CallGetReservedPath(
256       item.get(),
257       path,
258       create_directory,
259       conflict_action,
260       &reserved_path,
261       &verified);
262   EXPECT_TRUE(IsPathInUse(path));
263   EXPECT_TRUE(verified);
264   EXPECT_EQ(path.value(), reserved_path.value());
265
266   // Once the download completes, the path should become available again. For a
267   // real download, at this point only the path reservation will be released.
268   // The path wouldn't be available since it is occupied on disk by the
269   // completed download.
270   item->SetState(DownloadItem::COMPLETE);
271   message_loop_.RunUntilIdle();
272   EXPECT_FALSE(IsPathInUse(path));
273 }
274
275 // If there are files on the file system, a unique reservation should uniquify
276 // around it.
277 TEST_F(DownloadPathReservationTrackerTest, ConflictingFiles) {
278   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
279   base::FilePath path(
280       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
281   base::FilePath path1(
282       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo (1).txt")));
283   // Create a file at |path|, and a .crdownload file at |path1|.
284   ASSERT_EQ(0, file_util::WriteFile(path, "", 0));
285   ASSERT_EQ(0,
286             file_util::WriteFile(
287                 DownloadTargetDeterminer::GetCrDownloadPath(path1), "", 0));
288   ASSERT_TRUE(IsPathInUse(path));
289
290   base::FilePath reserved_path;
291   bool verified = false;
292   bool create_directory = false;
293   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
294     DownloadPathReservationTracker::UNIQUIFY;
295   CallGetReservedPath(
296       item.get(),
297       path,
298       create_directory,
299       conflict_action,
300       &reserved_path,
301       &verified);
302   EXPECT_TRUE(IsPathInUse(path));
303   EXPECT_TRUE(IsPathInUse(reserved_path));
304   EXPECT_TRUE(verified);
305   // The path should be uniquified, skipping over foo.txt but not over
306   // "foo (1).txt.crdownload"
307   EXPECT_EQ(
308       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo (1).txt")).value(),
309       reserved_path.value());
310
311   item->SetState(DownloadItem::COMPLETE);
312   item.reset();
313   message_loop_.RunUntilIdle();
314   EXPECT_TRUE(IsPathInUse(path));
315   EXPECT_FALSE(IsPathInUse(reserved_path));
316 }
317
318 // Multiple reservations for the same path should uniquify around each other.
319 TEST_F(DownloadPathReservationTrackerTest, ConflictingReservations) {
320   scoped_ptr<FakeDownloadItem> item1(CreateDownloadItem(1));
321   base::FilePath path(
322       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
323   base::FilePath uniquified_path(
324       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo (1).txt")));
325   ASSERT_FALSE(IsPathInUse(path));
326   ASSERT_FALSE(IsPathInUse(uniquified_path));
327
328   base::FilePath reserved_path1;
329   bool verified = false;
330   bool create_directory = false;
331
332   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
333     DownloadPathReservationTracker::UNIQUIFY;
334   CallGetReservedPath(
335       item1.get(),
336       path,
337       create_directory,
338       conflict_action,
339       &reserved_path1,
340       &verified);
341   EXPECT_TRUE(IsPathInUse(path));
342   EXPECT_TRUE(verified);
343
344
345   {
346     // Requesting a reservation for the same path with uniquification results in
347     // a uniquified path.
348     scoped_ptr<FakeDownloadItem> item2(CreateDownloadItem(2));
349     base::FilePath reserved_path2;
350     CallGetReservedPath(
351         item2.get(),
352         path,
353         create_directory,
354         conflict_action,
355         &reserved_path2,
356         &verified);
357     EXPECT_TRUE(IsPathInUse(path));
358     EXPECT_TRUE(IsPathInUse(uniquified_path));
359     EXPECT_EQ(uniquified_path.value(), reserved_path2.value());
360     item2->SetState(DownloadItem::COMPLETE);
361   }
362   message_loop_.RunUntilIdle();
363   EXPECT_TRUE(IsPathInUse(path));
364   EXPECT_FALSE(IsPathInUse(uniquified_path));
365
366   {
367     // Since the previous download item was removed, requesting a reservation
368     // for the same path should result in the same uniquified path.
369     scoped_ptr<FakeDownloadItem> item2(CreateDownloadItem(2));
370     base::FilePath reserved_path2;
371     CallGetReservedPath(
372         item2.get(),
373         path,
374         create_directory,
375         conflict_action,
376         &reserved_path2,
377         &verified);
378     EXPECT_TRUE(IsPathInUse(path));
379     EXPECT_TRUE(IsPathInUse(uniquified_path));
380     EXPECT_EQ(uniquified_path.value(), reserved_path2.value());
381     item2->SetState(DownloadItem::COMPLETE);
382   }
383   message_loop_.RunUntilIdle();
384
385   // Now acquire an overwriting reservation. We should end up with the same
386   // non-uniquified path for both reservations.
387   scoped_ptr<FakeDownloadItem> item3(CreateDownloadItem(2));
388   base::FilePath reserved_path3;
389   conflict_action = DownloadPathReservationTracker::OVERWRITE;
390   CallGetReservedPath(
391       item3.get(),
392       path,
393       create_directory,
394       conflict_action,
395       &reserved_path3,
396       &verified);
397   EXPECT_TRUE(IsPathInUse(path));
398   EXPECT_FALSE(IsPathInUse(uniquified_path));
399
400   EXPECT_EQ(path.value(), reserved_path1.value());
401   EXPECT_EQ(path.value(), reserved_path3.value());
402
403   item1->SetState(DownloadItem::COMPLETE);
404   item3->SetState(DownloadItem::COMPLETE);
405 }
406
407 // If a unique path cannot be determined after trying kMaxUniqueFiles
408 // uniquifiers, then the callback should notified that verification failed, and
409 // the returned path should be set to the original requested path.
410 TEST_F(DownloadPathReservationTrackerTest, UnresolvedConflicts) {
411   base::FilePath path(
412       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
413   scoped_ptr<FakeDownloadItem> items[
414       DownloadPathReservationTracker::kMaxUniqueFiles + 1];
415   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
416     DownloadPathReservationTracker::UNIQUIFY;
417   bool create_directory = false;
418
419   // Create |kMaxUniqueFiles + 1| reservations for |path|. The first reservation
420   // will have no uniquifier. The |kMaxUniqueFiles| remaining reservations do.
421   for (int i = 0; i <= DownloadPathReservationTracker::kMaxUniqueFiles; i++) {
422     base::FilePath reserved_path;
423     base::FilePath expected_path;
424     bool verified = false;
425     if (i > 0) {
426       expected_path =
427           path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", i));
428     } else {
429       expected_path = path;
430     }
431     items[i].reset(CreateDownloadItem(i));
432     EXPECT_FALSE(IsPathInUse(expected_path));
433     CallGetReservedPath(
434         items[i].get(),
435         path,
436         create_directory,
437         conflict_action,
438         &reserved_path,
439         &verified);
440     EXPECT_TRUE(IsPathInUse(expected_path));
441     EXPECT_EQ(expected_path.value(), reserved_path.value());
442     EXPECT_TRUE(verified);
443   }
444   // The next reservation for |path| will fail to be unique.
445   scoped_ptr<FakeDownloadItem> item(
446       CreateDownloadItem(DownloadPathReservationTracker::kMaxUniqueFiles + 1));
447   base::FilePath reserved_path;
448   bool verified = true;
449   CallGetReservedPath(
450       item.get(),
451       path,
452       create_directory,
453       conflict_action,
454       &reserved_path,
455       &verified);
456   EXPECT_FALSE(verified);
457   EXPECT_EQ(path.value(), reserved_path.value());
458
459   item->SetState(DownloadItem::COMPLETE);
460   for (int i = 0; i <= DownloadPathReservationTracker::kMaxUniqueFiles; i++) {
461     items[i]->SetState(DownloadItem::COMPLETE);
462   }
463 }
464
465 // If the target directory is unwriteable, then callback should be notified that
466 // verification failed.
467 TEST_F(DownloadPathReservationTrackerTest, UnwriteableDirectory) {
468   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
469   base::FilePath path(
470       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
471   base::FilePath dir(path.DirName());
472   ASSERT_FALSE(IsPathInUse(path));
473
474   {
475     // Scope for PermissionRestorer
476     file_util::PermissionRestorer restorer(dir);
477     EXPECT_TRUE(file_util::MakeFileUnwritable(dir));
478     base::FilePath reserved_path;
479     bool verified = true;
480     DownloadPathReservationTracker::FilenameConflictAction conflict_action =
481       DownloadPathReservationTracker::OVERWRITE;
482     bool create_directory = false;
483     CallGetReservedPath(
484         item.get(),
485         path,
486         create_directory,
487         conflict_action,
488         &reserved_path,
489         &verified);
490     // Verification fails.
491     EXPECT_FALSE(verified);
492     EXPECT_EQ(path.BaseName().value(), reserved_path.BaseName().value());
493   }
494   item->SetState(DownloadItem::COMPLETE);
495 }
496
497 // If the default download directory doesn't exist, then it should be
498 // created. But only if we are actually going to create the download path there.
499 TEST_F(DownloadPathReservationTrackerTest, CreateDefaultDownloadPath) {
500   base::FilePath path(
501       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo/foo.txt")));
502   base::FilePath dir(path.DirName());
503   ASSERT_FALSE(base::DirectoryExists(dir));
504   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
505     DownloadPathReservationTracker::OVERWRITE;
506   bool create_directory = false;
507
508   {
509     scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
510     base::FilePath reserved_path;
511     bool verified = true;
512     CallGetReservedPath(
513         item.get(),
514         path,
515         create_directory,
516         conflict_action,
517         &reserved_path,
518         &verified);
519     // Verification fails because the directory doesn't exist.
520     EXPECT_FALSE(verified);
521     item->SetState(DownloadItem::COMPLETE);
522   }
523   ASSERT_FALSE(IsPathInUse(path));
524   {
525     scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
526     base::FilePath reserved_path;
527     bool verified = true;
528     set_default_download_path(dir);
529     CallGetReservedPath(
530         item.get(),
531         path,
532         create_directory,
533         conflict_action,
534         &reserved_path,
535         &verified);
536     // Verification succeeds because the directory is created.
537     EXPECT_TRUE(verified);
538     EXPECT_TRUE(base::DirectoryExists(dir));
539     item->SetState(DownloadItem::COMPLETE);
540   }
541 }
542
543 // If the target path of the download item changes, the reservation should be
544 // updated to match.
545 TEST_F(DownloadPathReservationTrackerTest, UpdatesToTargetPath) {
546   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
547   base::FilePath path(
548       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
549   ASSERT_FALSE(IsPathInUse(path));
550
551   base::FilePath reserved_path;
552   bool verified = false;
553   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
554     DownloadPathReservationTracker::OVERWRITE;
555   bool create_directory = false;
556   CallGetReservedPath(
557       item.get(),
558       path,
559       create_directory,
560       conflict_action,
561       &reserved_path,
562       &verified);
563   EXPECT_TRUE(IsPathInUse(path));
564   EXPECT_TRUE(verified);
565   EXPECT_EQ(path.value(), reserved_path.value());
566
567   // The target path is initially empty. If an OnDownloadUpdated() is issued in
568   // this state, we shouldn't lose the reservation.
569   ASSERT_EQ(base::FilePath::StringType(), item->GetTargetFilePath().value());
570   item->UpdateObservers();
571   message_loop_.RunUntilIdle();
572   EXPECT_TRUE(IsPathInUse(path));
573
574   // If the target path changes, we should update the reservation to match.
575   base::FilePath new_target_path(
576       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("bar.txt")));
577   ASSERT_FALSE(IsPathInUse(new_target_path));
578   EXPECT_CALL(*item, GetTargetFilePath())
579       .WillRepeatedly(ReturnRef(new_target_path));
580   item->UpdateObservers();
581   message_loop_.RunUntilIdle();
582   EXPECT_FALSE(IsPathInUse(path));
583   EXPECT_TRUE(IsPathInUse(new_target_path));
584
585   // Destroying the item should release the reservation.
586   item->SetState(DownloadItem::COMPLETE);
587   item.reset();
588   message_loop_.RunUntilIdle();
589   EXPECT_FALSE(IsPathInUse(new_target_path));
590 }
591
592 // Tests for long name truncation. On other platforms automatic truncation
593 // is not performed (yet).
594 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
595
596 TEST_F(DownloadPathReservationTrackerTest, BasicTruncation) {
597   int real_max_length =
598       file_util::GetMaximumPathComponentLength(default_download_path());
599   ASSERT_NE(-1, real_max_length);
600
601   // TODO(kinaba): the current implementation leaves spaces for appending
602   // ".crdownload". So take it into account. Should be removed in the future.
603   const size_t max_length = real_max_length - 11;
604
605   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
606   base::FilePath path(GetLongNamePathInDownloadsDirectory(
607       max_length, FILE_PATH_LITERAL(".txt")));
608   ASSERT_FALSE(IsPathInUse(path));
609
610   base::FilePath reserved_path;
611   bool verified = false;
612   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
613     DownloadPathReservationTracker::OVERWRITE;
614   bool create_directory = false;
615   CallGetReservedPath(
616       item.get(),
617       path,
618       create_directory,
619       conflict_action,
620       &reserved_path,
621       &verified);
622   EXPECT_TRUE(IsPathInUse(reserved_path));
623   EXPECT_TRUE(verified);
624   // The file name length is truncated to max_length.
625   EXPECT_EQ(max_length, reserved_path.BaseName().value().size());
626   // But the extension is kept unchanged.
627   EXPECT_EQ(path.Extension(), reserved_path.Extension());
628   item->SetState(DownloadItem::COMPLETE);
629 }
630
631 TEST_F(DownloadPathReservationTrackerTest, TruncationConflict) {
632   int real_max_length =
633       file_util::GetMaximumPathComponentLength(default_download_path());
634   ASSERT_NE(-1, real_max_length);
635   const size_t max_length = real_max_length - 11;
636
637   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
638   base::FilePath path(GetLongNamePathInDownloadsDirectory(
639       max_length, FILE_PATH_LITERAL(".txt")));
640   base::FilePath path0(GetLongNamePathInDownloadsDirectory(
641       max_length - 4, FILE_PATH_LITERAL(".txt")));
642   base::FilePath path1(GetLongNamePathInDownloadsDirectory(
643       max_length - 8, FILE_PATH_LITERAL(" (1).txt")));
644   base::FilePath path2(GetLongNamePathInDownloadsDirectory(
645       max_length - 8, FILE_PATH_LITERAL(" (2).txt")));
646   ASSERT_FALSE(IsPathInUse(path));
647   // "aaa...aaaaaaa.txt" (truncated path) and
648   // "aaa...aaa (1).txt" (truncated and first uniquification try) exists.
649   // "aaa...aaa (2).txt" should be used.
650   ASSERT_EQ(0, file_util::WriteFile(path0, "", 0));
651   ASSERT_EQ(0, file_util::WriteFile(path1, "", 0));
652
653   base::FilePath reserved_path;
654   bool verified = false;
655   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
656     DownloadPathReservationTracker::UNIQUIFY;
657   bool create_directory = false;
658   CallGetReservedPath(
659       item.get(),
660       path,
661       create_directory,
662       conflict_action,
663       &reserved_path,
664       &verified);
665   EXPECT_TRUE(IsPathInUse(reserved_path));
666   EXPECT_TRUE(verified);
667   EXPECT_EQ(path2, reserved_path);
668   item->SetState(DownloadItem::COMPLETE);
669 }
670
671 TEST_F(DownloadPathReservationTrackerTest, TruncationFail) {
672   int real_max_length =
673       file_util::GetMaximumPathComponentLength(default_download_path());
674   ASSERT_NE(-1, real_max_length);
675   const size_t max_length = real_max_length - 11;
676
677   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
678   base::FilePath path(GetPathInDownloadsDirectory(
679       (FILE_PATH_LITERAL("a.") +
680           base::FilePath::StringType(max_length, 'b')).c_str()));
681   ASSERT_FALSE(IsPathInUse(path));
682
683   base::FilePath reserved_path;
684   bool verified = false;
685   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
686     DownloadPathReservationTracker::OVERWRITE;
687   bool create_directory = false;
688   CallGetReservedPath(
689       item.get(),
690       path,
691       create_directory,
692       conflict_action,
693       &reserved_path,
694       &verified);
695   // We cannot truncate a path with very long extension.
696   EXPECT_FALSE(verified);
697   item->SetState(DownloadItem::COMPLETE);
698 }
699
700 #endif