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