filesystem_test.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "common/filesystem.h"
  5. #include <gmock/gmock.h>
  6. #include <gtest/gtest.h>
  7. #include <concepts>
  8. #include <string>
  9. #include <thread>
  10. #include <utility>
  11. #include "common/error_test_helpers.h"
  12. namespace Carbon::Filesystem {
  13. namespace {
  14. using ::testing::_;
  15. using ::testing::Eq;
  16. using ::testing::HasSubstr;
  17. using Testing::IsError;
  18. using Testing::IsSuccess;
  19. using ::testing::UnorderedElementsAre;
  20. class FilesystemTest : public ::testing::Test {
  21. public:
  22. explicit FilesystemTest() {
  23. auto result = MakeTmpDir();
  24. CARBON_CHECK(result.ok(), "{0}", result.error());
  25. dir_ = std::move(*result);
  26. }
  27. ~FilesystemTest() override {
  28. auto result = std::move(dir_).Remove();
  29. CARBON_CHECK(result.ok(), "{0}", result.error());
  30. }
  31. auto path() const -> const std::filesystem::path& { return dir_.abs_path(); }
  32. // The test's temp directory, deleted on destruction.
  33. RemovingDir dir_;
  34. };
  35. TEST_F(FilesystemTest, CreateOpenCloseAndUnlink) {
  36. auto unlink_result = dir_.Unlink("test");
  37. ASSERT_FALSE(unlink_result.ok());
  38. EXPECT_TRUE(unlink_result.error().no_entity());
  39. #if defined(_GNU_SOURCE) && \
  40. (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32))
  41. EXPECT_THAT(unlink_result, IsError(HasSubstr("ENOENT")));
  42. #endif
  43. EXPECT_THAT(unlink_result, IsError(HasSubstr("No such file")));
  44. auto f = dir_.OpenWriteOnly("test", CreationOptions::CreateNew);
  45. ASSERT_THAT(f, IsSuccess(_));
  46. auto result = (*std::move(f)).Close();
  47. EXPECT_THAT(result, IsSuccess(_));
  48. f = dir_.OpenWriteOnly("test", CreationOptions::CreateNew);
  49. ASSERT_FALSE(f.ok());
  50. EXPECT_TRUE(f.error().already_exists());
  51. #if defined(_GNU_SOURCE) && \
  52. (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32))
  53. EXPECT_THAT(f, IsError(HasSubstr("EEXIST")));
  54. #endif
  55. EXPECT_THAT(f, IsError(HasSubstr("File exists")));
  56. f = dir_.OpenWriteOnly("test");
  57. ASSERT_THAT(f, IsSuccess(_));
  58. result = std::move(*f).Close();
  59. EXPECT_THAT(result, IsSuccess(_));
  60. f = dir_.OpenWriteOnly("test");
  61. ASSERT_THAT(f, IsSuccess(_));
  62. result = std::move(*f).Close();
  63. EXPECT_THAT(result, IsSuccess(_));
  64. unlink_result = dir_.Unlink("test");
  65. EXPECT_THAT(unlink_result, IsSuccess(_));
  66. f = dir_.OpenWriteOnly("test");
  67. EXPECT_FALSE(f.ok());
  68. EXPECT_TRUE(f.error().no_entity());
  69. #if defined(_GNU_SOURCE) && \
  70. (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32))
  71. EXPECT_THAT(f, IsError(HasSubstr("ENOENT")));
  72. #endif
  73. EXPECT_THAT(f, IsError(HasSubstr("No such file")));
  74. f = dir_.OpenWriteOnly("test", CreationOptions::OpenAlways);
  75. ASSERT_THAT(f, IsSuccess(_));
  76. result = std::move(*f).Close();
  77. EXPECT_THAT(result, IsSuccess(_));
  78. unlink_result = dir_.Unlink("test");
  79. EXPECT_THAT(unlink_result, IsSuccess(_));
  80. }
  81. TEST_F(FilesystemTest, BasicWriteAndRead) {
  82. std::string content_str = "0123456789";
  83. {
  84. auto f = dir_.OpenWriteOnly("test", CreationOptions::CreateNew);
  85. ASSERT_THAT(f, IsSuccess(_));
  86. auto write_result = f->WriteFileFromString(content_str);
  87. EXPECT_THAT(write_result, IsSuccess(_));
  88. (*std::move(f)).Close().Check();
  89. }
  90. {
  91. auto f = dir_.OpenReadOnly("test");
  92. ASSERT_THAT(f, IsSuccess(_));
  93. auto read_result = f->ReadFileToString();
  94. EXPECT_THAT(read_result, IsSuccess(Eq(content_str)));
  95. }
  96. auto unlink_result = dir_.Unlink("test");
  97. EXPECT_THAT(unlink_result, IsSuccess(_));
  98. }
  99. TEST_F(FilesystemTest, SeekReadAndWrite) {
  100. std::string content_str = "0123456789";
  101. // First write some initial content.
  102. {
  103. auto f = dir_.OpenWriteOnly("test", CreationOptions::CreateNew);
  104. ASSERT_THAT(f, IsSuccess(_));
  105. auto write_result = f->WriteFileFromString(content_str);
  106. EXPECT_THAT(write_result, IsSuccess(_));
  107. (*std::move(f)).Close().Check();
  108. }
  109. // Now seek and read.
  110. {
  111. auto f = dir_.OpenReadOnly("test");
  112. ASSERT_THAT(f, IsSuccess(_));
  113. auto seek_result = f->Seek(3);
  114. ASSERT_THAT(seek_result, IsSuccess(Eq(3)));
  115. std::array<std::byte, 4> buffer;
  116. auto read_result = f->ReadToBuffer(buffer);
  117. ASSERT_THAT(read_result, IsSuccess(_));
  118. EXPECT_THAT(std::string(reinterpret_cast<char*>(read_result->data()),
  119. read_result->size()),
  120. Eq(content_str.substr(3, read_result->size())));
  121. // Now test that we can seek back to the beginning and read the full file.
  122. auto read_file_result = f->ReadFileToString();
  123. EXPECT_THAT(read_file_result, IsSuccess(Eq(content_str)));
  124. }
  125. // Now a mixture of reads, writes, an seeking.
  126. {
  127. auto f = dir_.OpenReadWrite("test");
  128. ASSERT_THAT(f, IsSuccess(_));
  129. auto seek_result = f->SeekFromEnd(-6);
  130. ASSERT_THAT(seek_result, IsSuccess(Eq(content_str.size() - 6)));
  131. std::string new_content_str = "abcdefg";
  132. llvm::ArrayRef<std::byte> new_content_bytes(
  133. reinterpret_cast<std::byte*>(new_content_str.data()),
  134. new_content_str.size());
  135. for (auto write_bytes = new_content_bytes.slice(0, 4);
  136. !write_bytes.empty();) {
  137. auto write_result = f->WriteFromBuffer(write_bytes);
  138. ASSERT_THAT(write_result, IsSuccess(_));
  139. write_bytes = *write_result;
  140. }
  141. std::array<std::byte, 4> buffer;
  142. auto read_result = f->ReadToBuffer(buffer);
  143. ASSERT_THAT(read_result, IsSuccess(_));
  144. EXPECT_THAT(std::string(reinterpret_cast<char*>(read_result->data()),
  145. read_result->size()),
  146. Eq(content_str.substr(8, read_result->size())));
  147. EXPECT_THAT(*f->ReadFileToString(), "0123abcd89");
  148. // Now write the entire file, also changing its size, after a fresh seek.
  149. seek_result = f->Seek(-6);
  150. ASSERT_THAT(seek_result, IsSuccess(Eq(content_str.size() - 6)));
  151. auto write_file_result = f->WriteFileFromString(new_content_str);
  152. EXPECT_THAT(write_file_result, IsSuccess(_));
  153. EXPECT_THAT(*f->ReadFileToString(), "abcdefg");
  154. (*std::move(f)).Close().Check();
  155. }
  156. auto unlink_result = dir_.Unlink("test");
  157. EXPECT_THAT(unlink_result, IsSuccess(_));
  158. }
  159. TEST_F(FilesystemTest, CreateAndRemoveDirecotries) {
  160. auto d1 = Cwd().CreateDirectories(path() / "a" / "b" / "c" / "test1");
  161. ASSERT_THAT(d1, IsSuccess(_));
  162. auto d2 = Cwd().CreateDirectories(path() / "a" / "b" / "c" / "test2");
  163. ASSERT_THAT(d2, IsSuccess(_));
  164. auto d3 = Cwd().CreateDirectories(path() / "a" / "b" / "c" / "test3");
  165. ASSERT_THAT(d3, IsSuccess(_));
  166. // Get a directory object to use, this shouldn't cover much new.
  167. auto d4 = Cwd().CreateDirectories(path());
  168. EXPECT_THAT(d4, IsSuccess(_));
  169. // Single, present, relative component.
  170. auto d5 = d4->CreateDirectories("a");
  171. EXPECT_THAT(d5, IsSuccess(_));
  172. // Multiple, present, but relative components.
  173. auto d6 = d5->CreateDirectories(std::filesystem::path("b") / "c");
  174. EXPECT_THAT(d6, IsSuccess(_));
  175. // Single new component.
  176. auto d7 = d6->CreateDirectories("test4");
  177. ASSERT_THAT(d7, IsSuccess(_));
  178. // Two new relative components.
  179. auto d8 = d6->CreateDirectories(std::filesystem::path("test5") / "d");
  180. EXPECT_THAT(d8, IsSuccess(_));
  181. // Mixed relative components.
  182. auto d9 = d5->CreateDirectories(std::filesystem::path("b") / "test6");
  183. EXPECT_THAT(d9, IsSuccess(_));
  184. {
  185. auto f1 = d1->OpenWriteOnly("file1", CreateNew);
  186. ASSERT_THAT(f1, IsSuccess(_));
  187. auto f2 = d2->OpenWriteOnly("file2", CreateNew);
  188. ASSERT_THAT(f2, IsSuccess(_));
  189. auto f3 = d3->OpenWriteOnly("file3", CreateNew);
  190. ASSERT_THAT(f3, IsSuccess(_));
  191. auto f4 = d7->OpenWriteOnly("file4", CreateNew);
  192. ASSERT_THAT(f4, IsSuccess(_));
  193. (*std::move(f1)).Close().Check();
  194. (*std::move(f2)).Close().Check();
  195. (*std::move(f3)).Close().Check();
  196. (*std::move(f4)).Close().Check();
  197. }
  198. auto rm_result = Cwd().Rmtree(path() / "a");
  199. ASSERT_THAT(rm_result, IsSuccess(_));
  200. }
  201. TEST_F(FilesystemTest, StatAndAccess) {
  202. auto access_result = dir_.Access("test");
  203. ASSERT_FALSE(access_result.ok());
  204. EXPECT_TRUE(access_result.error().no_entity());
  205. // Make sure the flags and bit-or-ing them works in the boring case.
  206. access_result =
  207. dir_.Access("test", AccessCheckFlags::Read | AccessCheckFlags::Write |
  208. AccessCheckFlags::Execute);
  209. ASSERT_FALSE(access_result.ok());
  210. EXPECT_TRUE(access_result.error().no_entity());
  211. auto stat_result = dir_.Stat("test");
  212. ASSERT_FALSE(access_result.ok());
  213. EXPECT_TRUE(access_result.error().no_entity());
  214. // Create a file for testing, using very unusual and minimal permissions to
  215. // help us test. Hopefully this isn't modified on the usual `umask` tests run
  216. // under.
  217. std::string content_str = "0123456789";
  218. ModeType permissions = 0450;
  219. auto f = dir_.OpenWriteOnly("test", CreationOptions::CreateNew, permissions);
  220. ASSERT_THAT(f, IsSuccess(_));
  221. auto write_result = f->WriteFileFromString(content_str);
  222. EXPECT_THAT(write_result, IsSuccess(_));
  223. access_result = dir_.Access("test");
  224. EXPECT_THAT(access_result, IsSuccess(_));
  225. access_result = dir_.Access("test", AccessCheckFlags::Read);
  226. EXPECT_THAT(access_result, IsSuccess(_));
  227. // Neither write nor execute permission should be present though.
  228. access_result = dir_.Access("test", AccessCheckFlags::Write);
  229. ASSERT_FALSE(access_result.ok());
  230. EXPECT_TRUE(access_result.error().access_denied());
  231. access_result =
  232. dir_.Access("test", AccessCheckFlags::Read | AccessCheckFlags::Write |
  233. AccessCheckFlags::Execute);
  234. ASSERT_FALSE(access_result.ok());
  235. EXPECT_TRUE(access_result.error().access_denied());
  236. stat_result = dir_.Stat("test");
  237. ASSERT_THAT(stat_result, IsSuccess(_));
  238. EXPECT_TRUE(stat_result->is_file());
  239. EXPECT_FALSE(stat_result->is_dir());
  240. EXPECT_FALSE(stat_result->is_symlink());
  241. EXPECT_THAT(stat_result->size(), Eq(content_str.size()));
  242. EXPECT_THAT(stat_result->permissions(), Eq(permissions));
  243. // Directory instead of file.
  244. access_result =
  245. dir_.Access(".", AccessCheckFlags::Read | AccessCheckFlags::Write |
  246. AccessCheckFlags::Execute);
  247. EXPECT_THAT(access_result, IsSuccess(_));
  248. stat_result = dir_.Stat(".");
  249. ASSERT_THAT(stat_result, IsSuccess(_));
  250. EXPECT_FALSE(stat_result->is_file());
  251. EXPECT_TRUE(stat_result->is_dir());
  252. EXPECT_FALSE(stat_result->is_symlink());
  253. // Can remove file but still stat through the file.
  254. auto unlink_result = dir_.Unlink("test");
  255. ASSERT_THAT(unlink_result, IsSuccess(_));
  256. auto file_stat_result = f->Stat();
  257. ASSERT_THAT(file_stat_result, IsSuccess(_));
  258. EXPECT_TRUE(file_stat_result->is_file());
  259. EXPECT_FALSE(file_stat_result->is_dir());
  260. EXPECT_FALSE(file_stat_result->is_symlink());
  261. EXPECT_THAT(file_stat_result->size(), Eq(content_str.size()));
  262. EXPECT_THAT(file_stat_result->permissions(), Eq(permissions));
  263. (*std::move(f)).Close().Check();
  264. }
  265. TEST_F(FilesystemTest, Symlinks) {
  266. auto readlink_result = dir_.Readlink("test");
  267. ASSERT_FALSE(readlink_result.ok());
  268. EXPECT_TRUE(readlink_result.error().no_entity());
  269. auto lstat_result = dir_.Lstat("test");
  270. ASSERT_FALSE(lstat_result.ok());
  271. EXPECT_TRUE(lstat_result.error().no_entity());
  272. auto symlink_result = dir_.Symlink("test", "abc");
  273. EXPECT_THAT(symlink_result, IsSuccess(_));
  274. readlink_result = dir_.Readlink("test");
  275. EXPECT_THAT(readlink_result, IsSuccess(Eq("abc")));
  276. symlink_result = dir_.Symlink("test", "def");
  277. ASSERT_FALSE(symlink_result.ok());
  278. EXPECT_TRUE(symlink_result.error().already_exists());
  279. lstat_result = dir_.Lstat("test");
  280. ASSERT_THAT(lstat_result, IsSuccess(_));
  281. EXPECT_FALSE(lstat_result->is_file());
  282. EXPECT_FALSE(lstat_result->is_dir());
  283. EXPECT_TRUE(lstat_result->is_symlink());
  284. EXPECT_THAT(lstat_result->size(), Eq(strlen("abc")));
  285. auto unlink_result = dir_.Unlink("test");
  286. EXPECT_THAT(unlink_result, IsSuccess(_));
  287. readlink_result = dir_.Readlink("test");
  288. ASSERT_FALSE(readlink_result.ok());
  289. EXPECT_TRUE(readlink_result.error().no_entity());
  290. // Try a symlink with null bytes for fun. This demonstrates that the symlink
  291. // syscall only uses the leading C-string.
  292. symlink_result = dir_.Symlink("test", std::string("a\0b\0c", 5));
  293. EXPECT_THAT(symlink_result, IsSuccess(_));
  294. readlink_result = dir_.Readlink("test");
  295. EXPECT_THAT(readlink_result, IsSuccess(Eq("a")));
  296. }
  297. TEST_F(FilesystemTest, Chdir) {
  298. auto current_result = Cwd().OpenDir(".");
  299. ASSERT_THAT(current_result, IsSuccess(_));
  300. auto symlink_result = dir_.Symlink("test", "abc");
  301. EXPECT_THAT(symlink_result, IsSuccess(_));
  302. auto chdir_result = dir_.Chdir();
  303. EXPECT_THAT(chdir_result, IsSuccess(_));
  304. auto readlink_result = Cwd().Readlink("test");
  305. EXPECT_THAT(readlink_result, IsSuccess(Eq("abc")));
  306. auto chdir_path_result = dir_.Chdir("missing");
  307. ASSERT_FALSE(chdir_path_result.ok());
  308. EXPECT_TRUE(chdir_path_result.error().no_entity());
  309. // Dangling symlink.
  310. chdir_path_result = dir_.Chdir("test");
  311. ASSERT_FALSE(chdir_path_result.ok());
  312. EXPECT_TRUE(chdir_path_result.error().no_entity());
  313. // Create a regular file and try to chdir to that.
  314. auto f = dir_.OpenWriteOnly("test2", CreationOptions::CreateNew);
  315. ASSERT_THAT(f, IsSuccess(_));
  316. auto write_result = f->WriteFileFromString("test2");
  317. EXPECT_THAT(write_result, IsSuccess(_));
  318. chdir_path_result = dir_.Chdir("test2");
  319. ASSERT_FALSE(chdir_path_result.ok());
  320. EXPECT_TRUE(chdir_path_result.error().not_dir());
  321. auto d2_result = Cwd().OpenDir("test_d2", CreationOptions::CreateNew);
  322. ASSERT_THAT(d2_result, IsSuccess(_));
  323. symlink_result = d2_result->Symlink("test2", "def");
  324. EXPECT_THAT(symlink_result, IsSuccess(_));
  325. chdir_path_result = dir_.Chdir("test_d2");
  326. ASSERT_THAT(chdir_path_result, IsSuccess(_));
  327. readlink_result = Cwd().Readlink("test2");
  328. EXPECT_THAT(readlink_result, IsSuccess(Eq("def")));
  329. readlink_result = Cwd().Readlink("../test");
  330. EXPECT_THAT(readlink_result, IsSuccess(Eq("abc")));
  331. chdir_result = current_result->Chdir();
  332. ASSERT_THAT(chdir_result, IsSuccess(_));
  333. readlink_result = Cwd().Readlink("test");
  334. ASSERT_FALSE(readlink_result.ok());
  335. EXPECT_TRUE(readlink_result.error().no_entity());
  336. (*std::move(f)).Close().Check();
  337. }
  338. TEST_F(FilesystemTest, WriteStream) {
  339. std::string content_str = "0123456789";
  340. auto write = dir_.OpenWriteOnly("test", CreationOptions::CreateNew);
  341. ASSERT_THAT(write, IsSuccess(_));
  342. {
  343. llvm::raw_fd_ostream os = write->WriteStream();
  344. os << content_str;
  345. EXPECT_FALSE(os.has_error()) << os.error();
  346. }
  347. (*std::move(write)).Close().Check();
  348. EXPECT_THAT(dir_.ReadFileToString("test"), IsSuccess(Eq(content_str)));
  349. }
  350. TEST_F(FilesystemTest, Rename) {
  351. // Rename a file within a directory.
  352. ASSERT_THAT(dir_.WriteFileFromString("file1", "content1"), IsSuccess(_));
  353. EXPECT_THAT(dir_.Rename("file1", dir_, "file2"), IsSuccess(_));
  354. EXPECT_THAT(dir_.ReadFileToString("file2"), IsSuccess(Eq("content1")));
  355. auto read_missing = dir_.ReadFileToString("file1");
  356. EXPECT_FALSE(read_missing.ok());
  357. EXPECT_TRUE(read_missing.error().no_entity());
  358. // Rename a file between two directories.
  359. auto d1 = *dir_.CreateDirectories("subdir1");
  360. EXPECT_THAT(dir_.Rename("file2", d1, "file1"), IsSuccess(_));
  361. EXPECT_THAT(d1.ReadFileToString("file1"), IsSuccess(Eq("content1")));
  362. auto d2 = *dir_.CreateDirectories("subdir2");
  363. EXPECT_THAT(d1.Rename("file1", d2, "file1"), IsSuccess(_));
  364. EXPECT_THAT(d2.ReadFileToString("file1"), IsSuccess(Eq("content1")));
  365. // Close the first directory.
  366. d1 = Filesystem::Dir();
  367. EXPECT_THAT(dir_.Rmdir("subdir1"), IsSuccess(_))
  368. << "Directory should have bene empty!";
  369. // Rename directories.
  370. ASSERT_THAT(dir_.ReadFileToString(std::filesystem::path("subdir2") / "file1"),
  371. IsSuccess(Eq("content1")));
  372. EXPECT_THAT(dir_.Rename("subdir2", dir_, "subdir1"), IsSuccess(_));
  373. EXPECT_THAT(dir_.ReadFileToString(std::filesystem::path("subdir1") / "file1"),
  374. IsSuccess(Eq("content1")));
  375. // The open directory `d2` should survive the rename and point at the same
  376. // directory.
  377. EXPECT_THAT(d2.ReadFileToString("file1"), IsSuccess(Eq("content1")));
  378. EXPECT_THAT(d2.WriteFileFromString("file2", "content2"), IsSuccess(_));
  379. EXPECT_THAT(dir_.ReadFileToString(std::filesystem::path("subdir1") / "file2"),
  380. IsSuccess(Eq("content2")));
  381. // Rename over an existing file.
  382. EXPECT_THAT(d2.Rename("file2", d2, "file1"), IsSuccess(_));
  383. EXPECT_THAT(d2.ReadFileToString("file1"), IsSuccess(Eq("content2")));
  384. // Test error calls as well.
  385. auto result = dir_.Rename("missing1", dir_, "missing2");
  386. EXPECT_TRUE(result.error().no_entity()) << result.error();
  387. result = d2.Rename("file1", dir_,
  388. std::filesystem::path("missing_subdir") / "file2");
  389. EXPECT_TRUE(result.error().no_entity()) << result.error();
  390. // Note that `d2` was renamed `subdir1` above, which is why this creates
  391. // infinite subdirectories.
  392. result = dir_.Rename("subdir1", d2, "infinite_subdirs");
  393. EXPECT_THAT(result.error().unix_errnum(), EINVAL) << result.error();
  394. }
  395. TEST_F(FilesystemTest, TryLock) {
  396. auto file = dir_.OpenReadWrite("test_file", CreateNew);
  397. ASSERT_THAT(file, IsSuccess(_));
  398. // Acquire an exclusive lock.
  399. auto lock = file->TryLock(FileLock::Exclusive);
  400. ASSERT_THAT(lock, IsSuccess(_));
  401. EXPECT_TRUE(lock->is_locked());
  402. // Try to acquire a second lock from a different file object.
  403. auto file2 = dir_.OpenReadOnly("test_file");
  404. ASSERT_THAT(file2, IsSuccess(_));
  405. auto lock2 = file2->TryLock(FileLock::Exclusive);
  406. ASSERT_THAT(lock2, IsError(_));
  407. EXPECT_TRUE(lock2.error().would_block());
  408. // A shared lock should also fail.
  409. auto lock3 = file2->TryLock(FileLock::Shared);
  410. ASSERT_THAT(lock3, IsError(_));
  411. EXPECT_TRUE(lock3.error().would_block());
  412. // Release the first lock.
  413. *lock = {};
  414. EXPECT_FALSE(lock->is_locked());
  415. // Now we can acquire an exclusive lock.
  416. lock2 = file2->TryLock(FileLock::Exclusive);
  417. ASSERT_THAT(lock2, IsSuccess(_));
  418. EXPECT_TRUE(lock2->is_locked());
  419. *lock2 = {};
  420. // Test shared locks.
  421. auto shared_lock1 = file->TryLock(FileLock::Shared);
  422. ASSERT_THAT(shared_lock1, IsSuccess(_));
  423. EXPECT_TRUE(shared_lock1->is_locked());
  424. auto shared_lock2 = file2->TryLock(FileLock::Shared);
  425. ASSERT_THAT(shared_lock2, IsSuccess(_));
  426. EXPECT_TRUE(shared_lock2->is_locked());
  427. // An exclusive lock should fail.
  428. auto file3 = dir_.OpenReadOnly("test_file");
  429. ASSERT_THAT(file3, IsSuccess(_));
  430. auto exclusive_lock = file3->TryLock(FileLock::Exclusive);
  431. ASSERT_THAT(exclusive_lock, IsError(_));
  432. EXPECT_TRUE(exclusive_lock.error().would_block());
  433. // Release locks and close files.
  434. *shared_lock1 = {};
  435. *shared_lock2 = {};
  436. ASSERT_THAT((*std::move(file)).Close(), IsSuccess(_));
  437. ASSERT_THAT((*std::move(file2)).Close(), IsSuccess(_));
  438. ASSERT_THAT((*std::move(file3)).Close(), IsSuccess(_));
  439. }
  440. TEST_F(FilesystemTest, ReadAndAppendEntries) {
  441. // Test with an empty directory.
  442. {
  443. auto entries = dir_.ReadEntries();
  444. ASSERT_THAT(entries, IsSuccess(_));
  445. EXPECT_TRUE(entries->empty());
  446. }
  447. {
  448. llvm::SmallVector<std::filesystem::path> entries;
  449. EXPECT_THAT(dir_.AppendEntriesIf(entries), IsSuccess(_));
  450. EXPECT_TRUE(entries.empty());
  451. }
  452. // Create some files and directories.
  453. ASSERT_THAT(dir_.WriteFileFromString("file1", ""), IsSuccess(_));
  454. ASSERT_THAT(dir_.WriteFileFromString("file2", ""), IsSuccess(_));
  455. ASSERT_THAT(dir_.WriteFileFromString(".hidden", ""), IsSuccess(_));
  456. ASSERT_THAT(dir_.CreateDirectories("subdir1"), IsSuccess(_));
  457. ASSERT_THAT(dir_.CreateDirectories("subdir2"), IsSuccess(_));
  458. // Test ReadEntries.
  459. {
  460. auto entries = dir_.ReadEntries();
  461. ASSERT_THAT(entries, IsSuccess(_));
  462. EXPECT_THAT(*entries, UnorderedElementsAre(".hidden", "file1", "file2",
  463. "subdir1", "subdir2"));
  464. }
  465. // Test AppendEntriesIf with no predicate.
  466. {
  467. llvm::SmallVector<std::filesystem::path> entries;
  468. EXPECT_THAT(dir_.AppendEntriesIf(entries), IsSuccess(_));
  469. EXPECT_THAT(entries, UnorderedElementsAre(".hidden", "file1", "file2",
  470. "subdir1", "subdir2"));
  471. }
  472. // Test AppendEntriesIf with a predicate.
  473. {
  474. llvm::SmallVector<std::filesystem::path> entries;
  475. auto result = dir_.AppendEntriesIf(
  476. entries, [](llvm::StringRef name) { return name.starts_with("file"); });
  477. EXPECT_THAT(result, IsSuccess(_));
  478. EXPECT_THAT(entries, UnorderedElementsAre("file1", "file2"));
  479. }
  480. // Test AppendEntriesIf with directory splitting and a predicate.
  481. {
  482. llvm::SmallVector<std::filesystem::path> dir_entries;
  483. llvm::SmallVector<std::filesystem::path> non_dir_entries;
  484. auto result = dir_.AppendEntriesIf(
  485. dir_entries, non_dir_entries,
  486. [](llvm::StringRef name) { return !name.starts_with("."); });
  487. EXPECT_THAT(result, IsSuccess(_));
  488. EXPECT_THAT(dir_entries, UnorderedElementsAre("subdir1", "subdir2"));
  489. EXPECT_THAT(non_dir_entries, UnorderedElementsAre("file1", "file2"));
  490. }
  491. }
  492. TEST_F(FilesystemTest, MtimeAndUpdateTimes) {
  493. // Test UpdateTimes on a path that doesn't exist.
  494. auto update_missing = dir_.UpdateTimes("test_file");
  495. ASSERT_THAT(update_missing, IsError(_));
  496. EXPECT_TRUE(update_missing.error().no_entity());
  497. // Create a file and get its initial modification time.
  498. ASSERT_THAT(dir_.WriteFileFromString("test_file", "content"), IsSuccess(_));
  499. auto stat = dir_.Stat("test_file");
  500. ASSERT_THAT(stat, IsSuccess(_));
  501. auto time1 = stat->mtime();
  502. // Repeated stats have stable time.
  503. stat = dir_.Stat("test_file");
  504. ASSERT_THAT(stat, IsSuccess(_));
  505. EXPECT_THAT(stat->mtime(), Eq(time1));
  506. // Update the timestamp to a specific time in the past.
  507. auto past_time = time1 - std::chrono::seconds(120);
  508. ASSERT_THAT(dir_.UpdateTimes("test_file", past_time), IsSuccess(_));
  509. stat = dir_.Stat("test_file");
  510. ASSERT_THAT(stat, IsSuccess(_));
  511. EXPECT_THAT(stat->mtime(), Eq(past_time));
  512. // Now test updating times on an open file. Should still be at `past_time`.
  513. auto file = *dir_.OpenReadWrite("test_file");
  514. auto file_stat = file.Stat();
  515. ASSERT_THAT(file_stat, IsSuccess(_));
  516. EXPECT_THAT(file_stat->mtime(), Eq(past_time));
  517. // Update the times through the file and verify those updates arrived.
  518. ASSERT_THAT(file.UpdateTimes(time1), IsSuccess(_));
  519. file_stat = file.Stat();
  520. ASSERT_THAT(file_stat, IsSuccess(_));
  521. EXPECT_THAT(file_stat->mtime(), Eq(time1));
  522. ASSERT_THAT(std::move(file).Close(), IsSuccess(_));
  523. }
  524. } // namespace
  525. } // namespace Carbon::Filesystem