fs_ut.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. #include "fs.h"
  2. #include <library/cpp/testing/unittest/registar.h>
  3. #include "file.h"
  4. #include "fstat.h"
  5. #include <util/folder/path.h>
  6. // WARNING: on windows the test must be run with administative rules
  7. class TFsTest: public TTestBase {
  8. UNIT_TEST_SUITE(TFsTest);
  9. UNIT_TEST(TestCreateRemove);
  10. UNIT_TEST(TestRename);
  11. UNIT_TEST(TestSymlink);
  12. UNIT_TEST(TestHardlink);
  13. UNIT_TEST(TestCwdOpts);
  14. UNIT_TEST(TestEnsureExists);
  15. UNIT_TEST_SUITE_END();
  16. public:
  17. void TestCreateRemove();
  18. void TestRename();
  19. void TestSymlink();
  20. void TestHardlink();
  21. void TestCwdOpts();
  22. void TestEnsureExists();
  23. };
  24. UNIT_TEST_SUITE_REGISTRATION(TFsTest);
  25. static void Touch(const TFsPath& path) {
  26. TFile file(path, CreateAlways | WrOnly);
  27. file.Write("123", 3);
  28. }
  29. void TFsTest::TestCreateRemove() {
  30. TFsPath dir1 = "dir_aбвг";
  31. NFs::RemoveRecursive(dir1);
  32. UNIT_ASSERT(!NFs::Exists(dir1));
  33. UNIT_ASSERT(NFs::MakeDirectory(dir1));
  34. UNIT_ASSERT(TFileStat(dir1).IsDir());
  35. UNIT_ASSERT(!NFs::MakeDirectory(dir1));
  36. UNIT_ASSERT(NFs::Exists(dir1));
  37. TFsPath subdir1 = dir1 / "a" / "b";
  38. // TFsPath link = dir1 / "link";
  39. UNIT_ASSERT(NFs::MakeDirectoryRecursive(subdir1, NFs::FP_COMMON_FILE, true));
  40. UNIT_ASSERT(NFs::Exists(subdir1));
  41. UNIT_ASSERT(NFs::MakeDirectoryRecursive(subdir1, NFs::FP_COMMON_FILE, false));
  42. UNIT_ASSERT(NFs::MakeDirectoryRecursive(subdir1, NFs::FP_COMMON_FILE));
  43. UNIT_ASSERT_EXCEPTION(NFs::MakeDirectoryRecursive(subdir1, NFs::FP_COMMON_FILE, true), TIoException);
  44. TFsPath file1 = dir1 / "f1.txt";
  45. TFsPath file2 = subdir1 + TString("_f2.txt");
  46. TFsPath file3 = subdir1 / "f2.txt";
  47. Touch(file1);
  48. Touch(file2);
  49. Touch(file3);
  50. // UNIT_ASSERT(NFs::SymLink(file3.RealPath(), link));
  51. UNIT_ASSERT(NFs::MakeDirectoryRecursive(dir1 / "subdir1" / "subdir2" / "subdir3" / "subdir4", NFs::FP_COMMON_FILE, false));
  52. UNIT_ASSERT(NFs::MakeDirectoryRecursive(dir1 / "subdir1" / "subdir2", NFs::FP_COMMON_FILE, false));
  53. // the target path is a file or "subdirectory" of a file
  54. UNIT_ASSERT(!NFs::MakeDirectoryRecursive(file1 / "subdir1" / "subdir2", NFs::FP_COMMON_FILE, false));
  55. UNIT_ASSERT(!NFs::MakeDirectoryRecursive(file1, NFs::FP_COMMON_FILE, false));
  56. TString longUtf8Name = "";
  57. while (longUtf8Name.size() < 255) {
  58. longUtf8Name = longUtf8Name + "fф";
  59. }
  60. UNIT_ASSERT_EQUAL(longUtf8Name.size(), 255);
  61. TFsPath longfile = dir1 / longUtf8Name;
  62. Touch(longfile);
  63. UNIT_ASSERT(NFs::Exists(longfile));
  64. UNIT_ASSERT(NFs::Exists(file1));
  65. UNIT_ASSERT(NFs::Exists(file2));
  66. UNIT_ASSERT(NFs::Exists(file3));
  67. // UNIT_ASSERT(NFs::Exists(link));
  68. UNIT_ASSERT(!NFs::Remove(dir1));
  69. NFs::RemoveRecursive(dir1);
  70. UNIT_ASSERT(!NFs::Exists(file1));
  71. UNIT_ASSERT(!NFs::Exists(file2));
  72. UNIT_ASSERT(!NFs::Exists(file3));
  73. // UNIT_ASSERT(!NFs::Exists(link));
  74. UNIT_ASSERT(!NFs::Exists(subdir1));
  75. UNIT_ASSERT(!NFs::Exists(longfile));
  76. UNIT_ASSERT(!NFs::Exists(dir1));
  77. }
  78. void RunRenameTest(TFsPath src, TFsPath dst) {
  79. // if previous running was failed
  80. TFsPath dir1 = "dir";
  81. TFsPath dir2 = "dst_dir";
  82. NFs::Remove(src);
  83. NFs::Remove(dst);
  84. NFs::Remove(dir1 / src);
  85. NFs::Remove(dir1);
  86. NFs::Remove(dir2 / src);
  87. NFs::Remove(dir2);
  88. {
  89. TFile file(src, CreateNew | WrOnly);
  90. file.Write("123", 3);
  91. }
  92. UNIT_ASSERT(NFs::Rename(src, dst));
  93. UNIT_ASSERT(NFs::Exists(dst));
  94. UNIT_ASSERT(!NFs::Exists(src));
  95. {
  96. TFile file(dst, OpenExisting);
  97. UNIT_ASSERT_VALUES_EQUAL(file.GetLength(), 3);
  98. }
  99. NFs::MakeDirectory(dir1);
  100. {
  101. TFile file(dir1 / src, CreateNew | WrOnly);
  102. file.Write("123", 3);
  103. }
  104. UNIT_ASSERT(NFs::Rename(dir1, dir2));
  105. UNIT_ASSERT(NFs::Exists(dir2 / src));
  106. UNIT_ASSERT(!NFs::Exists(dir1));
  107. {
  108. TFile file(dir2 / src, OpenExisting);
  109. UNIT_ASSERT_VALUES_EQUAL(file.GetLength(), 3);
  110. }
  111. UNIT_ASSERT(!NFs::Remove(src));
  112. UNIT_ASSERT(NFs::Remove(dst));
  113. UNIT_ASSERT(!NFs::Remove(dir1));
  114. UNIT_ASSERT(NFs::Remove(dir2 / src));
  115. UNIT_ASSERT(NFs::Remove(dir2));
  116. }
  117. void TFsTest::TestRename() {
  118. RunRenameTest("src.txt", "dst.txt");
  119. RunRenameTest("src_абвг.txt", "dst_абвг.txt");
  120. }
  121. static void RunHardlinkTest(const TFsPath& src, const TFsPath& dst) {
  122. NFs::Remove(src);
  123. NFs::Remove(dst);
  124. {
  125. TFile file(src, CreateNew | WrOnly);
  126. file.Write("123", 3);
  127. }
  128. UNIT_ASSERT(NFs::HardLink(src, dst));
  129. {
  130. TFile file(dst, OpenExisting | RdOnly);
  131. UNIT_ASSERT_VALUES_EQUAL(file.GetLength(), 3);
  132. }
  133. {
  134. TFile file(src, OpenExisting | WrOnly);
  135. file.Write("1234", 4);
  136. }
  137. {
  138. TFile file(dst, OpenExisting | RdOnly);
  139. UNIT_ASSERT_VALUES_EQUAL(file.GetLength(), 4);
  140. }
  141. {
  142. TFile file(dst, OpenExisting | WrOnly);
  143. file.Write("12345", 5);
  144. }
  145. {
  146. TFile file(src, OpenExisting | RdOnly);
  147. UNIT_ASSERT_VALUES_EQUAL(file.GetLength(), 5);
  148. }
  149. UNIT_ASSERT(NFs::Remove(dst));
  150. UNIT_ASSERT(NFs::Remove(src));
  151. }
  152. void TFsTest::TestHardlink() {
  153. RunHardlinkTest("tempfile", "hardlinkfile");
  154. RunHardlinkTest("tempfile_абвг", "hardlinkfile_абвг"); // utf-8 names
  155. }
  156. static void RunSymLinkTest(TString fileLocalName, TString symLinkName) {
  157. // if previous running was failed
  158. TFsPath subDir = "tempsubdir";
  159. TFsPath srcFile = subDir / fileLocalName;
  160. TFsPath subsubDir1 = subDir / "dir1";
  161. TFsPath subsubDir2 = subDir / "dir2";
  162. TFsPath linkD1 = "symlinkdir";
  163. TFsPath linkD2 = subsubDir1 / "linkd2";
  164. TFsPath dangling = subsubDir1 / "dangling";
  165. NFs::Remove(srcFile);
  166. NFs::Remove(symLinkName);
  167. NFs::Remove(linkD2);
  168. NFs::Remove(dangling);
  169. NFs::Remove(subsubDir1);
  170. NFs::Remove(subsubDir2);
  171. NFs::Remove(subDir);
  172. NFs::Remove(linkD1);
  173. NFs::MakeDirectory(subDir);
  174. NFs::MakeDirectory(subsubDir1, NFs::FP_NONSECRET_FILE);
  175. NFs::MakeDirectory(subsubDir2, NFs::FP_SECRET_FILE);
  176. {
  177. TFile file(srcFile, CreateNew | WrOnly);
  178. file.Write("1234567", 7);
  179. }
  180. UNIT_ASSERT(NFs::SymLink(subDir, linkD1));
  181. UNIT_ASSERT(NFs::SymLink("../dir2", linkD2));
  182. UNIT_ASSERT(NFs::SymLink("../dir3", dangling));
  183. UNIT_ASSERT_STRINGS_EQUAL(NFs::ReadLink(linkD2), TString("..") + LOCSLASH_S "dir2");
  184. UNIT_ASSERT_STRINGS_EQUAL(NFs::ReadLink(dangling), TString("..") + LOCSLASH_S "dir3");
  185. {
  186. TFile file(linkD1 / fileLocalName, OpenExisting | RdOnly);
  187. UNIT_ASSERT_VALUES_EQUAL(file.GetLength(), 7);
  188. }
  189. UNIT_ASSERT(NFs::SymLink(srcFile, symLinkName));
  190. {
  191. TFile file(symLinkName, OpenExisting | RdOnly);
  192. UNIT_ASSERT_VALUES_EQUAL(file.GetLength(), 7);
  193. }
  194. {
  195. TFileStat fs(linkD1);
  196. UNIT_ASSERT(!fs.IsFile());
  197. UNIT_ASSERT(fs.IsDir());
  198. UNIT_ASSERT(!fs.IsSymlink());
  199. }
  200. {
  201. TFileStat fs(linkD1, true);
  202. UNIT_ASSERT(!fs.IsFile());
  203. // UNIT_ASSERT(fs.IsDir()); // failed on unix
  204. UNIT_ASSERT(fs.IsSymlink());
  205. }
  206. {
  207. TFileStat fs(symLinkName);
  208. UNIT_ASSERT(fs.IsFile());
  209. UNIT_ASSERT(!fs.IsDir());
  210. UNIT_ASSERT(!fs.IsSymlink());
  211. UNIT_ASSERT_VALUES_EQUAL(fs.Size, 7u);
  212. }
  213. {
  214. TFileStat fs(symLinkName, true);
  215. // UNIT_ASSERT(fs.IsFile()); // no evidence that symlink has to be a file as well
  216. UNIT_ASSERT(!fs.IsDir());
  217. UNIT_ASSERT(fs.IsSymlink());
  218. }
  219. UNIT_ASSERT(NFs::Remove(symLinkName));
  220. UNIT_ASSERT(NFs::Exists(srcFile));
  221. UNIT_ASSERT(NFs::Remove(linkD1));
  222. UNIT_ASSERT(NFs::Exists(srcFile));
  223. UNIT_ASSERT(!NFs::Remove(subDir));
  224. UNIT_ASSERT(NFs::Remove(srcFile));
  225. UNIT_ASSERT(NFs::Remove(linkD2));
  226. UNIT_ASSERT(NFs::Remove(dangling));
  227. UNIT_ASSERT(NFs::Remove(subsubDir1));
  228. UNIT_ASSERT(NFs::Remove(subsubDir2));
  229. UNIT_ASSERT(NFs::Remove(subDir));
  230. }
  231. void TFsTest::TestSymlink() {
  232. // if previous running was failed
  233. RunSymLinkTest("f.txt", "fl.txt");
  234. RunSymLinkTest("f_абвг.txt", "fl_абвг.txt"); // utf-8 names
  235. }
  236. void TFsTest::TestCwdOpts() {
  237. TFsPath initialCwd = NFs::CurrentWorkingDirectory();
  238. TFsPath subdir = "dir_forcwd_абвг";
  239. NFs::MakeDirectory(subdir, NFs::FP_SECRET_FILE | NFs::FP_ALL_READ);
  240. NFs::SetCurrentWorkingDirectory(subdir);
  241. TFsPath newCwd = NFs::CurrentWorkingDirectory();
  242. UNIT_ASSERT_EQUAL(newCwd.Fix(), (initialCwd / subdir).Fix());
  243. NFs::SetCurrentWorkingDirectory("..");
  244. TFsPath newCwd2 = NFs::CurrentWorkingDirectory();
  245. UNIT_ASSERT_EQUAL(newCwd2.Fix(), initialCwd.Fix());
  246. UNIT_ASSERT(NFs::Remove(subdir));
  247. }
  248. void TFsTest::TestEnsureExists() {
  249. TFsPath fileExists = "tmp_file_абвг.txt";
  250. TFsPath nonExists = "tmp2_file_абвг.txt";
  251. {
  252. NFs::Remove(fileExists);
  253. NFs::Remove(nonExists);
  254. TFile file(fileExists, CreateNew | WrOnly);
  255. file.Write("1234567", 7);
  256. }
  257. UNIT_ASSERT_NO_EXCEPTION(NFs::EnsureExists(fileExists));
  258. UNIT_ASSERT_EXCEPTION(NFs::EnsureExists(nonExists), TFileError);
  259. TStringBuilder expected;
  260. TString got;
  261. try {
  262. NFs::EnsureExists(nonExists);
  263. expected << __LOCATION__;
  264. } catch (const TFileError& err) {
  265. got = err.what();
  266. }
  267. UNIT_ASSERT(got.Contains(expected));
  268. UNIT_ASSERT(got.Contains(NFs::CurrentWorkingDirectory()));
  269. UNIT_ASSERT(NFs::Remove(fileExists));
  270. }