[docs] Fix build-docs.sh
[llvm-project.git] / llvm / unittests / Support / VirtualFileSystemTest.cpp
blob1e300eec711d109000c265b1914bb64b920f1c38
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 //===----------------------------------------------------------------------===//
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 "llvm/Testing/Support/SupportHelpers.h"
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20 #include <map>
21 #include <string>
23 using namespace llvm;
24 using llvm::sys::fs::UniqueID;
25 using llvm::unittest::TempDir;
26 using llvm::unittest::TempFile;
27 using llvm::unittest::TempLink;
28 using testing::ElementsAre;
29 using testing::Pair;
30 using testing::UnorderedElementsAre;
32 namespace {
33 struct DummyFile : public vfs::File {
34 vfs::Status S;
35 explicit DummyFile(vfs::Status S) : S(S) {}
36 llvm::ErrorOr<vfs::Status> status() override { return S; }
37 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
38 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
39 bool IsVolatile) override {
40 llvm_unreachable("unimplemented");
42 std::error_code close() override { return std::error_code(); }
45 class DummyFileSystem : public vfs::FileSystem {
46 int FSID; // used to produce UniqueIDs
47 int FileID; // used to produce UniqueIDs
48 std::string WorkingDirectory;
49 std::map<std::string, vfs::Status> FilesAndDirs;
50 typedef std::map<std::string, vfs::Status>::const_iterator const_iterator;
52 static int getNextFSID() {
53 static int Count = 0;
54 return Count++;
57 public:
58 DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
60 ErrorOr<vfs::Status> status(const Twine &Path) override {
61 auto I = findEntry(Path);
62 if (I == FilesAndDirs.end())
63 return make_error_code(llvm::errc::no_such_file_or_directory);
64 return I->second;
66 ErrorOr<std::unique_ptr<vfs::File>>
67 openFileForRead(const Twine &Path) override {
68 auto S = status(Path);
69 if (S)
70 return std::unique_ptr<vfs::File>(new DummyFile{*S});
71 return S.getError();
73 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
74 return WorkingDirectory;
76 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
77 WorkingDirectory = Path.str();
78 return std::error_code();
80 // Map any symlink to "/symlink".
81 std::error_code getRealPath(const Twine &Path,
82 SmallVectorImpl<char> &Output) const override {
83 auto I = findEntry(Path);
84 if (I == FilesAndDirs.end())
85 return make_error_code(llvm::errc::no_such_file_or_directory);
86 if (I->second.isSymlink()) {
87 Output.clear();
88 Twine("/symlink").toVector(Output);
89 return std::error_code();
91 Output.clear();
92 Path.toVector(Output);
93 return std::error_code();
96 struct DirIterImpl : public llvm::vfs::detail::DirIterImpl {
97 std::map<std::string, vfs::Status> &FilesAndDirs;
98 std::map<std::string, vfs::Status>::iterator I;
99 std::string Path;
100 bool isInPath(StringRef S) {
101 if (Path.size() < S.size() && S.find(Path) == 0) {
102 auto LastSep = S.find_last_of('/');
103 if (LastSep == Path.size() || LastSep == Path.size() - 1)
104 return true;
106 return false;
108 DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
109 const Twine &_Path)
110 : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
111 Path(_Path.str()) {
112 for (; I != FilesAndDirs.end(); ++I) {
113 if (isInPath(I->first)) {
114 CurrentEntry = vfs::directory_entry(std::string(I->second.getName()),
115 I->second.getType());
116 break;
120 std::error_code increment() override {
121 ++I;
122 for (; I != FilesAndDirs.end(); ++I) {
123 if (isInPath(I->first)) {
124 CurrentEntry = vfs::directory_entry(std::string(I->second.getName()),
125 I->second.getType());
126 break;
129 if (I == FilesAndDirs.end())
130 CurrentEntry = vfs::directory_entry();
131 return std::error_code();
135 vfs::directory_iterator dir_begin(const Twine &Dir,
136 std::error_code &EC) override {
137 return vfs::directory_iterator(
138 std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
141 void addEntry(StringRef Path, const vfs::Status &Status) {
142 FilesAndDirs[std::string(Path)] = Status;
145 const_iterator findEntry(const Twine &Path) const {
146 SmallString<128> P;
147 Path.toVector(P);
148 std::error_code EC = makeAbsolute(P);
149 assert(!EC);
150 (void)EC;
151 return FilesAndDirs.find(std::string(P.str()));
154 void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
155 vfs::Status S(Path, UniqueID(FSID, FileID++),
156 std::chrono::system_clock::now(), 0, 0, 1024,
157 sys::fs::file_type::regular_file, Perms);
158 addEntry(Path, S);
161 void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
162 vfs::Status S(Path, UniqueID(FSID, FileID++),
163 std::chrono::system_clock::now(), 0, 0, 0,
164 sys::fs::file_type::directory_file, Perms);
165 addEntry(Path, S);
168 void addSymlink(StringRef Path) {
169 vfs::Status S(Path, UniqueID(FSID, FileID++),
170 std::chrono::system_clock::now(), 0, 0, 0,
171 sys::fs::file_type::symlink_file, sys::fs::all_all);
172 addEntry(Path, S);
175 protected:
176 void printImpl(raw_ostream &OS, PrintType Type,
177 unsigned IndentLevel) const override {
178 printIndent(OS, IndentLevel);
179 OS << "DummyFileSystem (";
180 switch (Type) {
181 case vfs::FileSystem::PrintType::Summary:
182 OS << "Summary";
183 break;
184 case vfs::FileSystem::PrintType::Contents:
185 OS << "Contents";
186 break;
187 case vfs::FileSystem::PrintType::RecursiveContents:
188 OS << "RecursiveContents";
189 break;
191 OS << ")\n";
195 class ErrorDummyFileSystem : public DummyFileSystem {
196 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
197 return llvm::errc::no_such_file_or_directory;
201 /// Replace back-slashes by front-slashes.
202 std::string getPosixPath(const Twine &S) {
203 SmallString<128> Result;
204 llvm::sys::path::native(S, Result, llvm::sys::path::Style::posix);
205 return std::string(Result.str());
207 } // end anonymous namespace
209 TEST(VirtualFileSystemTest, StatusQueries) {
210 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
211 ErrorOr<vfs::Status> Status((std::error_code()));
213 D->addRegularFile("/foo");
214 Status = D->status("/foo");
215 ASSERT_FALSE(Status.getError());
216 EXPECT_TRUE(Status->isStatusKnown());
217 EXPECT_FALSE(Status->isDirectory());
218 EXPECT_TRUE(Status->isRegularFile());
219 EXPECT_FALSE(Status->isSymlink());
220 EXPECT_FALSE(Status->isOther());
221 EXPECT_TRUE(Status->exists());
223 D->addDirectory("/bar");
224 Status = D->status("/bar");
225 ASSERT_FALSE(Status.getError());
226 EXPECT_TRUE(Status->isStatusKnown());
227 EXPECT_TRUE(Status->isDirectory());
228 EXPECT_FALSE(Status->isRegularFile());
229 EXPECT_FALSE(Status->isSymlink());
230 EXPECT_FALSE(Status->isOther());
231 EXPECT_TRUE(Status->exists());
233 D->addSymlink("/baz");
234 Status = D->status("/baz");
235 ASSERT_FALSE(Status.getError());
236 EXPECT_TRUE(Status->isStatusKnown());
237 EXPECT_FALSE(Status->isDirectory());
238 EXPECT_FALSE(Status->isRegularFile());
239 EXPECT_TRUE(Status->isSymlink());
240 EXPECT_FALSE(Status->isOther());
241 EXPECT_TRUE(Status->exists());
243 EXPECT_TRUE(Status->equivalent(*Status));
244 ErrorOr<vfs::Status> Status2 = D->status("/foo");
245 ASSERT_FALSE(Status2.getError());
246 EXPECT_FALSE(Status->equivalent(*Status2));
249 TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
250 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
251 ErrorOr<vfs::Status> Status((std::error_code()));
252 EXPECT_FALSE(Status = D->status("/foo"));
254 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
255 EXPECT_FALSE(Status = O->status("/foo"));
257 D->addRegularFile("/foo");
258 Status = D->status("/foo");
259 EXPECT_FALSE(Status.getError());
261 ErrorOr<vfs::Status> Status2((std::error_code()));
262 Status2 = O->status("/foo");
263 EXPECT_FALSE(Status2.getError());
264 EXPECT_TRUE(Status->equivalent(*Status2));
267 TEST(VirtualFileSystemTest, GetRealPathInOverlay) {
268 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
269 Lower->addRegularFile("/foo");
270 Lower->addSymlink("/lower_link");
271 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
273 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
274 new vfs::OverlayFileSystem(Lower));
275 O->pushOverlay(Upper);
277 // Regular file.
278 SmallString<16> RealPath;
279 EXPECT_FALSE(O->getRealPath("/foo", RealPath));
280 EXPECT_EQ(RealPath.str(), "/foo");
282 // Expect no error getting real path for symlink in lower overlay.
283 EXPECT_FALSE(O->getRealPath("/lower_link", RealPath));
284 EXPECT_EQ(RealPath.str(), "/symlink");
286 // Try a non-existing link.
287 EXPECT_EQ(O->getRealPath("/upper_link", RealPath),
288 errc::no_such_file_or_directory);
290 // Add a new symlink in upper.
291 Upper->addSymlink("/upper_link");
292 EXPECT_FALSE(O->getRealPath("/upper_link", RealPath));
293 EXPECT_EQ(RealPath.str(), "/symlink");
296 TEST(VirtualFileSystemTest, OverlayFiles) {
297 IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
298 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
299 IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
300 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
301 new vfs::OverlayFileSystem(Base));
302 O->pushOverlay(Middle);
303 O->pushOverlay(Top);
305 ErrorOr<vfs::Status> Status1((std::error_code())),
306 Status2((std::error_code())), Status3((std::error_code())),
307 StatusB((std::error_code())), StatusM((std::error_code())),
308 StatusT((std::error_code()));
310 Base->addRegularFile("/foo");
311 StatusB = Base->status("/foo");
312 ASSERT_FALSE(StatusB.getError());
313 Status1 = O->status("/foo");
314 ASSERT_FALSE(Status1.getError());
315 Middle->addRegularFile("/foo");
316 StatusM = Middle->status("/foo");
317 ASSERT_FALSE(StatusM.getError());
318 Status2 = O->status("/foo");
319 ASSERT_FALSE(Status2.getError());
320 Top->addRegularFile("/foo");
321 StatusT = Top->status("/foo");
322 ASSERT_FALSE(StatusT.getError());
323 Status3 = O->status("/foo");
324 ASSERT_FALSE(Status3.getError());
326 EXPECT_TRUE(Status1->equivalent(*StatusB));
327 EXPECT_TRUE(Status2->equivalent(*StatusM));
328 EXPECT_TRUE(Status3->equivalent(*StatusT));
330 EXPECT_FALSE(Status1->equivalent(*Status2));
331 EXPECT_FALSE(Status2->equivalent(*Status3));
332 EXPECT_FALSE(Status1->equivalent(*Status3));
335 TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
336 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
337 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
338 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
339 new vfs::OverlayFileSystem(Lower));
340 O->pushOverlay(Upper);
342 Lower->addDirectory("/lower-only");
343 Upper->addDirectory("/upper-only");
345 // non-merged paths should be the same
346 ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
347 ASSERT_FALSE(Status1.getError());
348 ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
349 ASSERT_FALSE(Status2.getError());
350 EXPECT_TRUE(Status1->equivalent(*Status2));
352 Status1 = Upper->status("/upper-only");
353 ASSERT_FALSE(Status1.getError());
354 Status2 = O->status("/upper-only");
355 ASSERT_FALSE(Status2.getError());
356 EXPECT_TRUE(Status1->equivalent(*Status2));
359 TEST(VirtualFileSystemTest, MergedDirPermissions) {
360 // merged directories get the permissions of the upper dir
361 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
362 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
363 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
364 new vfs::OverlayFileSystem(Lower));
365 O->pushOverlay(Upper);
367 ErrorOr<vfs::Status> Status((std::error_code()));
368 Lower->addDirectory("/both", sys::fs::owner_read);
369 Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
370 Status = O->status("/both");
371 ASSERT_FALSE(Status.getError());
372 EXPECT_EQ(0740, Status->getPermissions());
374 // permissions (as usual) are not recursively applied
375 Lower->addRegularFile("/both/foo", sys::fs::owner_read);
376 Upper->addRegularFile("/both/bar", sys::fs::owner_write);
377 Status = O->status("/both/foo");
378 ASSERT_FALSE(Status.getError());
379 EXPECT_EQ(0400, Status->getPermissions());
380 Status = O->status("/both/bar");
381 ASSERT_FALSE(Status.getError());
382 EXPECT_EQ(0200, Status->getPermissions());
385 TEST(VirtualFileSystemTest, OverlayIterator) {
386 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
387 Lower->addRegularFile("/foo");
388 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
390 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
391 new vfs::OverlayFileSystem(Lower));
392 O->pushOverlay(Upper);
394 ErrorOr<vfs::Status> Status((std::error_code()));
396 auto it = O->overlays_begin();
397 auto end = O->overlays_end();
399 EXPECT_NE(it, end);
401 Status = (*it)->status("/foo");
402 ASSERT_TRUE(Status.getError());
404 it++;
405 EXPECT_NE(it, end);
407 Status = (*it)->status("/foo");
408 ASSERT_FALSE(Status.getError());
409 EXPECT_TRUE(Status->exists());
411 it++;
412 EXPECT_EQ(it, end);
416 auto it = O->overlays_rbegin();
417 auto end = O->overlays_rend();
419 EXPECT_NE(it, end);
421 Status = (*it)->status("/foo");
422 ASSERT_FALSE(Status.getError());
423 EXPECT_TRUE(Status->exists());
425 it++;
426 EXPECT_NE(it, end);
428 Status = (*it)->status("/foo");
429 ASSERT_TRUE(Status.getError());
431 it++;
432 EXPECT_EQ(it, end);
436 TEST(VirtualFileSystemTest, BasicRealFSIteration) {
437 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
438 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
440 std::error_code EC;
441 vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory.path()), EC);
442 ASSERT_FALSE(EC);
443 EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
445 TempDir _a(TestDirectory.path("a"));
446 TempDir _ab(TestDirectory.path("a/b"));
447 TempDir _c(TestDirectory.path("c"));
448 TempDir _cd(TestDirectory.path("c/d"));
450 I = FS->dir_begin(Twine(TestDirectory.path()), EC);
451 ASSERT_FALSE(EC);
452 ASSERT_NE(vfs::directory_iterator(), I);
453 // Check either a or c, since we can't rely on the iteration order.
454 EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
455 I.increment(EC);
456 ASSERT_FALSE(EC);
457 ASSERT_NE(vfs::directory_iterator(), I);
458 EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
459 I.increment(EC);
460 EXPECT_EQ(vfs::directory_iterator(), I);
463 #ifdef LLVM_ON_UNIX
464 TEST(VirtualFileSystemTest, MultipleWorkingDirs) {
465 // Our root contains a/aa, b/bb, c, where c is a link to a/.
466 // Run tests both in root/b/ and root/c/ (to test "normal" and symlink dirs).
467 // Interleave operations to show the working directories are independent.
468 TempDir Root("r", /*Unique*/ true);
469 TempDir ADir(Root.path("a"));
470 TempDir BDir(Root.path("b"));
471 TempLink C(ADir.path(), Root.path("c"));
472 TempFile AA(ADir.path("aa"), "", "aaaa");
473 TempFile BB(BDir.path("bb"), "", "bbbb");
474 std::unique_ptr<vfs::FileSystem> BFS = vfs::createPhysicalFileSystem(),
475 CFS = vfs::createPhysicalFileSystem();
477 ASSERT_FALSE(BFS->setCurrentWorkingDirectory(BDir.path()));
478 ASSERT_FALSE(CFS->setCurrentWorkingDirectory(C.path()));
479 EXPECT_EQ(BDir.path(), *BFS->getCurrentWorkingDirectory());
480 EXPECT_EQ(C.path(), *CFS->getCurrentWorkingDirectory());
482 // openFileForRead(), indirectly.
483 auto BBuf = BFS->getBufferForFile("bb");
484 ASSERT_TRUE(BBuf);
485 EXPECT_EQ("bbbb", (*BBuf)->getBuffer());
487 auto ABuf = CFS->getBufferForFile("aa");
488 ASSERT_TRUE(ABuf);
489 EXPECT_EQ("aaaa", (*ABuf)->getBuffer());
491 // status()
492 auto BStat = BFS->status("bb");
493 ASSERT_TRUE(BStat);
494 EXPECT_EQ("bb", BStat->getName());
496 auto AStat = CFS->status("aa");
497 ASSERT_TRUE(AStat);
498 EXPECT_EQ("aa", AStat->getName()); // unresolved name
500 // getRealPath()
501 SmallString<128> BPath;
502 ASSERT_FALSE(BFS->getRealPath("bb", BPath));
503 EXPECT_EQ(BB.path(), BPath);
505 SmallString<128> APath;
506 ASSERT_FALSE(CFS->getRealPath("aa", APath));
507 EXPECT_EQ(AA.path(), APath); // Reports resolved name.
509 // dir_begin
510 std::error_code EC;
511 auto BIt = BFS->dir_begin(".", EC);
512 ASSERT_FALSE(EC);
513 ASSERT_NE(BIt, vfs::directory_iterator());
514 EXPECT_EQ((BDir.path() + "/./bb").str(), BIt->path());
515 BIt.increment(EC);
516 ASSERT_FALSE(EC);
517 ASSERT_EQ(BIt, vfs::directory_iterator());
519 auto CIt = CFS->dir_begin(".", EC);
520 ASSERT_FALSE(EC);
521 ASSERT_NE(CIt, vfs::directory_iterator());
522 EXPECT_EQ((ADir.path() + "/./aa").str(),
523 CIt->path()); // Partly resolved name!
524 CIt.increment(EC); // Because likely to read through this path.
525 ASSERT_FALSE(EC);
526 ASSERT_EQ(CIt, vfs::directory_iterator());
529 TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
530 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
531 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
533 TempLink _a("no_such_file", TestDirectory.path("a"));
534 TempDir _b(TestDirectory.path("b"));
535 TempLink _c("no_such_file", TestDirectory.path("c"));
537 // Should get no iteration error, but a stat error for the broken symlinks.
538 std::map<std::string, std::error_code> StatResults;
539 std::error_code EC;
540 for (vfs::directory_iterator
541 I = FS->dir_begin(Twine(TestDirectory.path()), EC),
543 I != E; I.increment(EC)) {
544 EXPECT_FALSE(EC);
545 StatResults[std::string(sys::path::filename(I->path()))] =
546 FS->status(I->path()).getError();
548 EXPECT_THAT(
549 StatResults,
550 ElementsAre(
551 Pair("a", std::make_error_code(std::errc::no_such_file_or_directory)),
552 Pair("b", std::error_code()),
553 Pair("c",
554 std::make_error_code(std::errc::no_such_file_or_directory))));
556 #endif
558 TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
559 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
560 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
562 std::error_code EC;
563 auto I =
564 vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC);
565 ASSERT_FALSE(EC);
566 EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
568 TempDir _a(TestDirectory.path("a"));
569 TempDir _ab(TestDirectory.path("a/b"));
570 TempDir _c(TestDirectory.path("c"));
571 TempDir _cd(TestDirectory.path("c/d"));
573 I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC);
574 ASSERT_FALSE(EC);
575 ASSERT_NE(vfs::recursive_directory_iterator(), I);
577 std::vector<std::string> Contents;
578 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
579 I.increment(EC)) {
580 Contents.push_back(std::string(I->path()));
583 // Check contents, which may be in any order
584 EXPECT_EQ(4U, Contents.size());
585 int Counts[4] = {0, 0, 0, 0};
586 for (const std::string &Name : Contents) {
587 ASSERT_FALSE(Name.empty());
588 int Index = Name[Name.size() - 1] - 'a';
589 ASSERT_GE(Index, 0);
590 ASSERT_LT(Index, 4);
591 Counts[Index]++;
593 EXPECT_EQ(1, Counts[0]); // a
594 EXPECT_EQ(1, Counts[1]); // b
595 EXPECT_EQ(1, Counts[2]); // c
596 EXPECT_EQ(1, Counts[3]); // d
599 TEST(VirtualFileSystemTest, BasicRealFSRecursiveIterationNoPush) {
600 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
602 TempDir _a(TestDirectory.path("a"));
603 TempDir _ab(TestDirectory.path("a/b"));
604 TempDir _c(TestDirectory.path("c"));
605 TempDir _cd(TestDirectory.path("c/d"));
606 TempDir _e(TestDirectory.path("e"));
607 TempDir _ef(TestDirectory.path("e/f"));
608 TempDir _g(TestDirectory.path("g"));
610 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
612 // Test that calling no_push on entries without subdirectories has no effect.
614 std::error_code EC;
615 auto I =
616 vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC);
617 ASSERT_FALSE(EC);
619 std::vector<std::string> Contents;
620 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
621 I.increment(EC)) {
622 Contents.push_back(std::string(I->path()));
623 char last = I->path().back();
624 switch (last) {
625 case 'b':
626 case 'd':
627 case 'f':
628 case 'g':
629 I.no_push();
630 break;
631 default:
632 break;
635 EXPECT_EQ(7U, Contents.size());
638 // Test that calling no_push skips subdirectories.
640 std::error_code EC;
641 auto I =
642 vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC);
643 ASSERT_FALSE(EC);
645 std::vector<std::string> Contents;
646 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
647 I.increment(EC)) {
648 Contents.push_back(std::string(I->path()));
649 char last = I->path().back();
650 switch (last) {
651 case 'a':
652 case 'c':
653 case 'e':
654 I.no_push();
655 break;
656 default:
657 break;
661 // Check contents, which may be in any order
662 EXPECT_EQ(4U, Contents.size());
663 int Counts[7] = {0, 0, 0, 0, 0, 0, 0};
664 for (const std::string &Name : Contents) {
665 ASSERT_FALSE(Name.empty());
666 int Index = Name[Name.size() - 1] - 'a';
667 ASSERT_GE(Index, 0);
668 ASSERT_LT(Index, 7);
669 Counts[Index]++;
671 EXPECT_EQ(1, Counts[0]); // a
672 EXPECT_EQ(0, Counts[1]); // b
673 EXPECT_EQ(1, Counts[2]); // c
674 EXPECT_EQ(0, Counts[3]); // d
675 EXPECT_EQ(1, Counts[4]); // e
676 EXPECT_EQ(0, Counts[5]); // f
677 EXPECT_EQ(1, Counts[6]); // g
681 #ifdef LLVM_ON_UNIX
682 TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
683 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
684 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
686 TempLink _a("no_such_file", TestDirectory.path("a"));
687 TempDir _b(TestDirectory.path("b"));
688 TempLink _ba("no_such_file", TestDirectory.path("b/a"));
689 TempDir _bb(TestDirectory.path("b/b"));
690 TempLink _bc("no_such_file", TestDirectory.path("b/c"));
691 TempLink _c("no_such_file", TestDirectory.path("c"));
692 TempDir _d(TestDirectory.path("d"));
693 TempDir _dd(TestDirectory.path("d/d"));
694 TempDir _ddd(TestDirectory.path("d/d/d"));
695 TempLink _e("no_such_file", TestDirectory.path("e"));
697 std::vector<std::string> VisitedBrokenSymlinks;
698 std::vector<std::string> VisitedNonBrokenSymlinks;
699 std::error_code EC;
700 for (vfs::recursive_directory_iterator
701 I(*FS, Twine(TestDirectory.path()), EC),
703 I != E; I.increment(EC)) {
704 EXPECT_FALSE(EC);
705 (FS->status(I->path()) ? VisitedNonBrokenSymlinks : VisitedBrokenSymlinks)
706 .push_back(std::string(I->path()));
709 // Check visited file names.
710 EXPECT_THAT(VisitedBrokenSymlinks,
711 UnorderedElementsAre(_a.path().str(), _ba.path().str(),
712 _bc.path().str(), _c.path().str(),
713 _e.path().str()));
714 EXPECT_THAT(VisitedNonBrokenSymlinks,
715 UnorderedElementsAre(_b.path().str(), _bb.path().str(),
716 _d.path().str(), _dd.path().str(),
717 _ddd.path().str()));
719 #endif
721 template <typename DirIter>
722 static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
723 std::error_code EC;
724 SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
725 SmallVector<std::string, 4> InputToCheck;
727 // Do not rely on iteration order to check for contents, sort both
728 // content vectors before comparison.
729 for (DirIter E; !EC && I != E; I.increment(EC))
730 InputToCheck.push_back(std::string(I->path()));
732 llvm::sort(InputToCheck);
733 llvm::sort(Expected);
734 EXPECT_EQ(InputToCheck.size(), Expected.size());
736 unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
737 for (unsigned Idx = 0; Idx != LastElt; ++Idx)
738 EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
741 TEST(VirtualFileSystemTest, OverlayIteration) {
742 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
743 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
744 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
745 new vfs::OverlayFileSystem(Lower));
746 O->pushOverlay(Upper);
748 std::error_code EC;
749 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
751 Lower->addRegularFile("/file1");
752 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
754 Upper->addRegularFile("/file2");
755 checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
757 Lower->addDirectory("/dir1");
758 Lower->addRegularFile("/dir1/foo");
759 Upper->addDirectory("/dir2");
760 Upper->addRegularFile("/dir2/foo");
761 checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
762 checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
765 TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
766 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
767 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
768 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
769 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
770 new vfs::OverlayFileSystem(Lower));
771 O->pushOverlay(Middle);
772 O->pushOverlay(Upper);
774 std::error_code EC;
775 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
776 ArrayRef<StringRef>());
778 Lower->addRegularFile("/file1");
779 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
780 ArrayRef<StringRef>("/file1"));
782 Upper->addDirectory("/dir");
783 Upper->addRegularFile("/dir/file2");
784 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
785 {"/dir", "/dir/file2", "/file1"});
787 Lower->addDirectory("/dir1");
788 Lower->addRegularFile("/dir1/foo");
789 Lower->addDirectory("/dir1/a");
790 Lower->addRegularFile("/dir1/a/b");
791 Middle->addDirectory("/a");
792 Middle->addDirectory("/a/b");
793 Middle->addDirectory("/a/b/c");
794 Middle->addRegularFile("/a/b/c/d");
795 Middle->addRegularFile("/hiddenByUp");
796 Upper->addDirectory("/dir2");
797 Upper->addRegularFile("/dir2/foo");
798 Upper->addRegularFile("/hiddenByUp");
799 checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
800 ArrayRef<StringRef>("/dir2/foo"));
801 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
802 {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
803 "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
804 "/dir1/a/b", "/dir1/foo", "/file1"});
807 TEST(VirtualFileSystemTest, ThreeLevelIteration) {
808 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
809 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
810 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
811 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
812 new vfs::OverlayFileSystem(Lower));
813 O->pushOverlay(Middle);
814 O->pushOverlay(Upper);
816 std::error_code EC;
817 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
819 Middle->addRegularFile("/file2");
820 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
822 Lower->addRegularFile("/file1");
823 Upper->addRegularFile("/file3");
824 checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
827 TEST(VirtualFileSystemTest, HiddenInIteration) {
828 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
829 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
830 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
831 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
832 new vfs::OverlayFileSystem(Lower));
833 O->pushOverlay(Middle);
834 O->pushOverlay(Upper);
836 std::error_code EC;
837 Lower->addRegularFile("/onlyInLow");
838 Lower->addDirectory("/hiddenByMid");
839 Lower->addDirectory("/hiddenByUp");
840 Middle->addRegularFile("/onlyInMid");
841 Middle->addRegularFile("/hiddenByMid");
842 Middle->addDirectory("/hiddenByUp");
843 Upper->addRegularFile("/onlyInUp");
844 Upper->addRegularFile("/hiddenByUp");
845 checkContents(
846 O->dir_begin("/", EC),
847 {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
849 // Make sure we get the top-most entry
851 std::error_code EC;
852 vfs::directory_iterator I = O->dir_begin("/", EC), E;
853 for (; !EC && I != E; I.increment(EC))
854 if (I->path() == "/hiddenByUp")
855 break;
856 ASSERT_NE(E, I);
857 EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
860 std::error_code EC;
861 vfs::directory_iterator I = O->dir_begin("/", EC), E;
862 for (; !EC && I != E; I.increment(EC))
863 if (I->path() == "/hiddenByMid")
864 break;
865 ASSERT_NE(E, I);
866 EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
870 TEST(OverlayFileSystemTest, PrintOutput) {
871 auto Dummy = makeIntrusiveRefCnt<DummyFileSystem>();
872 auto Overlay1 = makeIntrusiveRefCnt<vfs::OverlayFileSystem>(Dummy);
873 Overlay1->pushOverlay(Dummy);
874 auto Overlay2 = makeIntrusiveRefCnt<vfs::OverlayFileSystem>(Overlay1);
875 Overlay2->pushOverlay(Dummy);
877 SmallString<0> Output;
878 raw_svector_ostream OuputStream{Output};
880 Overlay2->print(OuputStream, vfs::FileSystem::PrintType::Summary);
881 ASSERT_EQ("OverlayFileSystem\n", Output);
883 Output.clear();
884 Overlay2->print(OuputStream, vfs::FileSystem::PrintType::Contents);
885 ASSERT_EQ("OverlayFileSystem\n"
886 " DummyFileSystem (Summary)\n"
887 " OverlayFileSystem\n",
888 Output);
890 Output.clear();
891 Overlay2->print(OuputStream, vfs::FileSystem::PrintType::RecursiveContents);
892 ASSERT_EQ("OverlayFileSystem\n"
893 " DummyFileSystem (RecursiveContents)\n"
894 " OverlayFileSystem\n"
895 " DummyFileSystem (RecursiveContents)\n"
896 " DummyFileSystem (RecursiveContents)\n",
897 Output);
900 TEST(ProxyFileSystemTest, Basic) {
901 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> Base(
902 new vfs::InMemoryFileSystem());
903 vfs::ProxyFileSystem PFS(Base);
905 Base->addFile("/a", 0, MemoryBuffer::getMemBuffer("test"));
907 auto Stat = PFS.status("/a");
908 ASSERT_FALSE(Stat.getError());
910 auto File = PFS.openFileForRead("/a");
911 ASSERT_FALSE(File.getError());
912 EXPECT_EQ("test", (*(*File)->getBuffer("ignored"))->getBuffer());
914 std::error_code EC;
915 vfs::directory_iterator I = PFS.dir_begin("/", EC);
916 ASSERT_FALSE(EC);
917 ASSERT_EQ("/a", I->path());
918 I.increment(EC);
919 ASSERT_FALSE(EC);
920 ASSERT_EQ(vfs::directory_iterator(), I);
922 ASSERT_FALSE(PFS.setCurrentWorkingDirectory("/"));
924 auto PWD = PFS.getCurrentWorkingDirectory();
925 ASSERT_FALSE(PWD.getError());
926 ASSERT_EQ("/", getPosixPath(*PWD));
928 SmallString<16> Path;
929 ASSERT_FALSE(PFS.getRealPath("a", Path));
930 ASSERT_EQ("/a", getPosixPath(Path));
932 bool Local = true;
933 ASSERT_FALSE(PFS.isLocal("/a", Local));
934 EXPECT_FALSE(Local);
937 class InMemoryFileSystemTest : public ::testing::Test {
938 protected:
939 llvm::vfs::InMemoryFileSystem FS;
940 llvm::vfs::InMemoryFileSystem NormalizedFS;
942 InMemoryFileSystemTest()
943 : FS(/*UseNormalizedPaths=*/false),
944 NormalizedFS(/*UseNormalizedPaths=*/true) {}
947 MATCHER_P2(IsHardLinkTo, FS, Target, "") {
948 StringRef From = arg;
949 StringRef To = Target;
950 auto OpenedFrom = FS->openFileForRead(From);
951 auto OpenedTo = FS->openFileForRead(To);
952 return !OpenedFrom.getError() && !OpenedTo.getError() &&
953 (*OpenedFrom)->status()->getUniqueID() ==
954 (*OpenedTo)->status()->getUniqueID();
957 TEST_F(InMemoryFileSystemTest, IsEmpty) {
958 auto Stat = FS.status("/a");
959 ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
960 Stat = FS.status("/");
961 ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
964 TEST_F(InMemoryFileSystemTest, WindowsPath) {
965 FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
966 auto Stat = FS.status("c:");
967 #if !defined(_WIN32)
968 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
969 #endif
970 Stat = FS.status("c:/windows/system128/foo.cpp");
971 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
972 FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
973 Stat = FS.status("d:/windows/foo.cpp");
974 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
977 TEST_F(InMemoryFileSystemTest, OverlayFile) {
978 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
979 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
980 auto Stat = FS.status("/");
981 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
982 Stat = FS.status("/.");
983 ASSERT_FALSE(Stat);
984 Stat = NormalizedFS.status("/.");
985 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
986 Stat = FS.status("/a");
987 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
988 ASSERT_EQ("/a", Stat->getName());
991 TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
992 auto Buf = MemoryBuffer::getMemBuffer("a");
993 FS.addFileNoOwn("/a", 0, *Buf);
994 auto Stat = FS.status("/a");
995 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
996 ASSERT_EQ("/a", Stat->getName());
999 TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
1000 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
1001 FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
1002 FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
1003 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
1004 NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
1005 NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
1006 auto File = FS.openFileForRead("/a");
1007 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
1008 File = FS.openFileForRead("/a"); // Open again.
1009 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
1010 File = NormalizedFS.openFileForRead("/././a"); // Open again.
1011 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
1012 File = FS.openFileForRead("/");
1013 ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
1014 File = FS.openFileForRead("/b");
1015 ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
1016 File = FS.openFileForRead("./c");
1017 ASSERT_FALSE(File);
1018 File = FS.openFileForRead("e/../d");
1019 ASSERT_FALSE(File);
1020 File = NormalizedFS.openFileForRead("./c");
1021 ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
1022 File = NormalizedFS.openFileForRead("e/../d");
1023 ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
1026 TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
1027 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
1028 ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
1029 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
1030 ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
1033 TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
1034 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
1035 FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
1037 std::error_code EC;
1038 vfs::directory_iterator I = FS.dir_begin("/", EC);
1039 ASSERT_FALSE(EC);
1040 ASSERT_EQ("/a", I->path());
1041 I.increment(EC);
1042 ASSERT_FALSE(EC);
1043 ASSERT_EQ("/b", I->path());
1044 I.increment(EC);
1045 ASSERT_FALSE(EC);
1046 ASSERT_EQ(vfs::directory_iterator(), I);
1048 I = FS.dir_begin("/b", EC);
1049 ASSERT_FALSE(EC);
1050 // When on Windows, we end up with "/b\\c" as the name. Convert to Posix
1051 // path for the sake of the comparison.
1052 ASSERT_EQ("/b/c", getPosixPath(std::string(I->path())));
1053 I.increment(EC);
1054 ASSERT_FALSE(EC);
1055 ASSERT_EQ(vfs::directory_iterator(), I);
1058 TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
1059 FS.setCurrentWorkingDirectory("/b");
1060 FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
1062 auto Stat = FS.status("/b/c");
1063 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1064 ASSERT_EQ("/b/c", Stat->getName());
1065 ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
1067 Stat = FS.status("c");
1068 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1070 NormalizedFS.setCurrentWorkingDirectory("/b/c");
1071 NormalizedFS.setCurrentWorkingDirectory(".");
1072 ASSERT_EQ("/b/c",
1073 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
1074 NormalizedFS.setCurrentWorkingDirectory("..");
1075 ASSERT_EQ("/b",
1076 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
1079 TEST_F(InMemoryFileSystemTest, IsLocal) {
1080 FS.setCurrentWorkingDirectory("/b");
1081 FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
1083 std::error_code EC;
1084 bool IsLocal = true;
1085 EC = FS.isLocal("c", IsLocal);
1086 ASSERT_FALSE(EC);
1087 ASSERT_FALSE(IsLocal);
1090 #if !defined(_WIN32)
1091 TEST_F(InMemoryFileSystemTest, GetRealPath) {
1092 SmallString<16> Path;
1093 EXPECT_EQ(FS.getRealPath("b", Path), errc::operation_not_permitted);
1095 auto GetRealPath = [this](StringRef P) {
1096 SmallString<16> Output;
1097 auto EC = FS.getRealPath(P, Output);
1098 EXPECT_FALSE(EC);
1099 return std::string(Output);
1102 FS.setCurrentWorkingDirectory("a");
1103 EXPECT_EQ(GetRealPath("b"), "a/b");
1104 EXPECT_EQ(GetRealPath("../b"), "b");
1105 EXPECT_EQ(GetRealPath("b/./c"), "a/b/c");
1107 FS.setCurrentWorkingDirectory("/a");
1108 EXPECT_EQ(GetRealPath("b"), "/a/b");
1109 EXPECT_EQ(GetRealPath("../b"), "/b");
1110 EXPECT_EQ(GetRealPath("b/./c"), "/a/b/c");
1112 #endif // _WIN32
1114 TEST_F(InMemoryFileSystemTest, AddFileWithUser) {
1115 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
1116 auto Stat = FS.status("/a");
1117 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1118 ASSERT_TRUE(Stat->isDirectory());
1119 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
1120 Stat = FS.status("/a/b");
1121 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1122 ASSERT_TRUE(Stat->isDirectory());
1123 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
1124 Stat = FS.status("/a/b/c");
1125 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1126 ASSERT_TRUE(Stat->isRegularFile());
1127 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
1128 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
1131 TEST_F(InMemoryFileSystemTest, AddFileWithGroup) {
1132 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00);
1133 auto Stat = FS.status("/a");
1134 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1135 ASSERT_TRUE(Stat->isDirectory());
1136 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
1137 Stat = FS.status("/a/b");
1138 ASSERT_TRUE(Stat->isDirectory());
1139 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1140 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
1141 Stat = FS.status("/a/b/c");
1142 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1143 ASSERT_TRUE(Stat->isRegularFile());
1144 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
1145 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
1148 TEST_F(InMemoryFileSystemTest, AddFileWithFileType) {
1149 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
1150 sys::fs::file_type::socket_file);
1151 auto Stat = FS.status("/a");
1152 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1153 ASSERT_TRUE(Stat->isDirectory());
1154 Stat = FS.status("/a/b");
1155 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1156 ASSERT_TRUE(Stat->isDirectory());
1157 Stat = FS.status("/a/b/c");
1158 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1159 ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType());
1160 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
1163 TEST_F(InMemoryFileSystemTest, AddFileWithPerms) {
1164 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None, None,
1165 sys::fs::perms::owner_read | sys::fs::perms::owner_write);
1166 auto Stat = FS.status("/a");
1167 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1168 ASSERT_TRUE(Stat->isDirectory());
1169 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
1170 sys::fs::perms::owner_exe,
1171 Stat->getPermissions());
1172 Stat = FS.status("/a/b");
1173 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1174 ASSERT_TRUE(Stat->isDirectory());
1175 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
1176 sys::fs::perms::owner_exe,
1177 Stat->getPermissions());
1178 Stat = FS.status("/a/b/c");
1179 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1180 ASSERT_TRUE(Stat->isRegularFile());
1181 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write,
1182 Stat->getPermissions());
1185 TEST_F(InMemoryFileSystemTest, AddDirectoryThenAddChild) {
1186 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None,
1187 /*Group=*/None, sys::fs::file_type::directory_file);
1188 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None,
1189 /*Group=*/None, sys::fs::file_type::regular_file);
1190 auto Stat = FS.status("/a");
1191 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1192 ASSERT_TRUE(Stat->isDirectory());
1193 Stat = FS.status("/a/b");
1194 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1195 ASSERT_TRUE(Stat->isRegularFile());
1198 // Test that the name returned by status() is in the same form as the path that
1199 // was requested (to match the behavior of RealFileSystem).
1200 TEST_F(InMemoryFileSystemTest, StatusName) {
1201 NormalizedFS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"),
1202 /*User=*/None,
1203 /*Group=*/None, sys::fs::file_type::regular_file);
1204 NormalizedFS.setCurrentWorkingDirectory("/a/b");
1206 // Access using InMemoryFileSystem::status.
1207 auto Stat = NormalizedFS.status("../b/c");
1208 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1209 << NormalizedFS.toString();
1210 ASSERT_TRUE(Stat->isRegularFile());
1211 ASSERT_EQ("../b/c", Stat->getName());
1213 // Access using InMemoryFileAdaptor::status.
1214 auto File = NormalizedFS.openFileForRead("../b/c");
1215 ASSERT_FALSE(File.getError()) << File.getError() << "\n"
1216 << NormalizedFS.toString();
1217 Stat = (*File)->status();
1218 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1219 << NormalizedFS.toString();
1220 ASSERT_TRUE(Stat->isRegularFile());
1221 ASSERT_EQ("../b/c", Stat->getName());
1223 // Access using a directory iterator.
1224 std::error_code EC;
1225 llvm::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC);
1226 // When on Windows, we end up with "../b\\c" as the name. Convert to Posix
1227 // path for the sake of the comparison.
1228 ASSERT_EQ("../b/c", getPosixPath(std::string(It->path())));
1231 TEST_F(InMemoryFileSystemTest, AddHardLinkToFile) {
1232 StringRef FromLink = "/path/to/FROM/link";
1233 StringRef Target = "/path/to/TO/file";
1234 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1235 EXPECT_TRUE(FS.addHardLink(FromLink, Target));
1236 EXPECT_THAT(FromLink, IsHardLinkTo(&FS, Target));
1237 EXPECT_EQ(FS.status(FromLink)->getSize(), FS.status(Target)->getSize());
1238 EXPECT_EQ(FS.getBufferForFile(FromLink)->get()->getBuffer(),
1239 FS.getBufferForFile(Target)->get()->getBuffer());
1242 TEST_F(InMemoryFileSystemTest, AddHardLinkInChainPattern) {
1243 StringRef Link0 = "/path/to/0/link";
1244 StringRef Link1 = "/path/to/1/link";
1245 StringRef Link2 = "/path/to/2/link";
1246 StringRef Target = "/path/to/target";
1247 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target file"));
1248 EXPECT_TRUE(FS.addHardLink(Link2, Target));
1249 EXPECT_TRUE(FS.addHardLink(Link1, Link2));
1250 EXPECT_TRUE(FS.addHardLink(Link0, Link1));
1251 EXPECT_THAT(Link0, IsHardLinkTo(&FS, Target));
1252 EXPECT_THAT(Link1, IsHardLinkTo(&FS, Target));
1253 EXPECT_THAT(Link2, IsHardLinkTo(&FS, Target));
1256 TEST_F(InMemoryFileSystemTest, AddHardLinkToAFileThatWasNotAddedBefore) {
1257 EXPECT_FALSE(FS.addHardLink("/path/to/link", "/path/to/target"));
1260 TEST_F(InMemoryFileSystemTest, AddHardLinkFromAFileThatWasAddedBefore) {
1261 StringRef Link = "/path/to/link";
1262 StringRef Target = "/path/to/target";
1263 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1264 FS.addFile(Link, 0, MemoryBuffer::getMemBuffer("content of link"));
1265 EXPECT_FALSE(FS.addHardLink(Link, Target));
1268 TEST_F(InMemoryFileSystemTest, AddSameHardLinkMoreThanOnce) {
1269 StringRef Link = "/path/to/link";
1270 StringRef Target = "/path/to/target";
1271 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1272 EXPECT_TRUE(FS.addHardLink(Link, Target));
1273 EXPECT_FALSE(FS.addHardLink(Link, Target));
1276 TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithSameContent) {
1277 StringRef Link = "/path/to/link";
1278 StringRef Target = "/path/to/target";
1279 StringRef Content = "content of target";
1280 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1281 EXPECT_TRUE(FS.addHardLink(Link, Target));
1282 EXPECT_TRUE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(Content)));
1285 TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithDifferentContent) {
1286 StringRef Link = "/path/to/link";
1287 StringRef Target = "/path/to/target";
1288 StringRef Content = "content of target";
1289 StringRef LinkContent = "different content of link";
1290 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1291 EXPECT_TRUE(FS.addHardLink(Link, Target));
1292 EXPECT_FALSE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(LinkContent)));
1295 TEST_F(InMemoryFileSystemTest, AddHardLinkToADirectory) {
1296 StringRef Dir = "path/to/dummy/dir";
1297 StringRef Link = "/path/to/link";
1298 StringRef File = "path/to/dummy/dir/target";
1299 StringRef Content = "content of target";
1300 EXPECT_TRUE(FS.addFile(File, 0, MemoryBuffer::getMemBuffer(Content)));
1301 EXPECT_FALSE(FS.addHardLink(Link, Dir));
1304 TEST_F(InMemoryFileSystemTest, AddHardLinkToASymlink) {
1305 EXPECT_TRUE(FS.addFile("/file", 0, MemoryBuffer::getMemBuffer("content")));
1306 EXPECT_TRUE(FS.addSymbolicLink("/symlink", "/file", 0));
1307 EXPECT_TRUE(FS.addHardLink("/hardlink", "/symlink"));
1308 EXPECT_EQ((*FS.getBufferForFile("/hardlink"))->getBuffer(), "content");
1311 TEST_F(InMemoryFileSystemTest, AddHardLinkFromADirectory) {
1312 StringRef Dir = "path/to/dummy/dir";
1313 StringRef Target = "path/to/dummy/dir/target";
1314 StringRef Content = "content of target";
1315 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1316 EXPECT_FALSE(FS.addHardLink(Dir, Target));
1319 TEST_F(InMemoryFileSystemTest, AddHardLinkUnderAFile) {
1320 StringRef CommonContent = "content string";
1321 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer(CommonContent));
1322 FS.addFile("/c/d", 0, MemoryBuffer::getMemBuffer(CommonContent));
1323 EXPECT_FALSE(FS.addHardLink("/c/d/e", "/a/b"));
1326 TEST_F(InMemoryFileSystemTest, RecursiveIterationWithHardLink) {
1327 std::error_code EC;
1328 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("content string"));
1329 EXPECT_TRUE(FS.addHardLink("/c/d", "/a/b"));
1330 auto I = vfs::recursive_directory_iterator(FS, "/", EC);
1331 ASSERT_FALSE(EC);
1332 std::vector<std::string> Nodes;
1333 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
1334 I.increment(EC)) {
1335 Nodes.push_back(getPosixPath(std::string(I->path())));
1337 EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d"));
1340 TEST_F(InMemoryFileSystemTest, UniqueID) {
1341 ASSERT_TRUE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("text")));
1342 ASSERT_TRUE(FS.addFile("/c/d", 0, MemoryBuffer::getMemBuffer("text")));
1343 ASSERT_TRUE(FS.addHardLink("/e/f", "/a/b"));
1345 EXPECT_EQ(FS.status("/a/b")->getUniqueID(), FS.status("/a/b")->getUniqueID());
1346 EXPECT_NE(FS.status("/a/b")->getUniqueID(), FS.status("/c/d")->getUniqueID());
1347 EXPECT_EQ(FS.status("/a/b")->getUniqueID(), FS.status("/e/f")->getUniqueID());
1348 EXPECT_EQ(FS.status("/a")->getUniqueID(), FS.status("/a")->getUniqueID());
1349 EXPECT_NE(FS.status("/a")->getUniqueID(), FS.status("/c")->getUniqueID());
1350 EXPECT_NE(FS.status("/a")->getUniqueID(), FS.status("/e")->getUniqueID());
1352 // Recreating the "same" FS yields the same UniqueIDs.
1353 // Note: FS2 should match FS with respect to path normalization.
1354 vfs::InMemoryFileSystem FS2(/*UseNormalizedPath=*/false);
1355 ASSERT_TRUE(FS2.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("text")));
1356 EXPECT_EQ(FS.status("/a/b")->getUniqueID(),
1357 FS2.status("/a/b")->getUniqueID());
1358 EXPECT_EQ(FS.status("/a")->getUniqueID(), FS2.status("/a")->getUniqueID());
1361 TEST_F(InMemoryFileSystemTest, AddSymlinkToAFile) {
1362 EXPECT_TRUE(
1363 FS.addFile("/some/file", 0, MemoryBuffer::getMemBuffer("contents")));
1364 EXPECT_TRUE(FS.addSymbolicLink("/other/file/link", "/some/file", 0));
1365 ErrorOr<vfs::Status> Stat = FS.status("/some/file");
1366 EXPECT_TRUE(Stat->isRegularFile());
1369 TEST_F(InMemoryFileSystemTest, AddSymlinkToADirectory) {
1370 EXPECT_TRUE(FS.addSymbolicLink("/link", "/target", 0));
1371 EXPECT_TRUE(
1372 FS.addFile("/target/foo.h", 0, MemoryBuffer::getMemBuffer("foo")));
1373 ErrorOr<vfs::Status> Stat = FS.status("/link/foo.h");
1374 EXPECT_TRUE(Stat);
1375 EXPECT_EQ((*Stat).getName(), "/link/foo.h");
1376 EXPECT_TRUE(Stat->isRegularFile());
1379 TEST_F(InMemoryFileSystemTest, AddSymlinkToASymlink) {
1380 EXPECT_TRUE(FS.addSymbolicLink("/first", "/second", 0));
1381 EXPECT_TRUE(FS.addSymbolicLink("/second", "/third", 0));
1382 EXPECT_TRUE(FS.addFile("/third", 0, MemoryBuffer::getMemBuffer("")));
1383 ErrorOr<vfs::Status> Stat = FS.status("/first");
1384 EXPECT_TRUE(Stat);
1385 EXPECT_EQ((*Stat).getName(), "/first");
1386 // Follow-through symlinks by default. This matches RealFileSystem's
1387 // semantics.
1388 EXPECT_TRUE(Stat->isRegularFile());
1389 Stat = FS.status("/second");
1390 EXPECT_TRUE(Stat);
1391 EXPECT_EQ((*Stat).getName(), "/second");
1392 EXPECT_TRUE(Stat->isRegularFile());
1393 Stat = FS.status("/third");
1394 EXPECT_TRUE(Stat);
1395 EXPECT_EQ((*Stat).getName(), "/third");
1396 EXPECT_TRUE(Stat->isRegularFile());
1399 TEST_F(InMemoryFileSystemTest, AddRecursiveSymlink) {
1400 EXPECT_TRUE(FS.addSymbolicLink("/link-a", "/link-b", 0));
1401 EXPECT_TRUE(FS.addSymbolicLink("/link-b", "/link-a", 0));
1402 ErrorOr<vfs::Status> Stat = FS.status("/link-a/foo");
1403 EXPECT_FALSE(Stat);
1404 EXPECT_EQ(Stat.getError(), errc::no_such_file_or_directory);
1407 TEST_F(InMemoryFileSystemTest, DirectoryIteratorWithSymlinkToAFile) {
1408 std::error_code EC;
1410 EXPECT_TRUE(FS.addFile("/file", 0, MemoryBuffer::getMemBuffer("")));
1411 EXPECT_TRUE(FS.addSymbolicLink("/symlink", "/file", 0));
1413 vfs::directory_iterator I = FS.dir_begin("/", EC), E;
1414 ASSERT_FALSE(EC);
1416 std::vector<std::string> Nodes;
1417 for (; !EC && I != E; I.increment(EC))
1418 Nodes.push_back(getPosixPath(std::string(I->path())));
1420 EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/file", "/file"));
1423 TEST_F(InMemoryFileSystemTest, RecursiveDirectoryIteratorWithSymlinkToADir) {
1424 std::error_code EC;
1426 EXPECT_TRUE(FS.addFile("/dir/file", 0, MemoryBuffer::getMemBuffer("")));
1427 EXPECT_TRUE(FS.addSymbolicLink("/dir_symlink", "/dir", 0));
1429 vfs::recursive_directory_iterator I(FS, "/", EC), E;
1430 ASSERT_FALSE(EC);
1432 std::vector<std::string> Nodes;
1433 for (; !EC && I != E; I.increment(EC))
1434 Nodes.push_back(getPosixPath(std::string(I->path())));
1436 EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/dir", "/dir/file", "/dir",
1437 "/dir/file"));
1440 // NOTE: in the tests below, we use '//root/' as our root directory, since it is
1441 // a legal *absolute* path on Windows as well as *nix.
1442 class VFSFromYAMLTest : public ::testing::Test {
1443 public:
1444 int NumDiagnostics;
1446 void SetUp() override { NumDiagnostics = 0; }
1448 static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
1449 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
1450 ++Test->NumDiagnostics;
1453 std::unique_ptr<vfs::FileSystem>
1454 getFromYAMLRawString(StringRef Content,
1455 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
1456 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
1457 return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
1458 ExternalFS);
1461 std::unique_ptr<vfs::FileSystem> getFromYAMLString(
1462 StringRef Content,
1463 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
1464 std::string VersionPlusContent("{\n 'version':0,\n");
1465 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
1466 return getFromYAMLRawString(VersionPlusContent, ExternalFS);
1469 // This is intended as a "XFAIL" for windows hosts.
1470 bool supportsSameDirMultipleYAMLEntries() {
1471 Triple Host(Triple::normalize(sys::getProcessTriple()));
1472 return !Host.isOSWindows();
1476 TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
1477 IntrusiveRefCntPtr<vfs::FileSystem> FS;
1478 FS = getFromYAMLString("");
1479 EXPECT_EQ(nullptr, FS.get());
1480 FS = getFromYAMLString("[]");
1481 EXPECT_EQ(nullptr, FS.get());
1482 FS = getFromYAMLString("'string'");
1483 EXPECT_EQ(nullptr, FS.get());
1484 EXPECT_EQ(3, NumDiagnostics);
1487 TEST_F(VFSFromYAMLTest, MappedFiles) {
1488 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1489 Lower->addDirectory("//root/foo/bar");
1490 Lower->addRegularFile("//root/foo/bar/a");
1491 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1492 "{ 'roots': [\n"
1493 "{\n"
1494 " 'type': 'directory',\n"
1495 " 'name': '//root/',\n"
1496 " 'contents': [ {\n"
1497 " 'type': 'file',\n"
1498 " 'name': 'file1',\n"
1499 " 'external-contents': '//root/foo/bar/a'\n"
1500 " },\n"
1501 " {\n"
1502 " 'type': 'file',\n"
1503 " 'name': 'file2',\n"
1504 " 'external-contents': '//root/foo/b'\n"
1505 " },\n"
1506 " {\n"
1507 " 'type': 'directory-remap',\n"
1508 " 'name': 'mappeddir',\n"
1509 " 'external-contents': '//root/foo/bar'\n"
1510 " },\n"
1511 " {\n"
1512 " 'type': 'directory-remap',\n"
1513 " 'name': 'mappeddir2',\n"
1514 " 'use-external-name': false,\n"
1515 " 'external-contents': '//root/foo/bar'\n"
1516 " }\n"
1517 " ]\n"
1518 "}\n"
1519 "]\n"
1520 "}",
1521 Lower);
1522 ASSERT_NE(FS.get(), nullptr);
1524 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1525 new vfs::OverlayFileSystem(Lower));
1526 O->pushOverlay(FS);
1528 // file
1529 ErrorOr<vfs::Status> S = O->status("//root/file1");
1530 ASSERT_FALSE(S.getError());
1531 EXPECT_EQ("//root/foo/bar/a", S->getName());
1532 EXPECT_TRUE(S->IsVFSMapped);
1533 EXPECT_TRUE(S->ExposesExternalVFSPath);
1535 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
1536 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
1537 EXPECT_TRUE(S->equivalent(*SLower));
1538 EXPECT_FALSE(SLower->IsVFSMapped);
1539 EXPECT_FALSE(SLower->ExposesExternalVFSPath);
1541 // file after opening
1542 auto OpenedF = O->openFileForRead("//root/file1");
1543 ASSERT_FALSE(OpenedF.getError());
1544 auto OpenedS = (*OpenedF)->status();
1545 ASSERT_FALSE(OpenedS.getError());
1546 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
1547 EXPECT_TRUE(OpenedS->IsVFSMapped);
1548 EXPECT_TRUE(OpenedS->ExposesExternalVFSPath);
1550 // directory
1551 S = O->status("//root/");
1552 ASSERT_FALSE(S.getError());
1553 EXPECT_TRUE(S->isDirectory());
1554 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
1556 // remapped directory
1557 S = O->status("//root/mappeddir");
1558 ASSERT_FALSE(S.getError());
1559 EXPECT_TRUE(S->isDirectory());
1560 EXPECT_TRUE(S->IsVFSMapped);
1561 EXPECT_TRUE(S->ExposesExternalVFSPath);
1562 EXPECT_TRUE(S->equivalent(*O->status("//root/foo/bar")));
1564 SLower = O->status("//root/foo/bar");
1565 EXPECT_EQ("//root/foo/bar", SLower->getName());
1566 EXPECT_TRUE(S->equivalent(*SLower));
1567 EXPECT_FALSE(SLower->IsVFSMapped);
1568 EXPECT_FALSE(SLower->ExposesExternalVFSPath);
1570 // file in remapped directory
1571 S = O->status("//root/mappeddir/a");
1572 ASSERT_FALSE(S.getError());
1573 EXPECT_FALSE(S->isDirectory());
1574 EXPECT_TRUE(S->IsVFSMapped);
1575 EXPECT_TRUE(S->ExposesExternalVFSPath);
1576 EXPECT_EQ("//root/foo/bar/a", S->getName());
1578 // file in remapped directory, with use-external-name=false
1579 S = O->status("//root/mappeddir2/a");
1580 ASSERT_FALSE(S.getError());
1581 EXPECT_FALSE(S->isDirectory());
1582 EXPECT_TRUE(S->IsVFSMapped);
1583 EXPECT_FALSE(S->ExposesExternalVFSPath);
1584 EXPECT_EQ("//root/mappeddir2/a", S->getName());
1586 // file contents in remapped directory
1587 OpenedF = O->openFileForRead("//root/mappeddir/a");
1588 ASSERT_FALSE(OpenedF.getError());
1589 OpenedS = (*OpenedF)->status();
1590 ASSERT_FALSE(OpenedS.getError());
1591 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
1592 EXPECT_TRUE(OpenedS->IsVFSMapped);
1593 EXPECT_TRUE(OpenedS->ExposesExternalVFSPath);
1595 // file contents in remapped directory, with use-external-name=false
1596 OpenedF = O->openFileForRead("//root/mappeddir2/a");
1597 ASSERT_FALSE(OpenedF.getError());
1598 OpenedS = (*OpenedF)->status();
1599 ASSERT_FALSE(OpenedS.getError());
1600 EXPECT_EQ("//root/mappeddir2/a", OpenedS->getName());
1601 EXPECT_TRUE(OpenedS->IsVFSMapped);
1602 EXPECT_FALSE(OpenedS->ExposesExternalVFSPath);
1604 // broken mapping
1605 EXPECT_EQ(O->status("//root/file2").getError(),
1606 llvm::errc::no_such_file_or_directory);
1607 EXPECT_EQ(0, NumDiagnostics);
1610 TEST_F(VFSFromYAMLTest, MappedRoot) {
1611 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1612 Lower->addDirectory("//root/foo/bar");
1613 Lower->addRegularFile("//root/foo/bar/a");
1614 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1615 getFromYAMLString("{ 'roots': [\n"
1616 "{\n"
1617 " 'type': 'directory-remap',\n"
1618 " 'name': '//mappedroot/',\n"
1619 " 'external-contents': '//root/foo/bar'\n"
1620 "}\n"
1621 "]\n"
1622 "}",
1623 Lower);
1624 ASSERT_NE(FS.get(), nullptr);
1626 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1627 new vfs::OverlayFileSystem(Lower));
1628 O->pushOverlay(FS);
1630 // file
1631 ErrorOr<vfs::Status> S = O->status("//mappedroot/a");
1632 ASSERT_FALSE(S.getError());
1633 EXPECT_EQ("//root/foo/bar/a", S->getName());
1634 EXPECT_TRUE(S->IsVFSMapped);
1635 EXPECT_TRUE(S->ExposesExternalVFSPath);
1637 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
1638 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
1639 EXPECT_TRUE(S->equivalent(*SLower));
1640 EXPECT_FALSE(SLower->IsVFSMapped);
1641 EXPECT_FALSE(SLower->ExposesExternalVFSPath);
1643 // file after opening
1644 auto OpenedF = O->openFileForRead("//mappedroot/a");
1645 ASSERT_FALSE(OpenedF.getError());
1646 auto OpenedS = (*OpenedF)->status();
1647 ASSERT_FALSE(OpenedS.getError());
1648 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
1649 EXPECT_TRUE(OpenedS->IsVFSMapped);
1650 EXPECT_TRUE(OpenedS->ExposesExternalVFSPath);
1652 EXPECT_EQ(0, NumDiagnostics);
1655 TEST_F(VFSFromYAMLTest, RemappedDirectoryOverlay) {
1656 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1657 Lower->addDirectory("//root/foo");
1658 Lower->addRegularFile("//root/foo/a");
1659 Lower->addDirectory("//root/bar");
1660 Lower->addRegularFile("//root/bar/b");
1661 Lower->addRegularFile("//root/bar/c");
1662 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1663 getFromYAMLString("{ 'roots': [\n"
1664 "{\n"
1665 " 'type': 'directory',\n"
1666 " 'name': '//root/',\n"
1667 " 'contents': [ {\n"
1668 " 'type': 'directory-remap',\n"
1669 " 'name': 'bar',\n"
1670 " 'external-contents': '//root/foo'\n"
1671 " }\n"
1672 " ]\n"
1673 "}]}",
1674 Lower);
1675 ASSERT_NE(FS.get(), nullptr);
1677 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1678 new vfs::OverlayFileSystem(Lower));
1679 O->pushOverlay(FS);
1681 ErrorOr<vfs::Status> S = O->status("//root/foo");
1682 ASSERT_FALSE(S.getError());
1684 ErrorOr<vfs::Status> SS = O->status("//root/bar");
1685 ASSERT_FALSE(SS.getError());
1686 EXPECT_TRUE(S->equivalent(*SS));
1688 std::error_code EC;
1689 checkContents(O->dir_begin("//root/bar", EC),
1690 {"//root/foo/a", "//root/bar/b", "//root/bar/c"});
1692 Lower->addRegularFile("//root/foo/b");
1693 checkContents(O->dir_begin("//root/bar", EC),
1694 {"//root/foo/a", "//root/foo/b", "//root/bar/c"});
1696 EXPECT_EQ(0, NumDiagnostics);
1699 TEST_F(VFSFromYAMLTest, RemappedDirectoryOverlayNoExternalNames) {
1700 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1701 Lower->addDirectory("//root/foo");
1702 Lower->addRegularFile("//root/foo/a");
1703 Lower->addDirectory("//root/bar");
1704 Lower->addRegularFile("//root/bar/b");
1705 Lower->addRegularFile("//root/bar/c");
1706 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1707 getFromYAMLString("{ 'use-external-names': false,\n"
1708 " 'roots': [\n"
1709 "{\n"
1710 " 'type': 'directory',\n"
1711 " 'name': '//root/',\n"
1712 " 'contents': [ {\n"
1713 " 'type': 'directory-remap',\n"
1714 " 'name': 'bar',\n"
1715 " 'external-contents': '//root/foo'\n"
1716 " }\n"
1717 " ]\n"
1718 "}]}",
1719 Lower);
1720 ASSERT_NE(FS.get(), nullptr);
1722 ErrorOr<vfs::Status> S = FS->status("//root/foo");
1723 ASSERT_FALSE(S.getError());
1725 ErrorOr<vfs::Status> SS = FS->status("//root/bar");
1726 ASSERT_FALSE(SS.getError());
1727 EXPECT_TRUE(S->equivalent(*SS));
1729 std::error_code EC;
1730 checkContents(FS->dir_begin("//root/bar", EC),
1731 {"//root/bar/a", "//root/bar/b", "//root/bar/c"});
1733 Lower->addRegularFile("//root/foo/b");
1734 checkContents(FS->dir_begin("//root/bar", EC),
1735 {"//root/bar/a", "//root/bar/b", "//root/bar/c"});
1737 EXPECT_EQ(0, NumDiagnostics);
1740 TEST_F(VFSFromYAMLTest, RemappedDirectoryOverlayNoFallthrough) {
1741 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1742 Lower->addDirectory("//root/foo");
1743 Lower->addRegularFile("//root/foo/a");
1744 Lower->addDirectory("//root/bar");
1745 Lower->addRegularFile("//root/bar/b");
1746 Lower->addRegularFile("//root/bar/c");
1747 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1748 getFromYAMLString("{ 'fallthrough': false,\n"
1749 " 'roots': [\n"
1750 "{\n"
1751 " 'type': 'directory',\n"
1752 " 'name': '//root/',\n"
1753 " 'contents': [ {\n"
1754 " 'type': 'directory-remap',\n"
1755 " 'name': 'bar',\n"
1756 " 'external-contents': '//root/foo'\n"
1757 " }\n"
1758 " ]\n"
1759 "}]}",
1760 Lower);
1761 ASSERT_NE(FS.get(), nullptr);
1763 ErrorOr<vfs::Status> S = Lower->status("//root/foo");
1764 ASSERT_FALSE(S.getError());
1766 ErrorOr<vfs::Status> SS = FS->status("//root/bar");
1767 ASSERT_FALSE(SS.getError());
1768 EXPECT_TRUE(S->equivalent(*SS));
1770 std::error_code EC;
1771 checkContents(FS->dir_begin("//root/bar", EC), {"//root/foo/a"});
1773 Lower->addRegularFile("//root/foo/b");
1774 checkContents(FS->dir_begin("//root/bar", EC),
1775 {"//root/foo/a", "//root/foo/b"});
1777 EXPECT_EQ(0, NumDiagnostics);
1780 TEST_F(VFSFromYAMLTest, ReturnsRequestedPathVFSMiss) {
1781 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS(
1782 new vfs::InMemoryFileSystem);
1783 BaseFS->addFile("//root/foo/a", 0,
1784 MemoryBuffer::getMemBuffer("contents of a"));
1785 ASSERT_FALSE(BaseFS->setCurrentWorkingDirectory("//root/foo"));
1786 auto RemappedFS = vfs::RedirectingFileSystem::create(
1787 {}, /*UseExternalNames=*/false, *BaseFS);
1789 auto OpenedF = RemappedFS->openFileForRead("a");
1790 ASSERT_FALSE(OpenedF.getError());
1791 llvm::ErrorOr<std::string> Name = (*OpenedF)->getName();
1792 ASSERT_FALSE(Name.getError());
1793 EXPECT_EQ("a", Name.get());
1795 auto OpenedS = (*OpenedF)->status();
1796 ASSERT_FALSE(OpenedS.getError());
1797 EXPECT_EQ("a", OpenedS->getName());
1798 EXPECT_FALSE(OpenedS->IsVFSMapped);
1799 EXPECT_FALSE(OpenedS->ExposesExternalVFSPath);
1801 auto DirectS = RemappedFS->status("a");
1802 ASSERT_FALSE(DirectS.getError());
1803 EXPECT_EQ("a", DirectS->getName());
1804 EXPECT_FALSE(DirectS->IsVFSMapped);
1805 EXPECT_FALSE(DirectS->ExposesExternalVFSPath);
1807 EXPECT_EQ(0, NumDiagnostics);
1810 TEST_F(VFSFromYAMLTest, ReturnsExternalPathVFSHit) {
1811 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS(
1812 new vfs::InMemoryFileSystem);
1813 BaseFS->addFile("//root/foo/realname", 0,
1814 MemoryBuffer::getMemBuffer("contents of a"));
1815 auto FS =
1816 getFromYAMLString("{ 'use-external-names': true,\n"
1817 " 'roots': [\n"
1818 "{\n"
1819 " 'type': 'directory',\n"
1820 " 'name': '//root/foo',\n"
1821 " 'contents': [ {\n"
1822 " 'type': 'file',\n"
1823 " 'name': 'vfsname',\n"
1824 " 'external-contents': 'realname'\n"
1825 " }\n"
1826 " ]\n"
1827 "}]}",
1828 BaseFS);
1829 ASSERT_FALSE(FS->setCurrentWorkingDirectory("//root/foo"));
1831 auto OpenedF = FS->openFileForRead("vfsname");
1832 ASSERT_FALSE(OpenedF.getError());
1833 llvm::ErrorOr<std::string> Name = (*OpenedF)->getName();
1834 ASSERT_FALSE(Name.getError());
1835 EXPECT_EQ("realname", Name.get());
1837 auto OpenedS = (*OpenedF)->status();
1838 ASSERT_FALSE(OpenedS.getError());
1839 EXPECT_EQ("realname", OpenedS->getName());
1840 EXPECT_TRUE(OpenedS->IsVFSMapped);
1841 EXPECT_TRUE(OpenedS->ExposesExternalVFSPath);
1843 auto DirectS = FS->status("vfsname");
1844 ASSERT_FALSE(DirectS.getError());
1845 EXPECT_EQ("realname", DirectS->getName());
1846 EXPECT_TRUE(DirectS->IsVFSMapped);
1847 EXPECT_TRUE(DirectS->ExposesExternalVFSPath);
1849 EXPECT_EQ(0, NumDiagnostics);
1852 TEST_F(VFSFromYAMLTest, ReturnsInternalPathVFSHit) {
1853 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS(
1854 new vfs::InMemoryFileSystem);
1855 BaseFS->addFile("//root/foo/realname", 0,
1856 MemoryBuffer::getMemBuffer("contents of a"));
1857 auto FS =
1858 getFromYAMLString("{ 'use-external-names': false,\n"
1859 " 'roots': [\n"
1860 "{\n"
1861 " 'type': 'directory',\n"
1862 " 'name': '//root/foo',\n"
1863 " 'contents': [ {\n"
1864 " 'type': 'file',\n"
1865 " 'name': 'vfsname',\n"
1866 " 'external-contents': 'realname'\n"
1867 " }\n"
1868 " ]\n"
1869 "}]}",
1870 BaseFS);
1871 ASSERT_FALSE(FS->setCurrentWorkingDirectory("//root/foo"));
1873 auto OpenedF = FS->openFileForRead("vfsname");
1874 ASSERT_FALSE(OpenedF.getError());
1875 llvm::ErrorOr<std::string> Name = (*OpenedF)->getName();
1876 ASSERT_FALSE(Name.getError());
1877 EXPECT_EQ("vfsname", Name.get());
1879 auto OpenedS = (*OpenedF)->status();
1880 ASSERT_FALSE(OpenedS.getError());
1881 EXPECT_EQ("vfsname", OpenedS->getName());
1882 EXPECT_TRUE(OpenedS->IsVFSMapped);
1883 EXPECT_FALSE(OpenedS->ExposesExternalVFSPath);
1885 auto DirectS = FS->status("vfsname");
1886 ASSERT_FALSE(DirectS.getError());
1887 EXPECT_EQ("vfsname", DirectS->getName());
1888 EXPECT_TRUE(DirectS->IsVFSMapped);
1889 EXPECT_FALSE(DirectS->ExposesExternalVFSPath);
1891 EXPECT_EQ(0, NumDiagnostics);
1894 TEST_F(VFSFromYAMLTest, CaseInsensitive) {
1895 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1896 Lower->addRegularFile("//root/foo/bar/a");
1897 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1898 "{ 'case-sensitive': 'false',\n"
1899 " 'roots': [\n"
1900 "{\n"
1901 " 'type': 'directory',\n"
1902 " 'name': '//root/',\n"
1903 " 'contents': [ {\n"
1904 " 'type': 'file',\n"
1905 " 'name': 'XX',\n"
1906 " 'external-contents': '//root/foo/bar/a'\n"
1907 " }\n"
1908 " ]\n"
1909 "}]}",
1910 Lower);
1911 ASSERT_NE(FS.get(), nullptr);
1913 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1914 new vfs::OverlayFileSystem(Lower));
1915 O->pushOverlay(FS);
1917 ErrorOr<vfs::Status> S = O->status("//root/XX");
1918 ASSERT_FALSE(S.getError());
1920 ErrorOr<vfs::Status> SS = O->status("//root/xx");
1921 ASSERT_FALSE(SS.getError());
1922 EXPECT_TRUE(S->equivalent(*SS));
1923 SS = O->status("//root/xX");
1924 EXPECT_TRUE(S->equivalent(*SS));
1925 SS = O->status("//root/Xx");
1926 EXPECT_TRUE(S->equivalent(*SS));
1927 EXPECT_EQ(0, NumDiagnostics);
1930 TEST_F(VFSFromYAMLTest, CaseSensitive) {
1931 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1932 Lower->addRegularFile("//root/foo/bar/a");
1933 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1934 "{ 'case-sensitive': 'true',\n"
1935 " 'roots': [\n"
1936 "{\n"
1937 " 'type': 'directory',\n"
1938 " 'name': '//root/',\n"
1939 " 'contents': [ {\n"
1940 " 'type': 'file',\n"
1941 " 'name': 'XX',\n"
1942 " 'external-contents': '//root/foo/bar/a'\n"
1943 " }\n"
1944 " ]\n"
1945 "}]}",
1946 Lower);
1947 ASSERT_NE(FS.get(), nullptr);
1949 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1950 new vfs::OverlayFileSystem(Lower));
1951 O->pushOverlay(FS);
1953 ErrorOr<vfs::Status> SS = O->status("//root/xx");
1954 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1955 SS = O->status("//root/xX");
1956 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1957 SS = O->status("//root/Xx");
1958 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1959 EXPECT_EQ(0, NumDiagnostics);
1962 TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
1963 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1965 // invalid YAML at top-level
1966 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
1967 EXPECT_EQ(nullptr, FS.get());
1968 // invalid YAML in roots
1969 FS = getFromYAMLString("{ 'roots':[}", Lower);
1970 // invalid YAML in directory
1971 FS = getFromYAMLString(
1972 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
1973 Lower);
1974 EXPECT_EQ(nullptr, FS.get());
1976 // invalid configuration
1977 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
1978 EXPECT_EQ(nullptr, FS.get());
1979 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
1980 EXPECT_EQ(nullptr, FS.get());
1982 // invalid roots
1983 FS = getFromYAMLString("{ 'roots':'' }", Lower);
1984 EXPECT_EQ(nullptr, FS.get());
1985 FS = getFromYAMLString("{ 'roots':{} }", Lower);
1986 EXPECT_EQ(nullptr, FS.get());
1988 // invalid entries
1989 FS = getFromYAMLString(
1990 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
1991 EXPECT_EQ(nullptr, FS.get());
1992 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
1993 "'external-contents': 'other' }",
1994 Lower);
1995 EXPECT_EQ(nullptr, FS.get());
1996 FS = getFromYAMLString(
1997 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1998 Lower);
1999 EXPECT_EQ(nullptr, FS.get());
2000 FS = getFromYAMLString(
2001 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
2002 Lower);
2003 EXPECT_EQ(nullptr, FS.get());
2004 FS = getFromYAMLString(
2005 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
2006 Lower);
2007 EXPECT_EQ(nullptr, FS.get());
2008 FS = getFromYAMLString(
2009 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
2010 Lower);
2011 EXPECT_EQ(nullptr, FS.get());
2012 FS = getFromYAMLString(
2013 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
2014 Lower);
2015 EXPECT_EQ(nullptr, FS.get());
2017 // missing mandatory fields
2018 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
2019 EXPECT_EQ(nullptr, FS.get());
2020 FS = getFromYAMLString(
2021 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
2022 EXPECT_EQ(nullptr, FS.get());
2023 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
2024 EXPECT_EQ(nullptr, FS.get());
2026 // duplicate keys
2027 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
2028 EXPECT_EQ(nullptr, FS.get());
2029 FS = getFromYAMLString(
2030 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
2031 Lower);
2032 EXPECT_EQ(nullptr, FS.get());
2033 FS =
2034 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
2035 "'external-contents':'blah' } ] }",
2036 Lower);
2037 EXPECT_EQ(nullptr, FS.get());
2039 // missing version
2040 FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
2041 EXPECT_EQ(nullptr, FS.get());
2043 // bad version number
2044 FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
2045 EXPECT_EQ(nullptr, FS.get());
2046 FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
2047 EXPECT_EQ(nullptr, FS.get());
2048 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
2049 EXPECT_EQ(nullptr, FS.get());
2051 // both 'external-contents' and 'contents' specified
2052 Lower->addDirectory("//root/external/dir");
2053 FS = getFromYAMLString(
2054 "{ 'roots':[ \n"
2055 "{ 'type': 'directory', 'name': '//root/A', 'contents': [],\n"
2056 " 'external-contents': '//root/external/dir'}]}",
2057 Lower);
2058 EXPECT_EQ(nullptr, FS.get());
2060 // 'directory-remap' with 'contents'
2061 FS = getFromYAMLString(
2062 "{ 'roots':[ \n"
2063 "{ 'type': 'directory-remap', 'name': '//root/A', 'contents': [] }]}",
2064 Lower);
2065 EXPECT_EQ(nullptr, FS.get());
2067 // invalid redirect kind
2068 FS = getFromYAMLString("{ 'redirecting-with': 'none', 'roots': [{\n"
2069 " 'type': 'directory-remap',\n"
2070 " 'name': '//root/A',\n"
2071 " 'external-contents': '//root/B' }]}",
2072 Lower);
2073 EXPECT_EQ(nullptr, FS.get());
2075 // redirect and fallthrough passed
2076 FS = getFromYAMLString("{ 'redirecting-with': 'fallthrough',\n"
2077 " 'fallthrough': true,\n"
2078 " 'roots': [{\n"
2079 " 'type': 'directory-remap',\n"
2080 " 'name': '//root/A',\n"
2081 " 'external-contents': '//root/B' }]}",
2082 Lower);
2083 EXPECT_EQ(nullptr, FS.get());
2085 EXPECT_EQ(28, NumDiagnostics);
2088 TEST_F(VFSFromYAMLTest, UseExternalName) {
2089 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2090 Lower->addRegularFile("//root/external/file");
2092 IntrusiveRefCntPtr<vfs::FileSystem> FS =
2093 getFromYAMLString("{ 'roots': [\n"
2094 " { 'type': 'file', 'name': '//root/A',\n"
2095 " 'external-contents': '//root/external/file'\n"
2096 " },\n"
2097 " { 'type': 'file', 'name': '//root/B',\n"
2098 " 'use-external-name': true,\n"
2099 " 'external-contents': '//root/external/file'\n"
2100 " },\n"
2101 " { 'type': 'file', 'name': '//root/C',\n"
2102 " 'use-external-name': false,\n"
2103 " 'external-contents': '//root/external/file'\n"
2104 " }\n"
2105 "] }",
2106 Lower);
2107 ASSERT_NE(nullptr, FS.get());
2109 // default true
2110 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
2111 // explicit
2112 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
2113 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
2115 // global configuration
2116 FS = getFromYAMLString("{ 'use-external-names': false,\n"
2117 " 'roots': [\n"
2118 " { 'type': 'file', 'name': '//root/A',\n"
2119 " 'external-contents': '//root/external/file'\n"
2120 " },\n"
2121 " { 'type': 'file', 'name': '//root/B',\n"
2122 " 'use-external-name': true,\n"
2123 " 'external-contents': '//root/external/file'\n"
2124 " },\n"
2125 " { 'type': 'file', 'name': '//root/C',\n"
2126 " 'use-external-name': false,\n"
2127 " 'external-contents': '//root/external/file'\n"
2128 " }\n"
2129 "] }",
2130 Lower);
2131 ASSERT_NE(nullptr, FS.get());
2133 // default
2134 EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
2135 // explicit
2136 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
2137 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
2140 TEST_F(VFSFromYAMLTest, MultiComponentPath) {
2141 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2142 Lower->addRegularFile("//root/other");
2144 // file in roots
2145 IntrusiveRefCntPtr<vfs::FileSystem> FS =
2146 getFromYAMLString("{ 'roots': [\n"
2147 " { 'type': 'file', 'name': '//root/path/to/file',\n"
2148 " 'external-contents': '//root/other' }]\n"
2149 "}",
2150 Lower);
2151 ASSERT_NE(nullptr, FS.get());
2152 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
2153 EXPECT_FALSE(FS->status("//root/path/to").getError());
2154 EXPECT_FALSE(FS->status("//root/path").getError());
2155 EXPECT_FALSE(FS->status("//root/").getError());
2157 // at the start
2158 FS = getFromYAMLString(
2159 "{ 'roots': [\n"
2160 " { 'type': 'directory', 'name': '//root/path/to',\n"
2161 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
2162 " 'external-contents': '//root/other' }]}]\n"
2163 "}",
2164 Lower);
2165 ASSERT_NE(nullptr, FS.get());
2166 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
2167 EXPECT_FALSE(FS->status("//root/path/to").getError());
2168 EXPECT_FALSE(FS->status("//root/path").getError());
2169 EXPECT_FALSE(FS->status("//root/").getError());
2171 // at the end
2172 FS = getFromYAMLString(
2173 "{ 'roots': [\n"
2174 " { 'type': 'directory', 'name': '//root/',\n"
2175 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
2176 " 'external-contents': '//root/other' }]}]\n"
2177 "}",
2178 Lower);
2179 ASSERT_NE(nullptr, FS.get());
2180 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
2181 EXPECT_FALSE(FS->status("//root/path/to").getError());
2182 EXPECT_FALSE(FS->status("//root/path").getError());
2183 EXPECT_FALSE(FS->status("//root/").getError());
2186 TEST_F(VFSFromYAMLTest, TrailingSlashes) {
2187 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2188 Lower->addRegularFile("//root/other");
2190 // file in roots
2191 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2192 "{ 'roots': [\n"
2193 " { 'type': 'directory', 'name': '//root/path/to////',\n"
2194 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
2195 " 'external-contents': '//root/other' }]}]\n"
2196 "}",
2197 Lower);
2198 ASSERT_NE(nullptr, FS.get());
2199 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
2200 EXPECT_FALSE(FS->status("//root/path/to").getError());
2201 EXPECT_FALSE(FS->status("//root/path").getError());
2202 EXPECT_FALSE(FS->status("//root/").getError());
2205 TEST_F(VFSFromYAMLTest, DirectoryIteration) {
2206 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2207 Lower->addDirectory("//root/");
2208 Lower->addDirectory("//root/foo");
2209 Lower->addDirectory("//root/foo/bar");
2210 Lower->addRegularFile("//root/foo/bar/a");
2211 Lower->addRegularFile("//root/foo/bar/b");
2212 Lower->addRegularFile("//root/file3");
2213 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2214 "{ 'use-external-names': false,\n"
2215 " 'roots': [\n"
2216 "{\n"
2217 " 'type': 'directory',\n"
2218 " 'name': '//root/',\n"
2219 " 'contents': [ {\n"
2220 " 'type': 'file',\n"
2221 " 'name': 'file1',\n"
2222 " 'external-contents': '//root/foo/bar/a'\n"
2223 " },\n"
2224 " {\n"
2225 " 'type': 'file',\n"
2226 " 'name': 'file2',\n"
2227 " 'external-contents': '//root/foo/bar/b'\n"
2228 " }\n"
2229 " ]\n"
2230 "}\n"
2231 "]\n"
2232 "}",
2233 Lower);
2234 ASSERT_NE(FS.get(), nullptr);
2236 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
2237 new vfs::OverlayFileSystem(Lower));
2238 O->pushOverlay(FS);
2240 std::error_code EC;
2241 checkContents(O->dir_begin("//root/", EC),
2242 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
2244 checkContents(O->dir_begin("//root/foo/bar", EC),
2245 {"//root/foo/bar/a", "//root/foo/bar/b"});
2248 TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
2249 // https://llvm.org/bugs/show_bug.cgi?id=27725
2250 if (!supportsSameDirMultipleYAMLEntries())
2251 GTEST_SKIP();
2253 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2254 Lower->addDirectory("//root/zab");
2255 Lower->addDirectory("//root/baz");
2256 Lower->addRegularFile("//root/zab/a");
2257 Lower->addRegularFile("//root/zab/b");
2258 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2259 "{ 'use-external-names': false,\n"
2260 " 'roots': [\n"
2261 "{\n"
2262 " 'type': 'directory',\n"
2263 " 'name': '//root/baz/',\n"
2264 " 'contents': [ {\n"
2265 " 'type': 'file',\n"
2266 " 'name': 'x',\n"
2267 " 'external-contents': '//root/zab/a'\n"
2268 " }\n"
2269 " ]\n"
2270 "},\n"
2271 "{\n"
2272 " 'type': 'directory',\n"
2273 " 'name': '//root/baz/',\n"
2274 " 'contents': [ {\n"
2275 " 'type': 'file',\n"
2276 " 'name': 'y',\n"
2277 " 'external-contents': '//root/zab/b'\n"
2278 " }\n"
2279 " ]\n"
2280 "}\n"
2281 "]\n"
2282 "}",
2283 Lower);
2284 ASSERT_NE(FS.get(), nullptr);
2286 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
2287 new vfs::OverlayFileSystem(Lower));
2288 O->pushOverlay(FS);
2290 std::error_code EC;
2292 checkContents(O->dir_begin("//root/baz/", EC),
2293 {"//root/baz/x", "//root/baz/y"});
2296 TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
2298 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2299 Lower->addDirectory("//root/a");
2300 Lower->addDirectory("//root/a/b");
2301 Lower->addDirectory("//root/a/b/c");
2302 Lower->addRegularFile("//root/a/b/c/file");
2303 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2304 "{ 'use-external-names': false,\n"
2305 " 'roots': [\n"
2306 "{\n"
2307 " 'type': 'directory',\n"
2308 " 'name': '//root/a/b/c/',\n"
2309 " 'contents': [ {\n"
2310 " 'type': 'file',\n"
2311 " 'name': 'file',\n"
2312 " 'external-contents': '//root/a/b/c/file'\n"
2313 " }\n"
2314 " ]\n"
2315 "},\n"
2316 "]\n"
2317 "}",
2318 Lower);
2319 ASSERT_NE(FS.get(), nullptr);
2321 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
2322 new vfs::OverlayFileSystem(Lower));
2323 O->pushOverlay(FS);
2325 std::error_code EC;
2327 // Test recursive_directory_iterator level()
2328 vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
2329 *O, "//root", EC),
2331 ASSERT_FALSE(EC);
2332 for (int l = 0; I != E; I.increment(EC), ++l) {
2333 ASSERT_FALSE(EC);
2334 EXPECT_EQ(I.level(), l);
2336 EXPECT_EQ(I, E);
2339 TEST_F(VFSFromYAMLTest, RelativePaths) {
2340 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2341 std::error_code EC;
2342 SmallString<128> CWD;
2343 EC = llvm::sys::fs::current_path(CWD);
2344 ASSERT_FALSE(EC);
2346 // Filename at root level without a parent directory.
2347 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2348 "{ 'roots': [\n"
2349 " { 'type': 'file', 'name': 'file-not-in-directory.h',\n"
2350 " 'external-contents': '//root/external/file'\n"
2351 " }\n"
2352 "] }",
2353 Lower);
2354 ASSERT_TRUE(FS.get() != nullptr);
2355 SmallString<128> ExpectedPathNotInDir("file-not-in-directory.h");
2356 llvm::sys::fs::make_absolute(ExpectedPathNotInDir);
2357 checkContents(FS->dir_begin(CWD, EC), {ExpectedPathNotInDir});
2359 // Relative file path.
2360 FS = getFromYAMLString("{ 'roots': [\n"
2361 " { 'type': 'file', 'name': 'relative/path.h',\n"
2362 " 'external-contents': '//root/external/file'\n"
2363 " }\n"
2364 "] }",
2365 Lower);
2366 ASSERT_TRUE(FS.get() != nullptr);
2367 SmallString<128> Parent("relative");
2368 llvm::sys::fs::make_absolute(Parent);
2369 auto I = FS->dir_begin(Parent, EC);
2370 ASSERT_FALSE(EC);
2371 // Convert to POSIX path for comparison of windows paths
2372 ASSERT_EQ("relative/path.h",
2373 getPosixPath(std::string(I->path().substr(CWD.size() + 1))));
2375 // Relative directory path.
2376 FS = getFromYAMLString(
2377 "{ 'roots': [\n"
2378 " { 'type': 'directory', 'name': 'relative/directory/path.h',\n"
2379 " 'contents': []\n"
2380 " }\n"
2381 "] }",
2382 Lower);
2383 ASSERT_TRUE(FS.get() != nullptr);
2384 SmallString<128> Root("relative/directory");
2385 llvm::sys::fs::make_absolute(Root);
2386 I = FS->dir_begin(Root, EC);
2387 ASSERT_FALSE(EC);
2388 ASSERT_EQ("path.h", std::string(I->path().substr(Root.size() + 1)));
2390 EXPECT_EQ(0, NumDiagnostics);
2393 TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) {
2394 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2395 Lower->addDirectory("//root/");
2396 Lower->addRegularFile("//root/a");
2397 Lower->addRegularFile("//root/b");
2398 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2399 "{ 'use-external-names': false,\n"
2400 " 'fallthrough': false,\n"
2401 " 'roots': [\n"
2402 "{\n"
2403 " 'type': 'directory',\n"
2404 " 'name': '//root/',\n"
2405 " 'contents': [ {\n"
2406 " 'type': 'file',\n"
2407 " 'name': 'c',\n"
2408 " 'external-contents': '//root/a'\n"
2409 " }\n"
2410 " ]\n"
2411 "}\n"
2412 "]\n"
2413 "}",
2414 Lower);
2415 ASSERT_NE(FS.get(), nullptr);
2417 std::error_code EC;
2418 checkContents(FS->dir_begin("//root/", EC),
2419 {"//root/c"});
2422 TEST_F(VFSFromYAMLTest, DirectoryIterationWithDuplicates) {
2423 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2424 Lower->addDirectory("//root/");
2425 Lower->addRegularFile("//root/a");
2426 Lower->addRegularFile("//root/b");
2427 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2428 "{ 'use-external-names': false,\n"
2429 " 'roots': [\n"
2430 "{\n"
2431 " 'type': 'directory',\n"
2432 " 'name': '//root/',\n"
2433 " 'contents': [ {\n"
2434 " 'type': 'file',\n"
2435 " 'name': 'a',\n"
2436 " 'external-contents': '//root/a'\n"
2437 " }\n"
2438 " ]\n"
2439 "}\n"
2440 "]\n"
2441 "}",
2442 Lower);
2443 ASSERT_NE(FS.get(), nullptr);
2445 std::error_code EC;
2446 checkContents(FS->dir_begin("//root/", EC),
2447 {"//root/a", "//root/b"});
2450 TEST_F(VFSFromYAMLTest, DirectoryIterationErrorInVFSLayer) {
2451 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2452 Lower->addDirectory("//root/");
2453 Lower->addDirectory("//root/foo");
2454 Lower->addRegularFile("//root/foo/a");
2455 Lower->addRegularFile("//root/foo/b");
2456 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2457 "{ 'use-external-names': false,\n"
2458 " 'roots': [\n"
2459 "{\n"
2460 " 'type': 'directory',\n"
2461 " 'name': '//root/',\n"
2462 " 'contents': [ {\n"
2463 " 'type': 'file',\n"
2464 " 'name': 'bar/a',\n"
2465 " 'external-contents': '//root/foo/a'\n"
2466 " }\n"
2467 " ]\n"
2468 "}\n"
2469 "]\n"
2470 "}",
2471 Lower);
2472 ASSERT_NE(FS.get(), nullptr);
2474 std::error_code EC;
2475 checkContents(FS->dir_begin("//root/foo", EC),
2476 {"//root/foo/a", "//root/foo/b"});
2479 TEST_F(VFSFromYAMLTest, GetRealPath) {
2480 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2481 Lower->addDirectory("//dir/");
2482 Lower->addRegularFile("/foo");
2483 Lower->addSymlink("/link");
2484 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2485 "{ 'use-external-names': false,\n"
2486 " 'roots': [\n"
2487 "{\n"
2488 " 'type': 'directory',\n"
2489 " 'name': '//root/',\n"
2490 " 'contents': [ {\n"
2491 " 'type': 'file',\n"
2492 " 'name': 'bar',\n"
2493 " 'external-contents': '/link'\n"
2494 " }\n"
2495 " ]\n"
2496 "},\n"
2497 "{\n"
2498 " 'type': 'directory',\n"
2499 " 'name': '//dir/',\n"
2500 " 'contents': []\n"
2501 "}\n"
2502 "]\n"
2503 "}",
2504 Lower);
2505 ASSERT_NE(FS.get(), nullptr);
2507 // Regular file present in underlying file system.
2508 SmallString<16> RealPath;
2509 EXPECT_FALSE(FS->getRealPath("/foo", RealPath));
2510 EXPECT_EQ(RealPath.str(), "/foo");
2512 // File present in YAML pointing to symlink in underlying file system.
2513 EXPECT_FALSE(FS->getRealPath("//root/bar", RealPath));
2514 EXPECT_EQ(RealPath.str(), "/symlink");
2516 // Directories should fall back to the underlying file system is possible.
2517 EXPECT_FALSE(FS->getRealPath("//dir/", RealPath));
2518 EXPECT_EQ(RealPath.str(), "//dir/");
2520 // Try a non-existing file.
2521 EXPECT_EQ(FS->getRealPath("/non_existing", RealPath),
2522 errc::no_such_file_or_directory);
2525 TEST_F(VFSFromYAMLTest, WorkingDirectory) {
2526 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2527 Lower->addDirectory("//root/");
2528 Lower->addDirectory("//root/foo");
2529 Lower->addRegularFile("//root/foo/a");
2530 Lower->addRegularFile("//root/foo/b");
2531 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2532 "{ 'use-external-names': false,\n"
2533 " 'roots': [\n"
2534 "{\n"
2535 " 'type': 'directory',\n"
2536 " 'name': '//root/bar',\n"
2537 " 'contents': [ {\n"
2538 " 'type': 'file',\n"
2539 " 'name': 'a',\n"
2540 " 'external-contents': '//root/foo/a'\n"
2541 " }\n"
2542 " ]\n"
2543 "}\n"
2544 "]\n"
2545 "}",
2546 Lower);
2547 ASSERT_NE(FS.get(), nullptr);
2548 std::error_code EC = FS->setCurrentWorkingDirectory("//root/bar");
2549 ASSERT_FALSE(EC);
2551 llvm::ErrorOr<std::string> WorkingDir = FS->getCurrentWorkingDirectory();
2552 ASSERT_TRUE(WorkingDir);
2553 EXPECT_EQ(*WorkingDir, "//root/bar");
2555 llvm::ErrorOr<vfs::Status> Status = FS->status("./a");
2556 ASSERT_FALSE(Status.getError());
2557 EXPECT_TRUE(Status->isStatusKnown());
2558 EXPECT_FALSE(Status->isDirectory());
2559 EXPECT_TRUE(Status->isRegularFile());
2560 EXPECT_FALSE(Status->isSymlink());
2561 EXPECT_FALSE(Status->isOther());
2562 EXPECT_TRUE(Status->exists());
2564 EC = FS->setCurrentWorkingDirectory("bogus");
2565 ASSERT_TRUE(EC);
2566 WorkingDir = FS->getCurrentWorkingDirectory();
2567 ASSERT_TRUE(WorkingDir);
2568 EXPECT_EQ(*WorkingDir, "//root/bar");
2570 EC = FS->setCurrentWorkingDirectory("//root/");
2571 ASSERT_FALSE(EC);
2572 WorkingDir = FS->getCurrentWorkingDirectory();
2573 ASSERT_TRUE(WorkingDir);
2574 EXPECT_EQ(*WorkingDir, "//root/");
2576 EC = FS->setCurrentWorkingDirectory("bar");
2577 ASSERT_FALSE(EC);
2578 WorkingDir = FS->getCurrentWorkingDirectory();
2579 ASSERT_TRUE(WorkingDir);
2580 EXPECT_EQ(*WorkingDir, "//root/bar");
2583 TEST_F(VFSFromYAMLTest, WorkingDirectoryFallthrough) {
2584 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
2585 Lower->addDirectory("//root/");
2586 Lower->addDirectory("//root/foo");
2587 Lower->addRegularFile("//root/foo/a");
2588 Lower->addRegularFile("//root/foo/b");
2589 Lower->addRegularFile("//root/c");
2590 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2591 "{ 'use-external-names': false,\n"
2592 " 'roots': [\n"
2593 "{\n"
2594 " 'type': 'directory',\n"
2595 " 'name': '//root/bar',\n"
2596 " 'contents': [ {\n"
2597 " 'type': 'file',\n"
2598 " 'name': 'a',\n"
2599 " 'external-contents': '//root/foo/a'\n"
2600 " }\n"
2601 " ]\n"
2602 "},\n"
2603 "{\n"
2604 " 'type': 'directory',\n"
2605 " 'name': '//root/bar/baz',\n"
2606 " 'contents': [ {\n"
2607 " 'type': 'file',\n"
2608 " 'name': 'a',\n"
2609 " 'external-contents': '//root/foo/a'\n"
2610 " }\n"
2611 " ]\n"
2612 "}\n"
2613 "]\n"
2614 "}",
2615 Lower);
2616 ASSERT_NE(FS.get(), nullptr);
2617 std::error_code EC = FS->setCurrentWorkingDirectory("//root/");
2618 ASSERT_FALSE(EC);
2619 ASSERT_NE(FS.get(), nullptr);
2621 llvm::ErrorOr<vfs::Status> Status = FS->status("bar/a");
2622 ASSERT_FALSE(Status.getError());
2623 EXPECT_TRUE(Status->exists());
2625 Status = FS->status("foo/a");
2626 ASSERT_FALSE(Status.getError());
2627 EXPECT_TRUE(Status->exists());
2629 EC = FS->setCurrentWorkingDirectory("//root/bar");
2630 ASSERT_FALSE(EC);
2632 Status = FS->status("./a");
2633 ASSERT_FALSE(Status.getError());
2634 EXPECT_TRUE(Status->exists());
2636 Status = FS->status("./b");
2637 ASSERT_TRUE(Status.getError());
2639 Status = FS->status("./c");
2640 ASSERT_TRUE(Status.getError());
2642 EC = FS->setCurrentWorkingDirectory("//root/");
2643 ASSERT_FALSE(EC);
2645 Status = FS->status("c");
2646 ASSERT_FALSE(Status.getError());
2647 EXPECT_TRUE(Status->exists());
2649 Status = FS->status("./bar/baz/a");
2650 ASSERT_FALSE(Status.getError());
2651 EXPECT_TRUE(Status->exists());
2653 EC = FS->setCurrentWorkingDirectory("//root/bar");
2654 ASSERT_FALSE(EC);
2656 Status = FS->status("./baz/a");
2657 ASSERT_FALSE(Status.getError());
2658 EXPECT_TRUE(Status->exists());
2660 Status = FS->status("../bar/baz/a");
2661 ASSERT_FALSE(Status.getError());
2662 EXPECT_TRUE(Status->exists());
2665 TEST_F(VFSFromYAMLTest, WorkingDirectoryFallthroughInvalid) {
2666 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
2667 Lower->addDirectory("//root/");
2668 Lower->addDirectory("//root/foo");
2669 Lower->addRegularFile("//root/foo/a");
2670 Lower->addRegularFile("//root/foo/b");
2671 Lower->addRegularFile("//root/c");
2672 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2673 "{ 'use-external-names': false,\n"
2674 " 'roots': [\n"
2675 "{\n"
2676 " 'type': 'directory',\n"
2677 " 'name': '//root/bar',\n"
2678 " 'contents': [ {\n"
2679 " 'type': 'file',\n"
2680 " 'name': 'a',\n"
2681 " 'external-contents': '//root/foo/a'\n"
2682 " }\n"
2683 " ]\n"
2684 "}\n"
2685 "]\n"
2686 "}",
2687 Lower);
2688 ASSERT_NE(FS.get(), nullptr);
2689 std::error_code EC = FS->setCurrentWorkingDirectory("//root/");
2690 ASSERT_FALSE(EC);
2691 ASSERT_NE(FS.get(), nullptr);
2693 llvm::ErrorOr<vfs::Status> Status = FS->status("bar/a");
2694 ASSERT_FALSE(Status.getError());
2695 EXPECT_TRUE(Status->exists());
2697 Status = FS->status("foo/a");
2698 ASSERT_FALSE(Status.getError());
2699 EXPECT_TRUE(Status->exists());
2702 TEST_F(VFSFromYAMLTest, VirtualWorkingDirectory) {
2703 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
2704 Lower->addDirectory("//root/");
2705 Lower->addDirectory("//root/foo");
2706 Lower->addRegularFile("//root/foo/a");
2707 Lower->addRegularFile("//root/foo/b");
2708 Lower->addRegularFile("//root/c");
2709 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
2710 "{ 'use-external-names': false,\n"
2711 " 'roots': [\n"
2712 "{\n"
2713 " 'type': 'directory',\n"
2714 " 'name': '//root/bar',\n"
2715 " 'contents': [ {\n"
2716 " 'type': 'file',\n"
2717 " 'name': 'a',\n"
2718 " 'external-contents': '//root/foo/a'\n"
2719 " }\n"
2720 " ]\n"
2721 "}\n"
2722 "]\n"
2723 "}",
2724 Lower);
2725 ASSERT_NE(FS.get(), nullptr);
2726 std::error_code EC = FS->setCurrentWorkingDirectory("//root/bar");
2727 ASSERT_FALSE(EC);
2728 ASSERT_NE(FS.get(), nullptr);
2730 llvm::ErrorOr<vfs::Status> Status = FS->status("a");
2731 ASSERT_FALSE(Status.getError());
2732 EXPECT_TRUE(Status->exists());
2735 TEST_F(VFSFromYAMLTest, YAMLVFSWriterTest) {
2736 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
2737 TempDir _a(TestDirectory.path("a"));
2738 TempFile _ab(TestDirectory.path("a, b"));
2739 TempDir _c(TestDirectory.path("c"));
2740 TempFile _cd(TestDirectory.path("c/d"));
2741 TempDir _e(TestDirectory.path("e"));
2742 TempDir _ef(TestDirectory.path("e/f"));
2743 TempFile _g(TestDirectory.path("g"));
2744 TempDir _h(TestDirectory.path("h"));
2746 vfs::YAMLVFSWriter VFSWriter;
2747 VFSWriter.addDirectoryMapping(_a.path(), "//root/a");
2748 VFSWriter.addFileMapping(_ab.path(), "//root/a/b");
2749 VFSWriter.addFileMapping(_cd.path(), "//root/c/d");
2750 VFSWriter.addDirectoryMapping(_e.path(), "//root/e");
2751 VFSWriter.addDirectoryMapping(_ef.path(), "//root/e/f");
2752 VFSWriter.addFileMapping(_g.path(), "//root/g");
2753 VFSWriter.addDirectoryMapping(_h.path(), "//root/h");
2755 std::string Buffer;
2756 raw_string_ostream OS(Buffer);
2757 VFSWriter.write(OS);
2758 OS.flush();
2760 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
2761 Lower->addDirectory("//root/");
2762 Lower->addDirectory("//root/a");
2763 Lower->addRegularFile("//root/a/b");
2764 Lower->addDirectory("//root/b");
2765 Lower->addDirectory("//root/c");
2766 Lower->addRegularFile("//root/c/d");
2767 Lower->addDirectory("//root/e");
2768 Lower->addDirectory("//root/e/f");
2769 Lower->addRegularFile("//root/g");
2770 Lower->addDirectory("//root/h");
2772 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower);
2773 ASSERT_NE(FS.get(), nullptr);
2775 EXPECT_TRUE(FS->exists(_a.path()));
2776 EXPECT_TRUE(FS->exists(_ab.path()));
2777 EXPECT_TRUE(FS->exists(_c.path()));
2778 EXPECT_TRUE(FS->exists(_cd.path()));
2779 EXPECT_TRUE(FS->exists(_e.path()));
2780 EXPECT_TRUE(FS->exists(_ef.path()));
2781 EXPECT_TRUE(FS->exists(_g.path()));
2782 EXPECT_TRUE(FS->exists(_h.path()));
2785 TEST_F(VFSFromYAMLTest, YAMLVFSWriterTest2) {
2786 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
2787 TempDir _a(TestDirectory.path("a"));
2788 TempFile _ab(TestDirectory.path("a/b"));
2789 TempDir _ac(TestDirectory.path("a/c"));
2790 TempFile _acd(TestDirectory.path("a/c/d"));
2791 TempFile _ace(TestDirectory.path("a/c/e"));
2792 TempFile _acf(TestDirectory.path("a/c/f"));
2793 TempDir _ag(TestDirectory.path("a/g"));
2794 TempFile _agh(TestDirectory.path("a/g/h"));
2796 vfs::YAMLVFSWriter VFSWriter;
2797 VFSWriter.addDirectoryMapping(_a.path(), "//root/a");
2798 VFSWriter.addFileMapping(_ab.path(), "//root/a/b");
2799 VFSWriter.addDirectoryMapping(_ac.path(), "//root/a/c");
2800 VFSWriter.addFileMapping(_acd.path(), "//root/a/c/d");
2801 VFSWriter.addFileMapping(_ace.path(), "//root/a/c/e");
2802 VFSWriter.addFileMapping(_acf.path(), "//root/a/c/f");
2803 VFSWriter.addDirectoryMapping(_ag.path(), "//root/a/g");
2804 VFSWriter.addFileMapping(_agh.path(), "//root/a/g/h");
2806 std::string Buffer;
2807 raw_string_ostream OS(Buffer);
2808 VFSWriter.write(OS);
2809 OS.flush();
2811 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
2812 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower);
2813 EXPECT_NE(FS.get(), nullptr);
2816 TEST_F(VFSFromYAMLTest, YAMLVFSWriterTest3) {
2817 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
2818 TempDir _a(TestDirectory.path("a"));
2819 TempFile _ab(TestDirectory.path("a/b"));
2820 TempDir _ac(TestDirectory.path("a/c"));
2821 TempDir _acd(TestDirectory.path("a/c/d"));
2822 TempDir _acde(TestDirectory.path("a/c/d/e"));
2823 TempFile _acdef(TestDirectory.path("a/c/d/e/f"));
2824 TempFile _acdeg(TestDirectory.path("a/c/d/e/g"));
2825 TempDir _ah(TestDirectory.path("a/h"));
2826 TempFile _ahi(TestDirectory.path("a/h/i"));
2828 vfs::YAMLVFSWriter VFSWriter;
2829 VFSWriter.addDirectoryMapping(_a.path(), "//root/a");
2830 VFSWriter.addFileMapping(_ab.path(), "//root/a/b");
2831 VFSWriter.addDirectoryMapping(_ac.path(), "//root/a/c");
2832 VFSWriter.addDirectoryMapping(_acd.path(), "//root/a/c/d");
2833 VFSWriter.addDirectoryMapping(_acde.path(), "//root/a/c/d/e");
2834 VFSWriter.addFileMapping(_acdef.path(), "//root/a/c/d/e/f");
2835 VFSWriter.addFileMapping(_acdeg.path(), "//root/a/c/d/e/g");
2836 VFSWriter.addDirectoryMapping(_ahi.path(), "//root/a/h");
2837 VFSWriter.addFileMapping(_ahi.path(), "//root/a/h/i");
2839 std::string Buffer;
2840 raw_string_ostream OS(Buffer);
2841 VFSWriter.write(OS);
2842 OS.flush();
2844 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
2845 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower);
2846 EXPECT_NE(FS.get(), nullptr);
2849 TEST_F(VFSFromYAMLTest, YAMLVFSWriterTestHandleDirs) {
2850 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
2851 TempDir _a(TestDirectory.path("a"));
2852 TempDir _b(TestDirectory.path("b"));
2853 TempDir _c(TestDirectory.path("c"));
2855 vfs::YAMLVFSWriter VFSWriter;
2856 VFSWriter.addDirectoryMapping(_a.path(), "//root/a");
2857 VFSWriter.addDirectoryMapping(_b.path(), "//root/b");
2858 VFSWriter.addDirectoryMapping(_c.path(), "//root/c");
2860 std::string Buffer;
2861 raw_string_ostream OS(Buffer);
2862 VFSWriter.write(OS);
2863 OS.flush();
2865 // We didn't add a single file - only directories.
2866 EXPECT_EQ(Buffer.find("'type': 'file'"), std::string::npos);
2868 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
2869 Lower->addDirectory("//root/a");
2870 Lower->addDirectory("//root/b");
2871 Lower->addDirectory("//root/c");
2872 // canaries
2873 Lower->addRegularFile("//root/a/a");
2874 Lower->addRegularFile("//root/b/b");
2875 Lower->addRegularFile("//root/c/c");
2877 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower);
2878 ASSERT_NE(FS.get(), nullptr);
2880 EXPECT_FALSE(FS->exists(_a.path("a")));
2881 EXPECT_FALSE(FS->exists(_b.path("b")));
2882 EXPECT_FALSE(FS->exists(_c.path("c")));
2885 TEST_F(VFSFromYAMLTest, RedirectingWith) {
2886 IntrusiveRefCntPtr<DummyFileSystem> Both(new DummyFileSystem());
2887 Both->addDirectory("//root/a");
2888 Both->addRegularFile("//root/a/f");
2889 Both->addDirectory("//root/b");
2890 Both->addRegularFile("//root/b/f");
2892 IntrusiveRefCntPtr<DummyFileSystem> AOnly(new DummyFileSystem());
2893 AOnly->addDirectory("//root/a");
2894 AOnly->addRegularFile("//root/a/f");
2896 IntrusiveRefCntPtr<DummyFileSystem> BOnly(new DummyFileSystem());
2897 BOnly->addDirectory("//root/b");
2898 BOnly->addRegularFile("//root/b/f");
2900 auto BaseStr = std::string(" 'roots': [\n"
2901 " {\n"
2902 " 'type': 'directory-remap',\n"
2903 " 'name': '//root/a',\n"
2904 " 'external-contents': '//root/b'\n"
2905 " }\n"
2906 " ]\n"
2907 "}");
2908 auto FallthroughStr = "{ 'redirecting-with': 'fallthrough',\n" + BaseStr;
2909 auto FallbackStr = "{ 'redirecting-with': 'fallback',\n" + BaseStr;
2910 auto RedirectOnlyStr = "{ 'redirecting-with': 'redirect-only',\n" + BaseStr;
2912 auto ExpectPath = [&](vfs::FileSystem &FS, StringRef Expected,
2913 StringRef Message) {
2914 auto AF = FS.openFileForRead("//root/a/f");
2915 ASSERT_FALSE(AF.getError()) << Message;
2916 auto AFName = (*AF)->getName();
2917 ASSERT_FALSE(AFName.getError()) << Message;
2918 EXPECT_EQ(Expected.str(), AFName.get()) << Message;
2920 auto AS = FS.status("//root/a/f");
2921 ASSERT_FALSE(AS.getError()) << Message;
2922 EXPECT_EQ(Expected.str(), AS->getName()) << Message;
2925 auto ExpectFailure = [&](vfs::FileSystem &FS, StringRef Message) {
2926 EXPECT_TRUE(FS.openFileForRead("//root/a/f").getError()) << Message;
2927 EXPECT_TRUE(FS.status("//root/a/f").getError()) << Message;
2931 // `f` in both `a` and `b`
2933 // `fallthrough` tries `external-name` first, so should be `b`
2934 IntrusiveRefCntPtr<vfs::FileSystem> Fallthrough =
2935 getFromYAMLString(FallthroughStr, Both);
2936 ASSERT_TRUE(Fallthrough.get() != nullptr);
2937 ExpectPath(*Fallthrough, "//root/b/f", "fallthrough, both exist");
2939 // `fallback` tries the original name first, so should be `a`
2940 IntrusiveRefCntPtr<vfs::FileSystem> Fallback =
2941 getFromYAMLString(FallbackStr, Both);
2942 ASSERT_TRUE(Fallback.get() != nullptr);
2943 ExpectPath(*Fallback, "//root/a/f", "fallback, both exist");
2945 // `redirect-only` is the same as `fallthrough` but doesn't try the
2946 // original on failure, so no change here (ie. `b`)
2947 IntrusiveRefCntPtr<vfs::FileSystem> Redirect =
2948 getFromYAMLString(RedirectOnlyStr, Both);
2949 ASSERT_TRUE(Redirect.get() != nullptr);
2950 ExpectPath(*Redirect, "//root/b/f", "redirect-only, both exist");
2954 // `f` in `a` only
2956 // Fallthrough to the original path, `a`
2957 IntrusiveRefCntPtr<vfs::FileSystem> Fallthrough =
2958 getFromYAMLString(FallthroughStr, AOnly);
2959 ASSERT_TRUE(Fallthrough.get() != nullptr);
2960 ExpectPath(*Fallthrough, "//root/a/f", "fallthrough, a only");
2962 // Original first, so still `a`
2963 IntrusiveRefCntPtr<vfs::FileSystem> Fallback =
2964 getFromYAMLString(FallbackStr, AOnly);
2965 ASSERT_TRUE(Fallback.get() != nullptr);
2966 ExpectPath(*Fallback, "//root/a/f", "fallback, a only");
2968 // Fails since no fallthrough
2969 IntrusiveRefCntPtr<vfs::FileSystem> Redirect =
2970 getFromYAMLString(RedirectOnlyStr, AOnly);
2971 ASSERT_TRUE(Redirect.get() != nullptr);
2972 ExpectFailure(*Redirect, "redirect-only, a only");
2976 // `f` in `b` only
2978 // Tries `b` first (no fallthrough)
2979 IntrusiveRefCntPtr<vfs::FileSystem> Fallthrough =
2980 getFromYAMLString(FallthroughStr, BOnly);
2981 ASSERT_TRUE(Fallthrough.get() != nullptr);
2982 ExpectPath(*Fallthrough, "//root/b/f", "fallthrough, b only");
2984 // Tries original first but then fallsback to `b`
2985 IntrusiveRefCntPtr<vfs::FileSystem> Fallback =
2986 getFromYAMLString(FallbackStr, BOnly);
2987 ASSERT_TRUE(Fallback.get() != nullptr);
2988 ExpectPath(*Fallback, "//root/b/f", "fallback, b only");
2990 // Redirect exists, so uses it (`b`)
2991 IntrusiveRefCntPtr<vfs::FileSystem> Redirect =
2992 getFromYAMLString(RedirectOnlyStr, BOnly);
2993 ASSERT_TRUE(Redirect.get() != nullptr);
2994 ExpectPath(*Redirect, "//root/b/f", "redirect-only, b only");
2997 EXPECT_EQ(0, NumDiagnostics);
3000 TEST(VFSFromRemappedFilesTest, Basic) {
3001 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS =
3002 new vfs::InMemoryFileSystem;
3003 BaseFS->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b"));
3004 BaseFS->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c"));
3006 std::vector<std::pair<std::string, std::string>> RemappedFiles = {
3007 {"//root/a/a", "//root/b"},
3008 {"//root/a/b/c", "//root/c"},
3010 auto RemappedFS = vfs::RedirectingFileSystem::create(
3011 RemappedFiles, /*UseExternalNames=*/false, *BaseFS);
3013 auto StatA = RemappedFS->status("//root/a/a");
3014 auto StatB = RemappedFS->status("//root/a/b/c");
3015 ASSERT_TRUE(StatA);
3016 ASSERT_TRUE(StatB);
3017 EXPECT_EQ("//root/a/a", StatA->getName());
3018 EXPECT_EQ("//root/a/b/c", StatB->getName());
3020 auto BufferA = RemappedFS->getBufferForFile("//root/a/a");
3021 auto BufferB = RemappedFS->getBufferForFile("//root/a/b/c");
3022 ASSERT_TRUE(BufferA);
3023 ASSERT_TRUE(BufferB);
3024 EXPECT_EQ("contents of b", (*BufferA)->getBuffer());
3025 EXPECT_EQ("contents of c", (*BufferB)->getBuffer());
3028 TEST(VFSFromRemappedFilesTest, UseExternalNames) {
3029 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS =
3030 new vfs::InMemoryFileSystem;
3031 BaseFS->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b"));
3032 BaseFS->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c"));
3034 std::vector<std::pair<std::string, std::string>> RemappedFiles = {
3035 {"//root/a/a", "//root/b"},
3036 {"//root/a/b/c", "//root/c"},
3038 auto RemappedFS = vfs::RedirectingFileSystem::create(
3039 RemappedFiles, /*UseExternalNames=*/true, *BaseFS);
3041 auto StatA = RemappedFS->status("//root/a/a");
3042 auto StatB = RemappedFS->status("//root/a/b/c");
3043 ASSERT_TRUE(StatA);
3044 ASSERT_TRUE(StatB);
3045 EXPECT_EQ("//root/b", StatA->getName());
3046 EXPECT_EQ("//root/c", StatB->getName());
3048 auto BufferA = RemappedFS->getBufferForFile("//root/a/a");
3049 auto BufferB = RemappedFS->getBufferForFile("//root/a/b/c");
3050 ASSERT_TRUE(BufferA);
3051 ASSERT_TRUE(BufferB);
3052 EXPECT_EQ("contents of b", (*BufferA)->getBuffer());
3053 EXPECT_EQ("contents of c", (*BufferB)->getBuffer());
3056 TEST(VFSFromRemappedFilesTest, LastMappingWins) {
3057 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS =
3058 new vfs::InMemoryFileSystem;
3059 BaseFS->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b"));
3060 BaseFS->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c"));
3062 std::vector<std::pair<std::string, std::string>> RemappedFiles = {
3063 {"//root/a", "//root/b"},
3064 {"//root/a", "//root/c"},
3066 auto RemappedFSKeepName = vfs::RedirectingFileSystem::create(
3067 RemappedFiles, /*UseExternalNames=*/false, *BaseFS);
3068 auto RemappedFSExternalName = vfs::RedirectingFileSystem::create(
3069 RemappedFiles, /*UseExternalNames=*/true, *BaseFS);
3071 auto StatKeepA = RemappedFSKeepName->status("//root/a");
3072 auto StatExternalA = RemappedFSExternalName->status("//root/a");
3073 ASSERT_TRUE(StatKeepA);
3074 ASSERT_TRUE(StatExternalA);
3075 EXPECT_EQ("//root/a", StatKeepA->getName());
3076 EXPECT_EQ("//root/c", StatExternalA->getName());
3078 auto BufferKeepA = RemappedFSKeepName->getBufferForFile("//root/a");
3079 auto BufferExternalA = RemappedFSExternalName->getBufferForFile("//root/a");
3080 ASSERT_TRUE(BufferKeepA);
3081 ASSERT_TRUE(BufferExternalA);
3082 EXPECT_EQ("contents of c", (*BufferKeepA)->getBuffer());
3083 EXPECT_EQ("contents of c", (*BufferExternalA)->getBuffer());
3086 TEST(RedirectingFileSystemTest, PrintOutput) {
3087 auto Buffer =
3088 MemoryBuffer::getMemBuffer("{\n"
3089 " 'version': 0,\n"
3090 " 'roots': [\n"
3091 " {\n"
3092 " 'type': 'directory-remap',\n"
3093 " 'name': '/dremap',\n"
3094 " 'external-contents': '/a',\n"
3095 " },"
3096 " {\n"
3097 " 'type': 'directory',\n"
3098 " 'name': '/vdir',\n"
3099 " 'contents': ["
3100 " {\n"
3101 " 'type': 'directory-remap',\n"
3102 " 'name': 'dremap',\n"
3103 " 'external-contents': '/b'\n"
3104 " 'use-external-name': 'true'\n"
3105 " },\n"
3106 " {\n"
3107 " 'type': 'file',\n"
3108 " 'name': 'vfile',\n"
3109 " 'external-contents': '/c'\n"
3110 " 'use-external-name': 'false'\n"
3111 " }]\n"
3112 " }]\n"
3113 "}");
3115 auto Dummy = makeIntrusiveRefCnt<DummyFileSystem>();
3116 auto Redirecting = vfs::RedirectingFileSystem::create(
3117 std::move(Buffer), nullptr, "", nullptr, Dummy);
3119 SmallString<0> Output;
3120 raw_svector_ostream OuputStream{Output};
3122 Redirecting->print(OuputStream, vfs::FileSystem::PrintType::Summary);
3123 ASSERT_EQ("RedirectingFileSystem (UseExternalNames: true)\n", Output);
3125 Output.clear();
3126 Redirecting->print(OuputStream, vfs::FileSystem::PrintType::Contents);
3127 ASSERT_EQ("RedirectingFileSystem (UseExternalNames: true)\n"
3128 "'/'\n"
3129 " 'dremap' -> '/a'\n"
3130 " 'vdir'\n"
3131 " 'dremap' -> '/b' (UseExternalName: true)\n"
3132 " 'vfile' -> '/c' (UseExternalName: false)\n"
3133 "ExternalFS:\n"
3134 " DummyFileSystem (Summary)\n",
3135 Output);
3137 Output.clear();
3138 Redirecting->print(OuputStream, vfs::FileSystem::PrintType::Contents, 1);
3139 ASSERT_EQ(" RedirectingFileSystem (UseExternalNames: true)\n"
3140 " '/'\n"
3141 " 'dremap' -> '/a'\n"
3142 " 'vdir'\n"
3143 " 'dremap' -> '/b' (UseExternalName: true)\n"
3144 " 'vfile' -> '/c' (UseExternalName: false)\n"
3145 " ExternalFS:\n"
3146 " DummyFileSystem (Summary)\n",
3147 Output);
3149 Output.clear();
3150 Redirecting->print(OuputStream,
3151 vfs::FileSystem::PrintType::RecursiveContents);
3152 ASSERT_EQ("RedirectingFileSystem (UseExternalNames: true)\n"
3153 "'/'\n"
3154 " 'dremap' -> '/a'\n"
3155 " 'vdir'\n"
3156 " 'dremap' -> '/b' (UseExternalName: true)\n"
3157 " 'vfile' -> '/c' (UseExternalName: false)\n"
3158 "ExternalFS:\n"
3159 " DummyFileSystem (RecursiveContents)\n",
3160 Output);