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