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 701