xref: /llvm-project/llvm/unittests/Support/VirtualFileSystemTest.cpp (revision 937a1047f64495696ac84db6c647bb96d75a3806)
1 //===- unittests/Support/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 
10 #include "llvm/Support/VirtualFileSystem.h"
11 #include "llvm/ADT/Triple.h"
12 #include "llvm/Config/llvm-config.h"
13 #include "llvm/Support/Errc.h"
14 #include "llvm/Support/Host.h"
15 #include "llvm/Support/MemoryBuffer.h"
16 #include "llvm/Support/Path.h"
17 #include "llvm/Support/SourceMgr.h"
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20 #include <map>
21 #include <string>
22 
23 using namespace llvm;
24 using llvm::sys::fs::UniqueID;
25 using testing::ElementsAre;
26 using testing::Pair;
27 using testing::UnorderedElementsAre;
28 
29 namespace {
30 struct DummyFile : public vfs::File {
31   vfs::Status S;
32   explicit DummyFile(vfs::Status S) : S(S) {}
33   llvm::ErrorOr<vfs::Status> status() override { return S; }
34   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
35   getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
36             bool IsVolatile) override {
37     llvm_unreachable("unimplemented");
38   }
39   std::error_code close() override { return std::error_code(); }
40 };
41 
42 class DummyFileSystem : public vfs::FileSystem {
43   int FSID;   // used to produce UniqueIDs
44   int FileID; // used to produce UniqueIDs
45   std::map<std::string, vfs::Status> FilesAndDirs;
46 
47   static int getNextFSID() {
48     static int Count = 0;
49     return Count++;
50   }
51 
52 public:
53   DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
54 
55   ErrorOr<vfs::Status> status(const Twine &Path) override {
56     std::map<std::string, vfs::Status>::iterator I =
57         FilesAndDirs.find(Path.str());
58     if (I == FilesAndDirs.end())
59       return make_error_code(llvm::errc::no_such_file_or_directory);
60     return I->second;
61   }
62   ErrorOr<std::unique_ptr<vfs::File>>
63   openFileForRead(const Twine &Path) override {
64     auto S = status(Path);
65     if (S)
66       return std::unique_ptr<vfs::File>(new DummyFile{*S});
67     return S.getError();
68   }
69   llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
70     return std::string();
71   }
72   std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
73     return std::error_code();
74   }
75   // Map any symlink to "/symlink".
76   std::error_code getRealPath(const Twine &Path,
77                               SmallVectorImpl<char> &Output) const override {
78     auto I = FilesAndDirs.find(Path.str());
79     if (I == FilesAndDirs.end())
80       return make_error_code(llvm::errc::no_such_file_or_directory);
81     if (I->second.isSymlink()) {
82       Output.clear();
83       Twine("/symlink").toVector(Output);
84       return std::error_code();
85     }
86     Output.clear();
87     Path.toVector(Output);
88     return std::error_code();
89   }
90 
91   struct DirIterImpl : public llvm::vfs::detail::DirIterImpl {
92     std::map<std::string, vfs::Status> &FilesAndDirs;
93     std::map<std::string, vfs::Status>::iterator I;
94     std::string Path;
95     bool isInPath(StringRef S) {
96       if (Path.size() < S.size() && S.find(Path) == 0) {
97         auto LastSep = S.find_last_of('/');
98         if (LastSep == Path.size() || LastSep == Path.size() - 1)
99           return true;
100       }
101       return false;
102     }
103     DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
104                 const Twine &_Path)
105         : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
106           Path(_Path.str()) {
107       for (; I != FilesAndDirs.end(); ++I) {
108         if (isInPath(I->first)) {
109           CurrentEntry =
110               vfs::directory_entry(I->second.getName(), I->second.getType());
111           break;
112         }
113       }
114     }
115     std::error_code increment() override {
116       ++I;
117       for (; I != FilesAndDirs.end(); ++I) {
118         if (isInPath(I->first)) {
119           CurrentEntry =
120               vfs::directory_entry(I->second.getName(), I->second.getType());
121           break;
122         }
123       }
124       if (I == FilesAndDirs.end())
125         CurrentEntry = vfs::directory_entry();
126       return std::error_code();
127     }
128   };
129 
130   vfs::directory_iterator dir_begin(const Twine &Dir,
131                                     std::error_code &EC) override {
132     return vfs::directory_iterator(
133         std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
134   }
135 
136   void addEntry(StringRef Path, const vfs::Status &Status) {
137     FilesAndDirs[Path] = Status;
138   }
139 
140   void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
141     vfs::Status S(Path, UniqueID(FSID, FileID++),
142                   std::chrono::system_clock::now(), 0, 0, 1024,
143                   sys::fs::file_type::regular_file, Perms);
144     addEntry(Path, S);
145   }
146 
147   void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
148     vfs::Status S(Path, UniqueID(FSID, FileID++),
149                   std::chrono::system_clock::now(), 0, 0, 0,
150                   sys::fs::file_type::directory_file, Perms);
151     addEntry(Path, S);
152   }
153 
154   void addSymlink(StringRef Path) {
155     vfs::Status S(Path, UniqueID(FSID, FileID++),
156                   std::chrono::system_clock::now(), 0, 0, 0,
157                   sys::fs::file_type::symlink_file, sys::fs::all_all);
158     addEntry(Path, S);
159   }
160 };
161 
162 /// Replace back-slashes by front-slashes.
163 std::string getPosixPath(std::string S) {
164   SmallString<128> Result;
165   llvm::sys::path::native(S, Result, llvm::sys::path::Style::posix);
166   return Result.str();
167 }
168 } // end anonymous namespace
169 
170 TEST(VirtualFileSystemTest, StatusQueries) {
171   IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
172   ErrorOr<vfs::Status> Status((std::error_code()));
173 
174   D->addRegularFile("/foo");
175   Status = D->status("/foo");
176   ASSERT_FALSE(Status.getError());
177   EXPECT_TRUE(Status->isStatusKnown());
178   EXPECT_FALSE(Status->isDirectory());
179   EXPECT_TRUE(Status->isRegularFile());
180   EXPECT_FALSE(Status->isSymlink());
181   EXPECT_FALSE(Status->isOther());
182   EXPECT_TRUE(Status->exists());
183 
184   D->addDirectory("/bar");
185   Status = D->status("/bar");
186   ASSERT_FALSE(Status.getError());
187   EXPECT_TRUE(Status->isStatusKnown());
188   EXPECT_TRUE(Status->isDirectory());
189   EXPECT_FALSE(Status->isRegularFile());
190   EXPECT_FALSE(Status->isSymlink());
191   EXPECT_FALSE(Status->isOther());
192   EXPECT_TRUE(Status->exists());
193 
194   D->addSymlink("/baz");
195   Status = D->status("/baz");
196   ASSERT_FALSE(Status.getError());
197   EXPECT_TRUE(Status->isStatusKnown());
198   EXPECT_FALSE(Status->isDirectory());
199   EXPECT_FALSE(Status->isRegularFile());
200   EXPECT_TRUE(Status->isSymlink());
201   EXPECT_FALSE(Status->isOther());
202   EXPECT_TRUE(Status->exists());
203 
204   EXPECT_TRUE(Status->equivalent(*Status));
205   ErrorOr<vfs::Status> Status2 = D->status("/foo");
206   ASSERT_FALSE(Status2.getError());
207   EXPECT_FALSE(Status->equivalent(*Status2));
208 }
209 
210 TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
211   IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
212   ErrorOr<vfs::Status> Status((std::error_code()));
213   EXPECT_FALSE(Status = D->status("/foo"));
214 
215   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
216   EXPECT_FALSE(Status = O->status("/foo"));
217 
218   D->addRegularFile("/foo");
219   Status = D->status("/foo");
220   EXPECT_FALSE(Status.getError());
221 
222   ErrorOr<vfs::Status> Status2((std::error_code()));
223   Status2 = O->status("/foo");
224   EXPECT_FALSE(Status2.getError());
225   EXPECT_TRUE(Status->equivalent(*Status2));
226 }
227 
228 TEST(VirtualFileSystemTest, GetRealPathInOverlay) {
229   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
230   Lower->addRegularFile("/foo");
231   Lower->addSymlink("/lower_link");
232   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
233 
234   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
235       new vfs::OverlayFileSystem(Lower));
236   O->pushOverlay(Upper);
237 
238   // Regular file.
239   SmallString<16> RealPath;
240   EXPECT_FALSE(O->getRealPath("/foo", RealPath));
241   EXPECT_EQ(RealPath.str(), "/foo");
242 
243   // Expect no error getting real path for symlink in lower overlay.
244   EXPECT_FALSE(O->getRealPath("/lower_link", RealPath));
245   EXPECT_EQ(RealPath.str(), "/symlink");
246 
247   // Try a non-existing link.
248   EXPECT_EQ(O->getRealPath("/upper_link", RealPath),
249             errc::no_such_file_or_directory);
250 
251   // Add a new symlink in upper.
252   Upper->addSymlink("/upper_link");
253   EXPECT_FALSE(O->getRealPath("/upper_link", RealPath));
254   EXPECT_EQ(RealPath.str(), "/symlink");
255 }
256 
257 TEST(VirtualFileSystemTest, OverlayFiles) {
258   IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
259   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
260   IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
261   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
262       new vfs::OverlayFileSystem(Base));
263   O->pushOverlay(Middle);
264   O->pushOverlay(Top);
265 
266   ErrorOr<vfs::Status> Status1((std::error_code())),
267       Status2((std::error_code())), Status3((std::error_code())),
268       StatusB((std::error_code())), StatusM((std::error_code())),
269       StatusT((std::error_code()));
270 
271   Base->addRegularFile("/foo");
272   StatusB = Base->status("/foo");
273   ASSERT_FALSE(StatusB.getError());
274   Status1 = O->status("/foo");
275   ASSERT_FALSE(Status1.getError());
276   Middle->addRegularFile("/foo");
277   StatusM = Middle->status("/foo");
278   ASSERT_FALSE(StatusM.getError());
279   Status2 = O->status("/foo");
280   ASSERT_FALSE(Status2.getError());
281   Top->addRegularFile("/foo");
282   StatusT = Top->status("/foo");
283   ASSERT_FALSE(StatusT.getError());
284   Status3 = O->status("/foo");
285   ASSERT_FALSE(Status3.getError());
286 
287   EXPECT_TRUE(Status1->equivalent(*StatusB));
288   EXPECT_TRUE(Status2->equivalent(*StatusM));
289   EXPECT_TRUE(Status3->equivalent(*StatusT));
290 
291   EXPECT_FALSE(Status1->equivalent(*Status2));
292   EXPECT_FALSE(Status2->equivalent(*Status3));
293   EXPECT_FALSE(Status1->equivalent(*Status3));
294 }
295 
296 TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
297   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
298   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
299   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
300       new vfs::OverlayFileSystem(Lower));
301   O->pushOverlay(Upper);
302 
303   Lower->addDirectory("/lower-only");
304   Upper->addDirectory("/upper-only");
305 
306   // non-merged paths should be the same
307   ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
308   ASSERT_FALSE(Status1.getError());
309   ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
310   ASSERT_FALSE(Status2.getError());
311   EXPECT_TRUE(Status1->equivalent(*Status2));
312 
313   Status1 = Upper->status("/upper-only");
314   ASSERT_FALSE(Status1.getError());
315   Status2 = O->status("/upper-only");
316   ASSERT_FALSE(Status2.getError());
317   EXPECT_TRUE(Status1->equivalent(*Status2));
318 }
319 
320 TEST(VirtualFileSystemTest, MergedDirPermissions) {
321   // merged directories get the permissions of the upper dir
322   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
323   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
324   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
325       new vfs::OverlayFileSystem(Lower));
326   O->pushOverlay(Upper);
327 
328   ErrorOr<vfs::Status> Status((std::error_code()));
329   Lower->addDirectory("/both", sys::fs::owner_read);
330   Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
331   Status = O->status("/both");
332   ASSERT_FALSE(Status.getError());
333   EXPECT_EQ(0740, Status->getPermissions());
334 
335   // permissions (as usual) are not recursively applied
336   Lower->addRegularFile("/both/foo", sys::fs::owner_read);
337   Upper->addRegularFile("/both/bar", sys::fs::owner_write);
338   Status = O->status("/both/foo");
339   ASSERT_FALSE(Status.getError());
340   EXPECT_EQ(0400, Status->getPermissions());
341   Status = O->status("/both/bar");
342   ASSERT_FALSE(Status.getError());
343   EXPECT_EQ(0200, Status->getPermissions());
344 }
345 
346 namespace {
347 struct ScopedDir {
348   SmallString<128> Path;
349   ScopedDir(const Twine &Name, bool Unique = false) {
350     std::error_code EC;
351     if (Unique) {
352       EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
353     } else {
354       Path = Name.str();
355       EC = llvm::sys::fs::create_directory(Twine(Path));
356     }
357     if (EC)
358       Path = "";
359     EXPECT_FALSE(EC);
360   }
361   ~ScopedDir() {
362     if (Path != "") {
363       EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
364     }
365   }
366   operator StringRef() { return Path.str(); }
367 };
368 
369 struct ScopedLink {
370   SmallString<128> Path;
371   ScopedLink(const Twine &To, const Twine &From) {
372     Path = From.str();
373     std::error_code EC = sys::fs::create_link(To, From);
374     if (EC)
375       Path = "";
376     EXPECT_FALSE(EC);
377   }
378   ~ScopedLink() {
379     if (Path != "") {
380       EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
381     }
382   }
383   operator StringRef() { return Path.str(); }
384 };
385 } // end anonymous namespace
386 
387 TEST(VirtualFileSystemTest, BasicRealFSIteration) {
388   ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
389   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
390 
391   std::error_code EC;
392   vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
393   ASSERT_FALSE(EC);
394   EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
395 
396   ScopedDir _a(TestDirectory + "/a");
397   ScopedDir _ab(TestDirectory + "/a/b");
398   ScopedDir _c(TestDirectory + "/c");
399   ScopedDir _cd(TestDirectory + "/c/d");
400 
401   I = FS->dir_begin(Twine(TestDirectory), EC);
402   ASSERT_FALSE(EC);
403   ASSERT_NE(vfs::directory_iterator(), I);
404   // Check either a or c, since we can't rely on the iteration order.
405   EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
406   I.increment(EC);
407   ASSERT_FALSE(EC);
408   ASSERT_NE(vfs::directory_iterator(), I);
409   EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
410   I.increment(EC);
411   EXPECT_EQ(vfs::directory_iterator(), I);
412 }
413 
414 #ifdef LLVM_ON_UNIX
415 TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
416   ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
417   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
418 
419   ScopedLink _a("no_such_file", TestDirectory + "/a");
420   ScopedDir _b(TestDirectory + "/b");
421   ScopedLink _c("no_such_file", TestDirectory + "/c");
422 
423   // Should get no iteration error, but a stat error for the broken symlinks.
424   std::map<std::string, std::error_code> StatResults;
425   std::error_code EC;
426   for (vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC), E;
427        I != E; I.increment(EC)) {
428     EXPECT_FALSE(EC);
429     StatResults[sys::path::filename(I->path())] =
430         FS->status(I->path()).getError();
431   }
432   EXPECT_THAT(
433       StatResults,
434       ElementsAre(
435           Pair("a", std::make_error_code(std::errc::no_such_file_or_directory)),
436           Pair("b", std::error_code()),
437           Pair("c",
438                std::make_error_code(std::errc::no_such_file_or_directory))));
439 }
440 #endif
441 
442 TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
443   ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
444   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
445 
446   std::error_code EC;
447   auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
448   ASSERT_FALSE(EC);
449   EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
450 
451   ScopedDir _a(TestDirectory + "/a");
452   ScopedDir _ab(TestDirectory + "/a/b");
453   ScopedDir _c(TestDirectory + "/c");
454   ScopedDir _cd(TestDirectory + "/c/d");
455 
456   I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
457   ASSERT_FALSE(EC);
458   ASSERT_NE(vfs::recursive_directory_iterator(), I);
459 
460   std::vector<std::string> Contents;
461   for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
462        I.increment(EC)) {
463     Contents.push_back(I->path());
464   }
465 
466   // Check contents, which may be in any order
467   EXPECT_EQ(4U, Contents.size());
468   int Counts[4] = {0, 0, 0, 0};
469   for (const std::string &Name : Contents) {
470     ASSERT_FALSE(Name.empty());
471     int Index = Name[Name.size() - 1] - 'a';
472     ASSERT_TRUE(Index >= 0 && Index < 4);
473     Counts[Index]++;
474   }
475   EXPECT_EQ(1, Counts[0]); // a
476   EXPECT_EQ(1, Counts[1]); // b
477   EXPECT_EQ(1, Counts[2]); // c
478   EXPECT_EQ(1, Counts[3]); // d
479 }
480 
481 TEST(VirtualFileSystemTest, BasicRealFSRecursiveIterationNoPush) {
482   ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
483 
484   ScopedDir _a(TestDirectory + "/a");
485   ScopedDir _ab(TestDirectory + "/a/b");
486   ScopedDir _c(TestDirectory + "/c");
487   ScopedDir _cd(TestDirectory + "/c/d");
488   ScopedDir _e(TestDirectory + "/e");
489   ScopedDir _ef(TestDirectory + "/e/f");
490   ScopedDir _g(TestDirectory + "/g");
491 
492   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
493 
494   // Test that calling no_push on entries without subdirectories has no effect.
495   {
496     std::error_code EC;
497     auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
498     ASSERT_FALSE(EC);
499 
500     std::vector<std::string> Contents;
501     for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
502          I.increment(EC)) {
503       Contents.push_back(I->path());
504       char last = I->path().back();
505       switch (last) {
506       case 'b':
507       case 'd':
508       case 'f':
509       case 'g':
510         I.no_push();
511         break;
512       default:
513         break;
514       }
515     }
516     EXPECT_EQ(7U, Contents.size());
517   }
518 
519   // Test that calling no_push skips subdirectories.
520   {
521     std::error_code EC;
522     auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
523     ASSERT_FALSE(EC);
524 
525     std::vector<std::string> Contents;
526     for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
527          I.increment(EC)) {
528       Contents.push_back(I->path());
529       char last = I->path().back();
530       switch (last) {
531       case 'a':
532       case 'c':
533       case 'e':
534         I.no_push();
535         break;
536       default:
537         break;
538       }
539     }
540 
541     // Check contents, which may be in any order
542     EXPECT_EQ(4U, Contents.size());
543     int Counts[7] = {0, 0, 0, 0, 0, 0, 0};
544     for (const std::string &Name : Contents) {
545       ASSERT_FALSE(Name.empty());
546       int Index = Name[Name.size() - 1] - 'a';
547       ASSERT_TRUE(Index >= 0 && Index < 7);
548       Counts[Index]++;
549     }
550     EXPECT_EQ(1, Counts[0]); // a
551     EXPECT_EQ(0, Counts[1]); // b
552     EXPECT_EQ(1, Counts[2]); // c
553     EXPECT_EQ(0, Counts[3]); // d
554     EXPECT_EQ(1, Counts[4]); // e
555     EXPECT_EQ(0, Counts[5]); // f
556     EXPECT_EQ(1, Counts[6]); // g
557   }
558 }
559 
560 #ifdef LLVM_ON_UNIX
561 TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
562   ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
563   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
564 
565   ScopedLink _a("no_such_file", TestDirectory + "/a");
566   ScopedDir _b(TestDirectory + "/b");
567   ScopedLink _ba("no_such_file", TestDirectory + "/b/a");
568   ScopedDir _bb(TestDirectory + "/b/b");
569   ScopedLink _bc("no_such_file", TestDirectory + "/b/c");
570   ScopedLink _c("no_such_file", TestDirectory + "/c");
571   ScopedDir _d(TestDirectory + "/d");
572   ScopedDir _dd(TestDirectory + "/d/d");
573   ScopedDir _ddd(TestDirectory + "/d/d/d");
574   ScopedLink _e("no_such_file", TestDirectory + "/e");
575 
576   std::vector<std::string> VisitedBrokenSymlinks;
577   std::vector<std::string> VisitedNonBrokenSymlinks;
578   std::error_code EC;
579   for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E;
580        I != E; I.increment(EC)) {
581     EXPECT_FALSE(EC);
582     (FS->status(I->path()) ? VisitedNonBrokenSymlinks : VisitedBrokenSymlinks)
583         .push_back(I->path());
584   }
585 
586   // Check visited file names.
587   EXPECT_THAT(VisitedBrokenSymlinks,
588               UnorderedElementsAre(StringRef(_a), StringRef(_ba),
589                                    StringRef(_bc), StringRef(_c),
590                                    StringRef(_e)));
591   EXPECT_THAT(VisitedNonBrokenSymlinks,
592               UnorderedElementsAre(StringRef(_b), StringRef(_bb), StringRef(_d),
593                                    StringRef(_dd), StringRef(_ddd)));
594 }
595 #endif
596 
597 template <typename DirIter>
598 static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
599   std::error_code EC;
600   SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
601   SmallVector<std::string, 4> InputToCheck;
602 
603   // Do not rely on iteration order to check for contents, sort both
604   // content vectors before comparison.
605   for (DirIter E; !EC && I != E; I.increment(EC))
606     InputToCheck.push_back(I->path());
607 
608   llvm::sort(InputToCheck);
609   llvm::sort(Expected);
610   EXPECT_EQ(InputToCheck.size(), Expected.size());
611 
612   unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
613   for (unsigned Idx = 0; Idx != LastElt; ++Idx)
614     EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
615 }
616 
617 TEST(VirtualFileSystemTest, OverlayIteration) {
618   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
619   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
620   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
621       new vfs::OverlayFileSystem(Lower));
622   O->pushOverlay(Upper);
623 
624   std::error_code EC;
625   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
626 
627   Lower->addRegularFile("/file1");
628   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
629 
630   Upper->addRegularFile("/file2");
631   checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
632 
633   Lower->addDirectory("/dir1");
634   Lower->addRegularFile("/dir1/foo");
635   Upper->addDirectory("/dir2");
636   Upper->addRegularFile("/dir2/foo");
637   checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
638   checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
639 }
640 
641 TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
642   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
643   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
644   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
645   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
646       new vfs::OverlayFileSystem(Lower));
647   O->pushOverlay(Middle);
648   O->pushOverlay(Upper);
649 
650   std::error_code EC;
651   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
652                 ArrayRef<StringRef>());
653 
654   Lower->addRegularFile("/file1");
655   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
656                 ArrayRef<StringRef>("/file1"));
657 
658   Upper->addDirectory("/dir");
659   Upper->addRegularFile("/dir/file2");
660   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
661                 {"/dir", "/dir/file2", "/file1"});
662 
663   Lower->addDirectory("/dir1");
664   Lower->addRegularFile("/dir1/foo");
665   Lower->addDirectory("/dir1/a");
666   Lower->addRegularFile("/dir1/a/b");
667   Middle->addDirectory("/a");
668   Middle->addDirectory("/a/b");
669   Middle->addDirectory("/a/b/c");
670   Middle->addRegularFile("/a/b/c/d");
671   Middle->addRegularFile("/hiddenByUp");
672   Upper->addDirectory("/dir2");
673   Upper->addRegularFile("/dir2/foo");
674   Upper->addRegularFile("/hiddenByUp");
675   checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
676                 ArrayRef<StringRef>("/dir2/foo"));
677   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
678                 {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
679                  "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
680                  "/dir1/a/b", "/dir1/foo", "/file1"});
681 }
682 
683 TEST(VirtualFileSystemTest, ThreeLevelIteration) {
684   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
685   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
686   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
687   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
688       new vfs::OverlayFileSystem(Lower));
689   O->pushOverlay(Middle);
690   O->pushOverlay(Upper);
691 
692   std::error_code EC;
693   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
694 
695   Middle->addRegularFile("/file2");
696   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
697 
698   Lower->addRegularFile("/file1");
699   Upper->addRegularFile("/file3");
700   checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
701 }
702 
703 TEST(VirtualFileSystemTest, HiddenInIteration) {
704   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
705   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
706   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
707   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
708       new vfs::OverlayFileSystem(Lower));
709   O->pushOverlay(Middle);
710   O->pushOverlay(Upper);
711 
712   std::error_code EC;
713   Lower->addRegularFile("/onlyInLow");
714   Lower->addDirectory("/hiddenByMid");
715   Lower->addDirectory("/hiddenByUp");
716   Middle->addRegularFile("/onlyInMid");
717   Middle->addRegularFile("/hiddenByMid");
718   Middle->addDirectory("/hiddenByUp");
719   Upper->addRegularFile("/onlyInUp");
720   Upper->addRegularFile("/hiddenByUp");
721   checkContents(
722       O->dir_begin("/", EC),
723       {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
724 
725   // Make sure we get the top-most entry
726   {
727     std::error_code EC;
728     vfs::directory_iterator I = O->dir_begin("/", EC), E;
729     for (; !EC && I != E; I.increment(EC))
730       if (I->path() == "/hiddenByUp")
731         break;
732     ASSERT_NE(E, I);
733     EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
734   }
735   {
736     std::error_code EC;
737     vfs::directory_iterator I = O->dir_begin("/", EC), E;
738     for (; !EC && I != E; I.increment(EC))
739       if (I->path() == "/hiddenByMid")
740         break;
741     ASSERT_NE(E, I);
742     EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
743   }
744 }
745 
746 TEST(ProxyFileSystemTest, Basic) {
747   IntrusiveRefCntPtr<vfs::InMemoryFileSystem> Base(
748       new vfs::InMemoryFileSystem());
749   vfs::ProxyFileSystem PFS(Base);
750 
751   Base->addFile("/a", 0, MemoryBuffer::getMemBuffer("test"));
752 
753   auto Stat = PFS.status("/a");
754   ASSERT_FALSE(Stat.getError());
755 
756   auto File = PFS.openFileForRead("/a");
757   ASSERT_FALSE(File.getError());
758   EXPECT_EQ("test", (*(*File)->getBuffer("ignored"))->getBuffer());
759 
760   std::error_code EC;
761   vfs::directory_iterator I = PFS.dir_begin("/", EC);
762   ASSERT_FALSE(EC);
763   ASSERT_EQ("/a", I->path());
764   I.increment(EC);
765   ASSERT_FALSE(EC);
766   ASSERT_EQ(vfs::directory_iterator(), I);
767 
768   ASSERT_FALSE(PFS.setCurrentWorkingDirectory("/"));
769 
770   auto PWD = PFS.getCurrentWorkingDirectory();
771   ASSERT_FALSE(PWD.getError());
772   ASSERT_EQ("/", *PWD);
773 
774   SmallString<16> Path;
775   ASSERT_FALSE(PFS.getRealPath("a", Path));
776   ASSERT_EQ("/a", Path);
777 
778   bool Local = true;
779   ASSERT_FALSE(PFS.isLocal("/a", Local));
780   ASSERT_EQ(false, Local);
781 }
782 
783 class InMemoryFileSystemTest : public ::testing::Test {
784 protected:
785   llvm::vfs::InMemoryFileSystem FS;
786   llvm::vfs::InMemoryFileSystem NormalizedFS;
787 
788   InMemoryFileSystemTest()
789       : FS(/*UseNormalizedPaths=*/false),
790         NormalizedFS(/*UseNormalizedPaths=*/true) {}
791 };
792 
793 MATCHER_P2(IsHardLinkTo, FS, Target, "") {
794   StringRef From = arg;
795   StringRef To = Target;
796   auto OpenedFrom = FS->openFileForRead(From);
797   auto OpenedTo = FS->openFileForRead(To);
798   return !OpenedFrom.getError() && !OpenedTo.getError() &&
799          (*OpenedFrom)->status()->getUniqueID() ==
800              (*OpenedTo)->status()->getUniqueID();
801 }
802 
803 TEST_F(InMemoryFileSystemTest, IsEmpty) {
804   auto Stat = FS.status("/a");
805   ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
806   Stat = FS.status("/");
807   ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
808 }
809 
810 TEST_F(InMemoryFileSystemTest, WindowsPath) {
811   FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
812   auto Stat = FS.status("c:");
813 #if !defined(_WIN32)
814   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
815 #endif
816   Stat = FS.status("c:/windows/system128/foo.cpp");
817   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
818   FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
819   Stat = FS.status("d:/windows/foo.cpp");
820   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
821 }
822 
823 TEST_F(InMemoryFileSystemTest, OverlayFile) {
824   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
825   NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
826   auto Stat = FS.status("/");
827   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
828   Stat = FS.status("/.");
829   ASSERT_FALSE(Stat);
830   Stat = NormalizedFS.status("/.");
831   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
832   Stat = FS.status("/a");
833   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
834   ASSERT_EQ("/a", Stat->getName());
835 }
836 
837 TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
838   auto Buf = MemoryBuffer::getMemBuffer("a");
839   FS.addFileNoOwn("/a", 0, Buf.get());
840   auto Stat = FS.status("/a");
841   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
842   ASSERT_EQ("/a", Stat->getName());
843 }
844 
845 TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
846   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
847   FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
848   FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
849   NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
850   NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
851   NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
852   auto File = FS.openFileForRead("/a");
853   ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
854   File = FS.openFileForRead("/a"); // Open again.
855   ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
856   File = NormalizedFS.openFileForRead("/././a"); // Open again.
857   ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
858   File = FS.openFileForRead("/");
859   ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
860   File = FS.openFileForRead("/b");
861   ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
862   File = FS.openFileForRead("./c");
863   ASSERT_FALSE(File);
864   File = FS.openFileForRead("e/../d");
865   ASSERT_FALSE(File);
866   File = NormalizedFS.openFileForRead("./c");
867   ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
868   File = NormalizedFS.openFileForRead("e/../d");
869   ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
870 }
871 
872 TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
873   ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
874   ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
875   ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
876   ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
877 }
878 
879 TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
880   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
881   FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
882 
883   std::error_code EC;
884   vfs::directory_iterator I = FS.dir_begin("/", EC);
885   ASSERT_FALSE(EC);
886   ASSERT_EQ("/a", I->path());
887   I.increment(EC);
888   ASSERT_FALSE(EC);
889   ASSERT_EQ("/b", I->path());
890   I.increment(EC);
891   ASSERT_FALSE(EC);
892   ASSERT_EQ(vfs::directory_iterator(), I);
893 
894   I = FS.dir_begin("/b", EC);
895   ASSERT_FALSE(EC);
896   // When on Windows, we end up with "/b\\c" as the name.  Convert to Posix
897   // path for the sake of the comparison.
898   ASSERT_EQ("/b/c", getPosixPath(I->path()));
899   I.increment(EC);
900   ASSERT_FALSE(EC);
901   ASSERT_EQ(vfs::directory_iterator(), I);
902 }
903 
904 TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
905   FS.setCurrentWorkingDirectory("/b");
906   FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
907 
908   auto Stat = FS.status("/b/c");
909   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
910   ASSERT_EQ("/b/c", Stat->getName());
911   ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
912 
913   Stat = FS.status("c");
914   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
915 
916   NormalizedFS.setCurrentWorkingDirectory("/b/c");
917   NormalizedFS.setCurrentWorkingDirectory(".");
918   ASSERT_EQ("/b/c",
919             getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
920   NormalizedFS.setCurrentWorkingDirectory("..");
921   ASSERT_EQ("/b",
922             getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
923 }
924 
925 TEST_F(InMemoryFileSystemTest, IsLocal) {
926   FS.setCurrentWorkingDirectory("/b");
927   FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
928 
929   std::error_code EC;
930   bool IsLocal = true;
931   EC = FS.isLocal("c", IsLocal);
932   ASSERT_FALSE(EC);
933   ASSERT_FALSE(IsLocal);
934 }
935 
936 #if !defined(_WIN32)
937 TEST_F(InMemoryFileSystemTest, GetRealPath) {
938   SmallString<16> Path;
939   EXPECT_EQ(FS.getRealPath("b", Path), errc::operation_not_permitted);
940 
941   auto GetRealPath = [this](StringRef P) {
942     SmallString<16> Output;
943     auto EC = FS.getRealPath(P, Output);
944     EXPECT_FALSE(EC);
945     return Output.str().str();
946   };
947 
948   FS.setCurrentWorkingDirectory("a");
949   EXPECT_EQ(GetRealPath("b"), "a/b");
950   EXPECT_EQ(GetRealPath("../b"), "b");
951   EXPECT_EQ(GetRealPath("b/./c"), "a/b/c");
952 
953   FS.setCurrentWorkingDirectory("/a");
954   EXPECT_EQ(GetRealPath("b"), "/a/b");
955   EXPECT_EQ(GetRealPath("../b"), "/b");
956   EXPECT_EQ(GetRealPath("b/./c"), "/a/b/c");
957 }
958 #endif // _WIN32
959 
960 TEST_F(InMemoryFileSystemTest, AddFileWithUser) {
961   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
962   auto Stat = FS.status("/a");
963   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
964   ASSERT_TRUE(Stat->isDirectory());
965   ASSERT_EQ(0xFEEDFACE, Stat->getUser());
966   Stat = FS.status("/a/b");
967   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
968   ASSERT_TRUE(Stat->isDirectory());
969   ASSERT_EQ(0xFEEDFACE, Stat->getUser());
970   Stat = FS.status("/a/b/c");
971   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
972   ASSERT_TRUE(Stat->isRegularFile());
973   ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
974   ASSERT_EQ(0xFEEDFACE, Stat->getUser());
975 }
976 
977 TEST_F(InMemoryFileSystemTest, AddFileWithGroup) {
978   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00);
979   auto Stat = FS.status("/a");
980   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
981   ASSERT_TRUE(Stat->isDirectory());
982   ASSERT_EQ(0xDABBAD00, Stat->getGroup());
983   Stat = FS.status("/a/b");
984   ASSERT_TRUE(Stat->isDirectory());
985   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
986   ASSERT_EQ(0xDABBAD00, Stat->getGroup());
987   Stat = FS.status("/a/b/c");
988   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
989   ASSERT_TRUE(Stat->isRegularFile());
990   ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
991   ASSERT_EQ(0xDABBAD00, Stat->getGroup());
992 }
993 
994 TEST_F(InMemoryFileSystemTest, AddFileWithFileType) {
995   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
996              sys::fs::file_type::socket_file);
997   auto Stat = FS.status("/a");
998   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
999   ASSERT_TRUE(Stat->isDirectory());
1000   Stat = FS.status("/a/b");
1001   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1002   ASSERT_TRUE(Stat->isDirectory());
1003   Stat = FS.status("/a/b/c");
1004   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1005   ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType());
1006   ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
1007 }
1008 
1009 TEST_F(InMemoryFileSystemTest, AddFileWithPerms) {
1010   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None, None,
1011              sys::fs::perms::owner_read | sys::fs::perms::owner_write);
1012   auto Stat = FS.status("/a");
1013   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1014   ASSERT_TRUE(Stat->isDirectory());
1015   ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
1016                 sys::fs::perms::owner_exe,
1017             Stat->getPermissions());
1018   Stat = FS.status("/a/b");
1019   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1020   ASSERT_TRUE(Stat->isDirectory());
1021   ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
1022                 sys::fs::perms::owner_exe,
1023             Stat->getPermissions());
1024   Stat = FS.status("/a/b/c");
1025   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1026   ASSERT_TRUE(Stat->isRegularFile());
1027   ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write,
1028             Stat->getPermissions());
1029 }
1030 
1031 TEST_F(InMemoryFileSystemTest, AddDirectoryThenAddChild) {
1032   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None,
1033              /*Group=*/None, sys::fs::file_type::directory_file);
1034   FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None,
1035              /*Group=*/None, sys::fs::file_type::regular_file);
1036   auto Stat = FS.status("/a");
1037   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1038   ASSERT_TRUE(Stat->isDirectory());
1039   Stat = FS.status("/a/b");
1040   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1041   ASSERT_TRUE(Stat->isRegularFile());
1042 }
1043 
1044 // Test that the name returned by status() is in the same form as the path that
1045 // was requested (to match the behavior of RealFileSystem).
1046 TEST_F(InMemoryFileSystemTest, StatusName) {
1047   NormalizedFS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"),
1048                        /*User=*/None,
1049                        /*Group=*/None, sys::fs::file_type::regular_file);
1050   NormalizedFS.setCurrentWorkingDirectory("/a/b");
1051 
1052   // Access using InMemoryFileSystem::status.
1053   auto Stat = NormalizedFS.status("../b/c");
1054   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1055                                 << NormalizedFS.toString();
1056   ASSERT_TRUE(Stat->isRegularFile());
1057   ASSERT_EQ("../b/c", Stat->getName());
1058 
1059   // Access using InMemoryFileAdaptor::status.
1060   auto File = NormalizedFS.openFileForRead("../b/c");
1061   ASSERT_FALSE(File.getError()) << File.getError() << "\n"
1062                                 << NormalizedFS.toString();
1063   Stat = (*File)->status();
1064   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1065                                 << NormalizedFS.toString();
1066   ASSERT_TRUE(Stat->isRegularFile());
1067   ASSERT_EQ("../b/c", Stat->getName());
1068 
1069   // Access using a directory iterator.
1070   std::error_code EC;
1071   llvm::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC);
1072   // When on Windows, we end up with "../b\\c" as the name.  Convert to Posix
1073   // path for the sake of the comparison.
1074   ASSERT_EQ("../b/c", getPosixPath(It->path()));
1075 }
1076 
1077 TEST_F(InMemoryFileSystemTest, AddHardLinkToFile) {
1078   StringRef FromLink = "/path/to/FROM/link";
1079   StringRef Target = "/path/to/TO/file";
1080   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1081   EXPECT_TRUE(FS.addHardLink(FromLink, Target));
1082   EXPECT_THAT(FromLink, IsHardLinkTo(&FS, Target));
1083   EXPECT_TRUE(FS.status(FromLink)->getSize() == FS.status(Target)->getSize());
1084   EXPECT_TRUE(FS.getBufferForFile(FromLink)->get()->getBuffer() ==
1085               FS.getBufferForFile(Target)->get()->getBuffer());
1086 }
1087 
1088 TEST_F(InMemoryFileSystemTest, AddHardLinkInChainPattern) {
1089   StringRef Link0 = "/path/to/0/link";
1090   StringRef Link1 = "/path/to/1/link";
1091   StringRef Link2 = "/path/to/2/link";
1092   StringRef Target = "/path/to/target";
1093   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target file"));
1094   EXPECT_TRUE(FS.addHardLink(Link2, Target));
1095   EXPECT_TRUE(FS.addHardLink(Link1, Link2));
1096   EXPECT_TRUE(FS.addHardLink(Link0, Link1));
1097   EXPECT_THAT(Link0, IsHardLinkTo(&FS, Target));
1098   EXPECT_THAT(Link1, IsHardLinkTo(&FS, Target));
1099   EXPECT_THAT(Link2, IsHardLinkTo(&FS, Target));
1100 }
1101 
1102 TEST_F(InMemoryFileSystemTest, AddHardLinkToAFileThatWasNotAddedBefore) {
1103   EXPECT_FALSE(FS.addHardLink("/path/to/link", "/path/to/target"));
1104 }
1105 
1106 TEST_F(InMemoryFileSystemTest, AddHardLinkFromAFileThatWasAddedBefore) {
1107   StringRef Link = "/path/to/link";
1108   StringRef Target = "/path/to/target";
1109   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1110   FS.addFile(Link, 0, MemoryBuffer::getMemBuffer("content of link"));
1111   EXPECT_FALSE(FS.addHardLink(Link, Target));
1112 }
1113 
1114 TEST_F(InMemoryFileSystemTest, AddSameHardLinkMoreThanOnce) {
1115   StringRef Link = "/path/to/link";
1116   StringRef Target = "/path/to/target";
1117   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1118   EXPECT_TRUE(FS.addHardLink(Link, Target));
1119   EXPECT_FALSE(FS.addHardLink(Link, Target));
1120 }
1121 
1122 TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithSameContent) {
1123   StringRef Link = "/path/to/link";
1124   StringRef Target = "/path/to/target";
1125   StringRef Content = "content of target";
1126   EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1127   EXPECT_TRUE(FS.addHardLink(Link, Target));
1128   EXPECT_TRUE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(Content)));
1129 }
1130 
1131 TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithDifferentContent) {
1132   StringRef Link = "/path/to/link";
1133   StringRef Target = "/path/to/target";
1134   StringRef Content = "content of target";
1135   StringRef LinkContent = "different content of link";
1136   EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1137   EXPECT_TRUE(FS.addHardLink(Link, Target));
1138   EXPECT_FALSE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(LinkContent)));
1139 }
1140 
1141 TEST_F(InMemoryFileSystemTest, AddHardLinkToADirectory) {
1142   StringRef Dir = "path/to/dummy/dir";
1143   StringRef Link = "/path/to/link";
1144   StringRef File = "path/to/dummy/dir/target";
1145   StringRef Content = "content of target";
1146   EXPECT_TRUE(FS.addFile(File, 0, MemoryBuffer::getMemBuffer(Content)));
1147   EXPECT_FALSE(FS.addHardLink(Link, Dir));
1148 }
1149 
1150 TEST_F(InMemoryFileSystemTest, AddHardLinkFromADirectory) {
1151   StringRef Dir = "path/to/dummy/dir";
1152   StringRef Target = "path/to/dummy/dir/target";
1153   StringRef Content = "content of target";
1154   EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1155   EXPECT_FALSE(FS.addHardLink(Dir, Target));
1156 }
1157 
1158 TEST_F(InMemoryFileSystemTest, AddHardLinkUnderAFile) {
1159   StringRef CommonContent = "content string";
1160   FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer(CommonContent));
1161   FS.addFile("/c/d", 0, MemoryBuffer::getMemBuffer(CommonContent));
1162   EXPECT_FALSE(FS.addHardLink("/c/d/e", "/a/b"));
1163 }
1164 
1165 TEST_F(InMemoryFileSystemTest, RecursiveIterationWithHardLink) {
1166   std::error_code EC;
1167   FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("content string"));
1168   EXPECT_TRUE(FS.addHardLink("/c/d", "/a/b"));
1169   auto I = vfs::recursive_directory_iterator(FS, "/", EC);
1170   ASSERT_FALSE(EC);
1171   std::vector<std::string> Nodes;
1172   for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
1173        I.increment(EC)) {
1174     Nodes.push_back(getPosixPath(I->path()));
1175   }
1176   EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d"));
1177 }
1178 
1179 // NOTE: in the tests below, we use '//root/' as our root directory, since it is
1180 // a legal *absolute* path on Windows as well as *nix.
1181 class VFSFromYAMLTest : public ::testing::Test {
1182 public:
1183   int NumDiagnostics;
1184 
1185   void SetUp() override { NumDiagnostics = 0; }
1186 
1187   static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
1188     VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
1189     ++Test->NumDiagnostics;
1190   }
1191 
1192   IntrusiveRefCntPtr<vfs::FileSystem>
1193   getFromYAMLRawString(StringRef Content,
1194                        IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
1195     std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
1196     return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
1197                           ExternalFS);
1198   }
1199 
1200   IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
1201       StringRef Content,
1202       IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
1203     std::string VersionPlusContent("{\n  'version':0,\n");
1204     VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
1205     return getFromYAMLRawString(VersionPlusContent, ExternalFS);
1206   }
1207 
1208   // This is intended as a "XFAIL" for windows hosts.
1209   bool supportsSameDirMultipleYAMLEntries() {
1210     Triple Host(Triple::normalize(sys::getProcessTriple()));
1211     return !Host.isOSWindows();
1212   }
1213 };
1214 
1215 TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
1216   IntrusiveRefCntPtr<vfs::FileSystem> FS;
1217   FS = getFromYAMLString("");
1218   EXPECT_EQ(nullptr, FS.get());
1219   FS = getFromYAMLString("[]");
1220   EXPECT_EQ(nullptr, FS.get());
1221   FS = getFromYAMLString("'string'");
1222   EXPECT_EQ(nullptr, FS.get());
1223   EXPECT_EQ(3, NumDiagnostics);
1224 }
1225 
1226 TEST_F(VFSFromYAMLTest, MappedFiles) {
1227   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1228   Lower->addRegularFile("//root/foo/bar/a");
1229   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1230       "{ 'roots': [\n"
1231       "{\n"
1232       "  'type': 'directory',\n"
1233       "  'name': '//root/',\n"
1234       "  'contents': [ {\n"
1235       "                  'type': 'file',\n"
1236       "                  'name': 'file1',\n"
1237       "                  'external-contents': '//root/foo/bar/a'\n"
1238       "                },\n"
1239       "                {\n"
1240       "                  'type': 'file',\n"
1241       "                  'name': 'file2',\n"
1242       "                  'external-contents': '//root/foo/b'\n"
1243       "                }\n"
1244       "              ]\n"
1245       "}\n"
1246       "]\n"
1247       "}",
1248       Lower);
1249   ASSERT_TRUE(FS.get() != nullptr);
1250 
1251   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1252       new vfs::OverlayFileSystem(Lower));
1253   O->pushOverlay(FS);
1254 
1255   // file
1256   ErrorOr<vfs::Status> S = O->status("//root/file1");
1257   ASSERT_FALSE(S.getError());
1258   EXPECT_EQ("//root/foo/bar/a", S->getName());
1259   EXPECT_TRUE(S->IsVFSMapped);
1260 
1261   ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
1262   EXPECT_EQ("//root/foo/bar/a", SLower->getName());
1263   EXPECT_TRUE(S->equivalent(*SLower));
1264   EXPECT_FALSE(SLower->IsVFSMapped);
1265 
1266   // file after opening
1267   auto OpenedF = O->openFileForRead("//root/file1");
1268   ASSERT_FALSE(OpenedF.getError());
1269   auto OpenedS = (*OpenedF)->status();
1270   ASSERT_FALSE(OpenedS.getError());
1271   EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
1272   EXPECT_TRUE(OpenedS->IsVFSMapped);
1273 
1274   // directory
1275   S = O->status("//root/");
1276   ASSERT_FALSE(S.getError());
1277   EXPECT_TRUE(S->isDirectory());
1278   EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
1279 
1280   // broken mapping
1281   EXPECT_EQ(O->status("//root/file2").getError(),
1282             llvm::errc::no_such_file_or_directory);
1283   EXPECT_EQ(0, NumDiagnostics);
1284 }
1285 
1286 TEST_F(VFSFromYAMLTest, CaseInsensitive) {
1287   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1288   Lower->addRegularFile("//root/foo/bar/a");
1289   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1290       "{ 'case-sensitive': 'false',\n"
1291       "  'roots': [\n"
1292       "{\n"
1293       "  'type': 'directory',\n"
1294       "  'name': '//root/',\n"
1295       "  'contents': [ {\n"
1296       "                  'type': 'file',\n"
1297       "                  'name': 'XX',\n"
1298       "                  'external-contents': '//root/foo/bar/a'\n"
1299       "                }\n"
1300       "              ]\n"
1301       "}]}",
1302       Lower);
1303   ASSERT_TRUE(FS.get() != nullptr);
1304 
1305   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1306       new vfs::OverlayFileSystem(Lower));
1307   O->pushOverlay(FS);
1308 
1309   ErrorOr<vfs::Status> S = O->status("//root/XX");
1310   ASSERT_FALSE(S.getError());
1311 
1312   ErrorOr<vfs::Status> SS = O->status("//root/xx");
1313   ASSERT_FALSE(SS.getError());
1314   EXPECT_TRUE(S->equivalent(*SS));
1315   SS = O->status("//root/xX");
1316   EXPECT_TRUE(S->equivalent(*SS));
1317   SS = O->status("//root/Xx");
1318   EXPECT_TRUE(S->equivalent(*SS));
1319   EXPECT_EQ(0, NumDiagnostics);
1320 }
1321 
1322 TEST_F(VFSFromYAMLTest, CaseSensitive) {
1323   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1324   Lower->addRegularFile("//root/foo/bar/a");
1325   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1326       "{ 'case-sensitive': 'true',\n"
1327       "  'roots': [\n"
1328       "{\n"
1329       "  'type': 'directory',\n"
1330       "  'name': '//root/',\n"
1331       "  'contents': [ {\n"
1332       "                  'type': 'file',\n"
1333       "                  'name': 'XX',\n"
1334       "                  'external-contents': '//root/foo/bar/a'\n"
1335       "                }\n"
1336       "              ]\n"
1337       "}]}",
1338       Lower);
1339   ASSERT_TRUE(FS.get() != nullptr);
1340 
1341   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1342       new vfs::OverlayFileSystem(Lower));
1343   O->pushOverlay(FS);
1344 
1345   ErrorOr<vfs::Status> SS = O->status("//root/xx");
1346   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1347   SS = O->status("//root/xX");
1348   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1349   SS = O->status("//root/Xx");
1350   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1351   EXPECT_EQ(0, NumDiagnostics);
1352 }
1353 
1354 TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
1355   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1356 
1357   // invalid YAML at top-level
1358   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
1359   EXPECT_EQ(nullptr, FS.get());
1360   // invalid YAML in roots
1361   FS = getFromYAMLString("{ 'roots':[}", Lower);
1362   // invalid YAML in directory
1363   FS = getFromYAMLString(
1364       "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
1365       Lower);
1366   EXPECT_EQ(nullptr, FS.get());
1367 
1368   // invalid configuration
1369   FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
1370   EXPECT_EQ(nullptr, FS.get());
1371   FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
1372   EXPECT_EQ(nullptr, FS.get());
1373 
1374   // invalid roots
1375   FS = getFromYAMLString("{ 'roots':'' }", Lower);
1376   EXPECT_EQ(nullptr, FS.get());
1377   FS = getFromYAMLString("{ 'roots':{} }", Lower);
1378   EXPECT_EQ(nullptr, FS.get());
1379 
1380   // invalid entries
1381   FS = getFromYAMLString(
1382       "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
1383   EXPECT_EQ(nullptr, FS.get());
1384   FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
1385                          "'external-contents': 'other' }",
1386                          Lower);
1387   EXPECT_EQ(nullptr, FS.get());
1388   FS = getFromYAMLString(
1389       "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1390       Lower);
1391   EXPECT_EQ(nullptr, FS.get());
1392   FS = getFromYAMLString(
1393       "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
1394       Lower);
1395   EXPECT_EQ(nullptr, FS.get());
1396   FS = getFromYAMLString(
1397       "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
1398       Lower);
1399   EXPECT_EQ(nullptr, FS.get());
1400   FS = getFromYAMLString(
1401       "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
1402       Lower);
1403   EXPECT_EQ(nullptr, FS.get());
1404   FS = getFromYAMLString(
1405       "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
1406       Lower);
1407   EXPECT_EQ(nullptr, FS.get());
1408 
1409   // missing mandatory fields
1410   FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
1411   EXPECT_EQ(nullptr, FS.get());
1412   FS = getFromYAMLString(
1413       "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
1414   EXPECT_EQ(nullptr, FS.get());
1415   FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
1416   EXPECT_EQ(nullptr, FS.get());
1417 
1418   // duplicate keys
1419   FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
1420   EXPECT_EQ(nullptr, FS.get());
1421   FS = getFromYAMLString(
1422       "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1423       Lower);
1424   EXPECT_EQ(nullptr, FS.get());
1425   FS =
1426       getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1427                         "'external-contents':'blah' } ] }",
1428                         Lower);
1429   EXPECT_EQ(nullptr, FS.get());
1430 
1431   // missing version
1432   FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
1433   EXPECT_EQ(nullptr, FS.get());
1434 
1435   // bad version number
1436   FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
1437   EXPECT_EQ(nullptr, FS.get());
1438   FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
1439   EXPECT_EQ(nullptr, FS.get());
1440   FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
1441   EXPECT_EQ(nullptr, FS.get());
1442   EXPECT_EQ(24, NumDiagnostics);
1443 }
1444 
1445 TEST_F(VFSFromYAMLTest, UseExternalName) {
1446   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1447   Lower->addRegularFile("//root/external/file");
1448 
1449   IntrusiveRefCntPtr<vfs::FileSystem> FS =
1450       getFromYAMLString("{ 'roots': [\n"
1451                         "  { 'type': 'file', 'name': '//root/A',\n"
1452                         "    'external-contents': '//root/external/file'\n"
1453                         "  },\n"
1454                         "  { 'type': 'file', 'name': '//root/B',\n"
1455                         "    'use-external-name': true,\n"
1456                         "    'external-contents': '//root/external/file'\n"
1457                         "  },\n"
1458                         "  { 'type': 'file', 'name': '//root/C',\n"
1459                         "    'use-external-name': false,\n"
1460                         "    'external-contents': '//root/external/file'\n"
1461                         "  }\n"
1462                         "] }",
1463                         Lower);
1464   ASSERT_TRUE(nullptr != FS.get());
1465 
1466   // default true
1467   EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
1468   // explicit
1469   EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1470   EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
1471 
1472   // global configuration
1473   FS = getFromYAMLString("{ 'use-external-names': false,\n"
1474                          "  'roots': [\n"
1475                          "  { 'type': 'file', 'name': '//root/A',\n"
1476                          "    'external-contents': '//root/external/file'\n"
1477                          "  },\n"
1478                          "  { 'type': 'file', 'name': '//root/B',\n"
1479                          "    'use-external-name': true,\n"
1480                          "    'external-contents': '//root/external/file'\n"
1481                          "  },\n"
1482                          "  { 'type': 'file', 'name': '//root/C',\n"
1483                          "    'use-external-name': false,\n"
1484                          "    'external-contents': '//root/external/file'\n"
1485                          "  }\n"
1486                          "] }",
1487                          Lower);
1488   ASSERT_TRUE(nullptr != FS.get());
1489 
1490   // default
1491   EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
1492   // explicit
1493   EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1494   EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
1495 }
1496 
1497 TEST_F(VFSFromYAMLTest, MultiComponentPath) {
1498   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1499   Lower->addRegularFile("//root/other");
1500 
1501   // file in roots
1502   IntrusiveRefCntPtr<vfs::FileSystem> FS =
1503       getFromYAMLString("{ 'roots': [\n"
1504                         "  { 'type': 'file', 'name': '//root/path/to/file',\n"
1505                         "    'external-contents': '//root/other' }]\n"
1506                         "}",
1507                         Lower);
1508   ASSERT_TRUE(nullptr != FS.get());
1509   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1510   EXPECT_FALSE(FS->status("//root/path/to").getError());
1511   EXPECT_FALSE(FS->status("//root/path").getError());
1512   EXPECT_FALSE(FS->status("//root/").getError());
1513 
1514   // at the start
1515   FS = getFromYAMLString(
1516       "{ 'roots': [\n"
1517       "  { 'type': 'directory', 'name': '//root/path/to',\n"
1518       "    'contents': [ { 'type': 'file', 'name': 'file',\n"
1519       "                    'external-contents': '//root/other' }]}]\n"
1520       "}",
1521       Lower);
1522   ASSERT_TRUE(nullptr != FS.get());
1523   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1524   EXPECT_FALSE(FS->status("//root/path/to").getError());
1525   EXPECT_FALSE(FS->status("//root/path").getError());
1526   EXPECT_FALSE(FS->status("//root/").getError());
1527 
1528   // at the end
1529   FS = getFromYAMLString(
1530       "{ 'roots': [\n"
1531       "  { 'type': 'directory', 'name': '//root/',\n"
1532       "    'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
1533       "                    'external-contents': '//root/other' }]}]\n"
1534       "}",
1535       Lower);
1536   ASSERT_TRUE(nullptr != FS.get());
1537   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1538   EXPECT_FALSE(FS->status("//root/path/to").getError());
1539   EXPECT_FALSE(FS->status("//root/path").getError());
1540   EXPECT_FALSE(FS->status("//root/").getError());
1541 }
1542 
1543 TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1544   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1545   Lower->addRegularFile("//root/other");
1546 
1547   // file in roots
1548   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1549       "{ 'roots': [\n"
1550       "  { 'type': 'directory', 'name': '//root/path/to////',\n"
1551       "    'contents': [ { 'type': 'file', 'name': 'file',\n"
1552       "                    'external-contents': '//root/other' }]}]\n"
1553       "}",
1554       Lower);
1555   ASSERT_TRUE(nullptr != FS.get());
1556   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1557   EXPECT_FALSE(FS->status("//root/path/to").getError());
1558   EXPECT_FALSE(FS->status("//root/path").getError());
1559   EXPECT_FALSE(FS->status("//root/").getError());
1560 }
1561 
1562 TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1563   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1564   Lower->addDirectory("//root/");
1565   Lower->addDirectory("//root/foo");
1566   Lower->addDirectory("//root/foo/bar");
1567   Lower->addRegularFile("//root/foo/bar/a");
1568   Lower->addRegularFile("//root/foo/bar/b");
1569   Lower->addRegularFile("//root/file3");
1570   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1571       "{ 'use-external-names': false,\n"
1572       "  'roots': [\n"
1573       "{\n"
1574       "  'type': 'directory',\n"
1575       "  'name': '//root/',\n"
1576       "  'contents': [ {\n"
1577       "                  'type': 'file',\n"
1578       "                  'name': 'file1',\n"
1579       "                  'external-contents': '//root/foo/bar/a'\n"
1580       "                },\n"
1581       "                {\n"
1582       "                  'type': 'file',\n"
1583       "                  'name': 'file2',\n"
1584       "                  'external-contents': '//root/foo/bar/b'\n"
1585       "                }\n"
1586       "              ]\n"
1587       "}\n"
1588       "]\n"
1589       "}",
1590       Lower);
1591   ASSERT_TRUE(FS.get() != nullptr);
1592 
1593   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1594       new vfs::OverlayFileSystem(Lower));
1595   O->pushOverlay(FS);
1596 
1597   std::error_code EC;
1598   checkContents(O->dir_begin("//root/", EC),
1599                 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
1600 
1601   checkContents(O->dir_begin("//root/foo/bar", EC),
1602                 {"//root/foo/bar/a", "//root/foo/bar/b"});
1603 }
1604 
1605 TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1606   // https://llvm.org/bugs/show_bug.cgi?id=27725
1607   if (!supportsSameDirMultipleYAMLEntries())
1608     return;
1609 
1610   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1611   Lower->addDirectory("//root/zab");
1612   Lower->addDirectory("//root/baz");
1613   Lower->addRegularFile("//root/zab/a");
1614   Lower->addRegularFile("//root/zab/b");
1615   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1616       "{ 'use-external-names': false,\n"
1617       "  'roots': [\n"
1618       "{\n"
1619       "  'type': 'directory',\n"
1620       "  'name': '//root/baz/',\n"
1621       "  'contents': [ {\n"
1622       "                  'type': 'file',\n"
1623       "                  'name': 'x',\n"
1624       "                  'external-contents': '//root/zab/a'\n"
1625       "                }\n"
1626       "              ]\n"
1627       "},\n"
1628       "{\n"
1629       "  'type': 'directory',\n"
1630       "  'name': '//root/baz/',\n"
1631       "  'contents': [ {\n"
1632       "                  'type': 'file',\n"
1633       "                  'name': 'y',\n"
1634       "                  'external-contents': '//root/zab/b'\n"
1635       "                }\n"
1636       "              ]\n"
1637       "}\n"
1638       "]\n"
1639       "}",
1640       Lower);
1641   ASSERT_TRUE(FS.get() != nullptr);
1642 
1643   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1644       new vfs::OverlayFileSystem(Lower));
1645   O->pushOverlay(FS);
1646 
1647   std::error_code EC;
1648 
1649   checkContents(O->dir_begin("//root/baz/", EC),
1650                 {"//root/baz/x", "//root/baz/y"});
1651 }
1652 
1653 TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1654 
1655   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1656   Lower->addDirectory("//root/a");
1657   Lower->addDirectory("//root/a/b");
1658   Lower->addDirectory("//root/a/b/c");
1659   Lower->addRegularFile("//root/a/b/c/file");
1660   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1661       "{ 'use-external-names': false,\n"
1662       "  'roots': [\n"
1663       "{\n"
1664       "  'type': 'directory',\n"
1665       "  'name': '//root/a/b/c/',\n"
1666       "  'contents': [ {\n"
1667       "                  'type': 'file',\n"
1668       "                  'name': 'file',\n"
1669       "                  'external-contents': '//root/a/b/c/file'\n"
1670       "                }\n"
1671       "              ]\n"
1672       "},\n"
1673       "]\n"
1674       "}",
1675       Lower);
1676   ASSERT_TRUE(FS.get() != nullptr);
1677 
1678   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1679       new vfs::OverlayFileSystem(Lower));
1680   O->pushOverlay(FS);
1681 
1682   std::error_code EC;
1683 
1684   // Test recursive_directory_iterator level()
1685   vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
1686                                         *O, "//root", EC),
1687                                     E;
1688   ASSERT_FALSE(EC);
1689   for (int l = 0; I != E; I.increment(EC), ++l) {
1690     ASSERT_FALSE(EC);
1691     EXPECT_EQ(I.level(), l);
1692   }
1693   EXPECT_EQ(I, E);
1694 }
1695 
1696 TEST_F(VFSFromYAMLTest, RelativePaths) {
1697   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1698   // Filename at root level without a parent directory.
1699   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1700       "{ 'roots': [\n"
1701       "  { 'type': 'file', 'name': 'file-not-in-directory.h',\n"
1702       "    'external-contents': '//root/external/file'\n"
1703       "  }\n"
1704       "] }",
1705       Lower);
1706   EXPECT_EQ(nullptr, FS.get());
1707 
1708   // Relative file path.
1709   FS = getFromYAMLString("{ 'roots': [\n"
1710                          "  { 'type': 'file', 'name': 'relative/file/path.h',\n"
1711                          "    'external-contents': '//root/external/file'\n"
1712                          "  }\n"
1713                          "] }",
1714                          Lower);
1715   EXPECT_EQ(nullptr, FS.get());
1716 
1717   // Relative directory path.
1718   FS = getFromYAMLString(
1719       "{ 'roots': [\n"
1720       "  { 'type': 'directory', 'name': 'relative/directory/path.h',\n"
1721       "    'contents': []\n"
1722       "  }\n"
1723       "] }",
1724       Lower);
1725   EXPECT_EQ(nullptr, FS.get());
1726 
1727   EXPECT_EQ(3, NumDiagnostics);
1728 }
1729 
1730 TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) {
1731   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1732   Lower->addDirectory("//root/");
1733   Lower->addRegularFile("//root/a");
1734   Lower->addRegularFile("//root/b");
1735   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1736       "{ 'use-external-names': false,\n"
1737       "  'fallthrough': false,\n"
1738       "  'roots': [\n"
1739       "{\n"
1740       "  'type': 'directory',\n"
1741       "  'name': '//root/',\n"
1742       "  'contents': [ {\n"
1743       "                  'type': 'file',\n"
1744       "                  'name': 'c',\n"
1745       "                  'external-contents': '//root/a'\n"
1746       "                }\n"
1747       "              ]\n"
1748       "}\n"
1749       "]\n"
1750       "}",
1751       Lower);
1752   ASSERT_TRUE(FS.get() != nullptr);
1753 
1754   std::error_code EC;
1755   checkContents(FS->dir_begin("//root/", EC),
1756                 {"//root/c"});
1757 }
1758 
1759 TEST_F(VFSFromYAMLTest, DirectoryIterationWithDuplicates) {
1760   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1761   Lower->addDirectory("//root/");
1762   Lower->addRegularFile("//root/a");
1763   Lower->addRegularFile("//root/b");
1764   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1765       "{ 'use-external-names': false,\n"
1766       "  'roots': [\n"
1767       "{\n"
1768       "  'type': 'directory',\n"
1769       "  'name': '//root/',\n"
1770       "  'contents': [ {\n"
1771       "                  'type': 'file',\n"
1772       "                  'name': 'a',\n"
1773       "                  'external-contents': '//root/a'\n"
1774       "                }\n"
1775       "              ]\n"
1776       "}\n"
1777       "]\n"
1778       "}",
1779 	  Lower);
1780   ASSERT_TRUE(FS.get() != nullptr);
1781 
1782   std::error_code EC;
1783   checkContents(FS->dir_begin("//root/", EC),
1784                 {"//root/a", "//root/b"});
1785 }
1786 
1787 TEST_F(VFSFromYAMLTest, DirectoryIterationErrorInVFSLayer) {
1788   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1789   Lower->addDirectory("//root/");
1790   Lower->addDirectory("//root/foo");
1791   Lower->addRegularFile("//root/foo/a");
1792   Lower->addRegularFile("//root/foo/b");
1793   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1794       "{ 'use-external-names': false,\n"
1795       "  'roots': [\n"
1796       "{\n"
1797       "  'type': 'directory',\n"
1798       "  'name': '//root/',\n"
1799       "  'contents': [ {\n"
1800       "                  'type': 'file',\n"
1801       "                  'name': 'bar/a',\n"
1802       "                  'external-contents': '//root/foo/a'\n"
1803       "                }\n"
1804       "              ]\n"
1805       "}\n"
1806       "]\n"
1807       "}",
1808       Lower);
1809   ASSERT_TRUE(FS.get() != nullptr);
1810 
1811   std::error_code EC;
1812   checkContents(FS->dir_begin("//root/foo", EC),
1813                 {"//root/foo/a", "//root/foo/b"});
1814 }
1815 
1816 TEST_F(VFSFromYAMLTest, GetRealPath) {
1817   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1818   Lower->addDirectory("//dir/");
1819   Lower->addRegularFile("/foo");
1820   Lower->addSymlink("/link");
1821   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1822       "{ 'use-external-names': false,\n"
1823       "  'roots': [\n"
1824       "{\n"
1825       "  'type': 'directory',\n"
1826       "  'name': '//root/',\n"
1827       "  'contents': [ {\n"
1828       "                  'type': 'file',\n"
1829       "                  'name': 'bar',\n"
1830       "                  'external-contents': '/link'\n"
1831       "                }\n"
1832       "              ]\n"
1833       "},\n"
1834       "{\n"
1835       "  'type': 'directory',\n"
1836       "  'name': '//dir/',\n"
1837       "  'contents': []\n"
1838       "}\n"
1839       "]\n"
1840       "}",
1841       Lower);
1842   ASSERT_TRUE(FS.get() != nullptr);
1843 
1844   // Regular file present in underlying file system.
1845   SmallString<16> RealPath;
1846   EXPECT_FALSE(FS->getRealPath("/foo", RealPath));
1847   EXPECT_EQ(RealPath.str(), "/foo");
1848 
1849   // File present in YAML pointing to symlink in underlying file system.
1850   EXPECT_FALSE(FS->getRealPath("//root/bar", RealPath));
1851   EXPECT_EQ(RealPath.str(), "/symlink");
1852 
1853   // Directories should fall back to the underlying file system is possible.
1854   EXPECT_FALSE(FS->getRealPath("//dir/", RealPath));
1855   EXPECT_EQ(RealPath.str(), "//dir/");
1856 
1857   // Try a non-existing file.
1858   EXPECT_EQ(FS->getRealPath("/non_existing", RealPath),
1859             errc::no_such_file_or_directory);
1860 }
1861