VirtualFileSystemTest.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
  1. //===- unittests/Basic/VirtualFileSystem.cpp ---------------- VFS tests ---===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "clang/Basic/VirtualFileSystem.h"
  10. #include "llvm/ADT/Triple.h"
  11. #include "llvm/Support/Errc.h"
  12. #include "llvm/Support/Host.h"
  13. #include "llvm/Support/MemoryBuffer.h"
  14. #include "llvm/Support/SourceMgr.h"
  15. #include "gtest/gtest.h"
  16. #include <map>
  17. using namespace clang;
  18. using namespace llvm;
  19. using llvm::sys::fs::UniqueID;
  20. namespace {
  21. struct DummyFile : public vfs::File {
  22. vfs::Status S;
  23. explicit DummyFile(vfs::Status S) : S(S) {}
  24. llvm::ErrorOr<vfs::Status> status() override { return S; }
  25. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
  26. getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
  27. bool IsVolatile) override {
  28. llvm_unreachable("unimplemented");
  29. }
  30. std::error_code close() override { return std::error_code(); }
  31. };
  32. class DummyFileSystem : public vfs::FileSystem {
  33. int FSID; // used to produce UniqueIDs
  34. int FileID; // used to produce UniqueIDs
  35. std::map<std::string, vfs::Status> FilesAndDirs;
  36. static int getNextFSID() {
  37. static int Count = 0;
  38. return Count++;
  39. }
  40. public:
  41. DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
  42. ErrorOr<vfs::Status> status(const Twine &Path) override {
  43. std::map<std::string, vfs::Status>::iterator I =
  44. FilesAndDirs.find(Path.str());
  45. if (I == FilesAndDirs.end())
  46. return make_error_code(llvm::errc::no_such_file_or_directory);
  47. return I->second;
  48. }
  49. ErrorOr<std::unique_ptr<vfs::File>>
  50. openFileForRead(const Twine &Path) override {
  51. auto S = status(Path);
  52. if (S)
  53. return std::unique_ptr<vfs::File>(new DummyFile{*S});
  54. return S.getError();
  55. }
  56. llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
  57. return std::string();
  58. }
  59. std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
  60. return std::error_code();
  61. }
  62. struct DirIterImpl : public clang::vfs::detail::DirIterImpl {
  63. std::map<std::string, vfs::Status> &FilesAndDirs;
  64. std::map<std::string, vfs::Status>::iterator I;
  65. std::string Path;
  66. bool isInPath(StringRef S) {
  67. if (Path.size() < S.size() && S.find(Path) == 0) {
  68. auto LastSep = S.find_last_of('/');
  69. if (LastSep == Path.size() || LastSep == Path.size()-1)
  70. return true;
  71. }
  72. return false;
  73. }
  74. DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
  75. const Twine &_Path)
  76. : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
  77. Path(_Path.str()) {
  78. for ( ; I != FilesAndDirs.end(); ++I) {
  79. if (isInPath(I->first)) {
  80. CurrentEntry = I->second;
  81. break;
  82. }
  83. }
  84. }
  85. std::error_code increment() override {
  86. ++I;
  87. for ( ; I != FilesAndDirs.end(); ++I) {
  88. if (isInPath(I->first)) {
  89. CurrentEntry = I->second;
  90. break;
  91. }
  92. }
  93. if (I == FilesAndDirs.end())
  94. CurrentEntry = vfs::Status();
  95. return std::error_code();
  96. }
  97. };
  98. vfs::directory_iterator dir_begin(const Twine &Dir,
  99. std::error_code &EC) override {
  100. return vfs::directory_iterator(
  101. std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
  102. }
  103. void addEntry(StringRef Path, const vfs::Status &Status) {
  104. FilesAndDirs[Path] = Status;
  105. }
  106. void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
  107. vfs::Status S(Path, UniqueID(FSID, FileID++),
  108. std::chrono::system_clock::now(), 0, 0, 1024,
  109. sys::fs::file_type::regular_file, Perms);
  110. addEntry(Path, S);
  111. }
  112. void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
  113. vfs::Status S(Path, UniqueID(FSID, FileID++),
  114. std::chrono::system_clock::now(), 0, 0, 0,
  115. sys::fs::file_type::directory_file, Perms);
  116. addEntry(Path, S);
  117. }
  118. void addSymlink(StringRef Path) {
  119. vfs::Status S(Path, UniqueID(FSID, FileID++),
  120. std::chrono::system_clock::now(), 0, 0, 0,
  121. sys::fs::file_type::symlink_file, sys::fs::all_all);
  122. addEntry(Path, S);
  123. }
  124. };
  125. } // end anonymous namespace
  126. TEST(VirtualFileSystemTest, StatusQueries) {
  127. IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
  128. ErrorOr<vfs::Status> Status((std::error_code()));
  129. D->addRegularFile("/foo");
  130. Status = D->status("/foo");
  131. ASSERT_FALSE(Status.getError());
  132. EXPECT_TRUE(Status->isStatusKnown());
  133. EXPECT_FALSE(Status->isDirectory());
  134. EXPECT_TRUE(Status->isRegularFile());
  135. EXPECT_FALSE(Status->isSymlink());
  136. EXPECT_FALSE(Status->isOther());
  137. EXPECT_TRUE(Status->exists());
  138. D->addDirectory("/bar");
  139. Status = D->status("/bar");
  140. ASSERT_FALSE(Status.getError());
  141. EXPECT_TRUE(Status->isStatusKnown());
  142. EXPECT_TRUE(Status->isDirectory());
  143. EXPECT_FALSE(Status->isRegularFile());
  144. EXPECT_FALSE(Status->isSymlink());
  145. EXPECT_FALSE(Status->isOther());
  146. EXPECT_TRUE(Status->exists());
  147. D->addSymlink("/baz");
  148. Status = D->status("/baz");
  149. ASSERT_FALSE(Status.getError());
  150. EXPECT_TRUE(Status->isStatusKnown());
  151. EXPECT_FALSE(Status->isDirectory());
  152. EXPECT_FALSE(Status->isRegularFile());
  153. EXPECT_TRUE(Status->isSymlink());
  154. EXPECT_FALSE(Status->isOther());
  155. EXPECT_TRUE(Status->exists());
  156. EXPECT_TRUE(Status->equivalent(*Status));
  157. ErrorOr<vfs::Status> Status2 = D->status("/foo");
  158. ASSERT_FALSE(Status2.getError());
  159. EXPECT_FALSE(Status->equivalent(*Status2));
  160. }
  161. TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
  162. IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
  163. ErrorOr<vfs::Status> Status((std::error_code()));
  164. EXPECT_FALSE(Status = D->status("/foo"));
  165. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
  166. EXPECT_FALSE(Status = O->status("/foo"));
  167. D->addRegularFile("/foo");
  168. Status = D->status("/foo");
  169. EXPECT_FALSE(Status.getError());
  170. ErrorOr<vfs::Status> Status2((std::error_code()));
  171. Status2 = O->status("/foo");
  172. EXPECT_FALSE(Status2.getError());
  173. EXPECT_TRUE(Status->equivalent(*Status2));
  174. }
  175. TEST(VirtualFileSystemTest, OverlayFiles) {
  176. IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
  177. IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
  178. IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
  179. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  180. new vfs::OverlayFileSystem(Base));
  181. O->pushOverlay(Middle);
  182. O->pushOverlay(Top);
  183. ErrorOr<vfs::Status> Status1((std::error_code())),
  184. Status2((std::error_code())), Status3((std::error_code())),
  185. StatusB((std::error_code())), StatusM((std::error_code())),
  186. StatusT((std::error_code()));
  187. Base->addRegularFile("/foo");
  188. StatusB = Base->status("/foo");
  189. ASSERT_FALSE(StatusB.getError());
  190. Status1 = O->status("/foo");
  191. ASSERT_FALSE(Status1.getError());
  192. Middle->addRegularFile("/foo");
  193. StatusM = Middle->status("/foo");
  194. ASSERT_FALSE(StatusM.getError());
  195. Status2 = O->status("/foo");
  196. ASSERT_FALSE(Status2.getError());
  197. Top->addRegularFile("/foo");
  198. StatusT = Top->status("/foo");
  199. ASSERT_FALSE(StatusT.getError());
  200. Status3 = O->status("/foo");
  201. ASSERT_FALSE(Status3.getError());
  202. EXPECT_TRUE(Status1->equivalent(*StatusB));
  203. EXPECT_TRUE(Status2->equivalent(*StatusM));
  204. EXPECT_TRUE(Status3->equivalent(*StatusT));
  205. EXPECT_FALSE(Status1->equivalent(*Status2));
  206. EXPECT_FALSE(Status2->equivalent(*Status3));
  207. EXPECT_FALSE(Status1->equivalent(*Status3));
  208. }
  209. TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
  210. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  211. IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
  212. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  213. new vfs::OverlayFileSystem(Lower));
  214. O->pushOverlay(Upper);
  215. Lower->addDirectory("/lower-only");
  216. Upper->addDirectory("/upper-only");
  217. // non-merged paths should be the same
  218. ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
  219. ASSERT_FALSE(Status1.getError());
  220. ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
  221. ASSERT_FALSE(Status2.getError());
  222. EXPECT_TRUE(Status1->equivalent(*Status2));
  223. Status1 = Upper->status("/upper-only");
  224. ASSERT_FALSE(Status1.getError());
  225. Status2 = O->status("/upper-only");
  226. ASSERT_FALSE(Status2.getError());
  227. EXPECT_TRUE(Status1->equivalent(*Status2));
  228. }
  229. TEST(VirtualFileSystemTest, MergedDirPermissions) {
  230. // merged directories get the permissions of the upper dir
  231. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  232. IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
  233. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  234. new vfs::OverlayFileSystem(Lower));
  235. O->pushOverlay(Upper);
  236. ErrorOr<vfs::Status> Status((std::error_code()));
  237. Lower->addDirectory("/both", sys::fs::owner_read);
  238. Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
  239. Status = O->status("/both");
  240. ASSERT_FALSE(Status.getError());
  241. EXPECT_EQ(0740, Status->getPermissions());
  242. // permissions (as usual) are not recursively applied
  243. Lower->addRegularFile("/both/foo", sys::fs::owner_read);
  244. Upper->addRegularFile("/both/bar", sys::fs::owner_write);
  245. Status = O->status("/both/foo");
  246. ASSERT_FALSE( Status.getError());
  247. EXPECT_EQ(0400, Status->getPermissions());
  248. Status = O->status("/both/bar");
  249. ASSERT_FALSE(Status.getError());
  250. EXPECT_EQ(0200, Status->getPermissions());
  251. }
  252. namespace {
  253. struct ScopedDir {
  254. SmallString<128> Path;
  255. ScopedDir(const Twine &Name, bool Unique=false) {
  256. std::error_code EC;
  257. if (Unique) {
  258. EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
  259. } else {
  260. Path = Name.str();
  261. EC = llvm::sys::fs::create_directory(Twine(Path));
  262. }
  263. if (EC)
  264. Path = "";
  265. EXPECT_FALSE(EC);
  266. }
  267. ~ScopedDir() {
  268. if (Path != "")
  269. EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
  270. }
  271. operator StringRef() { return Path.str(); }
  272. };
  273. } // end anonymous namespace
  274. TEST(VirtualFileSystemTest, BasicRealFSIteration) {
  275. ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
  276. IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
  277. std::error_code EC;
  278. vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
  279. ASSERT_FALSE(EC);
  280. EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
  281. ScopedDir _a(TestDirectory+"/a");
  282. ScopedDir _ab(TestDirectory+"/a/b");
  283. ScopedDir _c(TestDirectory+"/c");
  284. ScopedDir _cd(TestDirectory+"/c/d");
  285. I = FS->dir_begin(Twine(TestDirectory), EC);
  286. ASSERT_FALSE(EC);
  287. ASSERT_NE(vfs::directory_iterator(), I);
  288. // Check either a or c, since we can't rely on the iteration order.
  289. EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
  290. I.increment(EC);
  291. ASSERT_FALSE(EC);
  292. ASSERT_NE(vfs::directory_iterator(), I);
  293. EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
  294. I.increment(EC);
  295. EXPECT_EQ(vfs::directory_iterator(), I);
  296. }
  297. TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
  298. ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
  299. IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
  300. std::error_code EC;
  301. auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
  302. ASSERT_FALSE(EC);
  303. EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
  304. ScopedDir _a(TestDirectory+"/a");
  305. ScopedDir _ab(TestDirectory+"/a/b");
  306. ScopedDir _c(TestDirectory+"/c");
  307. ScopedDir _cd(TestDirectory+"/c/d");
  308. I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
  309. ASSERT_FALSE(EC);
  310. ASSERT_NE(vfs::recursive_directory_iterator(), I);
  311. std::vector<std::string> Contents;
  312. for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
  313. I.increment(EC)) {
  314. Contents.push_back(I->getName());
  315. }
  316. // Check contents, which may be in any order
  317. EXPECT_EQ(4U, Contents.size());
  318. int Counts[4] = { 0, 0, 0, 0 };
  319. for (const std::string &Name : Contents) {
  320. ASSERT_FALSE(Name.empty());
  321. int Index = Name[Name.size()-1] - 'a';
  322. ASSERT_TRUE(Index >= 0 && Index < 4);
  323. Counts[Index]++;
  324. }
  325. EXPECT_EQ(1, Counts[0]); // a
  326. EXPECT_EQ(1, Counts[1]); // b
  327. EXPECT_EQ(1, Counts[2]); // c
  328. EXPECT_EQ(1, Counts[3]); // d
  329. }
  330. template <typename DirIter>
  331. static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
  332. std::error_code EC;
  333. SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
  334. SmallVector<std::string, 4> InputToCheck;
  335. // Do not rely on iteration order to check for contents, sort both
  336. // content vectors before comparison.
  337. for (DirIter E; !EC && I != E; I.increment(EC))
  338. InputToCheck.push_back(I->getName());
  339. std::sort(InputToCheck.begin(), InputToCheck.end());
  340. std::sort(Expected.begin(), Expected.end());
  341. EXPECT_EQ(InputToCheck.size(), Expected.size());
  342. unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
  343. for (unsigned Idx = 0; Idx != LastElt; ++Idx)
  344. EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
  345. }
  346. TEST(VirtualFileSystemTest, OverlayIteration) {
  347. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  348. IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
  349. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  350. new vfs::OverlayFileSystem(Lower));
  351. O->pushOverlay(Upper);
  352. std::error_code EC;
  353. checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
  354. Lower->addRegularFile("/file1");
  355. checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
  356. Upper->addRegularFile("/file2");
  357. checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
  358. Lower->addDirectory("/dir1");
  359. Lower->addRegularFile("/dir1/foo");
  360. Upper->addDirectory("/dir2");
  361. Upper->addRegularFile("/dir2/foo");
  362. checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
  363. checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
  364. }
  365. TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
  366. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  367. IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
  368. IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
  369. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  370. new vfs::OverlayFileSystem(Lower));
  371. O->pushOverlay(Middle);
  372. O->pushOverlay(Upper);
  373. std::error_code EC;
  374. checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
  375. ArrayRef<StringRef>());
  376. Lower->addRegularFile("/file1");
  377. checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
  378. ArrayRef<StringRef>("/file1"));
  379. Upper->addDirectory("/dir");
  380. Upper->addRegularFile("/dir/file2");
  381. checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
  382. {"/dir", "/dir/file2", "/file1"});
  383. Lower->addDirectory("/dir1");
  384. Lower->addRegularFile("/dir1/foo");
  385. Lower->addDirectory("/dir1/a");
  386. Lower->addRegularFile("/dir1/a/b");
  387. Middle->addDirectory("/a");
  388. Middle->addDirectory("/a/b");
  389. Middle->addDirectory("/a/b/c");
  390. Middle->addRegularFile("/a/b/c/d");
  391. Middle->addRegularFile("/hiddenByUp");
  392. Upper->addDirectory("/dir2");
  393. Upper->addRegularFile("/dir2/foo");
  394. Upper->addRegularFile("/hiddenByUp");
  395. checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
  396. ArrayRef<StringRef>("/dir2/foo"));
  397. checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
  398. {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
  399. "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
  400. "/dir1/a/b", "/dir1/foo", "/file1"});
  401. }
  402. TEST(VirtualFileSystemTest, ThreeLevelIteration) {
  403. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  404. IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
  405. IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
  406. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  407. new vfs::OverlayFileSystem(Lower));
  408. O->pushOverlay(Middle);
  409. O->pushOverlay(Upper);
  410. std::error_code EC;
  411. checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
  412. Middle->addRegularFile("/file2");
  413. checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
  414. Lower->addRegularFile("/file1");
  415. Upper->addRegularFile("/file3");
  416. checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
  417. }
  418. TEST(VirtualFileSystemTest, HiddenInIteration) {
  419. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  420. IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
  421. IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
  422. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  423. new vfs::OverlayFileSystem(Lower));
  424. O->pushOverlay(Middle);
  425. O->pushOverlay(Upper);
  426. std::error_code EC;
  427. Lower->addRegularFile("/onlyInLow", sys::fs::owner_read);
  428. Lower->addRegularFile("/hiddenByMid", sys::fs::owner_read);
  429. Lower->addRegularFile("/hiddenByUp", sys::fs::owner_read);
  430. Middle->addRegularFile("/onlyInMid", sys::fs::owner_write);
  431. Middle->addRegularFile("/hiddenByMid", sys::fs::owner_write);
  432. Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
  433. Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
  434. Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
  435. checkContents(
  436. O->dir_begin("/", EC),
  437. {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
  438. // Make sure we get the top-most entry
  439. {
  440. std::error_code EC;
  441. vfs::directory_iterator I = O->dir_begin("/", EC), E;
  442. for ( ; !EC && I != E; I.increment(EC))
  443. if (I->getName() == "/hiddenByUp")
  444. break;
  445. ASSERT_NE(E, I);
  446. EXPECT_EQ(sys::fs::owner_all, I->getPermissions());
  447. }
  448. {
  449. std::error_code EC;
  450. vfs::directory_iterator I = O->dir_begin("/", EC), E;
  451. for ( ; !EC && I != E; I.increment(EC))
  452. if (I->getName() == "/hiddenByMid")
  453. break;
  454. ASSERT_NE(E, I);
  455. EXPECT_EQ(sys::fs::owner_write, I->getPermissions());
  456. }
  457. }
  458. class InMemoryFileSystemTest : public ::testing::Test {
  459. protected:
  460. clang::vfs::InMemoryFileSystem FS;
  461. clang::vfs::InMemoryFileSystem NormalizedFS;
  462. InMemoryFileSystemTest()
  463. : FS(/*UseNormalizedPaths=*/false),
  464. NormalizedFS(/*UseNormalizedPaths=*/true) {}
  465. };
  466. TEST_F(InMemoryFileSystemTest, IsEmpty) {
  467. auto Stat = FS.status("/a");
  468. ASSERT_EQ(Stat.getError(),errc::no_such_file_or_directory) << FS.toString();
  469. Stat = FS.status("/");
  470. ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
  471. }
  472. TEST_F(InMemoryFileSystemTest, WindowsPath) {
  473. FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
  474. auto Stat = FS.status("c:");
  475. #if !defined(_WIN32)
  476. ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
  477. #endif
  478. Stat = FS.status("c:/windows/system128/foo.cpp");
  479. ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
  480. FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
  481. Stat = FS.status("d:/windows/foo.cpp");
  482. ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
  483. }
  484. TEST_F(InMemoryFileSystemTest, OverlayFile) {
  485. FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
  486. NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
  487. auto Stat = FS.status("/");
  488. ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
  489. Stat = FS.status("/.");
  490. ASSERT_FALSE(Stat);
  491. Stat = NormalizedFS.status("/.");
  492. ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
  493. Stat = FS.status("/a");
  494. ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
  495. ASSERT_EQ("/a", Stat->getName());
  496. }
  497. TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
  498. auto Buf = MemoryBuffer::getMemBuffer("a");
  499. FS.addFileNoOwn("/a", 0, Buf.get());
  500. auto Stat = FS.status("/a");
  501. ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
  502. ASSERT_EQ("/a", Stat->getName());
  503. }
  504. TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
  505. FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
  506. FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
  507. FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
  508. NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
  509. NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
  510. NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
  511. auto File = FS.openFileForRead("/a");
  512. ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
  513. File = FS.openFileForRead("/a"); // Open again.
  514. ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
  515. File = NormalizedFS.openFileForRead("/././a"); // Open again.
  516. ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
  517. File = FS.openFileForRead("/");
  518. ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
  519. File = FS.openFileForRead("/b");
  520. ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
  521. File = FS.openFileForRead("./c");
  522. ASSERT_FALSE(File);
  523. File = FS.openFileForRead("e/../d");
  524. ASSERT_FALSE(File);
  525. File = NormalizedFS.openFileForRead("./c");
  526. ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
  527. File = NormalizedFS.openFileForRead("e/../d");
  528. ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
  529. }
  530. TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
  531. ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
  532. ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
  533. ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
  534. ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
  535. }
  536. TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
  537. FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
  538. FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
  539. std::error_code EC;
  540. vfs::directory_iterator I = FS.dir_begin("/", EC);
  541. ASSERT_FALSE(EC);
  542. ASSERT_EQ("/a", I->getName());
  543. I.increment(EC);
  544. ASSERT_FALSE(EC);
  545. ASSERT_EQ("/b", I->getName());
  546. I.increment(EC);
  547. ASSERT_FALSE(EC);
  548. ASSERT_EQ(vfs::directory_iterator(), I);
  549. I = FS.dir_begin("/b", EC);
  550. ASSERT_FALSE(EC);
  551. ASSERT_EQ("/b/c", I->getName());
  552. I.increment(EC);
  553. ASSERT_FALSE(EC);
  554. ASSERT_EQ(vfs::directory_iterator(), I);
  555. }
  556. TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
  557. FS.setCurrentWorkingDirectory("/b");
  558. FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
  559. auto Stat = FS.status("/b/c");
  560. ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
  561. ASSERT_EQ("c", Stat->getName());
  562. ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
  563. Stat = FS.status("c");
  564. ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
  565. auto ReplaceBackslashes = [](std::string S) {
  566. std::replace(S.begin(), S.end(), '\\', '/');
  567. return S;
  568. };
  569. NormalizedFS.setCurrentWorkingDirectory("/b/c");
  570. NormalizedFS.setCurrentWorkingDirectory(".");
  571. ASSERT_EQ("/b/c", ReplaceBackslashes(
  572. NormalizedFS.getCurrentWorkingDirectory().get()));
  573. NormalizedFS.setCurrentWorkingDirectory("..");
  574. ASSERT_EQ("/b", ReplaceBackslashes(
  575. NormalizedFS.getCurrentWorkingDirectory().get()));
  576. }
  577. // NOTE: in the tests below, we use '//root/' as our root directory, since it is
  578. // a legal *absolute* path on Windows as well as *nix.
  579. class VFSFromYAMLTest : public ::testing::Test {
  580. public:
  581. int NumDiagnostics;
  582. void SetUp() override { NumDiagnostics = 0; }
  583. static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
  584. VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
  585. ++Test->NumDiagnostics;
  586. }
  587. IntrusiveRefCntPtr<vfs::FileSystem>
  588. getFromYAMLRawString(StringRef Content,
  589. IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
  590. std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
  591. return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
  592. ExternalFS);
  593. }
  594. IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
  595. StringRef Content,
  596. IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
  597. std::string VersionPlusContent("{\n 'version':0,\n");
  598. VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
  599. return getFromYAMLRawString(VersionPlusContent, ExternalFS);
  600. }
  601. // This is intended as a "XFAIL" for windows hosts.
  602. bool supportsSameDirMultipleYAMLEntries() {
  603. Triple Host(Triple::normalize(sys::getProcessTriple()));
  604. return !Host.isOSWindows();
  605. }
  606. };
  607. TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
  608. IntrusiveRefCntPtr<vfs::FileSystem> FS;
  609. FS = getFromYAMLString("");
  610. EXPECT_EQ(nullptr, FS.get());
  611. FS = getFromYAMLString("[]");
  612. EXPECT_EQ(nullptr, FS.get());
  613. FS = getFromYAMLString("'string'");
  614. EXPECT_EQ(nullptr, FS.get());
  615. EXPECT_EQ(3, NumDiagnostics);
  616. }
  617. TEST_F(VFSFromYAMLTest, MappedFiles) {
  618. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  619. Lower->addRegularFile("//root/foo/bar/a");
  620. IntrusiveRefCntPtr<vfs::FileSystem> FS =
  621. getFromYAMLString("{ 'roots': [\n"
  622. "{\n"
  623. " 'type': 'directory',\n"
  624. " 'name': '//root/',\n"
  625. " 'contents': [ {\n"
  626. " 'type': 'file',\n"
  627. " 'name': 'file1',\n"
  628. " 'external-contents': '//root/foo/bar/a'\n"
  629. " },\n"
  630. " {\n"
  631. " 'type': 'file',\n"
  632. " 'name': 'file2',\n"
  633. " 'external-contents': '//root/foo/b'\n"
  634. " }\n"
  635. " ]\n"
  636. "}\n"
  637. "]\n"
  638. "}",
  639. Lower);
  640. ASSERT_TRUE(FS.get() != nullptr);
  641. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  642. new vfs::OverlayFileSystem(Lower));
  643. O->pushOverlay(FS);
  644. // file
  645. ErrorOr<vfs::Status> S = O->status("//root/file1");
  646. ASSERT_FALSE(S.getError());
  647. EXPECT_EQ("//root/foo/bar/a", S->getName());
  648. EXPECT_TRUE(S->IsVFSMapped);
  649. ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
  650. EXPECT_EQ("//root/foo/bar/a", SLower->getName());
  651. EXPECT_TRUE(S->equivalent(*SLower));
  652. EXPECT_FALSE(SLower->IsVFSMapped);
  653. // file after opening
  654. auto OpenedF = O->openFileForRead("//root/file1");
  655. ASSERT_FALSE(OpenedF.getError());
  656. auto OpenedS = (*OpenedF)->status();
  657. ASSERT_FALSE(OpenedS.getError());
  658. EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
  659. EXPECT_TRUE(OpenedS->IsVFSMapped);
  660. // directory
  661. S = O->status("//root/");
  662. ASSERT_FALSE(S.getError());
  663. EXPECT_TRUE(S->isDirectory());
  664. EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
  665. // broken mapping
  666. EXPECT_EQ(O->status("//root/file2").getError(),
  667. llvm::errc::no_such_file_or_directory);
  668. EXPECT_EQ(0, NumDiagnostics);
  669. }
  670. TEST_F(VFSFromYAMLTest, CaseInsensitive) {
  671. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  672. Lower->addRegularFile("//root/foo/bar/a");
  673. IntrusiveRefCntPtr<vfs::FileSystem> FS =
  674. getFromYAMLString("{ 'case-sensitive': 'false',\n"
  675. " 'roots': [\n"
  676. "{\n"
  677. " 'type': 'directory',\n"
  678. " 'name': '//root/',\n"
  679. " 'contents': [ {\n"
  680. " 'type': 'file',\n"
  681. " 'name': 'XX',\n"
  682. " 'external-contents': '//root/foo/bar/a'\n"
  683. " }\n"
  684. " ]\n"
  685. "}]}",
  686. Lower);
  687. ASSERT_TRUE(FS.get() != nullptr);
  688. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  689. new vfs::OverlayFileSystem(Lower));
  690. O->pushOverlay(FS);
  691. ErrorOr<vfs::Status> S = O->status("//root/XX");
  692. ASSERT_FALSE(S.getError());
  693. ErrorOr<vfs::Status> SS = O->status("//root/xx");
  694. ASSERT_FALSE(SS.getError());
  695. EXPECT_TRUE(S->equivalent(*SS));
  696. SS = O->status("//root/xX");
  697. EXPECT_TRUE(S->equivalent(*SS));
  698. SS = O->status("//root/Xx");
  699. EXPECT_TRUE(S->equivalent(*SS));
  700. EXPECT_EQ(0, NumDiagnostics);
  701. }
  702. TEST_F(VFSFromYAMLTest, CaseSensitive) {
  703. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  704. Lower->addRegularFile("//root/foo/bar/a");
  705. IntrusiveRefCntPtr<vfs::FileSystem> FS =
  706. getFromYAMLString("{ 'case-sensitive': 'true',\n"
  707. " 'roots': [\n"
  708. "{\n"
  709. " 'type': 'directory',\n"
  710. " 'name': '//root/',\n"
  711. " 'contents': [ {\n"
  712. " 'type': 'file',\n"
  713. " 'name': 'XX',\n"
  714. " 'external-contents': '//root/foo/bar/a'\n"
  715. " }\n"
  716. " ]\n"
  717. "}]}",
  718. Lower);
  719. ASSERT_TRUE(FS.get() != nullptr);
  720. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  721. new vfs::OverlayFileSystem(Lower));
  722. O->pushOverlay(FS);
  723. ErrorOr<vfs::Status> SS = O->status("//root/xx");
  724. EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
  725. SS = O->status("//root/xX");
  726. EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
  727. SS = O->status("//root/Xx");
  728. EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
  729. EXPECT_EQ(0, NumDiagnostics);
  730. }
  731. TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
  732. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  733. // invalid YAML at top-level
  734. IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
  735. EXPECT_EQ(nullptr, FS.get());
  736. // invalid YAML in roots
  737. FS = getFromYAMLString("{ 'roots':[}", Lower);
  738. // invalid YAML in directory
  739. FS = getFromYAMLString(
  740. "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
  741. Lower);
  742. EXPECT_EQ(nullptr, FS.get());
  743. // invalid configuration
  744. FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
  745. EXPECT_EQ(nullptr, FS.get());
  746. FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
  747. EXPECT_EQ(nullptr, FS.get());
  748. // invalid roots
  749. FS = getFromYAMLString("{ 'roots':'' }", Lower);
  750. EXPECT_EQ(nullptr, FS.get());
  751. FS = getFromYAMLString("{ 'roots':{} }", Lower);
  752. EXPECT_EQ(nullptr, FS.get());
  753. // invalid entries
  754. FS = getFromYAMLString(
  755. "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
  756. EXPECT_EQ(nullptr, FS.get());
  757. FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
  758. "'external-contents': 'other' }",
  759. Lower);
  760. EXPECT_EQ(nullptr, FS.get());
  761. FS = getFromYAMLString(
  762. "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
  763. Lower);
  764. EXPECT_EQ(nullptr, FS.get());
  765. FS = getFromYAMLString(
  766. "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
  767. Lower);
  768. EXPECT_EQ(nullptr, FS.get());
  769. FS = getFromYAMLString(
  770. "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
  771. Lower);
  772. EXPECT_EQ(nullptr, FS.get());
  773. FS = getFromYAMLString(
  774. "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
  775. Lower);
  776. EXPECT_EQ(nullptr, FS.get());
  777. FS = getFromYAMLString(
  778. "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
  779. Lower);
  780. EXPECT_EQ(nullptr, FS.get());
  781. // missing mandatory fields
  782. FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
  783. EXPECT_EQ(nullptr, FS.get());
  784. FS = getFromYAMLString(
  785. "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
  786. EXPECT_EQ(nullptr, FS.get());
  787. FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
  788. EXPECT_EQ(nullptr, FS.get());
  789. // duplicate keys
  790. FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
  791. EXPECT_EQ(nullptr, FS.get());
  792. FS = getFromYAMLString(
  793. "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
  794. Lower);
  795. EXPECT_EQ(nullptr, FS.get());
  796. FS =
  797. getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
  798. "'external-contents':'blah' } ] }",
  799. Lower);
  800. EXPECT_EQ(nullptr, FS.get());
  801. // missing version
  802. FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
  803. EXPECT_EQ(nullptr, FS.get());
  804. // bad version number
  805. FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
  806. EXPECT_EQ(nullptr, FS.get());
  807. FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
  808. EXPECT_EQ(nullptr, FS.get());
  809. FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
  810. EXPECT_EQ(nullptr, FS.get());
  811. EXPECT_EQ(24, NumDiagnostics);
  812. }
  813. TEST_F(VFSFromYAMLTest, UseExternalName) {
  814. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  815. Lower->addRegularFile("//root/external/file");
  816. IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
  817. "{ 'roots': [\n"
  818. " { 'type': 'file', 'name': '//root/A',\n"
  819. " 'external-contents': '//root/external/file'\n"
  820. " },\n"
  821. " { 'type': 'file', 'name': '//root/B',\n"
  822. " 'use-external-name': true,\n"
  823. " 'external-contents': '//root/external/file'\n"
  824. " },\n"
  825. " { 'type': 'file', 'name': '//root/C',\n"
  826. " 'use-external-name': false,\n"
  827. " 'external-contents': '//root/external/file'\n"
  828. " }\n"
  829. "] }", Lower);
  830. ASSERT_TRUE(nullptr != FS.get());
  831. // default true
  832. EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
  833. // explicit
  834. EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
  835. EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
  836. // global configuration
  837. FS = getFromYAMLString(
  838. "{ 'use-external-names': false,\n"
  839. " 'roots': [\n"
  840. " { 'type': 'file', 'name': '//root/A',\n"
  841. " 'external-contents': '//root/external/file'\n"
  842. " },\n"
  843. " { 'type': 'file', 'name': '//root/B',\n"
  844. " 'use-external-name': true,\n"
  845. " 'external-contents': '//root/external/file'\n"
  846. " },\n"
  847. " { 'type': 'file', 'name': '//root/C',\n"
  848. " 'use-external-name': false,\n"
  849. " 'external-contents': '//root/external/file'\n"
  850. " }\n"
  851. "] }", Lower);
  852. ASSERT_TRUE(nullptr != FS.get());
  853. // default
  854. EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
  855. // explicit
  856. EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
  857. EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
  858. }
  859. TEST_F(VFSFromYAMLTest, MultiComponentPath) {
  860. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  861. Lower->addRegularFile("//root/other");
  862. // file in roots
  863. IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
  864. "{ 'roots': [\n"
  865. " { 'type': 'file', 'name': '//root/path/to/file',\n"
  866. " 'external-contents': '//root/other' }]\n"
  867. "}", Lower);
  868. ASSERT_TRUE(nullptr != FS.get());
  869. EXPECT_FALSE(FS->status("//root/path/to/file").getError());
  870. EXPECT_FALSE(FS->status("//root/path/to").getError());
  871. EXPECT_FALSE(FS->status("//root/path").getError());
  872. EXPECT_FALSE(FS->status("//root/").getError());
  873. // at the start
  874. FS = getFromYAMLString(
  875. "{ 'roots': [\n"
  876. " { 'type': 'directory', 'name': '//root/path/to',\n"
  877. " 'contents': [ { 'type': 'file', 'name': 'file',\n"
  878. " 'external-contents': '//root/other' }]}]\n"
  879. "}", Lower);
  880. ASSERT_TRUE(nullptr != FS.get());
  881. EXPECT_FALSE(FS->status("//root/path/to/file").getError());
  882. EXPECT_FALSE(FS->status("//root/path/to").getError());
  883. EXPECT_FALSE(FS->status("//root/path").getError());
  884. EXPECT_FALSE(FS->status("//root/").getError());
  885. // at the end
  886. FS = getFromYAMLString(
  887. "{ 'roots': [\n"
  888. " { 'type': 'directory', 'name': '//root/',\n"
  889. " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
  890. " 'external-contents': '//root/other' }]}]\n"
  891. "}", Lower);
  892. ASSERT_TRUE(nullptr != FS.get());
  893. EXPECT_FALSE(FS->status("//root/path/to/file").getError());
  894. EXPECT_FALSE(FS->status("//root/path/to").getError());
  895. EXPECT_FALSE(FS->status("//root/path").getError());
  896. EXPECT_FALSE(FS->status("//root/").getError());
  897. }
  898. TEST_F(VFSFromYAMLTest, TrailingSlashes) {
  899. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  900. Lower->addRegularFile("//root/other");
  901. // file in roots
  902. IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
  903. "{ 'roots': [\n"
  904. " { 'type': 'directory', 'name': '//root/path/to////',\n"
  905. " 'contents': [ { 'type': 'file', 'name': 'file',\n"
  906. " 'external-contents': '//root/other' }]}]\n"
  907. "}", Lower);
  908. ASSERT_TRUE(nullptr != FS.get());
  909. EXPECT_FALSE(FS->status("//root/path/to/file").getError());
  910. EXPECT_FALSE(FS->status("//root/path/to").getError());
  911. EXPECT_FALSE(FS->status("//root/path").getError());
  912. EXPECT_FALSE(FS->status("//root/").getError());
  913. }
  914. TEST_F(VFSFromYAMLTest, DirectoryIteration) {
  915. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  916. Lower->addDirectory("//root/");
  917. Lower->addDirectory("//root/foo");
  918. Lower->addDirectory("//root/foo/bar");
  919. Lower->addRegularFile("//root/foo/bar/a");
  920. Lower->addRegularFile("//root/foo/bar/b");
  921. Lower->addRegularFile("//root/file3");
  922. IntrusiveRefCntPtr<vfs::FileSystem> FS =
  923. getFromYAMLString("{ 'use-external-names': false,\n"
  924. " 'roots': [\n"
  925. "{\n"
  926. " 'type': 'directory',\n"
  927. " 'name': '//root/',\n"
  928. " 'contents': [ {\n"
  929. " 'type': 'file',\n"
  930. " 'name': 'file1',\n"
  931. " 'external-contents': '//root/foo/bar/a'\n"
  932. " },\n"
  933. " {\n"
  934. " 'type': 'file',\n"
  935. " 'name': 'file2',\n"
  936. " 'external-contents': '//root/foo/bar/b'\n"
  937. " }\n"
  938. " ]\n"
  939. "}\n"
  940. "]\n"
  941. "}",
  942. Lower);
  943. ASSERT_TRUE(FS.get() != nullptr);
  944. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  945. new vfs::OverlayFileSystem(Lower));
  946. O->pushOverlay(FS);
  947. std::error_code EC;
  948. checkContents(O->dir_begin("//root/", EC),
  949. {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
  950. checkContents(O->dir_begin("//root/foo/bar", EC),
  951. {"//root/foo/bar/a", "//root/foo/bar/b"});
  952. }
  953. TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
  954. // https://llvm.org/bugs/show_bug.cgi?id=27725
  955. if (!supportsSameDirMultipleYAMLEntries())
  956. return;
  957. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  958. Lower->addDirectory("//root/zab");
  959. Lower->addDirectory("//root/baz");
  960. Lower->addRegularFile("//root/zab/a");
  961. Lower->addRegularFile("//root/zab/b");
  962. IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
  963. "{ 'use-external-names': false,\n"
  964. " 'roots': [\n"
  965. "{\n"
  966. " 'type': 'directory',\n"
  967. " 'name': '//root/baz/',\n"
  968. " 'contents': [ {\n"
  969. " 'type': 'file',\n"
  970. " 'name': 'x',\n"
  971. " 'external-contents': '//root/zab/a'\n"
  972. " }\n"
  973. " ]\n"
  974. "},\n"
  975. "{\n"
  976. " 'type': 'directory',\n"
  977. " 'name': '//root/baz/',\n"
  978. " 'contents': [ {\n"
  979. " 'type': 'file',\n"
  980. " 'name': 'y',\n"
  981. " 'external-contents': '//root/zab/b'\n"
  982. " }\n"
  983. " ]\n"
  984. "}\n"
  985. "]\n"
  986. "}",
  987. Lower);
  988. ASSERT_TRUE(FS.get() != nullptr);
  989. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  990. new vfs::OverlayFileSystem(Lower));
  991. O->pushOverlay(FS);
  992. std::error_code EC;
  993. checkContents(O->dir_begin("//root/baz/", EC),
  994. {"//root/baz/x", "//root/baz/y"});
  995. }
  996. TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
  997. IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  998. Lower->addDirectory("//root/a");
  999. Lower->addDirectory("//root/a/b");
  1000. Lower->addDirectory("//root/a/b/c");
  1001. Lower->addRegularFile("//root/a/b/c/file");
  1002. IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
  1003. "{ 'use-external-names': false,\n"
  1004. " 'roots': [\n"
  1005. "{\n"
  1006. " 'type': 'directory',\n"
  1007. " 'name': '//root/a/b/c/',\n"
  1008. " 'contents': [ {\n"
  1009. " 'type': 'file',\n"
  1010. " 'name': 'file',\n"
  1011. " 'external-contents': '//root/a/b/c/file'\n"
  1012. " }\n"
  1013. " ]\n"
  1014. "},\n"
  1015. "]\n"
  1016. "}",
  1017. Lower);
  1018. ASSERT_TRUE(FS.get() != nullptr);
  1019. IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
  1020. new vfs::OverlayFileSystem(Lower));
  1021. O->pushOverlay(FS);
  1022. std::error_code EC;
  1023. // Test recursive_directory_iterator level()
  1024. vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
  1025. *O, "//root", EC), E;
  1026. ASSERT_FALSE(EC);
  1027. for (int l = 0; I != E; I.increment(EC), ++l) {
  1028. ASSERT_FALSE(EC);
  1029. EXPECT_EQ(I.level(), l);
  1030. }
  1031. EXPECT_EQ(I, E);
  1032. }