directory_lister_unittest.cc 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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. #include <list>
  5. #include <utility>
  6. #include <vector>
  7. #include "base/bind.h"
  8. #include "base/files/file_path.h"
  9. #include "base/files/file_util.h"
  10. #include "base/files/scoped_temp_dir.h"
  11. #include "base/i18n/file_util_icu.h"
  12. #include "base/memory/raw_ptr.h"
  13. #include "base/run_loop.h"
  14. #include "base/strings/stringprintf.h"
  15. #include "net/base/directory_lister.h"
  16. #include "net/base/net_errors.h"
  17. #include "net/test/gtest_util.h"
  18. #include "net/test/test_with_task_environment.h"
  19. #include "testing/gmock/include/gmock/gmock.h"
  20. #include "testing/gtest/include/gtest/gtest.h"
  21. #include "testing/platform_test.h"
  22. using net::test::IsError;
  23. using net::test::IsOk;
  24. namespace net {
  25. namespace {
  26. const int kMaxDepth = 3;
  27. const int kBranchingFactor = 4;
  28. const int kFilesPerDirectory = 5;
  29. class ListerDelegate : public DirectoryLister::DirectoryListerDelegate {
  30. public:
  31. explicit ListerDelegate(DirectoryLister::ListingType type) : type_(type) {}
  32. // When set to true, this signals that the directory list operation should be
  33. // cancelled (And the run loop quit) in the first call to OnListFile.
  34. void set_cancel_lister_on_list_file(bool cancel_lister_on_list_file) {
  35. cancel_lister_on_list_file_ = cancel_lister_on_list_file;
  36. }
  37. // When set to true, this signals that the directory list operation should be
  38. // cancelled (And the run loop quit) when OnDone is called.
  39. void set_cancel_lister_on_list_done(bool cancel_lister_on_list_done) {
  40. cancel_lister_on_list_done_ = cancel_lister_on_list_done;
  41. }
  42. void OnListFile(const DirectoryLister::DirectoryListerData& data) override {
  43. ASSERT_FALSE(done_);
  44. file_list_.push_back(data.info);
  45. paths_.push_back(data.path);
  46. if (cancel_lister_on_list_file_) {
  47. lister_->Cancel();
  48. run_loop.Quit();
  49. }
  50. }
  51. void OnListDone(int error) override {
  52. ASSERT_FALSE(done_);
  53. done_ = true;
  54. error_ = error;
  55. if (type_ == DirectoryLister::ALPHA_DIRS_FIRST)
  56. CheckSort();
  57. if (cancel_lister_on_list_done_)
  58. lister_->Cancel();
  59. run_loop.Quit();
  60. }
  61. void CheckSort() {
  62. // Check that we got files in the right order.
  63. if (!file_list_.empty()) {
  64. for (size_t previous = 0, current = 1;
  65. current < file_list_.size();
  66. previous++, current++) {
  67. // Directories should come before files.
  68. if (file_list_[previous].IsDirectory() &&
  69. !file_list_[current].IsDirectory()) {
  70. continue;
  71. }
  72. EXPECT_NE(FILE_PATH_LITERAL(".."),
  73. file_list_[current].GetName().BaseName().value());
  74. EXPECT_EQ(file_list_[previous].IsDirectory(),
  75. file_list_[current].IsDirectory());
  76. EXPECT_TRUE(base::i18n::LocaleAwareCompareFilenames(
  77. file_list_[previous].GetName(),
  78. file_list_[current].GetName()));
  79. }
  80. }
  81. }
  82. void Run(DirectoryLister* lister) {
  83. lister_ = lister;
  84. lister_->Start();
  85. run_loop.Run();
  86. }
  87. int error() const { return error_; }
  88. int num_files() const { return file_list_.size(); }
  89. bool done() const { return done_; }
  90. private:
  91. bool cancel_lister_on_list_file_ = false;
  92. bool cancel_lister_on_list_done_ = false;
  93. // This is owned by the individual tests, rather than the ListerDelegate.
  94. raw_ptr<DirectoryLister> lister_ = nullptr;
  95. base::RunLoop run_loop;
  96. bool done_ = false;
  97. int error_ = -1;
  98. DirectoryLister::ListingType type_;
  99. std::vector<base::FileEnumerator::FileInfo> file_list_;
  100. std::vector<base::FilePath> paths_;
  101. };
  102. } // namespace
  103. class DirectoryListerTest : public PlatformTest, public WithTaskEnvironment {
  104. public:
  105. DirectoryListerTest() = default;
  106. void SetUp() override {
  107. // Randomly create a directory structure of depth 3 in a temporary root
  108. // directory.
  109. std::list<std::pair<base::FilePath, int> > directories;
  110. ASSERT_TRUE(temp_root_dir_.CreateUniqueTempDir());
  111. directories.emplace_back(temp_root_dir_.GetPath(), 0);
  112. while (!directories.empty()) {
  113. std::pair<base::FilePath, int> dir_data = directories.front();
  114. directories.pop_front();
  115. for (int i = 0; i < kFilesPerDirectory; i++) {
  116. std::string file_name = base::StringPrintf("file_id_%d", i);
  117. base::FilePath file_path = dir_data.first.AppendASCII(file_name);
  118. base::File file(file_path,
  119. base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  120. ASSERT_TRUE(file.IsValid());
  121. ++total_created_file_system_objects_in_temp_root_dir_;
  122. if (dir_data.first == temp_root_dir_.GetPath())
  123. ++created_file_system_objects_in_temp_root_dir_;
  124. }
  125. if (dir_data.second < kMaxDepth - 1) {
  126. for (int i = 0; i < kBranchingFactor; i++) {
  127. std::string dir_name = base::StringPrintf("child_dir_%d", i);
  128. base::FilePath dir_path = dir_data.first.AppendASCII(dir_name);
  129. ASSERT_TRUE(base::CreateDirectory(dir_path));
  130. ++total_created_file_system_objects_in_temp_root_dir_;
  131. if (dir_data.first == temp_root_dir_.GetPath())
  132. ++created_file_system_objects_in_temp_root_dir_;
  133. directories.emplace_back(dir_path, dir_data.second + 1);
  134. }
  135. }
  136. }
  137. PlatformTest::SetUp();
  138. }
  139. const base::FilePath& root_path() const { return temp_root_dir_.GetPath(); }
  140. int expected_list_length_recursive() const {
  141. // List should include everything but the top level directory, and does not
  142. // include "..".
  143. return total_created_file_system_objects_in_temp_root_dir_;
  144. }
  145. int expected_list_length_non_recursive() const {
  146. // List should include everything in the top level directory, and "..".
  147. return created_file_system_objects_in_temp_root_dir_ + 1;
  148. }
  149. private:
  150. // Number of files and directories created in SetUp, excluding
  151. // |temp_root_dir_| itself. Includes all nested directories and their files.
  152. int total_created_file_system_objects_in_temp_root_dir_ = 0;
  153. // Number of files and directories created directly in |temp_root_dir_|.
  154. int created_file_system_objects_in_temp_root_dir_ = 0;
  155. base::ScopedTempDir temp_root_dir_;
  156. };
  157. TEST_F(DirectoryListerTest, BigDirTest) {
  158. ListerDelegate delegate(DirectoryLister::ALPHA_DIRS_FIRST);
  159. DirectoryLister lister(root_path(), &delegate);
  160. delegate.Run(&lister);
  161. EXPECT_TRUE(delegate.done());
  162. EXPECT_THAT(delegate.error(), IsOk());
  163. EXPECT_EQ(expected_list_length_non_recursive(), delegate.num_files());
  164. }
  165. TEST_F(DirectoryListerTest, BigDirRecursiveTest) {
  166. ListerDelegate delegate(DirectoryLister::NO_SORT_RECURSIVE);
  167. DirectoryLister lister(root_path(), DirectoryLister::NO_SORT_RECURSIVE,
  168. &delegate);
  169. delegate.Run(&lister);
  170. EXPECT_TRUE(delegate.done());
  171. EXPECT_THAT(delegate.error(), IsOk());
  172. EXPECT_EQ(expected_list_length_recursive(), delegate.num_files());
  173. }
  174. TEST_F(DirectoryListerTest, EmptyDirTest) {
  175. base::ScopedTempDir tempDir;
  176. EXPECT_TRUE(tempDir.CreateUniqueTempDir());
  177. ListerDelegate delegate(DirectoryLister::ALPHA_DIRS_FIRST);
  178. DirectoryLister lister(tempDir.GetPath(), &delegate);
  179. delegate.Run(&lister);
  180. EXPECT_TRUE(delegate.done());
  181. EXPECT_THAT(delegate.error(), IsOk());
  182. // Contains only the parent directory ("..").
  183. EXPECT_EQ(1, delegate.num_files());
  184. }
  185. // This doesn't really test much, except make sure calling cancel before any
  186. // callbacks are invoked doesn't crash. Can't wait for all tasks running on a
  187. // worker pool to complete, unfortunately.
  188. // TODO(mmenke): See if there's a way to make this fail more reliably on
  189. // regression.
  190. TEST_F(DirectoryListerTest, BasicCancelTest) {
  191. ListerDelegate delegate(DirectoryLister::ALPHA_DIRS_FIRST);
  192. auto lister = std::make_unique<DirectoryLister>(root_path(), &delegate);
  193. lister->Start();
  194. lister->Cancel();
  195. base::RunLoop().RunUntilIdle();
  196. EXPECT_FALSE(delegate.done());
  197. EXPECT_EQ(0, delegate.num_files());
  198. }
  199. TEST_F(DirectoryListerTest, CancelOnListFileTest) {
  200. ListerDelegate delegate(DirectoryLister::ALPHA_DIRS_FIRST);
  201. DirectoryLister lister(root_path(), &delegate);
  202. delegate.set_cancel_lister_on_list_file(true);
  203. delegate.Run(&lister);
  204. EXPECT_FALSE(delegate.done());
  205. EXPECT_EQ(1, delegate.num_files());
  206. }
  207. TEST_F(DirectoryListerTest, CancelOnListDoneTest) {
  208. ListerDelegate delegate(DirectoryLister::ALPHA_DIRS_FIRST);
  209. DirectoryLister lister(root_path(), &delegate);
  210. delegate.set_cancel_lister_on_list_done(true);
  211. delegate.Run(&lister);
  212. EXPECT_TRUE(delegate.done());
  213. EXPECT_THAT(delegate.error(), IsOk());
  214. EXPECT_EQ(expected_list_length_non_recursive(), delegate.num_files());
  215. }
  216. TEST_F(DirectoryListerTest, CancelOnLastElementTest) {
  217. base::ScopedTempDir tempDir;
  218. EXPECT_TRUE(tempDir.CreateUniqueTempDir());
  219. ListerDelegate delegate(DirectoryLister::ALPHA_DIRS_FIRST);
  220. DirectoryLister lister(tempDir.GetPath(), &delegate);
  221. delegate.set_cancel_lister_on_list_file(true);
  222. delegate.Run(&lister);
  223. EXPECT_FALSE(delegate.done());
  224. // Contains only the parent directory ("..").
  225. EXPECT_EQ(1, delegate.num_files());
  226. }
  227. TEST_F(DirectoryListerTest, NoSuchDirTest) {
  228. base::ScopedTempDir tempDir;
  229. EXPECT_TRUE(tempDir.CreateUniqueTempDir());
  230. ListerDelegate delegate(DirectoryLister::ALPHA_DIRS_FIRST);
  231. DirectoryLister lister(
  232. tempDir.GetPath().AppendASCII("this_path_does_not_exist"), &delegate);
  233. delegate.Run(&lister);
  234. EXPECT_THAT(delegate.error(), IsError(ERR_FILE_NOT_FOUND));
  235. EXPECT_EQ(0, delegate.num_files());
  236. }
  237. } // namespace net