file_ut.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. #include "file.h"
  2. #include "fs.h"
  3. #include "tempfile.h"
  4. #include <library/cpp/testing/unittest/registar.h>
  5. #include <util/stream/file.h>
  6. #include <util/generic/yexception.h>
  7. class TFileTest: public TTestBase {
  8. UNIT_TEST_SUITE(TFileTest);
  9. UNIT_TEST(TestOpen);
  10. UNIT_TEST(TestOpenSync);
  11. UNIT_TEST(TestRW);
  12. UNIT_TEST(TestReWrite);
  13. UNIT_TEST(TestAppend);
  14. UNIT_TEST(TestLinkTo);
  15. UNIT_TEST(TestResize);
  16. UNIT_TEST(TestLocale);
  17. UNIT_TEST(TestFlush);
  18. UNIT_TEST(TestFlushSpecialFile);
  19. UNIT_TEST(TestRawRead);
  20. UNIT_TEST(TestRead);
  21. UNIT_TEST(TestRawPread);
  22. UNIT_TEST(TestPread);
  23. UNIT_TEST(TestCache);
  24. UNIT_TEST_SUITE_END();
  25. public:
  26. void TestOpen();
  27. void TestOpenSync();
  28. void TestRW();
  29. void TestLocale();
  30. void TestFlush();
  31. void TestFlushSpecialFile();
  32. void TestRawRead();
  33. void TestRead();
  34. void TestRawPread();
  35. void TestPread();
  36. void TestCache();
  37. inline void TestLinkTo() {
  38. TTempFile tmp1("tmp1");
  39. TTempFile tmp2("tmp2");
  40. {
  41. TFile f1(tmp1.Name(), OpenAlways | WrOnly);
  42. TFile f2(tmp2.Name(), OpenAlways | WrOnly);
  43. f1.LinkTo(f2);
  44. f1.Write("12345", 5);
  45. f2.Write("67890", 5);
  46. }
  47. UNIT_ASSERT_EQUAL(TUnbufferedFileInput(tmp2.Name()).ReadAll(), "1234567890");
  48. }
  49. inline void TestAppend() {
  50. TTempFile tmp("tmp");
  51. {
  52. TFile f(tmp.Name(), OpenAlways | WrOnly);
  53. f.Write("12345678", 8);
  54. }
  55. {
  56. TFile f(tmp.Name(), OpenAlways | WrOnly | ForAppend);
  57. f.Write("67", 2);
  58. f.Write("89", 2);
  59. }
  60. UNIT_ASSERT_EQUAL(TUnbufferedFileInput(tmp.Name()).ReadAll(), "123456786789");
  61. }
  62. inline void TestReWrite() {
  63. TTempFile tmp("tmp");
  64. {
  65. TFile f(tmp.Name(), OpenAlways | WrOnly);
  66. f.Write("12345678", 8);
  67. }
  68. {
  69. TFile f(tmp.Name(), OpenAlways | WrOnly);
  70. f.Write("6789", 4);
  71. }
  72. UNIT_ASSERT_EQUAL(TUnbufferedFileInput(tmp.Name()).ReadAll(), "67895678");
  73. }
  74. inline void TestResize() {
  75. TTempFile tmp("tmp");
  76. {
  77. TFile file(tmp.Name(), OpenAlways | WrOnly);
  78. file.Write("1234567", 7);
  79. file.Seek(3, sSet);
  80. file.Resize(5);
  81. UNIT_ASSERT_EQUAL(file.GetLength(), 5);
  82. UNIT_ASSERT_EQUAL(file.GetPosition(), 3);
  83. file.Resize(12);
  84. UNIT_ASSERT_EQUAL(file.GetLength(), 12);
  85. UNIT_ASSERT_EQUAL(file.GetPosition(), 3);
  86. }
  87. const TString data = TUnbufferedFileInput(tmp.Name()).ReadAll();
  88. UNIT_ASSERT_EQUAL(data.length(), 12);
  89. UNIT_ASSERT(data.StartsWith("12345"));
  90. }
  91. };
  92. UNIT_TEST_SUITE_REGISTRATION(TFileTest);
  93. void TFileTest::TestOpen() {
  94. TString res;
  95. TFile f1;
  96. try {
  97. TFile f2("f1.txt", OpenExisting);
  98. } catch (const yexception& e) {
  99. res = e.what();
  100. }
  101. UNIT_ASSERT(!res.empty());
  102. res.remove();
  103. try {
  104. TFile f2("f1.txt", OpenAlways);
  105. f1 = f2;
  106. } catch (const yexception& e) {
  107. res = e.what();
  108. }
  109. UNIT_ASSERT(res.empty());
  110. UNIT_ASSERT(f1.IsOpen());
  111. UNIT_ASSERT_VALUES_EQUAL(f1.GetName(), "f1.txt");
  112. UNIT_ASSERT_VALUES_EQUAL(f1.GetLength(), 0);
  113. try {
  114. TFile f2("f1.txt", CreateNew);
  115. } catch (const yexception& e) {
  116. res = e.what();
  117. }
  118. UNIT_ASSERT(!res.empty());
  119. res.remove();
  120. f1.Close();
  121. UNIT_ASSERT(unlink("f1.txt") == 0);
  122. }
  123. void TFileTest::TestOpenSync() {
  124. TFile f1("f1.txt", CreateNew | Sync);
  125. UNIT_ASSERT(f1.IsOpen());
  126. f1.Close();
  127. UNIT_ASSERT(!f1.IsOpen());
  128. UNIT_ASSERT(unlink("f1.txt") == 0);
  129. }
  130. void TFileTest::TestRW() {
  131. TFile f1("f1.txt", CreateNew);
  132. UNIT_ASSERT(f1.IsOpen());
  133. UNIT_ASSERT_VALUES_EQUAL(f1.GetName(), "f1.txt");
  134. UNIT_ASSERT_VALUES_EQUAL(f1.GetLength(), 0);
  135. ui32 d[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  136. f1.Write(&d, sizeof(ui32) * 10);
  137. UNIT_ASSERT_VALUES_EQUAL(f1.GetLength(), 40);
  138. UNIT_ASSERT_VALUES_EQUAL(f1.GetPosition(), 40);
  139. UNIT_ASSERT_VALUES_EQUAL(f1.Seek(12, sSet), 12);
  140. f1.Flush();
  141. ui32 v;
  142. f1.Load(&v, sizeof(v));
  143. UNIT_ASSERT_VALUES_EQUAL(v, 3u);
  144. UNIT_ASSERT_VALUES_EQUAL(f1.GetPosition(), 16);
  145. TFile f2 = f1;
  146. UNIT_ASSERT(f2.IsOpen());
  147. UNIT_ASSERT_VALUES_EQUAL(f2.GetName(), "f1.txt");
  148. UNIT_ASSERT_VALUES_EQUAL(f2.GetPosition(), 16);
  149. UNIT_ASSERT_VALUES_EQUAL(f2.GetLength(), 40);
  150. f2.Write(&v, sizeof(v));
  151. UNIT_ASSERT_VALUES_EQUAL(f1.GetPosition(), 20);
  152. UNIT_ASSERT_VALUES_EQUAL(f1.Seek(-4, sCur), 16);
  153. v = 0;
  154. f1.Load(&v, sizeof(v));
  155. UNIT_ASSERT_VALUES_EQUAL(v, 3u);
  156. f1.Close();
  157. UNIT_ASSERT(!f1.IsOpen());
  158. UNIT_ASSERT(!f2.IsOpen());
  159. UNIT_ASSERT(unlink("f1.txt") == 0);
  160. }
  161. #ifdef _unix_
  162. #include <locale.h>
  163. #endif
  164. void TFileTest::TestLocale() {
  165. #ifdef _unix_
  166. const char* loc = setlocale(LC_CTYPE, nullptr);
  167. setlocale(LC_CTYPE, "ru_RU.UTF-8");
  168. #endif
  169. TFile f("Имя.txt", CreateNew);
  170. UNIT_ASSERT(f.IsOpen());
  171. UNIT_ASSERT_VALUES_EQUAL(f.GetName(), "Имя.txt");
  172. UNIT_ASSERT_VALUES_EQUAL(f.GetLength(), 0);
  173. f.Close();
  174. UNIT_ASSERT(NFs::Remove("Имя.txt"));
  175. #ifdef _unix_
  176. setlocale(LC_CTYPE, loc);
  177. #endif
  178. }
  179. void TFileTest::TestFlush() {
  180. TTempFile tmp("tmp");
  181. {
  182. TFile f(tmp.Name(), OpenAlways | WrOnly);
  183. f.Flush();
  184. f.FlushData();
  185. f.Close();
  186. UNIT_ASSERT_EXCEPTION(f.Flush(), TFileError);
  187. UNIT_ASSERT_EXCEPTION(f.FlushData(), TFileError);
  188. }
  189. }
  190. void TFileTest::TestFlushSpecialFile() {
  191. #ifdef _unix_
  192. TFile devNull("/dev/null", WrOnly);
  193. devNull.FlushData();
  194. devNull.Flush();
  195. devNull.Close();
  196. #endif
  197. }
  198. void TFileTest::TestRawRead() {
  199. TTempFile tmp("tmp");
  200. {
  201. TFile file(tmp.Name(), OpenAlways | WrOnly);
  202. file.Write("1234567", 7);
  203. file.Flush();
  204. file.Close();
  205. }
  206. {
  207. TFile file(tmp.Name(), OpenExisting | RdOnly);
  208. char buf[7];
  209. i32 reallyRead = file.RawRead(buf, 7);
  210. Y_ENSURE(0 <= reallyRead && reallyRead <= 7);
  211. Y_ENSURE(TStringBuf(buf, reallyRead) == TStringBuf("1234567").Head(reallyRead));
  212. }
  213. }
  214. void TFileTest::TestRead() {
  215. TTempFile tmp("tmp");
  216. {
  217. TFile file(tmp.Name(), OpenAlways | WrOnly);
  218. file.Write("1234567", 7);
  219. file.Flush();
  220. file.Close();
  221. }
  222. {
  223. TFile file(tmp.Name(), OpenExisting | RdOnly);
  224. char buf[7];
  225. Y_ENSURE(file.Read(buf, 7) == 7);
  226. Y_ENSURE(TStringBuf(buf, 7) == "1234567");
  227. memset(buf, 0, sizeof(buf));
  228. file.Seek(0, sSet);
  229. Y_ENSURE(file.Read(buf, 123) == 7);
  230. Y_ENSURE(TStringBuf(buf, 7) == "1234567");
  231. }
  232. }
  233. void TFileTest::TestRawPread() {
  234. TTempFile tmp("tmp");
  235. {
  236. TFile file(tmp.Name(), OpenAlways | WrOnly);
  237. file.Write("1234567", 7);
  238. file.Flush();
  239. file.Close();
  240. }
  241. {
  242. TFile file(tmp.Name(), OpenExisting | RdOnly);
  243. char buf[7];
  244. i32 reallyRead = file.RawPread(buf, 3, 1);
  245. Y_ENSURE(0 <= reallyRead && reallyRead <= 3);
  246. Y_ENSURE(TStringBuf(buf, reallyRead) == TStringBuf("234").Head(reallyRead));
  247. memset(buf, 0, sizeof(buf));
  248. reallyRead = file.RawPread(buf, 2, 5);
  249. Y_ENSURE(0 <= reallyRead && reallyRead <= 2);
  250. Y_ENSURE(TStringBuf(buf, reallyRead) == TStringBuf("67").Head(reallyRead));
  251. }
  252. }
  253. void TFileTest::TestPread() {
  254. TTempFile tmp("tmp");
  255. {
  256. TFile file(tmp.Name(), OpenAlways | WrOnly);
  257. file.Write("1234567", 7);
  258. file.Flush();
  259. file.Close();
  260. }
  261. {
  262. TFile file(tmp.Name(), OpenExisting | RdOnly);
  263. char buf[7];
  264. Y_ENSURE(file.Pread(buf, 3, 1) == 3);
  265. Y_ENSURE(TStringBuf(buf, 3) == "234");
  266. memset(buf, 0, sizeof(buf));
  267. Y_ENSURE(file.Pread(buf, 2, 5) == 2);
  268. Y_ENSURE(TStringBuf(buf, 2) == "67");
  269. }
  270. }
  271. #ifdef _linux_
  272. #include <sys/statfs.h>
  273. #endif
  274. #ifndef TMPFS_MAGIC
  275. #define TMPFS_MAGIC 0x01021994
  276. #endif
  277. void TFileTest::TestCache(){
  278. #ifdef _linux_
  279. {// create file in /tmp, current dir could be tmpfs which does not support fadvise
  280. TFile file(MakeTempName("/tmp"), OpenAlways | Transient | RdWr | NoReadAhead);
  281. struct statfs fs;
  282. if (!fstatfs(file.GetHandle(), &fs) && fs.f_type == TMPFS_MAGIC) {
  283. return;
  284. }
  285. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(), 0);
  286. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(0, 0), 0);
  287. file.Resize(7);
  288. file.PrefetchCache();
  289. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(), 7);
  290. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(3, 2), 2);
  291. file.FlushCache();
  292. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(), 7);
  293. file.EvictCache();
  294. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(), 0);
  295. file.PrefetchCache();
  296. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(), 7);
  297. file.Resize(12345);
  298. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(), 4096);
  299. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(4096, 0), 0);
  300. file.PrefetchCache();
  301. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(), 12345);
  302. file.FlushCache();
  303. file.EvictCache();
  304. UNIT_ASSERT_LE(file.CountCache(), 0);
  305. file.Resize(33333333);
  306. file.PrefetchCache(11111111, 11111111);
  307. UNIT_ASSERT_GE(file.CountCache(), 11111111);
  308. UNIT_ASSERT_LE(file.CountCache(0, 11111111), 1111111);
  309. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(11111111, 11111111), 11111111);
  310. UNIT_ASSERT_LE(file.CountCache(22222222, 11111111), 1111111);
  311. file.FlushCache(11111111, 11111111);
  312. UNIT_ASSERT_GE(file.CountCache(), 11111111);
  313. // first and last incomplete pages could stay in cache
  314. file.EvictCache(11111111, 11111111);
  315. UNIT_ASSERT_LT(file.CountCache(11111111, 11111111), 4096 * 2);
  316. file.EvictCache();
  317. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(), 0);
  318. }
  319. #else
  320. {TFile file(MakeTempName(), OpenAlways | Transient | RdWr);
  321. file.Resize(12345);
  322. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(), -1);
  323. file.PrefetchCache();
  324. file.FlushCache();
  325. file.EvictCache();
  326. UNIT_ASSERT_VALUES_EQUAL(file.CountCache(0, 12345), -1);
  327. }
  328. #endif
  329. }
  330. Y_UNIT_TEST_SUITE(TTestFileHandle) {
  331. Y_UNIT_TEST(MoveAssignment) {
  332. TTempFile tmp("tmp");
  333. {
  334. TFileHandle file1(tmp.Name(), OpenAlways | WrOnly);
  335. file1.Write("1", 1);
  336. TFileHandle file2;
  337. file2 = std::move(file1);
  338. Y_ENSURE(!file1.IsOpen());
  339. Y_ENSURE(file2.IsOpen());
  340. file2.Write("2", 1);
  341. }
  342. {
  343. TFileHandle file(tmp.Name(), OpenExisting | RdOnly);
  344. char buf[2];
  345. Y_ENSURE(file.Read(buf, 2) == 2);
  346. Y_ENSURE(TStringBuf(buf, 2) == "12");
  347. }
  348. }
  349. } // Y_UNIT_TEST_SUITE(TTestFileHandle)
  350. Y_UNIT_TEST_SUITE(TTestDecodeOpenMode) {
  351. Y_UNIT_TEST(It) {
  352. UNIT_ASSERT_VALUES_EQUAL("0", DecodeOpenMode(0));
  353. UNIT_ASSERT_VALUES_EQUAL("RdOnly", DecodeOpenMode(RdOnly));
  354. UNIT_ASSERT_VALUES_EQUAL("RdWr", DecodeOpenMode(RdWr));
  355. UNIT_ASSERT_VALUES_EQUAL("WrOnly|ForAppend", DecodeOpenMode(WrOnly | ForAppend));
  356. UNIT_ASSERT_VALUES_EQUAL("RdWr|CreateAlways|CreateNew|ForAppend|Transient|CloseOnExec|Temp|Sync|Direct|DirectAligned|Seq|NoReuse|NoReadAhead|AX|AR|AW|AWOther|0xF8888000", DecodeOpenMode(0xFFFFFFFF));
  357. }
  358. } // Y_UNIT_TEST_SUITE(TTestDecodeOpenMode)