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