xref: /llvm-project/llvm/unittests/Support/VirtualFileSystemTest.cpp (revision 91e131649fc3b79f5e3e619d65bb9a9b9ff6a839)
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 #ifdef LLVM_ON_UNIX
482 TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
483   ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
484   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
485 
486   ScopedLink _a("no_such_file", TestDirectory + "/a");
487   ScopedDir _b(TestDirectory + "/b");
488   ScopedLink _ba("no_such_file", TestDirectory + "/b/a");
489   ScopedDir _bb(TestDirectory + "/b/b");
490   ScopedLink _bc("no_such_file", TestDirectory + "/b/c");
491   ScopedLink _c("no_such_file", TestDirectory + "/c");
492   ScopedDir _d(TestDirectory + "/d");
493   ScopedDir _dd(TestDirectory + "/d/d");
494   ScopedDir _ddd(TestDirectory + "/d/d/d");
495   ScopedLink _e("no_such_file", TestDirectory + "/e");
496 
497   std::vector<std::string> VisitedBrokenSymlinks;
498   std::vector<std::string> VisitedNonBrokenSymlinks;
499   std::error_code EC;
500   for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E;
501        I != E; I.increment(EC)) {
502     EXPECT_FALSE(EC);
503     (FS->status(I->path()) ? VisitedNonBrokenSymlinks : VisitedBrokenSymlinks)
504         .push_back(I->path());
505   }
506 
507   // Check visited file names.
508   EXPECT_THAT(VisitedBrokenSymlinks,
509               UnorderedElementsAre(StringRef(_a), StringRef(_ba),
510                                    StringRef(_bc), StringRef(_c),
511                                    StringRef(_e)));
512   EXPECT_THAT(VisitedNonBrokenSymlinks,
513               UnorderedElementsAre(StringRef(_b), StringRef(_bb), StringRef(_d),
514                                    StringRef(_dd), StringRef(_ddd)));
515 }
516 #endif
517 
518 template <typename DirIter>
519 static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
520   std::error_code EC;
521   SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
522   SmallVector<std::string, 4> InputToCheck;
523 
524   // Do not rely on iteration order to check for contents, sort both
525   // content vectors before comparison.
526   for (DirIter E; !EC && I != E; I.increment(EC))
527     InputToCheck.push_back(I->path());
528 
529   llvm::sort(InputToCheck);
530   llvm::sort(Expected);
531   EXPECT_EQ(InputToCheck.size(), Expected.size());
532 
533   unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
534   for (unsigned Idx = 0; Idx != LastElt; ++Idx)
535     EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
536 }
537 
538 TEST(VirtualFileSystemTest, OverlayIteration) {
539   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
540   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
541   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
542       new vfs::OverlayFileSystem(Lower));
543   O->pushOverlay(Upper);
544 
545   std::error_code EC;
546   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
547 
548   Lower->addRegularFile("/file1");
549   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
550 
551   Upper->addRegularFile("/file2");
552   checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
553 
554   Lower->addDirectory("/dir1");
555   Lower->addRegularFile("/dir1/foo");
556   Upper->addDirectory("/dir2");
557   Upper->addRegularFile("/dir2/foo");
558   checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
559   checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
560 }
561 
562 TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
563   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
564   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
565   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
566   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
567       new vfs::OverlayFileSystem(Lower));
568   O->pushOverlay(Middle);
569   O->pushOverlay(Upper);
570 
571   std::error_code EC;
572   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
573                 ArrayRef<StringRef>());
574 
575   Lower->addRegularFile("/file1");
576   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
577                 ArrayRef<StringRef>("/file1"));
578 
579   Upper->addDirectory("/dir");
580   Upper->addRegularFile("/dir/file2");
581   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
582                 {"/dir", "/dir/file2", "/file1"});
583 
584   Lower->addDirectory("/dir1");
585   Lower->addRegularFile("/dir1/foo");
586   Lower->addDirectory("/dir1/a");
587   Lower->addRegularFile("/dir1/a/b");
588   Middle->addDirectory("/a");
589   Middle->addDirectory("/a/b");
590   Middle->addDirectory("/a/b/c");
591   Middle->addRegularFile("/a/b/c/d");
592   Middle->addRegularFile("/hiddenByUp");
593   Upper->addDirectory("/dir2");
594   Upper->addRegularFile("/dir2/foo");
595   Upper->addRegularFile("/hiddenByUp");
596   checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
597                 ArrayRef<StringRef>("/dir2/foo"));
598   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
599                 {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
600                  "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
601                  "/dir1/a/b", "/dir1/foo", "/file1"});
602 }
603 
604 TEST(VirtualFileSystemTest, ThreeLevelIteration) {
605   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
606   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
607   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
608   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
609       new vfs::OverlayFileSystem(Lower));
610   O->pushOverlay(Middle);
611   O->pushOverlay(Upper);
612 
613   std::error_code EC;
614   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
615 
616   Middle->addRegularFile("/file2");
617   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
618 
619   Lower->addRegularFile("/file1");
620   Upper->addRegularFile("/file3");
621   checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
622 }
623 
624 TEST(VirtualFileSystemTest, HiddenInIteration) {
625   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
626   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
627   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
628   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
629       new vfs::OverlayFileSystem(Lower));
630   O->pushOverlay(Middle);
631   O->pushOverlay(Upper);
632 
633   std::error_code EC;
634   Lower->addRegularFile("/onlyInLow");
635   Lower->addDirectory("/hiddenByMid");
636   Lower->addDirectory("/hiddenByUp");
637   Middle->addRegularFile("/onlyInMid");
638   Middle->addRegularFile("/hiddenByMid");
639   Middle->addDirectory("/hiddenByUp");
640   Upper->addRegularFile("/onlyInUp");
641   Upper->addRegularFile("/hiddenByUp");
642   checkContents(
643       O->dir_begin("/", EC),
644       {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
645 
646   // Make sure we get the top-most entry
647   {
648     std::error_code EC;
649     vfs::directory_iterator I = O->dir_begin("/", EC), E;
650     for (; !EC && I != E; I.increment(EC))
651       if (I->path() == "/hiddenByUp")
652         break;
653     ASSERT_NE(E, I);
654     EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
655   }
656   {
657     std::error_code EC;
658     vfs::directory_iterator I = O->dir_begin("/", EC), E;
659     for (; !EC && I != E; I.increment(EC))
660       if (I->path() == "/hiddenByMid")
661         break;
662     ASSERT_NE(E, I);
663     EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
664   }
665 }
666 
667 class InMemoryFileSystemTest : public ::testing::Test {
668 protected:
669   llvm::vfs::InMemoryFileSystem FS;
670   llvm::vfs::InMemoryFileSystem NormalizedFS;
671 
672   InMemoryFileSystemTest()
673       : FS(/*UseNormalizedPaths=*/false),
674         NormalizedFS(/*UseNormalizedPaths=*/true) {}
675 };
676 
677 MATCHER_P2(IsHardLinkTo, FS, Target, "") {
678   StringRef From = arg;
679   StringRef To = Target;
680   auto OpenedFrom = FS->openFileForRead(From);
681   auto OpenedTo = FS->openFileForRead(To);
682   return !OpenedFrom.getError() && !OpenedTo.getError() &&
683          (*OpenedFrom)->status()->getUniqueID() ==
684              (*OpenedTo)->status()->getUniqueID();
685 }
686 
687 TEST_F(InMemoryFileSystemTest, IsEmpty) {
688   auto Stat = FS.status("/a");
689   ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
690   Stat = FS.status("/");
691   ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
692 }
693 
694 TEST_F(InMemoryFileSystemTest, WindowsPath) {
695   FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
696   auto Stat = FS.status("c:");
697 #if !defined(_WIN32)
698   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
699 #endif
700   Stat = FS.status("c:/windows/system128/foo.cpp");
701   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
702   FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
703   Stat = FS.status("d:/windows/foo.cpp");
704   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
705 }
706 
707 TEST_F(InMemoryFileSystemTest, OverlayFile) {
708   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
709   NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
710   auto Stat = FS.status("/");
711   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
712   Stat = FS.status("/.");
713   ASSERT_FALSE(Stat);
714   Stat = NormalizedFS.status("/.");
715   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
716   Stat = FS.status("/a");
717   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
718   ASSERT_EQ("/a", Stat->getName());
719 }
720 
721 TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
722   auto Buf = MemoryBuffer::getMemBuffer("a");
723   FS.addFileNoOwn("/a", 0, Buf.get());
724   auto Stat = FS.status("/a");
725   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
726   ASSERT_EQ("/a", Stat->getName());
727 }
728 
729 TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
730   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
731   FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
732   FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
733   NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
734   NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
735   NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
736   auto File = FS.openFileForRead("/a");
737   ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
738   File = FS.openFileForRead("/a"); // Open again.
739   ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
740   File = NormalizedFS.openFileForRead("/././a"); // Open again.
741   ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
742   File = FS.openFileForRead("/");
743   ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
744   File = FS.openFileForRead("/b");
745   ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
746   File = FS.openFileForRead("./c");
747   ASSERT_FALSE(File);
748   File = FS.openFileForRead("e/../d");
749   ASSERT_FALSE(File);
750   File = NormalizedFS.openFileForRead("./c");
751   ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
752   File = NormalizedFS.openFileForRead("e/../d");
753   ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
754 }
755 
756 TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
757   ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
758   ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
759   ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
760   ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
761 }
762 
763 TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
764   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
765   FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
766 
767   std::error_code EC;
768   vfs::directory_iterator I = FS.dir_begin("/", EC);
769   ASSERT_FALSE(EC);
770   ASSERT_EQ("/a", I->path());
771   I.increment(EC);
772   ASSERT_FALSE(EC);
773   ASSERT_EQ("/b", I->path());
774   I.increment(EC);
775   ASSERT_FALSE(EC);
776   ASSERT_EQ(vfs::directory_iterator(), I);
777 
778   I = FS.dir_begin("/b", EC);
779   ASSERT_FALSE(EC);
780   // When on Windows, we end up with "/b\\c" as the name.  Convert to Posix
781   // path for the sake of the comparison.
782   ASSERT_EQ("/b/c", getPosixPath(I->path()));
783   I.increment(EC);
784   ASSERT_FALSE(EC);
785   ASSERT_EQ(vfs::directory_iterator(), I);
786 }
787 
788 TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
789   FS.setCurrentWorkingDirectory("/b");
790   FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
791 
792   auto Stat = FS.status("/b/c");
793   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
794   ASSERT_EQ("/b/c", Stat->getName());
795   ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
796 
797   Stat = FS.status("c");
798   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
799 
800   NormalizedFS.setCurrentWorkingDirectory("/b/c");
801   NormalizedFS.setCurrentWorkingDirectory(".");
802   ASSERT_EQ("/b/c",
803             getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
804   NormalizedFS.setCurrentWorkingDirectory("..");
805   ASSERT_EQ("/b",
806             getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
807 }
808 
809 #if !defined(_WIN32)
810 TEST_F(InMemoryFileSystemTest, GetRealPath) {
811   SmallString<16> Path;
812   EXPECT_EQ(FS.getRealPath("b", Path), errc::operation_not_permitted);
813 
814   auto GetRealPath = [this](StringRef P) {
815     SmallString<16> Output;
816     auto EC = FS.getRealPath(P, Output);
817     EXPECT_FALSE(EC);
818     return Output.str().str();
819   };
820 
821   FS.setCurrentWorkingDirectory("a");
822   EXPECT_EQ(GetRealPath("b"), "a/b");
823   EXPECT_EQ(GetRealPath("../b"), "b");
824   EXPECT_EQ(GetRealPath("b/./c"), "a/b/c");
825 
826   FS.setCurrentWorkingDirectory("/a");
827   EXPECT_EQ(GetRealPath("b"), "/a/b");
828   EXPECT_EQ(GetRealPath("../b"), "/b");
829   EXPECT_EQ(GetRealPath("b/./c"), "/a/b/c");
830 }
831 #endif // _WIN32
832 
833 TEST_F(InMemoryFileSystemTest, AddFileWithUser) {
834   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
835   auto Stat = FS.status("/a");
836   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
837   ASSERT_TRUE(Stat->isDirectory());
838   ASSERT_EQ(0xFEEDFACE, Stat->getUser());
839   Stat = FS.status("/a/b");
840   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
841   ASSERT_TRUE(Stat->isDirectory());
842   ASSERT_EQ(0xFEEDFACE, Stat->getUser());
843   Stat = FS.status("/a/b/c");
844   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
845   ASSERT_TRUE(Stat->isRegularFile());
846   ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
847   ASSERT_EQ(0xFEEDFACE, Stat->getUser());
848 }
849 
850 TEST_F(InMemoryFileSystemTest, AddFileWithGroup) {
851   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00);
852   auto Stat = FS.status("/a");
853   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
854   ASSERT_TRUE(Stat->isDirectory());
855   ASSERT_EQ(0xDABBAD00, Stat->getGroup());
856   Stat = FS.status("/a/b");
857   ASSERT_TRUE(Stat->isDirectory());
858   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
859   ASSERT_EQ(0xDABBAD00, Stat->getGroup());
860   Stat = FS.status("/a/b/c");
861   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
862   ASSERT_TRUE(Stat->isRegularFile());
863   ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
864   ASSERT_EQ(0xDABBAD00, Stat->getGroup());
865 }
866 
867 TEST_F(InMemoryFileSystemTest, AddFileWithFileType) {
868   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
869              sys::fs::file_type::socket_file);
870   auto Stat = FS.status("/a");
871   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
872   ASSERT_TRUE(Stat->isDirectory());
873   Stat = FS.status("/a/b");
874   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
875   ASSERT_TRUE(Stat->isDirectory());
876   Stat = FS.status("/a/b/c");
877   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
878   ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType());
879   ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
880 }
881 
882 TEST_F(InMemoryFileSystemTest, AddFileWithPerms) {
883   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None, None,
884              sys::fs::perms::owner_read | sys::fs::perms::owner_write);
885   auto Stat = FS.status("/a");
886   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
887   ASSERT_TRUE(Stat->isDirectory());
888   ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
889                 sys::fs::perms::owner_exe,
890             Stat->getPermissions());
891   Stat = FS.status("/a/b");
892   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
893   ASSERT_TRUE(Stat->isDirectory());
894   ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
895                 sys::fs::perms::owner_exe,
896             Stat->getPermissions());
897   Stat = FS.status("/a/b/c");
898   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
899   ASSERT_TRUE(Stat->isRegularFile());
900   ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write,
901             Stat->getPermissions());
902 }
903 
904 TEST_F(InMemoryFileSystemTest, AddDirectoryThenAddChild) {
905   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None,
906              /*Group=*/None, sys::fs::file_type::directory_file);
907   FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None,
908              /*Group=*/None, sys::fs::file_type::regular_file);
909   auto Stat = FS.status("/a");
910   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
911   ASSERT_TRUE(Stat->isDirectory());
912   Stat = FS.status("/a/b");
913   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
914   ASSERT_TRUE(Stat->isRegularFile());
915 }
916 
917 // Test that the name returned by status() is in the same form as the path that
918 // was requested (to match the behavior of RealFileSystem).
919 TEST_F(InMemoryFileSystemTest, StatusName) {
920   NormalizedFS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"),
921                        /*User=*/None,
922                        /*Group=*/None, sys::fs::file_type::regular_file);
923   NormalizedFS.setCurrentWorkingDirectory("/a/b");
924 
925   // Access using InMemoryFileSystem::status.
926   auto Stat = NormalizedFS.status("../b/c");
927   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
928                                 << NormalizedFS.toString();
929   ASSERT_TRUE(Stat->isRegularFile());
930   ASSERT_EQ("../b/c", Stat->getName());
931 
932   // Access using InMemoryFileAdaptor::status.
933   auto File = NormalizedFS.openFileForRead("../b/c");
934   ASSERT_FALSE(File.getError()) << File.getError() << "\n"
935                                 << NormalizedFS.toString();
936   Stat = (*File)->status();
937   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
938                                 << NormalizedFS.toString();
939   ASSERT_TRUE(Stat->isRegularFile());
940   ASSERT_EQ("../b/c", Stat->getName());
941 
942   // Access using a directory iterator.
943   std::error_code EC;
944   llvm::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC);
945   // When on Windows, we end up with "../b\\c" as the name.  Convert to Posix
946   // path for the sake of the comparison.
947   ASSERT_EQ("../b/c", getPosixPath(It->path()));
948 }
949 
950 TEST_F(InMemoryFileSystemTest, AddHardLinkToFile) {
951   StringRef FromLink = "/path/to/FROM/link";
952   StringRef Target = "/path/to/TO/file";
953   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
954   EXPECT_TRUE(FS.addHardLink(FromLink, Target));
955   EXPECT_THAT(FromLink, IsHardLinkTo(&FS, Target));
956   EXPECT_TRUE(FS.status(FromLink)->getSize() == FS.status(Target)->getSize());
957   EXPECT_TRUE(FS.getBufferForFile(FromLink)->get()->getBuffer() ==
958               FS.getBufferForFile(Target)->get()->getBuffer());
959 }
960 
961 TEST_F(InMemoryFileSystemTest, AddHardLinkInChainPattern) {
962   StringRef Link0 = "/path/to/0/link";
963   StringRef Link1 = "/path/to/1/link";
964   StringRef Link2 = "/path/to/2/link";
965   StringRef Target = "/path/to/target";
966   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target file"));
967   EXPECT_TRUE(FS.addHardLink(Link2, Target));
968   EXPECT_TRUE(FS.addHardLink(Link1, Link2));
969   EXPECT_TRUE(FS.addHardLink(Link0, Link1));
970   EXPECT_THAT(Link0, IsHardLinkTo(&FS, Target));
971   EXPECT_THAT(Link1, IsHardLinkTo(&FS, Target));
972   EXPECT_THAT(Link2, IsHardLinkTo(&FS, Target));
973 }
974 
975 TEST_F(InMemoryFileSystemTest, AddHardLinkToAFileThatWasNotAddedBefore) {
976   EXPECT_FALSE(FS.addHardLink("/path/to/link", "/path/to/target"));
977 }
978 
979 TEST_F(InMemoryFileSystemTest, AddHardLinkFromAFileThatWasAddedBefore) {
980   StringRef Link = "/path/to/link";
981   StringRef Target = "/path/to/target";
982   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
983   FS.addFile(Link, 0, MemoryBuffer::getMemBuffer("content of link"));
984   EXPECT_FALSE(FS.addHardLink(Link, Target));
985 }
986 
987 TEST_F(InMemoryFileSystemTest, AddSameHardLinkMoreThanOnce) {
988   StringRef Link = "/path/to/link";
989   StringRef Target = "/path/to/target";
990   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
991   EXPECT_TRUE(FS.addHardLink(Link, Target));
992   EXPECT_FALSE(FS.addHardLink(Link, Target));
993 }
994 
995 TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithSameContent) {
996   StringRef Link = "/path/to/link";
997   StringRef Target = "/path/to/target";
998   StringRef Content = "content of target";
999   EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1000   EXPECT_TRUE(FS.addHardLink(Link, Target));
1001   EXPECT_TRUE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(Content)));
1002 }
1003 
1004 TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithDifferentContent) {
1005   StringRef Link = "/path/to/link";
1006   StringRef Target = "/path/to/target";
1007   StringRef Content = "content of target";
1008   StringRef LinkContent = "different content of link";
1009   EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1010   EXPECT_TRUE(FS.addHardLink(Link, Target));
1011   EXPECT_FALSE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(LinkContent)));
1012 }
1013 
1014 TEST_F(InMemoryFileSystemTest, AddHardLinkToADirectory) {
1015   StringRef Dir = "path/to/dummy/dir";
1016   StringRef Link = "/path/to/link";
1017   StringRef File = "path/to/dummy/dir/target";
1018   StringRef Content = "content of target";
1019   EXPECT_TRUE(FS.addFile(File, 0, MemoryBuffer::getMemBuffer(Content)));
1020   EXPECT_FALSE(FS.addHardLink(Link, Dir));
1021 }
1022 
1023 TEST_F(InMemoryFileSystemTest, AddHardLinkFromADirectory) {
1024   StringRef Dir = "path/to/dummy/dir";
1025   StringRef Target = "path/to/dummy/dir/target";
1026   StringRef Content = "content of target";
1027   EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1028   EXPECT_FALSE(FS.addHardLink(Dir, Target));
1029 }
1030 
1031 TEST_F(InMemoryFileSystemTest, AddHardLinkUnderAFile) {
1032   StringRef CommonContent = "content string";
1033   FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer(CommonContent));
1034   FS.addFile("/c/d", 0, MemoryBuffer::getMemBuffer(CommonContent));
1035   EXPECT_FALSE(FS.addHardLink("/c/d/e", "/a/b"));
1036 }
1037 
1038 TEST_F(InMemoryFileSystemTest, RecursiveIterationWithHardLink) {
1039   std::error_code EC;
1040   FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("content string"));
1041   EXPECT_TRUE(FS.addHardLink("/c/d", "/a/b"));
1042   auto I = vfs::recursive_directory_iterator(FS, "/", EC);
1043   ASSERT_FALSE(EC);
1044   std::vector<std::string> Nodes;
1045   for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
1046        I.increment(EC)) {
1047     Nodes.push_back(getPosixPath(I->path()));
1048   }
1049   EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d"));
1050 }
1051 
1052 // NOTE: in the tests below, we use '//root/' as our root directory, since it is
1053 // a legal *absolute* path on Windows as well as *nix.
1054 class VFSFromYAMLTest : public ::testing::Test {
1055 public:
1056   int NumDiagnostics;
1057 
1058   void SetUp() override { NumDiagnostics = 0; }
1059 
1060   static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
1061     VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
1062     ++Test->NumDiagnostics;
1063   }
1064 
1065   IntrusiveRefCntPtr<vfs::FileSystem>
1066   getFromYAMLRawString(StringRef Content,
1067                        IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
1068     std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
1069     return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
1070                           ExternalFS);
1071   }
1072 
1073   IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
1074       StringRef Content,
1075       IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
1076     std::string VersionPlusContent("{\n  'version':0,\n");
1077     VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
1078     return getFromYAMLRawString(VersionPlusContent, ExternalFS);
1079   }
1080 
1081   // This is intended as a "XFAIL" for windows hosts.
1082   bool supportsSameDirMultipleYAMLEntries() {
1083     Triple Host(Triple::normalize(sys::getProcessTriple()));
1084     return !Host.isOSWindows();
1085   }
1086 };
1087 
1088 TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
1089   IntrusiveRefCntPtr<vfs::FileSystem> FS;
1090   FS = getFromYAMLString("");
1091   EXPECT_EQ(nullptr, FS.get());
1092   FS = getFromYAMLString("[]");
1093   EXPECT_EQ(nullptr, FS.get());
1094   FS = getFromYAMLString("'string'");
1095   EXPECT_EQ(nullptr, FS.get());
1096   EXPECT_EQ(3, NumDiagnostics);
1097 }
1098 
1099 TEST_F(VFSFromYAMLTest, MappedFiles) {
1100   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1101   Lower->addRegularFile("//root/foo/bar/a");
1102   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1103       "{ 'roots': [\n"
1104       "{\n"
1105       "  'type': 'directory',\n"
1106       "  'name': '//root/',\n"
1107       "  'contents': [ {\n"
1108       "                  'type': 'file',\n"
1109       "                  'name': 'file1',\n"
1110       "                  'external-contents': '//root/foo/bar/a'\n"
1111       "                },\n"
1112       "                {\n"
1113       "                  'type': 'file',\n"
1114       "                  'name': 'file2',\n"
1115       "                  'external-contents': '//root/foo/b'\n"
1116       "                }\n"
1117       "              ]\n"
1118       "}\n"
1119       "]\n"
1120       "}",
1121       Lower);
1122   ASSERT_TRUE(FS.get() != nullptr);
1123 
1124   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1125       new vfs::OverlayFileSystem(Lower));
1126   O->pushOverlay(FS);
1127 
1128   // file
1129   ErrorOr<vfs::Status> S = O->status("//root/file1");
1130   ASSERT_FALSE(S.getError());
1131   EXPECT_EQ("//root/foo/bar/a", S->getName());
1132   EXPECT_TRUE(S->IsVFSMapped);
1133 
1134   ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
1135   EXPECT_EQ("//root/foo/bar/a", SLower->getName());
1136   EXPECT_TRUE(S->equivalent(*SLower));
1137   EXPECT_FALSE(SLower->IsVFSMapped);
1138 
1139   // file after opening
1140   auto OpenedF = O->openFileForRead("//root/file1");
1141   ASSERT_FALSE(OpenedF.getError());
1142   auto OpenedS = (*OpenedF)->status();
1143   ASSERT_FALSE(OpenedS.getError());
1144   EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
1145   EXPECT_TRUE(OpenedS->IsVFSMapped);
1146 
1147   // directory
1148   S = O->status("//root/");
1149   ASSERT_FALSE(S.getError());
1150   EXPECT_TRUE(S->isDirectory());
1151   EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
1152 
1153   // broken mapping
1154   EXPECT_EQ(O->status("//root/file2").getError(),
1155             llvm::errc::no_such_file_or_directory);
1156   EXPECT_EQ(0, NumDiagnostics);
1157 }
1158 
1159 TEST_F(VFSFromYAMLTest, CaseInsensitive) {
1160   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1161   Lower->addRegularFile("//root/foo/bar/a");
1162   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1163       "{ 'case-sensitive': 'false',\n"
1164       "  'roots': [\n"
1165       "{\n"
1166       "  'type': 'directory',\n"
1167       "  'name': '//root/',\n"
1168       "  'contents': [ {\n"
1169       "                  'type': 'file',\n"
1170       "                  'name': 'XX',\n"
1171       "                  'external-contents': '//root/foo/bar/a'\n"
1172       "                }\n"
1173       "              ]\n"
1174       "}]}",
1175       Lower);
1176   ASSERT_TRUE(FS.get() != nullptr);
1177 
1178   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1179       new vfs::OverlayFileSystem(Lower));
1180   O->pushOverlay(FS);
1181 
1182   ErrorOr<vfs::Status> S = O->status("//root/XX");
1183   ASSERT_FALSE(S.getError());
1184 
1185   ErrorOr<vfs::Status> SS = O->status("//root/xx");
1186   ASSERT_FALSE(SS.getError());
1187   EXPECT_TRUE(S->equivalent(*SS));
1188   SS = O->status("//root/xX");
1189   EXPECT_TRUE(S->equivalent(*SS));
1190   SS = O->status("//root/Xx");
1191   EXPECT_TRUE(S->equivalent(*SS));
1192   EXPECT_EQ(0, NumDiagnostics);
1193 }
1194 
1195 TEST_F(VFSFromYAMLTest, CaseSensitive) {
1196   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1197   Lower->addRegularFile("//root/foo/bar/a");
1198   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1199       "{ 'case-sensitive': 'true',\n"
1200       "  'roots': [\n"
1201       "{\n"
1202       "  'type': 'directory',\n"
1203       "  'name': '//root/',\n"
1204       "  'contents': [ {\n"
1205       "                  'type': 'file',\n"
1206       "                  'name': 'XX',\n"
1207       "                  'external-contents': '//root/foo/bar/a'\n"
1208       "                }\n"
1209       "              ]\n"
1210       "}]}",
1211       Lower);
1212   ASSERT_TRUE(FS.get() != nullptr);
1213 
1214   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1215       new vfs::OverlayFileSystem(Lower));
1216   O->pushOverlay(FS);
1217 
1218   ErrorOr<vfs::Status> SS = O->status("//root/xx");
1219   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1220   SS = O->status("//root/xX");
1221   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1222   SS = O->status("//root/Xx");
1223   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1224   EXPECT_EQ(0, NumDiagnostics);
1225 }
1226 
1227 TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
1228   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1229 
1230   // invalid YAML at top-level
1231   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
1232   EXPECT_EQ(nullptr, FS.get());
1233   // invalid YAML in roots
1234   FS = getFromYAMLString("{ 'roots':[}", Lower);
1235   // invalid YAML in directory
1236   FS = getFromYAMLString(
1237       "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
1238       Lower);
1239   EXPECT_EQ(nullptr, FS.get());
1240 
1241   // invalid configuration
1242   FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
1243   EXPECT_EQ(nullptr, FS.get());
1244   FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
1245   EXPECT_EQ(nullptr, FS.get());
1246 
1247   // invalid roots
1248   FS = getFromYAMLString("{ 'roots':'' }", Lower);
1249   EXPECT_EQ(nullptr, FS.get());
1250   FS = getFromYAMLString("{ 'roots':{} }", Lower);
1251   EXPECT_EQ(nullptr, FS.get());
1252 
1253   // invalid entries
1254   FS = getFromYAMLString(
1255       "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
1256   EXPECT_EQ(nullptr, FS.get());
1257   FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
1258                          "'external-contents': 'other' }",
1259                          Lower);
1260   EXPECT_EQ(nullptr, FS.get());
1261   FS = getFromYAMLString(
1262       "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1263       Lower);
1264   EXPECT_EQ(nullptr, FS.get());
1265   FS = getFromYAMLString(
1266       "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
1267       Lower);
1268   EXPECT_EQ(nullptr, FS.get());
1269   FS = getFromYAMLString(
1270       "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
1271       Lower);
1272   EXPECT_EQ(nullptr, FS.get());
1273   FS = getFromYAMLString(
1274       "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
1275       Lower);
1276   EXPECT_EQ(nullptr, FS.get());
1277   FS = getFromYAMLString(
1278       "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
1279       Lower);
1280   EXPECT_EQ(nullptr, FS.get());
1281 
1282   // missing mandatory fields
1283   FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
1284   EXPECT_EQ(nullptr, FS.get());
1285   FS = getFromYAMLString(
1286       "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
1287   EXPECT_EQ(nullptr, FS.get());
1288   FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
1289   EXPECT_EQ(nullptr, FS.get());
1290 
1291   // duplicate keys
1292   FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
1293   EXPECT_EQ(nullptr, FS.get());
1294   FS = getFromYAMLString(
1295       "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1296       Lower);
1297   EXPECT_EQ(nullptr, FS.get());
1298   FS =
1299       getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1300                         "'external-contents':'blah' } ] }",
1301                         Lower);
1302   EXPECT_EQ(nullptr, FS.get());
1303 
1304   // missing version
1305   FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
1306   EXPECT_EQ(nullptr, FS.get());
1307 
1308   // bad version number
1309   FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
1310   EXPECT_EQ(nullptr, FS.get());
1311   FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
1312   EXPECT_EQ(nullptr, FS.get());
1313   FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
1314   EXPECT_EQ(nullptr, FS.get());
1315   EXPECT_EQ(24, NumDiagnostics);
1316 }
1317 
1318 TEST_F(VFSFromYAMLTest, UseExternalName) {
1319   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1320   Lower->addRegularFile("//root/external/file");
1321 
1322   IntrusiveRefCntPtr<vfs::FileSystem> FS =
1323       getFromYAMLString("{ 'roots': [\n"
1324                         "  { 'type': 'file', 'name': '//root/A',\n"
1325                         "    'external-contents': '//root/external/file'\n"
1326                         "  },\n"
1327                         "  { 'type': 'file', 'name': '//root/B',\n"
1328                         "    'use-external-name': true,\n"
1329                         "    'external-contents': '//root/external/file'\n"
1330                         "  },\n"
1331                         "  { 'type': 'file', 'name': '//root/C',\n"
1332                         "    'use-external-name': false,\n"
1333                         "    'external-contents': '//root/external/file'\n"
1334                         "  }\n"
1335                         "] }",
1336                         Lower);
1337   ASSERT_TRUE(nullptr != FS.get());
1338 
1339   // default true
1340   EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
1341   // explicit
1342   EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1343   EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
1344 
1345   // global configuration
1346   FS = getFromYAMLString("{ 'use-external-names': false,\n"
1347                          "  'roots': [\n"
1348                          "  { 'type': 'file', 'name': '//root/A',\n"
1349                          "    'external-contents': '//root/external/file'\n"
1350                          "  },\n"
1351                          "  { 'type': 'file', 'name': '//root/B',\n"
1352                          "    'use-external-name': true,\n"
1353                          "    'external-contents': '//root/external/file'\n"
1354                          "  },\n"
1355                          "  { 'type': 'file', 'name': '//root/C',\n"
1356                          "    'use-external-name': false,\n"
1357                          "    'external-contents': '//root/external/file'\n"
1358                          "  }\n"
1359                          "] }",
1360                          Lower);
1361   ASSERT_TRUE(nullptr != FS.get());
1362 
1363   // default
1364   EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
1365   // explicit
1366   EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1367   EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
1368 }
1369 
1370 TEST_F(VFSFromYAMLTest, MultiComponentPath) {
1371   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1372   Lower->addRegularFile("//root/other");
1373 
1374   // file in roots
1375   IntrusiveRefCntPtr<vfs::FileSystem> FS =
1376       getFromYAMLString("{ 'roots': [\n"
1377                         "  { 'type': 'file', 'name': '//root/path/to/file',\n"
1378                         "    'external-contents': '//root/other' }]\n"
1379                         "}",
1380                         Lower);
1381   ASSERT_TRUE(nullptr != FS.get());
1382   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1383   EXPECT_FALSE(FS->status("//root/path/to").getError());
1384   EXPECT_FALSE(FS->status("//root/path").getError());
1385   EXPECT_FALSE(FS->status("//root/").getError());
1386 
1387   // at the start
1388   FS = getFromYAMLString(
1389       "{ 'roots': [\n"
1390       "  { 'type': 'directory', 'name': '//root/path/to',\n"
1391       "    'contents': [ { 'type': 'file', 'name': 'file',\n"
1392       "                    'external-contents': '//root/other' }]}]\n"
1393       "}",
1394       Lower);
1395   ASSERT_TRUE(nullptr != FS.get());
1396   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1397   EXPECT_FALSE(FS->status("//root/path/to").getError());
1398   EXPECT_FALSE(FS->status("//root/path").getError());
1399   EXPECT_FALSE(FS->status("//root/").getError());
1400 
1401   // at the end
1402   FS = getFromYAMLString(
1403       "{ 'roots': [\n"
1404       "  { 'type': 'directory', 'name': '//root/',\n"
1405       "    'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
1406       "                    'external-contents': '//root/other' }]}]\n"
1407       "}",
1408       Lower);
1409   ASSERT_TRUE(nullptr != FS.get());
1410   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1411   EXPECT_FALSE(FS->status("//root/path/to").getError());
1412   EXPECT_FALSE(FS->status("//root/path").getError());
1413   EXPECT_FALSE(FS->status("//root/").getError());
1414 }
1415 
1416 TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1417   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1418   Lower->addRegularFile("//root/other");
1419 
1420   // file in roots
1421   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1422       "{ 'roots': [\n"
1423       "  { 'type': 'directory', 'name': '//root/path/to////',\n"
1424       "    'contents': [ { 'type': 'file', 'name': 'file',\n"
1425       "                    'external-contents': '//root/other' }]}]\n"
1426       "}",
1427       Lower);
1428   ASSERT_TRUE(nullptr != FS.get());
1429   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1430   EXPECT_FALSE(FS->status("//root/path/to").getError());
1431   EXPECT_FALSE(FS->status("//root/path").getError());
1432   EXPECT_FALSE(FS->status("//root/").getError());
1433 }
1434 
1435 TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1436   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1437   Lower->addDirectory("//root/");
1438   Lower->addDirectory("//root/foo");
1439   Lower->addDirectory("//root/foo/bar");
1440   Lower->addRegularFile("//root/foo/bar/a");
1441   Lower->addRegularFile("//root/foo/bar/b");
1442   Lower->addRegularFile("//root/file3");
1443   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1444       "{ 'use-external-names': false,\n"
1445       "  'roots': [\n"
1446       "{\n"
1447       "  'type': 'directory',\n"
1448       "  'name': '//root/',\n"
1449       "  'contents': [ {\n"
1450       "                  'type': 'file',\n"
1451       "                  'name': 'file1',\n"
1452       "                  'external-contents': '//root/foo/bar/a'\n"
1453       "                },\n"
1454       "                {\n"
1455       "                  'type': 'file',\n"
1456       "                  'name': 'file2',\n"
1457       "                  'external-contents': '//root/foo/bar/b'\n"
1458       "                }\n"
1459       "              ]\n"
1460       "}\n"
1461       "]\n"
1462       "}",
1463       Lower);
1464   ASSERT_TRUE(FS.get() != nullptr);
1465 
1466   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1467       new vfs::OverlayFileSystem(Lower));
1468   O->pushOverlay(FS);
1469 
1470   std::error_code EC;
1471   checkContents(O->dir_begin("//root/", EC),
1472                 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
1473 
1474   checkContents(O->dir_begin("//root/foo/bar", EC),
1475                 {"//root/foo/bar/a", "//root/foo/bar/b"});
1476 }
1477 
1478 TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1479   // https://llvm.org/bugs/show_bug.cgi?id=27725
1480   if (!supportsSameDirMultipleYAMLEntries())
1481     return;
1482 
1483   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1484   Lower->addDirectory("//root/zab");
1485   Lower->addDirectory("//root/baz");
1486   Lower->addRegularFile("//root/zab/a");
1487   Lower->addRegularFile("//root/zab/b");
1488   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1489       "{ 'use-external-names': false,\n"
1490       "  'roots': [\n"
1491       "{\n"
1492       "  'type': 'directory',\n"
1493       "  'name': '//root/baz/',\n"
1494       "  'contents': [ {\n"
1495       "                  'type': 'file',\n"
1496       "                  'name': 'x',\n"
1497       "                  'external-contents': '//root/zab/a'\n"
1498       "                }\n"
1499       "              ]\n"
1500       "},\n"
1501       "{\n"
1502       "  'type': 'directory',\n"
1503       "  'name': '//root/baz/',\n"
1504       "  'contents': [ {\n"
1505       "                  'type': 'file',\n"
1506       "                  'name': 'y',\n"
1507       "                  'external-contents': '//root/zab/b'\n"
1508       "                }\n"
1509       "              ]\n"
1510       "}\n"
1511       "]\n"
1512       "}",
1513       Lower);
1514   ASSERT_TRUE(FS.get() != nullptr);
1515 
1516   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1517       new vfs::OverlayFileSystem(Lower));
1518   O->pushOverlay(FS);
1519 
1520   std::error_code EC;
1521 
1522   checkContents(O->dir_begin("//root/baz/", EC),
1523                 {"//root/baz/x", "//root/baz/y"});
1524 }
1525 
1526 TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1527 
1528   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1529   Lower->addDirectory("//root/a");
1530   Lower->addDirectory("//root/a/b");
1531   Lower->addDirectory("//root/a/b/c");
1532   Lower->addRegularFile("//root/a/b/c/file");
1533   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1534       "{ 'use-external-names': false,\n"
1535       "  'roots': [\n"
1536       "{\n"
1537       "  'type': 'directory',\n"
1538       "  'name': '//root/a/b/c/',\n"
1539       "  'contents': [ {\n"
1540       "                  'type': 'file',\n"
1541       "                  'name': 'file',\n"
1542       "                  'external-contents': '//root/a/b/c/file'\n"
1543       "                }\n"
1544       "              ]\n"
1545       "},\n"
1546       "]\n"
1547       "}",
1548       Lower);
1549   ASSERT_TRUE(FS.get() != nullptr);
1550 
1551   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1552       new vfs::OverlayFileSystem(Lower));
1553   O->pushOverlay(FS);
1554 
1555   std::error_code EC;
1556 
1557   // Test recursive_directory_iterator level()
1558   vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
1559                                         *O, "//root", EC),
1560                                     E;
1561   ASSERT_FALSE(EC);
1562   for (int l = 0; I != E; I.increment(EC), ++l) {
1563     ASSERT_FALSE(EC);
1564     EXPECT_EQ(I.level(), l);
1565   }
1566   EXPECT_EQ(I, E);
1567 }
1568 
1569 TEST_F(VFSFromYAMLTest, RelativePaths) {
1570   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1571   // Filename at root level without a parent directory.
1572   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1573       "{ 'roots': [\n"
1574       "  { 'type': 'file', 'name': 'file-not-in-directory.h',\n"
1575       "    'external-contents': '//root/external/file'\n"
1576       "  }\n"
1577       "] }",
1578       Lower);
1579   EXPECT_EQ(nullptr, FS.get());
1580 
1581   // Relative file path.
1582   FS = getFromYAMLString("{ 'roots': [\n"
1583                          "  { 'type': 'file', 'name': 'relative/file/path.h',\n"
1584                          "    'external-contents': '//root/external/file'\n"
1585                          "  }\n"
1586                          "] }",
1587                          Lower);
1588   EXPECT_EQ(nullptr, FS.get());
1589 
1590   // Relative directory path.
1591   FS = getFromYAMLString(
1592       "{ 'roots': [\n"
1593       "  { 'type': 'directory', 'name': 'relative/directory/path.h',\n"
1594       "    'contents': []\n"
1595       "  }\n"
1596       "] }",
1597       Lower);
1598   EXPECT_EQ(nullptr, FS.get());
1599 
1600   EXPECT_EQ(3, NumDiagnostics);
1601 }
1602 
1603 TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) {
1604   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1605   Lower->addDirectory("//root/");
1606   Lower->addRegularFile("//root/a");
1607   Lower->addRegularFile("//root/b");
1608   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1609       "{ 'use-external-names': false,\n"
1610       "  'fallthrough': false,\n"
1611       "  'roots': [\n"
1612       "{\n"
1613       "  'type': 'directory',\n"
1614       "  'name': '//root/',\n"
1615       "  'contents': [ {\n"
1616       "                  'type': 'file',\n"
1617       "                  'name': 'c',\n"
1618       "                  'external-contents': '//root/a'\n"
1619       "                }\n"
1620       "              ]\n"
1621       "}\n"
1622       "]\n"
1623       "}",
1624       Lower);
1625   ASSERT_TRUE(FS.get() != nullptr);
1626 
1627   std::error_code EC;
1628   checkContents(FS->dir_begin("//root/", EC),
1629                 {"//root/c"});
1630 }
1631 
1632 TEST_F(VFSFromYAMLTest, DirectoryIterationWithDuplicates) {
1633   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1634   Lower->addDirectory("//root/");
1635   Lower->addRegularFile("//root/a");
1636   Lower->addRegularFile("//root/b");
1637   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1638       "{ 'use-external-names': false,\n"
1639       "  'roots': [\n"
1640       "{\n"
1641       "  'type': 'directory',\n"
1642       "  'name': '//root/',\n"
1643       "  'contents': [ {\n"
1644       "                  'type': 'file',\n"
1645       "                  'name': 'a',\n"
1646       "                  'external-contents': '//root/a'\n"
1647       "                }\n"
1648       "              ]\n"
1649       "}\n"
1650       "]\n"
1651       "}",
1652 	  Lower);
1653   ASSERT_TRUE(FS.get() != nullptr);
1654 
1655   std::error_code EC;
1656   checkContents(FS->dir_begin("//root/", EC),
1657                 {"//root/a", "//root/b"});
1658 }
1659 
1660 TEST_F(VFSFromYAMLTest, DirectoryIterationErrorInVFSLayer) {
1661   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1662   Lower->addDirectory("//root/");
1663   Lower->addDirectory("//root/foo");
1664   Lower->addRegularFile("//root/foo/a");
1665   Lower->addRegularFile("//root/foo/b");
1666   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1667       "{ 'use-external-names': false,\n"
1668       "  'roots': [\n"
1669       "{\n"
1670       "  'type': 'directory',\n"
1671       "  'name': '//root/',\n"
1672       "  'contents': [ {\n"
1673       "                  'type': 'file',\n"
1674       "                  'name': 'bar/a',\n"
1675       "                  'external-contents': '//root/foo/a'\n"
1676       "                }\n"
1677       "              ]\n"
1678       "}\n"
1679       "]\n"
1680       "}",
1681       Lower);
1682   ASSERT_TRUE(FS.get() != nullptr);
1683 
1684   std::error_code EC;
1685   checkContents(FS->dir_begin("//root/foo", EC),
1686                 {"//root/foo/a", "//root/foo/b"});
1687 }
1688