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 <list> 6 #include <utility> 7 8 #include "base/file_util.h" 9 #include "base/files/file_path.h" 10 #include "base/files/scoped_temp_dir.h" 11 #include "base/i18n/file_util_icu.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/platform_file.h" 14 #include "base/strings/stringprintf.h" 15 #include "net/base/directory_lister.h" 16 #include "net/base/net_errors.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 #include "testing/platform_test.h" 19 20 namespace net { 21 22 class ListerDelegate : public DirectoryLister::DirectoryListerDelegate { 23 public: 24 ListerDelegate(bool recursive, 25 bool quit_loop_after_each_file) 26 : error_(-1), 27 recursive_(recursive), 28 quit_loop_after_each_file_(quit_loop_after_each_file) { 29 } 30 31 virtual void OnListFile( 32 const DirectoryLister::DirectoryListerData& data) OVERRIDE { 33 file_list_.push_back(data.info); 34 paths_.push_back(data.path); 35 if (quit_loop_after_each_file_) 36 base::MessageLoop::current()->Quit(); 37 } 38 39 virtual void OnListDone(int error) OVERRIDE { 40 error_ = error; 41 base::MessageLoop::current()->Quit(); 42 if (recursive_) 43 CheckRecursiveSort(); 44 else 45 CheckSort(); 46 } 47 48 void CheckRecursiveSort() { 49 // Check that we got files in the right order. 50 if (!file_list_.empty()) { 51 for (size_t previous = 0, current = 1; 52 current < file_list_.size(); 53 previous++, current++) { 54 EXPECT_TRUE(file_util::LocaleAwareCompareFilenames( 55 paths_[previous], paths_[current])); 56 } 57 } 58 } 59 60 void CheckSort() { 61 // Check that we got files in the right order. 62 if (!file_list_.empty()) { 63 for (size_t previous = 0, current = 1; 64 current < file_list_.size(); 65 previous++, current++) { 66 // Directories should come before files. 67 if (file_list_[previous].IsDirectory() && 68 !file_list_[current].IsDirectory()) { 69 continue; 70 } 71 EXPECT_NE(FILE_PATH_LITERAL(".."), 72 file_list_[current].GetName().BaseName().value()); 73 EXPECT_EQ(file_list_[previous].IsDirectory(), 74 file_list_[current].IsDirectory()); 75 EXPECT_TRUE(file_util::LocaleAwareCompareFilenames( 76 file_list_[previous].GetName(), 77 file_list_[current].GetName())); 78 } 79 } 80 } 81 82 int error() const { return error_; } 83 84 int num_files() const { return file_list_.size(); } 85 86 private: 87 int error_; 88 bool recursive_; 89 bool quit_loop_after_each_file_; 90 std::vector<base::FileEnumerator::FileInfo> file_list_; 91 std::vector<base::FilePath> paths_; 92 }; 93 94 class DirectoryListerTest : public PlatformTest { 95 public: 96 97 virtual void SetUp() OVERRIDE { 98 const int kMaxDepth = 3; 99 const int kBranchingFactor = 4; 100 const int kFilesPerDirectory = 5; 101 102 // Randomly create a directory structure of depth 3 in a temporary root 103 // directory. 104 std::list<std::pair<base::FilePath, int> > directories; 105 ASSERT_TRUE(temp_root_dir_.CreateUniqueTempDir()); 106 directories.push_back(std::make_pair(temp_root_dir_.path(), 0)); 107 while (!directories.empty()) { 108 std::pair<base::FilePath, int> dir_data = directories.front(); 109 directories.pop_front(); 110 for (int i = 0; i < kFilesPerDirectory; i++) { 111 std::string file_name = base::StringPrintf("file_id_%d", i); 112 base::FilePath file_path = dir_data.first.AppendASCII(file_name); 113 base::PlatformFile file = base::CreatePlatformFile( 114 file_path, 115 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE, 116 NULL, 117 NULL); 118 ASSERT_NE(base::kInvalidPlatformFileValue, file); 119 ASSERT_TRUE(base::ClosePlatformFile(file)); 120 } 121 if (dir_data.second < kMaxDepth - 1) { 122 for (int i = 0; i < kBranchingFactor; i++) { 123 std::string dir_name = base::StringPrintf("child_dir_%d", i); 124 base::FilePath dir_path = dir_data.first.AppendASCII(dir_name); 125 ASSERT_TRUE(file_util::CreateDirectory(dir_path)); 126 directories.push_back(std::make_pair(dir_path, dir_data.second + 1)); 127 } 128 } 129 } 130 PlatformTest::SetUp(); 131 } 132 133 const base::FilePath& root_path() const { 134 return temp_root_dir_.path(); 135 } 136 137 private: 138 base::ScopedTempDir temp_root_dir_; 139 }; 140 141 TEST_F(DirectoryListerTest, BigDirTest) { 142 ListerDelegate delegate(false, false); 143 DirectoryLister lister(root_path(), &delegate); 144 lister.Start(); 145 146 base::MessageLoop::current()->Run(); 147 148 EXPECT_EQ(OK, delegate.error()); 149 } 150 151 TEST_F(DirectoryListerTest, BigDirRecursiveTest) { 152 ListerDelegate delegate(true, false); 153 DirectoryLister lister(root_path(), true, DirectoryLister::FULL_PATH, 154 &delegate); 155 lister.Start(); 156 157 base::MessageLoop::current()->Run(); 158 159 EXPECT_EQ(OK, delegate.error()); 160 } 161 162 TEST_F(DirectoryListerTest, CancelTest) { 163 ListerDelegate delegate(false, true); 164 DirectoryLister lister(root_path(), &delegate); 165 lister.Start(); 166 167 base::MessageLoop::current()->Run(); 168 169 int num_files = delegate.num_files(); 170 171 lister.Cancel(); 172 173 base::MessageLoop::current()->RunUntilIdle(); 174 175 EXPECT_EQ(num_files, delegate.num_files()); 176 } 177 178 TEST_F(DirectoryListerTest, EmptyDirTest) { 179 base::ScopedTempDir tempDir; 180 EXPECT_TRUE(tempDir.CreateUniqueTempDir()); 181 182 bool kRecursive = false; 183 bool kQuitLoopAfterEachFile = false; 184 ListerDelegate delegate(kRecursive, kQuitLoopAfterEachFile); 185 DirectoryLister lister(tempDir.path(), &delegate); 186 lister.Start(); 187 188 base::MessageLoop::current()->Run(); 189 190 // Contains only the parent directory ("..") 191 EXPECT_EQ(1, delegate.num_files()); 192 EXPECT_EQ(OK, delegate.error()); 193 } 194 195 } // namespace net 196