OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "build/build_config.h" | 5 #include "build/build_config.h" |
6 | 6 |
7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
8 #include <windows.h> | 8 #include <windows.h> |
| 9 #include <winioctl.h> |
9 #include <shellapi.h> | 10 #include <shellapi.h> |
10 #include <shlobj.h> | 11 #include <shlobj.h> |
11 #include <tchar.h> | 12 #include <tchar.h> |
12 #endif | 13 #endif |
13 | 14 |
14 #include <fstream> | 15 #include <fstream> |
15 #include <iostream> | 16 #include <iostream> |
16 #include <set> | 17 #include <set> |
17 | 18 |
18 #include "base/base_paths.h" | 19 #include "base/base_paths.h" |
19 #include "base/file_path.h" | 20 #include "base/file_path.h" |
20 #include "base/file_util.h" | 21 #include "base/file_util.h" |
21 #include "base/logging.h" | 22 #include "base/logging.h" |
22 #include "base/path_service.h" | 23 #include "base/path_service.h" |
23 #include "base/platform_thread.h" | 24 #include "base/platform_thread.h" |
| 25 #include "base/scoped_handle.h" |
24 #include "base/time.h" | 26 #include "base/time.h" |
25 #include "base/utf_string_conversions.h" | 27 #include "base/utf_string_conversions.h" |
26 #include "testing/gtest/include/gtest/gtest.h" | 28 #include "testing/gtest/include/gtest/gtest.h" |
27 #include "testing/platform_test.h" | 29 #include "testing/platform_test.h" |
28 | 30 |
29 // This macro helps avoid wrapped lines in the test structs. | 31 // This macro helps avoid wrapped lines in the test structs. |
30 #define FPL(x) FILE_PATH_LITERAL(x) | 32 #define FPL(x) FILE_PATH_LITERAL(x) |
31 | 33 |
32 namespace { | 34 namespace { |
33 | 35 |
| 36 // To test that file_util::Normalize FilePath() deals with NTFS reparse points |
| 37 // correctly, we need functions to create and delete reparse points. |
| 38 #if defined(OS_WIN) |
| 39 typedef struct _REPARSE_DATA_BUFFER { |
| 40 ULONG ReparseTag; |
| 41 USHORT ReparseDataLength; |
| 42 USHORT Reserved; |
| 43 union { |
| 44 struct { |
| 45 USHORT SubstituteNameOffset; |
| 46 USHORT SubstituteNameLength; |
| 47 USHORT PrintNameOffset; |
| 48 USHORT PrintNameLength; |
| 49 ULONG Flags; |
| 50 WCHAR PathBuffer[1]; |
| 51 } SymbolicLinkReparseBuffer; |
| 52 struct { |
| 53 USHORT SubstituteNameOffset; |
| 54 USHORT SubstituteNameLength; |
| 55 USHORT PrintNameOffset; |
| 56 USHORT PrintNameLength; |
| 57 WCHAR PathBuffer[1]; |
| 58 } MountPointReparseBuffer; |
| 59 struct { |
| 60 UCHAR DataBuffer[1]; |
| 61 } GenericReparseBuffer; |
| 62 }; |
| 63 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; |
| 64 |
| 65 // Sets a reparse point. |source| will now point to |target|. Returns true if |
| 66 // the call succeeds, false otherwise. |
| 67 bool SetReparsePoint(HANDLE source, const FilePath& target_path) { |
| 68 std::wstring kPathPrefix = L"\\??\\"; |
| 69 std::wstring target_str; |
| 70 // The juction will not work if the target path does not start with \??\ . |
| 71 if (kPathPrefix != target_path.value().substr(0, kPathPrefix.size())) |
| 72 target_str += kPathPrefix; |
| 73 target_str += target_path.value(); |
| 74 const wchar_t* target = target_str.c_str(); |
| 75 USHORT size_target = static_cast<USHORT>(wcslen(target)) * sizeof(target[0]); |
| 76 char buffer[2000] = {0}; |
| 77 DWORD returned; |
| 78 |
| 79 REPARSE_DATA_BUFFER* data = reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer); |
| 80 |
| 81 data->ReparseTag = 0xa0000003; |
| 82 memcpy(data->MountPointReparseBuffer.PathBuffer, target, size_target + 2); |
| 83 |
| 84 data->MountPointReparseBuffer.SubstituteNameLength = size_target; |
| 85 data->MountPointReparseBuffer.PrintNameOffset = size_target + 2; |
| 86 data->ReparseDataLength = size_target + 4 + 8; |
| 87 |
| 88 int data_size = data->ReparseDataLength + 8; |
| 89 |
| 90 if (!DeviceIoControl(source, FSCTL_SET_REPARSE_POINT, &buffer, data_size, |
| 91 NULL, 0, &returned, NULL)) { |
| 92 return false; |
| 93 } |
| 94 return true; |
| 95 } |
| 96 |
| 97 // Delete the reparse point referenced by |source|. Returns true if the call |
| 98 // succeeds, false otherwise. |
| 99 bool DeleteReparsePoint(HANDLE source) { |
| 100 DWORD returned; |
| 101 REPARSE_DATA_BUFFER data = {0}; |
| 102 data.ReparseTag = 0xa0000003; |
| 103 if (!DeviceIoControl(source, FSCTL_DELETE_REPARSE_POINT, &data, 8, NULL, 0, |
| 104 &returned, NULL)) { |
| 105 return false; |
| 106 } |
| 107 return true; |
| 108 } |
| 109 #endif |
| 110 |
34 const wchar_t bogus_content[] = L"I'm cannon fodder."; | 111 const wchar_t bogus_content[] = L"I'm cannon fodder."; |
35 | 112 |
36 const file_util::FileEnumerator::FILE_TYPE FILES_AND_DIRECTORIES = | 113 const file_util::FileEnumerator::FILE_TYPE FILES_AND_DIRECTORIES = |
37 static_cast<file_util::FileEnumerator::FILE_TYPE>( | 114 static_cast<file_util::FileEnumerator::FILE_TYPE>( |
38 file_util::FileEnumerator::FILES | | 115 file_util::FileEnumerator::FILES | |
39 file_util::FileEnumerator::DIRECTORIES); | 116 file_util::FileEnumerator::DIRECTORIES); |
40 | 117 |
41 // file_util winds up using autoreleased objects on the Mac, so this needs | 118 // file_util winds up using autoreleased objects on the Mac, so this needs |
42 // to be a PlatformTest | 119 // to be a PlatformTest |
43 class FileUtilTest : public PlatformTest { | 120 class FileUtilTest : public PlatformTest { |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 FilePath subsubdir_path = subdir_path.Append(FPL("Level3")); | 457 FilePath subsubdir_path = subdir_path.Append(FPL("Level3")); |
381 file_util::CreateDirectory(subsubdir_path); | 458 file_util::CreateDirectory(subsubdir_path); |
382 | 459 |
383 FilePath file_03 = subsubdir_path.Append(FPL("The file 03.txt")); | 460 FilePath file_03 = subsubdir_path.Append(FPL("The file 03.txt")); |
384 CreateTextFile(file_03, L"123"); | 461 CreateTextFile(file_03, L"123"); |
385 | 462 |
386 int64 computed_size = file_util::ComputeDirectorySize(test_dir_); | 463 int64 computed_size = file_util::ComputeDirectorySize(test_dir_); |
387 EXPECT_EQ(size_f1 + size_f2 + 3, computed_size); | 464 EXPECT_EQ(size_f1 + size_f2 + 3, computed_size); |
388 } | 465 } |
389 | 466 |
| 467 TEST_F(FileUtilTest, NormalizeFilePathBasic) { |
| 468 // Create a directory under the test dir. Because we create it, |
| 469 // we know it is not a link. |
| 470 FilePath file_a_path = test_dir_.Append(FPL("file_a")); |
| 471 FilePath dir_path = test_dir_.Append(FPL("dir")); |
| 472 FilePath file_b_path = dir_path.Append(FPL("file_b")); |
| 473 file_util::CreateDirectory(dir_path); |
| 474 |
| 475 FilePath normalized_file_a_path, normalized_file_b_path; |
| 476 ASSERT_FALSE(file_util::PathExists(file_a_path)); |
| 477 ASSERT_FALSE(file_util::NormalizeFilePath(file_a_path, |
| 478 &normalized_file_a_path)) |
| 479 << "NormalizeFilePath() should fail on nonexistant paths."; |
| 480 |
| 481 CreateTextFile(file_a_path, bogus_content); |
| 482 ASSERT_TRUE(file_util::PathExists(file_a_path)); |
| 483 ASSERT_TRUE(file_util::NormalizeFilePath(file_a_path, |
| 484 &normalized_file_a_path)); |
| 485 |
| 486 CreateTextFile(file_b_path, bogus_content); |
| 487 ASSERT_TRUE(file_util::PathExists(file_b_path)); |
| 488 ASSERT_TRUE(file_util::NormalizeFilePath(file_b_path, |
| 489 &normalized_file_b_path)); |
| 490 |
| 491 // Beacuse this test created |dir_path|, we know it is not a link |
| 492 // or junction. So, the real path of the directory holding file a |
| 493 // must be the parent of the path holding file b. |
| 494 ASSERT_TRUE(normalized_file_a_path.DirName() |
| 495 .IsParent(normalized_file_b_path.DirName())); |
| 496 } |
| 497 |
| 498 #if defined(OS_WIN) |
| 499 |
| 500 TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) { |
| 501 // Build the following directory structure: |
| 502 // |
| 503 // test_dir_ |
| 504 // |-> base_a |
| 505 // | |-> sub_a |
| 506 // | |-> file.txt |
| 507 // | |-> long_name___... (Very long name.) |
| 508 // | |-> sub_long |
| 509 // | |-> deep.txt |
| 510 // |-> base_b |
| 511 // |-> to_sub_a (reparse point to test_dir_\base_a\sub_a) |
| 512 // |-> to_base_b (reparse point to test_dir_\base_b) |
| 513 // |-> to_sub_long (reparse point to test_dir_\sub_a\long_name_\sub_long) |
| 514 |
| 515 FilePath base_a = test_dir_.Append(FPL("base_a")); |
| 516 ASSERT_TRUE(file_util::CreateDirectory(base_a)); |
| 517 |
| 518 FilePath sub_a = base_a.Append(FPL("sub_a")); |
| 519 ASSERT_TRUE(file_util::CreateDirectory(sub_a)); |
| 520 |
| 521 FilePath file_txt = sub_a.Append(FPL("file.txt")); |
| 522 CreateTextFile(file_txt, bogus_content); |
| 523 |
| 524 // Want a directory whose name is long enough to make the path to the file |
| 525 // inside just under MAX_PATH chars. This will be used to test that when |
| 526 // a junction expands to a path over MAX_PATH chars in length, |
| 527 // NormalizeFilePath() fails without crashing. |
| 528 FilePath sub_long_rel(FPL("sub_long")); |
| 529 FilePath deep_txt(FPL("deep.txt")); |
| 530 |
| 531 int target_length = MAX_PATH; |
| 532 target_length -= (sub_a.value().length() + 1); // +1 for the sepperator '\'. |
| 533 target_length -= (sub_long_rel.Append(deep_txt).value().length() + 1); |
| 534 // Without making the path a bit shorter, CreateDirectory() fails. |
| 535 // the resulting path is still long enough to hit the failing case in |
| 536 // NormalizePath(). |
| 537 const int kCreateDirLimit = 4; |
| 538 target_length -= kCreateDirLimit; |
| 539 FilePath::StringType long_name_str = FPL("long_name_"); |
| 540 long_name_str.resize(target_length, '_'); |
| 541 |
| 542 FilePath long_name = sub_a.Append(FilePath(long_name_str)); |
| 543 FilePath deep_file = long_name.Append(sub_long_rel).Append(deep_txt); |
| 544 ASSERT_EQ(MAX_PATH - kCreateDirLimit, deep_file.value().length()); |
| 545 |
| 546 FilePath sub_long = deep_file.DirName(); |
| 547 ASSERT_TRUE(file_util::CreateDirectory(sub_long)); |
| 548 CreateTextFile(deep_file, bogus_content); |
| 549 |
| 550 FilePath base_b = test_dir_.Append(FPL("base_b")); |
| 551 ASSERT_TRUE(file_util::CreateDirectory(base_b)); |
| 552 |
| 553 FilePath to_sub_a = base_b.Append(FPL("to_sub_a")); |
| 554 ASSERT_TRUE(file_util::CreateDirectory(to_sub_a)); |
| 555 ScopedHandle reparse_to_sub_a( |
| 556 ::CreateFile(to_sub_a.value().c_str(), |
| 557 FILE_ALL_ACCESS, |
| 558 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 559 NULL, |
| 560 OPEN_EXISTING, |
| 561 FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory. |
| 562 NULL)); |
| 563 ASSERT_NE(INVALID_HANDLE_VALUE, reparse_to_sub_a.Get()); |
| 564 ASSERT_TRUE(SetReparsePoint(reparse_to_sub_a, sub_a)); |
| 565 |
| 566 FilePath to_base_b = base_b.Append(FPL("to_base_b")); |
| 567 ASSERT_TRUE(file_util::CreateDirectory(to_base_b)); |
| 568 ScopedHandle reparse_to_base_b( |
| 569 ::CreateFile(to_base_b.value().c_str(), |
| 570 FILE_ALL_ACCESS, |
| 571 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 572 NULL, |
| 573 OPEN_EXISTING, |
| 574 FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory. |
| 575 NULL)); |
| 576 ASSERT_NE(INVALID_HANDLE_VALUE, reparse_to_base_b.Get()); |
| 577 ASSERT_TRUE(SetReparsePoint(reparse_to_base_b, base_b)); |
| 578 |
| 579 FilePath to_sub_long = base_b.Append(FPL("to_sub_long")); |
| 580 ASSERT_TRUE(file_util::CreateDirectory(to_sub_long)); |
| 581 ScopedHandle reparse_to_sub_long( |
| 582 ::CreateFile(to_sub_long.value().c_str(), |
| 583 FILE_ALL_ACCESS, |
| 584 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 585 NULL, |
| 586 OPEN_EXISTING, |
| 587 FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory. |
| 588 NULL)); |
| 589 ASSERT_NE(INVALID_HANDLE_VALUE, reparse_to_sub_long.Get()); |
| 590 ASSERT_TRUE(SetReparsePoint(reparse_to_sub_long, sub_long)); |
| 591 |
| 592 // Normalize a junction free path: base_a\sub_a\file.txt . |
| 593 FilePath normalized_path; |
| 594 ASSERT_TRUE(file_util::NormalizeFilePath(file_txt, &normalized_path)); |
| 595 ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str()); |
| 596 |
| 597 // Check that the path base_b\to_sub_a\file.txt can be normalized to exclude |
| 598 // the junction to_sub_a. |
| 599 ASSERT_TRUE(file_util::NormalizeFilePath(to_sub_a.Append(FPL("file.txt")), |
| 600 &normalized_path)); |
| 601 ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str()); |
| 602 |
| 603 // Check that the path base_b\to_base_b\to_base_b\to_sub_a\file.txt can be |
| 604 // normalized to exclude junctions to_base_b and to_sub_a . |
| 605 ASSERT_TRUE(file_util::NormalizeFilePath(base_b.Append(FPL("to_base_b")) |
| 606 .Append(FPL("to_base_b")) |
| 607 .Append(FPL("to_sub_a")) |
| 608 .Append(FPL("file.txt")), |
| 609 &normalized_path)); |
| 610 ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str()); |
| 611 |
| 612 // A long enough path will cause NormalizeFilePath() to fail. Make a long |
| 613 // path using to_base_b many times, and check that paths long enough to fail |
| 614 // do not cause a crash. |
| 615 FilePath long_path = base_b; |
| 616 const int kLengthLimit = MAX_PATH + 200; |
| 617 while (long_path.value().length() <= kLengthLimit) { |
| 618 long_path = long_path.Append(FPL("to_base_b")); |
| 619 } |
| 620 long_path = long_path.Append(FPL("to_sub_a")) |
| 621 .Append(FPL("file.txt")); |
| 622 |
| 623 ASSERT_FALSE(file_util::NormalizeFilePath(long_path, &normalized_path)); |
| 624 |
| 625 // Normalizing the junction to deep.txt should fail, because the expanded |
| 626 // path to deep.txt is longer than MAX_PATH. |
| 627 ASSERT_FALSE(file_util::NormalizeFilePath(to_sub_long.Append(deep_txt), |
| 628 &normalized_path)); |
| 629 |
| 630 // Delete the reparse points, and see that NormalizeFilePath() fails |
| 631 // to traverse them. |
| 632 ASSERT_TRUE(DeleteReparsePoint(reparse_to_sub_a)); |
| 633 ASSERT_TRUE(DeleteReparsePoint(reparse_to_base_b)); |
| 634 ASSERT_TRUE(DeleteReparsePoint(reparse_to_sub_long)); |
| 635 |
| 636 ASSERT_FALSE(file_util::NormalizeFilePath(to_sub_a.Append(FPL("file.txt")), |
| 637 &normalized_path)); |
| 638 } |
| 639 |
| 640 #endif // defined(OS_WIN) |
| 641 |
| 642 // The following test of NormalizeFilePath() require that we create a symlink. |
| 643 // This can not be done on windows before vista. On vista, creating a symlink |
| 644 // requires privilege "SeCreateSymbolicLinkPrivilege". |
| 645 // TODO(skerner): Investigate the possibility of giving base_unittests the |
| 646 // privileges required to create a symlink. |
390 #if defined(OS_POSIX) | 647 #if defined(OS_POSIX) |
391 TEST_F(FileUtilTest, RealPath) { | 648 |
392 // Get the real test directory, in case some future change to the | 649 bool MakeSymlink(const FilePath& link_to, const FilePath& link_from) { |
393 // test setup makes the path to test_dir_ include a symlink. | 650 return (symlink(link_to.value().c_str(), link_from.value().c_str()) == 0); |
394 FilePath real_test_dir; | 651 } |
395 ASSERT_TRUE(file_util::RealPath(test_dir_, &real_test_dir)); | 652 |
396 | 653 TEST_F(FileUtilTest, NormalizeFilePathSymlinks) { |
397 FilePath real_path; | 654 FilePath normalized_path; |
398 ASSERT_TRUE(file_util::RealPath(real_test_dir, &real_path)); | |
399 ASSERT_TRUE(real_test_dir == real_path); | |
400 | 655 |
401 // Link one file to another. | 656 // Link one file to another. |
402 FilePath link_from = real_test_dir.Append(FPL("from_file")); | 657 FilePath link_from = test_dir_.Append(FPL("from_file")); |
403 FilePath link_to = real_test_dir.Append(FPL("to_file")); | 658 FilePath link_to = test_dir_.Append(FPL("to_file")); |
404 CreateTextFile(link_to, bogus_content); | 659 CreateTextFile(link_to, bogus_content); |
405 | 660 |
406 ASSERT_EQ(0, symlink(link_to.value().c_str(), link_from.value().c_str())) | 661 ASSERT_TRUE(MakeSymlink(link_to, link_from)) |
407 << "Failed to create file symlink."; | 662 << "Failed to create file symlink."; |
408 | 663 |
409 // Check that RealPath sees the link. | 664 // Check that NormalizeFilePath sees the link. |
410 ASSERT_TRUE(file_util::RealPath(link_from, &real_path)); | 665 ASSERT_TRUE(file_util::NormalizeFilePath(link_from, &normalized_path)); |
411 ASSERT_TRUE(link_to != link_from); | 666 ASSERT_TRUE(link_to != link_from); |
412 ASSERT_TRUE(link_to == real_path); | 667 ASSERT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value()); |
413 | 668 ASSERT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value()); |
414 | 669 |
415 // Link to a directory. | 670 // Link to a directory. |
416 link_from = real_test_dir.Append(FPL("from_dir")); | 671 link_from = test_dir_.Append(FPL("from_dir")); |
417 link_to = real_test_dir.Append(FPL("to_dir")); | 672 link_to = test_dir_.Append(FPL("to_dir")); |
418 file_util::CreateDirectory(link_to); | 673 file_util::CreateDirectory(link_to); |
419 | 674 |
420 ASSERT_EQ(0, symlink(link_to.value().c_str(), link_from.value().c_str())) | 675 ASSERT_TRUE(MakeSymlink(link_to, link_from)) |
421 << "Failed to create directory symlink."; | 676 << "Failed to create directory symlink."; |
422 | 677 |
423 ASSERT_TRUE(file_util::RealPath(link_from, &real_path)); | 678 ASSERT_FALSE(file_util::NormalizeFilePath(link_from, &normalized_path)) |
424 ASSERT_TRUE(link_to != link_from); | 679 << "Links to directories should return false."; |
425 ASSERT_TRUE(link_to == real_path); | 680 |
426 | 681 // Test that a loop in the links causes NormalizeFilePath() to return false. |
427 | 682 link_from = test_dir_.Append(FPL("link_a")); |
428 // Test that a loop in the links causes RealPath() to return false. | 683 link_to = test_dir_.Append(FPL("link_b")); |
429 link_from = real_test_dir.Append(FPL("link_a")); | 684 ASSERT_TRUE(MakeSymlink(link_to, link_from)) |
430 link_to = real_test_dir.Append(FPL("link_b")); | |
431 ASSERT_EQ(0, symlink(link_to.value().c_str(), link_from.value().c_str())) | |
432 << "Failed to create loop symlink a."; | 685 << "Failed to create loop symlink a."; |
433 ASSERT_EQ(0, symlink(link_from.value().c_str(), link_to.value().c_str())) | 686 ASSERT_TRUE(MakeSymlink(link_from, link_to)) |
434 << "Failed to create loop symlink b."; | 687 << "Failed to create loop symlink b."; |
435 | 688 |
436 // Infinite loop! | 689 // Infinite loop! |
437 ASSERT_FALSE(file_util::RealPath(link_from, &real_path)); | 690 ASSERT_FALSE(file_util::NormalizeFilePath(link_from, &normalized_path)); |
438 } | 691 } |
439 #endif // defined(OS_POSIX) | 692 #endif // defined(OS_POSIX) |
440 | 693 |
441 TEST_F(FileUtilTest, DeleteNonExistent) { | 694 TEST_F(FileUtilTest, DeleteNonExistent) { |
442 FilePath non_existent = test_dir_.AppendASCII("bogus_file_dne.foobar"); | 695 FilePath non_existent = test_dir_.AppendASCII("bogus_file_dne.foobar"); |
443 ASSERT_FALSE(file_util::PathExists(non_existent)); | 696 ASSERT_FALSE(file_util::PathExists(non_existent)); |
444 | 697 |
445 EXPECT_TRUE(file_util::Delete(non_existent, false)); | 698 EXPECT_TRUE(file_util::Delete(non_existent, false)); |
446 ASSERT_FALSE(file_util::PathExists(non_existent)); | 699 ASSERT_FALSE(file_util::PathExists(non_existent)); |
447 EXPECT_TRUE(file_util::Delete(non_existent, true)); | 700 EXPECT_TRUE(file_util::Delete(non_existent, true)); |
(...skipping 1140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1588 EXPECT_TRUE(file_util::IsDirectoryEmpty(empty_dir)); | 1841 EXPECT_TRUE(file_util::IsDirectoryEmpty(empty_dir)); |
1589 | 1842 |
1590 FilePath foo(empty_dir.Append(FILE_PATH_LITERAL("foo.txt"))); | 1843 FilePath foo(empty_dir.Append(FILE_PATH_LITERAL("foo.txt"))); |
1591 std::string bar("baz"); | 1844 std::string bar("baz"); |
1592 ASSERT_TRUE(file_util::WriteFile(foo, bar.c_str(), bar.length())); | 1845 ASSERT_TRUE(file_util::WriteFile(foo, bar.c_str(), bar.length())); |
1593 | 1846 |
1594 EXPECT_FALSE(file_util::IsDirectoryEmpty(empty_dir)); | 1847 EXPECT_FALSE(file_util::IsDirectoryEmpty(empty_dir)); |
1595 } | 1848 } |
1596 | 1849 |
1597 } // namespace | 1850 } // namespace |
OLD | NEW |