iterator_ut.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #include "dirut.h"
  2. #include "iterator.h"
  3. #include <library/cpp/testing/unittest/registar.h>
  4. #include <util/system/fs.h>
  5. #include <util/system/file.h>
  6. #include <util/generic/hash.h>
  7. #include <util/generic/algorithm.h>
  8. #include <util/random/mersenne.h>
  9. static TString JoinWithNewline(const TVector<TString>& strings) {
  10. TStringStream ss;
  11. for (const auto& string : strings) {
  12. ss << string << "\n";
  13. }
  14. return ss.Str();
  15. }
  16. class TDirIteratorTest: public TTestBase {
  17. UNIT_TEST_SUITE(TDirIteratorTest);
  18. UNIT_TEST(TestIt)
  19. UNIT_TEST(TestError)
  20. UNIT_TEST(TestLocal)
  21. UNIT_TEST(TestSkip)
  22. UNIT_TEST(TestSort)
  23. UNIT_TEST_SUITE_END();
  24. private:
  25. class TDirHier {
  26. public:
  27. struct TPath {
  28. TString Path;
  29. int Type;
  30. };
  31. inline void AddFile(const TString& path) {
  32. Add(path, 0);
  33. }
  34. inline void AddDir(const TString& path) {
  35. Add(path, 1);
  36. }
  37. inline void Add(const TString& path, int type) {
  38. const TPath p = {
  39. path, type};
  40. Add(p);
  41. }
  42. inline void Add(const TPath& path) {
  43. switch (path.Type) {
  44. case 0:
  45. TFile(path.Path, CreateAlways | RdWr);
  46. break;
  47. case 1:
  48. MakeDirIfNotExist(path.Path.data());
  49. break;
  50. case 2:
  51. ythrow yexception() << "unknown path type";
  52. }
  53. Paths_.push_back(path);
  54. Srch_[path.Path] = path;
  55. }
  56. inline int Type(const TString& path) {
  57. THashMap<TString, TPath>::const_iterator it = Srch_.find(path);
  58. UNIT_ASSERT(it != Srch_.end());
  59. return it->second.Type;
  60. }
  61. inline bool Have(const TString& path, int type) {
  62. return Type(path) == type;
  63. }
  64. inline ~TDirHier() {
  65. for (size_t i = 0; i < Paths_.size(); ++i) {
  66. NFs::Remove(Paths_[Paths_.size() - i - 1].Path);
  67. }
  68. }
  69. private:
  70. TVector<TPath> Paths_;
  71. THashMap<TString, TPath> Srch_;
  72. };
  73. inline void TestLocal() {
  74. TString dirname("." LOCSLASH_S);
  75. TDirIterator d(dirname, FTS_NOCHDIR);
  76. for (auto it = d.begin(); it != d.end(); ++it) {
  77. }
  78. }
  79. inline void TestIt() {
  80. TDirHier hier;
  81. const TString dir = "tmpdir";
  82. const TDirHier::TPath path = {dir, 1};
  83. hier.Add(path);
  84. for (size_t i = 0; i < 10; ++i) {
  85. const TString dir1 = dir + LOCSLASH_C + ToString(i);
  86. const TDirHier::TPath path1 = {dir1, 1};
  87. hier.Add(path1);
  88. for (size_t j = 0; j < 10; ++j) {
  89. const TString subdir2 = ToString(j);
  90. const TString dir2 = dir1 + LOCSLASH_C + subdir2;
  91. const TDirHier::TPath path2 = {dir2, 1};
  92. hier.Add(path2);
  93. for (size_t k = 0; k < 3; ++k) {
  94. const TString file = dir2 + LOCSLASH_C + "file" + ToString(k);
  95. const TDirHier::TPath fpath = {file, 0};
  96. hier.Add(fpath);
  97. }
  98. }
  99. }
  100. TDirIterator d(dir);
  101. for (auto it = d.begin(); it != d.end(); ++it) {
  102. UNIT_ASSERT(hier.Have(it->fts_path, it->fts_info != FTS_F));
  103. }
  104. }
  105. inline void TestSkip() {
  106. TDirHier hier;
  107. const TString dir = "tmpdir";
  108. const TDirHier::TPath path = {dir, 1};
  109. hier.Add(path);
  110. hier.AddDir(dir + LOCSLASH_C + "dir1");
  111. hier.AddDir(dir + LOCSLASH_C + "dir1" + LOCSLASH_C + "dir2");
  112. //
  113. // Without skip
  114. //
  115. {
  116. TDirIterator di(dir);
  117. UNIT_ASSERT(di.Next());
  118. UNIT_ASSERT_EQUAL(TStringBuf(di.Next()->fts_name), "dir1");
  119. UNIT_ASSERT_EQUAL(TStringBuf(di.Next()->fts_name), "dir2");
  120. UNIT_ASSERT_EQUAL(TStringBuf(di.Next()->fts_name), "dir2");
  121. UNIT_ASSERT_EQUAL(TStringBuf(di.Next()->fts_name), "dir1");
  122. UNIT_ASSERT(di.Next());
  123. UNIT_ASSERT_EQUAL(di.Next(), nullptr);
  124. }
  125. //
  126. // With skip
  127. //
  128. {
  129. TDirIterator di(dir);
  130. UNIT_ASSERT(di.Next());
  131. auto ent = di.Next();
  132. UNIT_ASSERT_EQUAL(TStringBuf(ent->fts_name), "dir1");
  133. di.Skip(ent);
  134. UNIT_ASSERT_EQUAL(TStringBuf(di.Next()->fts_name), "dir1");
  135. UNIT_ASSERT(di.Next());
  136. UNIT_ASSERT_EQUAL(di.Next(), nullptr);
  137. }
  138. }
  139. inline void TestSort() {
  140. TDirHier dh;
  141. const TString dir("tmpdir");
  142. // prepare fs
  143. {
  144. TMersenne<ui32> rnd;
  145. const TString prefixes[] = {
  146. "a", "b", "xxx", "111", ""};
  147. dh.AddDir(dir);
  148. for (size_t i = 0; i < 100; ++i) {
  149. const TString fname = dir + LOCSLASH_C + prefixes[i % Y_ARRAY_SIZE(prefixes)] + ToString(rnd.GenRand());
  150. dh.AddFile(fname);
  151. }
  152. }
  153. TVector<TString> fnames;
  154. {
  155. TDirIterator d(dir, TDirIterator::TOptions().SetSortByName());
  156. for (auto it = d.begin(); it != d.end(); ++it) {
  157. if (it->fts_info == FTS_F) {
  158. fnames.push_back(it->fts_name);
  159. }
  160. }
  161. }
  162. TVector<TString> sorted(fnames);
  163. Sort(sorted.begin(), sorted.end());
  164. UNIT_ASSERT_VALUES_EQUAL(JoinWithNewline(fnames), JoinWithNewline(sorted));
  165. }
  166. inline void TestError() {
  167. UNIT_ASSERT_EXCEPTION(TDirIterator("./notexistingfilename"), TDirIterator::TError);
  168. }
  169. };
  170. UNIT_TEST_SUITE_REGISTRATION(TDirIteratorTest);