[PowerPC] Do not use vectors to codegen bswap with Altivec turned off
[llvm-core.git] / unittests / Support / VirtualFileSystemTest.cpp
blob458b07e6d4307d58c4bdb880ce44773a52370e7f
1 //===- unittests/Support/VirtualFileSystem.cpp -------------- VFS tests ---===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
10 #include "llvm/Support/VirtualFileSystem.h"
11 #include "llvm/ADT/Triple.h"
12 #include "llvm/Config/llvm-config.h"
13 #include "llvm/Support/Errc.h"
14 #include "llvm/Support/Host.h"
15 #include "llvm/Support/MemoryBuffer.h"
16 #include "llvm/Support/Path.h"
17 #include "llvm/Support/SourceMgr.h"
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20 #include <map>
21 #include <string>
23 using namespace llvm;
24 using llvm::sys::fs::UniqueID;
25 using testing::ElementsAre;
26 using testing::Pair;
27 using testing::UnorderedElementsAre;
29 namespace {
30 struct DummyFile : public vfs::File {
31 vfs::Status S;
32 explicit DummyFile(vfs::Status S) : S(S) {}
33 llvm::ErrorOr<vfs::Status> status() override { return S; }
34 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
35 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
36 bool IsVolatile) override {
37 llvm_unreachable("unimplemented");
39 std::error_code close() override { return std::error_code(); }
42 class DummyFileSystem : public vfs::FileSystem {
43 int FSID; // used to produce UniqueIDs
44 int FileID; // used to produce UniqueIDs
45 std::map<std::string, vfs::Status> FilesAndDirs;
47 static int getNextFSID() {
48 static int Count = 0;
49 return Count++;
52 public:
53 DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
55 ErrorOr<vfs::Status> status(const Twine &Path) override {
56 std::map<std::string, vfs::Status>::iterator I =
57 FilesAndDirs.find(Path.str());
58 if (I == FilesAndDirs.end())
59 return make_error_code(llvm::errc::no_such_file_or_directory);
60 return I->second;
62 ErrorOr<std::unique_ptr<vfs::File>>
63 openFileForRead(const Twine &Path) override {
64 auto S = status(Path);
65 if (S)
66 return std::unique_ptr<vfs::File>(new DummyFile{*S});
67 return S.getError();
69 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
70 return std::string();
72 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
73 return std::error_code();
75 // Map any symlink to "/symlink".
76 std::error_code getRealPath(const Twine &Path,
77 SmallVectorImpl<char> &Output) const override {
78 auto I = FilesAndDirs.find(Path.str());
79 if (I == FilesAndDirs.end())
80 return make_error_code(llvm::errc::no_such_file_or_directory);
81 if (I->second.isSymlink()) {
82 Output.clear();
83 Twine("/symlink").toVector(Output);
84 return std::error_code();
86 Output.clear();
87 Path.toVector(Output);
88 return std::error_code();
91 struct DirIterImpl : public llvm::vfs::detail::DirIterImpl {
92 std::map<std::string, vfs::Status> &FilesAndDirs;
93 std::map<std::string, vfs::Status>::iterator I;
94 std::string Path;
95 bool isInPath(StringRef S) {
96 if (Path.size() < S.size() && S.find(Path) == 0) {
97 auto LastSep = S.find_last_of('/');
98 if (LastSep == Path.size() || LastSep == Path.size() - 1)
99 return true;
101 return false;
103 DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
104 const Twine &_Path)
105 : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
106 Path(_Path.str()) {
107 for (; I != FilesAndDirs.end(); ++I) {
108 if (isInPath(I->first)) {
109 CurrentEntry =
110 vfs::directory_entry(I->second.getName(), I->second.getType());
111 break;
115 std::error_code increment() override {
116 ++I;
117 for (; I != FilesAndDirs.end(); ++I) {
118 if (isInPath(I->first)) {
119 CurrentEntry =
120 vfs::directory_entry(I->second.getName(), I->second.getType());
121 break;
124 if (I == FilesAndDirs.end())
125 CurrentEntry = vfs::directory_entry();
126 return std::error_code();
130 vfs::directory_iterator dir_begin(const Twine &Dir,
131 std::error_code &EC) override {
132 return vfs::directory_iterator(
133 std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
136 void addEntry(StringRef Path, const vfs::Status &Status) {
137 FilesAndDirs[Path] = Status;
140 void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
141 vfs::Status S(Path, UniqueID(FSID, FileID++),
142 std::chrono::system_clock::now(), 0, 0, 1024,
143 sys::fs::file_type::regular_file, Perms);
144 addEntry(Path, S);
147 void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
148 vfs::Status S(Path, UniqueID(FSID, FileID++),
149 std::chrono::system_clock::now(), 0, 0, 0,
150 sys::fs::file_type::directory_file, Perms);
151 addEntry(Path, S);
154 void addSymlink(StringRef Path) {
155 vfs::Status S(Path, UniqueID(FSID, FileID++),
156 std::chrono::system_clock::now(), 0, 0, 0,
157 sys::fs::file_type::symlink_file, sys::fs::all_all);
158 addEntry(Path, S);
162 /// Replace back-slashes by front-slashes.
163 std::string getPosixPath(std::string S) {
164 SmallString<128> Result;
165 llvm::sys::path::native(S, Result, llvm::sys::path::Style::posix);
166 return Result.str();
168 } // end anonymous namespace
170 TEST(VirtualFileSystemTest, StatusQueries) {
171 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
172 ErrorOr<vfs::Status> Status((std::error_code()));
174 D->addRegularFile("/foo");
175 Status = D->status("/foo");
176 ASSERT_FALSE(Status.getError());
177 EXPECT_TRUE(Status->isStatusKnown());
178 EXPECT_FALSE(Status->isDirectory());
179 EXPECT_TRUE(Status->isRegularFile());
180 EXPECT_FALSE(Status->isSymlink());
181 EXPECT_FALSE(Status->isOther());
182 EXPECT_TRUE(Status->exists());
184 D->addDirectory("/bar");
185 Status = D->status("/bar");
186 ASSERT_FALSE(Status.getError());
187 EXPECT_TRUE(Status->isStatusKnown());
188 EXPECT_TRUE(Status->isDirectory());
189 EXPECT_FALSE(Status->isRegularFile());
190 EXPECT_FALSE(Status->isSymlink());
191 EXPECT_FALSE(Status->isOther());
192 EXPECT_TRUE(Status->exists());
194 D->addSymlink("/baz");
195 Status = D->status("/baz");
196 ASSERT_FALSE(Status.getError());
197 EXPECT_TRUE(Status->isStatusKnown());
198 EXPECT_FALSE(Status->isDirectory());
199 EXPECT_FALSE(Status->isRegularFile());
200 EXPECT_TRUE(Status->isSymlink());
201 EXPECT_FALSE(Status->isOther());
202 EXPECT_TRUE(Status->exists());
204 EXPECT_TRUE(Status->equivalent(*Status));
205 ErrorOr<vfs::Status> Status2 = D->status("/foo");
206 ASSERT_FALSE(Status2.getError());
207 EXPECT_FALSE(Status->equivalent(*Status2));
210 TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
211 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
212 ErrorOr<vfs::Status> Status((std::error_code()));
213 EXPECT_FALSE(Status = D->status("/foo"));
215 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
216 EXPECT_FALSE(Status = O->status("/foo"));
218 D->addRegularFile("/foo");
219 Status = D->status("/foo");
220 EXPECT_FALSE(Status.getError());
222 ErrorOr<vfs::Status> Status2((std::error_code()));
223 Status2 = O->status("/foo");
224 EXPECT_FALSE(Status2.getError());
225 EXPECT_TRUE(Status->equivalent(*Status2));
228 TEST(VirtualFileSystemTest, GetRealPathInOverlay) {
229 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
230 Lower->addRegularFile("/foo");
231 Lower->addSymlink("/lower_link");
232 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
234 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
235 new vfs::OverlayFileSystem(Lower));
236 O->pushOverlay(Upper);
238 // Regular file.
239 SmallString<16> RealPath;
240 EXPECT_FALSE(O->getRealPath("/foo", RealPath));
241 EXPECT_EQ(RealPath.str(), "/foo");
243 // Expect no error getting real path for symlink in lower overlay.
244 EXPECT_FALSE(O->getRealPath("/lower_link", RealPath));
245 EXPECT_EQ(RealPath.str(), "/symlink");
247 // Try a non-existing link.
248 EXPECT_EQ(O->getRealPath("/upper_link", RealPath),
249 errc::no_such_file_or_directory);
251 // Add a new symlink in upper.
252 Upper->addSymlink("/upper_link");
253 EXPECT_FALSE(O->getRealPath("/upper_link", RealPath));
254 EXPECT_EQ(RealPath.str(), "/symlink");
257 TEST(VirtualFileSystemTest, OverlayFiles) {
258 IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
259 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
260 IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
261 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
262 new vfs::OverlayFileSystem(Base));
263 O->pushOverlay(Middle);
264 O->pushOverlay(Top);
266 ErrorOr<vfs::Status> Status1((std::error_code())),
267 Status2((std::error_code())), Status3((std::error_code())),
268 StatusB((std::error_code())), StatusM((std::error_code())),
269 StatusT((std::error_code()));
271 Base->addRegularFile("/foo");
272 StatusB = Base->status("/foo");
273 ASSERT_FALSE(StatusB.getError());
274 Status1 = O->status("/foo");
275 ASSERT_FALSE(Status1.getError());
276 Middle->addRegularFile("/foo");
277 StatusM = Middle->status("/foo");
278 ASSERT_FALSE(StatusM.getError());
279 Status2 = O->status("/foo");
280 ASSERT_FALSE(Status2.getError());
281 Top->addRegularFile("/foo");
282 StatusT = Top->status("/foo");
283 ASSERT_FALSE(StatusT.getError());
284 Status3 = O->status("/foo");
285 ASSERT_FALSE(Status3.getError());
287 EXPECT_TRUE(Status1->equivalent(*StatusB));
288 EXPECT_TRUE(Status2->equivalent(*StatusM));
289 EXPECT_TRUE(Status3->equivalent(*StatusT));
291 EXPECT_FALSE(Status1->equivalent(*Status2));
292 EXPECT_FALSE(Status2->equivalent(*Status3));
293 EXPECT_FALSE(Status1->equivalent(*Status3));
296 TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
297 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
298 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
299 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
300 new vfs::OverlayFileSystem(Lower));
301 O->pushOverlay(Upper);
303 Lower->addDirectory("/lower-only");
304 Upper->addDirectory("/upper-only");
306 // non-merged paths should be the same
307 ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
308 ASSERT_FALSE(Status1.getError());
309 ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
310 ASSERT_FALSE(Status2.getError());
311 EXPECT_TRUE(Status1->equivalent(*Status2));
313 Status1 = Upper->status("/upper-only");
314 ASSERT_FALSE(Status1.getError());
315 Status2 = O->status("/upper-only");
316 ASSERT_FALSE(Status2.getError());
317 EXPECT_TRUE(Status1->equivalent(*Status2));
320 TEST(VirtualFileSystemTest, MergedDirPermissions) {
321 // merged directories get the permissions of the upper dir
322 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
323 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
324 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
325 new vfs::OverlayFileSystem(Lower));
326 O->pushOverlay(Upper);
328 ErrorOr<vfs::Status> Status((std::error_code()));
329 Lower->addDirectory("/both", sys::fs::owner_read);
330 Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
331 Status = O->status("/both");
332 ASSERT_FALSE(Status.getError());
333 EXPECT_EQ(0740, Status->getPermissions());
335 // permissions (as usual) are not recursively applied
336 Lower->addRegularFile("/both/foo", sys::fs::owner_read);
337 Upper->addRegularFile("/both/bar", sys::fs::owner_write);
338 Status = O->status("/both/foo");
339 ASSERT_FALSE(Status.getError());
340 EXPECT_EQ(0400, Status->getPermissions());
341 Status = O->status("/both/bar");
342 ASSERT_FALSE(Status.getError());
343 EXPECT_EQ(0200, Status->getPermissions());
346 namespace {
347 struct ScopedDir {
348 SmallString<128> Path;
349 ScopedDir(const Twine &Name, bool Unique = false) {
350 std::error_code EC;
351 if (Unique) {
352 EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
353 } else {
354 Path = Name.str();
355 EC = llvm::sys::fs::create_directory(Twine(Path));
357 if (EC)
358 Path = "";
359 EXPECT_FALSE(EC);
361 ~ScopedDir() {
362 if (Path != "") {
363 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
366 operator StringRef() { return Path.str(); }
369 struct ScopedLink {
370 SmallString<128> Path;
371 ScopedLink(const Twine &To, const Twine &From) {
372 Path = From.str();
373 std::error_code EC = sys::fs::create_link(To, From);
374 if (EC)
375 Path = "";
376 EXPECT_FALSE(EC);
378 ~ScopedLink() {
379 if (Path != "") {
380 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
383 operator StringRef() { return Path.str(); }
385 } // end anonymous namespace
387 TEST(VirtualFileSystemTest, BasicRealFSIteration) {
388 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
389 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
391 std::error_code EC;
392 vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
393 ASSERT_FALSE(EC);
394 EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
396 ScopedDir _a(TestDirectory + "/a");
397 ScopedDir _ab(TestDirectory + "/a/b");
398 ScopedDir _c(TestDirectory + "/c");
399 ScopedDir _cd(TestDirectory + "/c/d");
401 I = FS->dir_begin(Twine(TestDirectory), EC);
402 ASSERT_FALSE(EC);
403 ASSERT_NE(vfs::directory_iterator(), I);
404 // Check either a or c, since we can't rely on the iteration order.
405 EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
406 I.increment(EC);
407 ASSERT_FALSE(EC);
408 ASSERT_NE(vfs::directory_iterator(), I);
409 EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
410 I.increment(EC);
411 EXPECT_EQ(vfs::directory_iterator(), I);
414 #ifdef LLVM_ON_UNIX
415 TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
416 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
417 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
419 ScopedLink _a("no_such_file", TestDirectory + "/a");
420 ScopedDir _b(TestDirectory + "/b");
421 ScopedLink _c("no_such_file", TestDirectory + "/c");
423 // Should get no iteration error, but a stat error for the broken symlinks.
424 std::map<std::string, std::error_code> StatResults;
425 std::error_code EC;
426 for (vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC), E;
427 I != E; I.increment(EC)) {
428 EXPECT_FALSE(EC);
429 StatResults[sys::path::filename(I->path())] =
430 FS->status(I->path()).getError();
432 EXPECT_THAT(
433 StatResults,
434 ElementsAre(
435 Pair("a", std::make_error_code(std::errc::no_such_file_or_directory)),
436 Pair("b", std::error_code()),
437 Pair("c",
438 std::make_error_code(std::errc::no_such_file_or_directory))));
440 #endif
442 TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
443 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
444 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
446 std::error_code EC;
447 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
448 ASSERT_FALSE(EC);
449 EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
451 ScopedDir _a(TestDirectory + "/a");
452 ScopedDir _ab(TestDirectory + "/a/b");
453 ScopedDir _c(TestDirectory + "/c");
454 ScopedDir _cd(TestDirectory + "/c/d");
456 I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
457 ASSERT_FALSE(EC);
458 ASSERT_NE(vfs::recursive_directory_iterator(), I);
460 std::vector<std::string> Contents;
461 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
462 I.increment(EC)) {
463 Contents.push_back(I->path());
466 // Check contents, which may be in any order
467 EXPECT_EQ(4U, Contents.size());
468 int Counts[4] = {0, 0, 0, 0};
469 for (const std::string &Name : Contents) {
470 ASSERT_FALSE(Name.empty());
471 int Index = Name[Name.size() - 1] - 'a';
472 ASSERT_TRUE(Index >= 0 && Index < 4);
473 Counts[Index]++;
475 EXPECT_EQ(1, Counts[0]); // a
476 EXPECT_EQ(1, Counts[1]); // b
477 EXPECT_EQ(1, Counts[2]); // c
478 EXPECT_EQ(1, Counts[3]); // d
481 TEST(VirtualFileSystemTest, BasicRealFSRecursiveIterationNoPush) {
482 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
484 ScopedDir _a(TestDirectory + "/a");
485 ScopedDir _ab(TestDirectory + "/a/b");
486 ScopedDir _c(TestDirectory + "/c");
487 ScopedDir _cd(TestDirectory + "/c/d");
488 ScopedDir _e(TestDirectory + "/e");
489 ScopedDir _ef(TestDirectory + "/e/f");
490 ScopedDir _g(TestDirectory + "/g");
492 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
494 // Test that calling no_push on entries without subdirectories has no effect.
496 std::error_code EC;
497 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
498 ASSERT_FALSE(EC);
500 std::vector<std::string> Contents;
501 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
502 I.increment(EC)) {
503 Contents.push_back(I->path());
504 char last = I->path().back();
505 switch (last) {
506 case 'b':
507 case 'd':
508 case 'f':
509 case 'g':
510 I.no_push();
511 break;
512 default:
513 break;
516 EXPECT_EQ(7U, Contents.size());
519 // Test that calling no_push skips subdirectories.
521 std::error_code EC;
522 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
523 ASSERT_FALSE(EC);
525 std::vector<std::string> Contents;
526 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
527 I.increment(EC)) {
528 Contents.push_back(I->path());
529 char last = I->path().back();
530 switch (last) {
531 case 'a':
532 case 'c':
533 case 'e':
534 I.no_push();
535 break;
536 default:
537 break;
541 // Check contents, which may be in any order
542 EXPECT_EQ(4U, Contents.size());
543 int Counts[7] = {0, 0, 0, 0, 0, 0, 0};
544 for (const std::string &Name : Contents) {
545 ASSERT_FALSE(Name.empty());
546 int Index = Name[Name.size() - 1] - 'a';
547 ASSERT_TRUE(Index >= 0 && Index < 7);
548 Counts[Index]++;
550 EXPECT_EQ(1, Counts[0]); // a
551 EXPECT_EQ(0, Counts[1]); // b
552 EXPECT_EQ(1, Counts[2]); // c
553 EXPECT_EQ(0, Counts[3]); // d
554 EXPECT_EQ(1, Counts[4]); // e
555 EXPECT_EQ(0, Counts[5]); // f
556 EXPECT_EQ(1, Counts[6]); // g
560 #ifdef LLVM_ON_UNIX
561 TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
562 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
563 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
565 ScopedLink _a("no_such_file", TestDirectory + "/a");
566 ScopedDir _b(TestDirectory + "/b");
567 ScopedLink _ba("no_such_file", TestDirectory + "/b/a");
568 ScopedDir _bb(TestDirectory + "/b/b");
569 ScopedLink _bc("no_such_file", TestDirectory + "/b/c");
570 ScopedLink _c("no_such_file", TestDirectory + "/c");
571 ScopedDir _d(TestDirectory + "/d");
572 ScopedDir _dd(TestDirectory + "/d/d");
573 ScopedDir _ddd(TestDirectory + "/d/d/d");
574 ScopedLink _e("no_such_file", TestDirectory + "/e");
576 std::vector<std::string> VisitedBrokenSymlinks;
577 std::vector<std::string> VisitedNonBrokenSymlinks;
578 std::error_code EC;
579 for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E;
580 I != E; I.increment(EC)) {
581 EXPECT_FALSE(EC);
582 (FS->status(I->path()) ? VisitedNonBrokenSymlinks : VisitedBrokenSymlinks)
583 .push_back(I->path());
586 // Check visited file names.
587 EXPECT_THAT(VisitedBrokenSymlinks,
588 UnorderedElementsAre(StringRef(_a), StringRef(_ba),
589 StringRef(_bc), StringRef(_c),
590 StringRef(_e)));
591 EXPECT_THAT(VisitedNonBrokenSymlinks,
592 UnorderedElementsAre(StringRef(_b), StringRef(_bb), StringRef(_d),
593 StringRef(_dd), StringRef(_ddd)));
595 #endif
597 template <typename DirIter>
598 static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
599 std::error_code EC;
600 SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
601 SmallVector<std::string, 4> InputToCheck;
603 // Do not rely on iteration order to check for contents, sort both
604 // content vectors before comparison.
605 for (DirIter E; !EC && I != E; I.increment(EC))
606 InputToCheck.push_back(I->path());
608 llvm::sort(InputToCheck);
609 llvm::sort(Expected);
610 EXPECT_EQ(InputToCheck.size(), Expected.size());
612 unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
613 for (unsigned Idx = 0; Idx != LastElt; ++Idx)
614 EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
617 TEST(VirtualFileSystemTest, OverlayIteration) {
618 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
619 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
620 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
621 new vfs::OverlayFileSystem(Lower));
622 O->pushOverlay(Upper);
624 std::error_code EC;
625 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
627 Lower->addRegularFile("/file1");
628 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
630 Upper->addRegularFile("/file2");
631 checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
633 Lower->addDirectory("/dir1");
634 Lower->addRegularFile("/dir1/foo");
635 Upper->addDirectory("/dir2");
636 Upper->addRegularFile("/dir2/foo");
637 checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
638 checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
641 TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
642 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
643 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
644 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
645 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
646 new vfs::OverlayFileSystem(Lower));
647 O->pushOverlay(Middle);
648 O->pushOverlay(Upper);
650 std::error_code EC;
651 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
652 ArrayRef<StringRef>());
654 Lower->addRegularFile("/file1");
655 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
656 ArrayRef<StringRef>("/file1"));
658 Upper->addDirectory("/dir");
659 Upper->addRegularFile("/dir/file2");
660 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
661 {"/dir", "/dir/file2", "/file1"});
663 Lower->addDirectory("/dir1");
664 Lower->addRegularFile("/dir1/foo");
665 Lower->addDirectory("/dir1/a");
666 Lower->addRegularFile("/dir1/a/b");
667 Middle->addDirectory("/a");
668 Middle->addDirectory("/a/b");
669 Middle->addDirectory("/a/b/c");
670 Middle->addRegularFile("/a/b/c/d");
671 Middle->addRegularFile("/hiddenByUp");
672 Upper->addDirectory("/dir2");
673 Upper->addRegularFile("/dir2/foo");
674 Upper->addRegularFile("/hiddenByUp");
675 checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
676 ArrayRef<StringRef>("/dir2/foo"));
677 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
678 {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
679 "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
680 "/dir1/a/b", "/dir1/foo", "/file1"});
683 TEST(VirtualFileSystemTest, ThreeLevelIteration) {
684 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
685 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
686 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
687 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
688 new vfs::OverlayFileSystem(Lower));
689 O->pushOverlay(Middle);
690 O->pushOverlay(Upper);
692 std::error_code EC;
693 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
695 Middle->addRegularFile("/file2");
696 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
698 Lower->addRegularFile("/file1");
699 Upper->addRegularFile("/file3");
700 checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
703 TEST(VirtualFileSystemTest, HiddenInIteration) {
704 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
705 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
706 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
707 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
708 new vfs::OverlayFileSystem(Lower));
709 O->pushOverlay(Middle);
710 O->pushOverlay(Upper);
712 std::error_code EC;
713 Lower->addRegularFile("/onlyInLow");
714 Lower->addDirectory("/hiddenByMid");
715 Lower->addDirectory("/hiddenByUp");
716 Middle->addRegularFile("/onlyInMid");
717 Middle->addRegularFile("/hiddenByMid");
718 Middle->addDirectory("/hiddenByUp");
719 Upper->addRegularFile("/onlyInUp");
720 Upper->addRegularFile("/hiddenByUp");
721 checkContents(
722 O->dir_begin("/", EC),
723 {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
725 // Make sure we get the top-most entry
727 std::error_code EC;
728 vfs::directory_iterator I = O->dir_begin("/", EC), E;
729 for (; !EC && I != E; I.increment(EC))
730 if (I->path() == "/hiddenByUp")
731 break;
732 ASSERT_NE(E, I);
733 EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
736 std::error_code EC;
737 vfs::directory_iterator I = O->dir_begin("/", EC), E;
738 for (; !EC && I != E; I.increment(EC))
739 if (I->path() == "/hiddenByMid")
740 break;
741 ASSERT_NE(E, I);
742 EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
746 class InMemoryFileSystemTest : public ::testing::Test {
747 protected:
748 llvm::vfs::InMemoryFileSystem FS;
749 llvm::vfs::InMemoryFileSystem NormalizedFS;
751 InMemoryFileSystemTest()
752 : FS(/*UseNormalizedPaths=*/false),
753 NormalizedFS(/*UseNormalizedPaths=*/true) {}
756 MATCHER_P2(IsHardLinkTo, FS, Target, "") {
757 StringRef From = arg;
758 StringRef To = Target;
759 auto OpenedFrom = FS->openFileForRead(From);
760 auto OpenedTo = FS->openFileForRead(To);
761 return !OpenedFrom.getError() && !OpenedTo.getError() &&
762 (*OpenedFrom)->status()->getUniqueID() ==
763 (*OpenedTo)->status()->getUniqueID();
766 TEST_F(InMemoryFileSystemTest, IsEmpty) {
767 auto Stat = FS.status("/a");
768 ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
769 Stat = FS.status("/");
770 ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
773 TEST_F(InMemoryFileSystemTest, WindowsPath) {
774 FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
775 auto Stat = FS.status("c:");
776 #if !defined(_WIN32)
777 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
778 #endif
779 Stat = FS.status("c:/windows/system128/foo.cpp");
780 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
781 FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
782 Stat = FS.status("d:/windows/foo.cpp");
783 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
786 TEST_F(InMemoryFileSystemTest, OverlayFile) {
787 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
788 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
789 auto Stat = FS.status("/");
790 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
791 Stat = FS.status("/.");
792 ASSERT_FALSE(Stat);
793 Stat = NormalizedFS.status("/.");
794 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
795 Stat = FS.status("/a");
796 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
797 ASSERT_EQ("/a", Stat->getName());
800 TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
801 auto Buf = MemoryBuffer::getMemBuffer("a");
802 FS.addFileNoOwn("/a", 0, Buf.get());
803 auto Stat = FS.status("/a");
804 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
805 ASSERT_EQ("/a", Stat->getName());
808 TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
809 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
810 FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
811 FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
812 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
813 NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
814 NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
815 auto File = FS.openFileForRead("/a");
816 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
817 File = FS.openFileForRead("/a"); // Open again.
818 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
819 File = NormalizedFS.openFileForRead("/././a"); // Open again.
820 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
821 File = FS.openFileForRead("/");
822 ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
823 File = FS.openFileForRead("/b");
824 ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
825 File = FS.openFileForRead("./c");
826 ASSERT_FALSE(File);
827 File = FS.openFileForRead("e/../d");
828 ASSERT_FALSE(File);
829 File = NormalizedFS.openFileForRead("./c");
830 ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
831 File = NormalizedFS.openFileForRead("e/../d");
832 ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
835 TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
836 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
837 ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
838 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
839 ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
842 TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
843 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
844 FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
846 std::error_code EC;
847 vfs::directory_iterator I = FS.dir_begin("/", EC);
848 ASSERT_FALSE(EC);
849 ASSERT_EQ("/a", I->path());
850 I.increment(EC);
851 ASSERT_FALSE(EC);
852 ASSERT_EQ("/b", I->path());
853 I.increment(EC);
854 ASSERT_FALSE(EC);
855 ASSERT_EQ(vfs::directory_iterator(), I);
857 I = FS.dir_begin("/b", EC);
858 ASSERT_FALSE(EC);
859 // When on Windows, we end up with "/b\\c" as the name. Convert to Posix
860 // path for the sake of the comparison.
861 ASSERT_EQ("/b/c", getPosixPath(I->path()));
862 I.increment(EC);
863 ASSERT_FALSE(EC);
864 ASSERT_EQ(vfs::directory_iterator(), I);
867 TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
868 FS.setCurrentWorkingDirectory("/b");
869 FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
871 auto Stat = FS.status("/b/c");
872 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
873 ASSERT_EQ("/b/c", Stat->getName());
874 ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
876 Stat = FS.status("c");
877 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
879 NormalizedFS.setCurrentWorkingDirectory("/b/c");
880 NormalizedFS.setCurrentWorkingDirectory(".");
881 ASSERT_EQ("/b/c",
882 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
883 NormalizedFS.setCurrentWorkingDirectory("..");
884 ASSERT_EQ("/b",
885 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
888 TEST_F(InMemoryFileSystemTest, IsLocal) {
889 FS.setCurrentWorkingDirectory("/b");
890 FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
892 std::error_code EC;
893 bool IsLocal = true;
894 EC = FS.isLocal("c", IsLocal);
895 ASSERT_FALSE(EC);
896 ASSERT_FALSE(IsLocal);
899 #if !defined(_WIN32)
900 TEST_F(InMemoryFileSystemTest, GetRealPath) {
901 SmallString<16> Path;
902 EXPECT_EQ(FS.getRealPath("b", Path), errc::operation_not_permitted);
904 auto GetRealPath = [this](StringRef P) {
905 SmallString<16> Output;
906 auto EC = FS.getRealPath(P, Output);
907 EXPECT_FALSE(EC);
908 return Output.str().str();
911 FS.setCurrentWorkingDirectory("a");
912 EXPECT_EQ(GetRealPath("b"), "a/b");
913 EXPECT_EQ(GetRealPath("../b"), "b");
914 EXPECT_EQ(GetRealPath("b/./c"), "a/b/c");
916 FS.setCurrentWorkingDirectory("/a");
917 EXPECT_EQ(GetRealPath("b"), "/a/b");
918 EXPECT_EQ(GetRealPath("../b"), "/b");
919 EXPECT_EQ(GetRealPath("b/./c"), "/a/b/c");
921 #endif // _WIN32
923 TEST_F(InMemoryFileSystemTest, AddFileWithUser) {
924 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
925 auto Stat = FS.status("/a");
926 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
927 ASSERT_TRUE(Stat->isDirectory());
928 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
929 Stat = FS.status("/a/b");
930 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
931 ASSERT_TRUE(Stat->isDirectory());
932 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
933 Stat = FS.status("/a/b/c");
934 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
935 ASSERT_TRUE(Stat->isRegularFile());
936 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
937 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
940 TEST_F(InMemoryFileSystemTest, AddFileWithGroup) {
941 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00);
942 auto Stat = FS.status("/a");
943 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
944 ASSERT_TRUE(Stat->isDirectory());
945 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
946 Stat = FS.status("/a/b");
947 ASSERT_TRUE(Stat->isDirectory());
948 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
949 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
950 Stat = FS.status("/a/b/c");
951 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
952 ASSERT_TRUE(Stat->isRegularFile());
953 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
954 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
957 TEST_F(InMemoryFileSystemTest, AddFileWithFileType) {
958 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
959 sys::fs::file_type::socket_file);
960 auto Stat = FS.status("/a");
961 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
962 ASSERT_TRUE(Stat->isDirectory());
963 Stat = FS.status("/a/b");
964 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
965 ASSERT_TRUE(Stat->isDirectory());
966 Stat = FS.status("/a/b/c");
967 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
968 ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType());
969 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
972 TEST_F(InMemoryFileSystemTest, AddFileWithPerms) {
973 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None, None,
974 sys::fs::perms::owner_read | sys::fs::perms::owner_write);
975 auto Stat = FS.status("/a");
976 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
977 ASSERT_TRUE(Stat->isDirectory());
978 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
979 sys::fs::perms::owner_exe,
980 Stat->getPermissions());
981 Stat = FS.status("/a/b");
982 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
983 ASSERT_TRUE(Stat->isDirectory());
984 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
985 sys::fs::perms::owner_exe,
986 Stat->getPermissions());
987 Stat = FS.status("/a/b/c");
988 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
989 ASSERT_TRUE(Stat->isRegularFile());
990 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write,
991 Stat->getPermissions());
994 TEST_F(InMemoryFileSystemTest, AddDirectoryThenAddChild) {
995 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None,
996 /*Group=*/None, sys::fs::file_type::directory_file);
997 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None,
998 /*Group=*/None, sys::fs::file_type::regular_file);
999 auto Stat = FS.status("/a");
1000 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1001 ASSERT_TRUE(Stat->isDirectory());
1002 Stat = FS.status("/a/b");
1003 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1004 ASSERT_TRUE(Stat->isRegularFile());
1007 // Test that the name returned by status() is in the same form as the path that
1008 // was requested (to match the behavior of RealFileSystem).
1009 TEST_F(InMemoryFileSystemTest, StatusName) {
1010 NormalizedFS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"),
1011 /*User=*/None,
1012 /*Group=*/None, sys::fs::file_type::regular_file);
1013 NormalizedFS.setCurrentWorkingDirectory("/a/b");
1015 // Access using InMemoryFileSystem::status.
1016 auto Stat = NormalizedFS.status("../b/c");
1017 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1018 << NormalizedFS.toString();
1019 ASSERT_TRUE(Stat->isRegularFile());
1020 ASSERT_EQ("../b/c", Stat->getName());
1022 // Access using InMemoryFileAdaptor::status.
1023 auto File = NormalizedFS.openFileForRead("../b/c");
1024 ASSERT_FALSE(File.getError()) << File.getError() << "\n"
1025 << NormalizedFS.toString();
1026 Stat = (*File)->status();
1027 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1028 << NormalizedFS.toString();
1029 ASSERT_TRUE(Stat->isRegularFile());
1030 ASSERT_EQ("../b/c", Stat->getName());
1032 // Access using a directory iterator.
1033 std::error_code EC;
1034 llvm::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC);
1035 // When on Windows, we end up with "../b\\c" as the name. Convert to Posix
1036 // path for the sake of the comparison.
1037 ASSERT_EQ("../b/c", getPosixPath(It->path()));
1040 TEST_F(InMemoryFileSystemTest, AddHardLinkToFile) {
1041 StringRef FromLink = "/path/to/FROM/link";
1042 StringRef Target = "/path/to/TO/file";
1043 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1044 EXPECT_TRUE(FS.addHardLink(FromLink, Target));
1045 EXPECT_THAT(FromLink, IsHardLinkTo(&FS, Target));
1046 EXPECT_TRUE(FS.status(FromLink)->getSize() == FS.status(Target)->getSize());
1047 EXPECT_TRUE(FS.getBufferForFile(FromLink)->get()->getBuffer() ==
1048 FS.getBufferForFile(Target)->get()->getBuffer());
1051 TEST_F(InMemoryFileSystemTest, AddHardLinkInChainPattern) {
1052 StringRef Link0 = "/path/to/0/link";
1053 StringRef Link1 = "/path/to/1/link";
1054 StringRef Link2 = "/path/to/2/link";
1055 StringRef Target = "/path/to/target";
1056 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target file"));
1057 EXPECT_TRUE(FS.addHardLink(Link2, Target));
1058 EXPECT_TRUE(FS.addHardLink(Link1, Link2));
1059 EXPECT_TRUE(FS.addHardLink(Link0, Link1));
1060 EXPECT_THAT(Link0, IsHardLinkTo(&FS, Target));
1061 EXPECT_THAT(Link1, IsHardLinkTo(&FS, Target));
1062 EXPECT_THAT(Link2, IsHardLinkTo(&FS, Target));
1065 TEST_F(InMemoryFileSystemTest, AddHardLinkToAFileThatWasNotAddedBefore) {
1066 EXPECT_FALSE(FS.addHardLink("/path/to/link", "/path/to/target"));
1069 TEST_F(InMemoryFileSystemTest, AddHardLinkFromAFileThatWasAddedBefore) {
1070 StringRef Link = "/path/to/link";
1071 StringRef Target = "/path/to/target";
1072 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1073 FS.addFile(Link, 0, MemoryBuffer::getMemBuffer("content of link"));
1074 EXPECT_FALSE(FS.addHardLink(Link, Target));
1077 TEST_F(InMemoryFileSystemTest, AddSameHardLinkMoreThanOnce) {
1078 StringRef Link = "/path/to/link";
1079 StringRef Target = "/path/to/target";
1080 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1081 EXPECT_TRUE(FS.addHardLink(Link, Target));
1082 EXPECT_FALSE(FS.addHardLink(Link, Target));
1085 TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithSameContent) {
1086 StringRef Link = "/path/to/link";
1087 StringRef Target = "/path/to/target";
1088 StringRef Content = "content of target";
1089 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1090 EXPECT_TRUE(FS.addHardLink(Link, Target));
1091 EXPECT_TRUE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(Content)));
1094 TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithDifferentContent) {
1095 StringRef Link = "/path/to/link";
1096 StringRef Target = "/path/to/target";
1097 StringRef Content = "content of target";
1098 StringRef LinkContent = "different content of link";
1099 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1100 EXPECT_TRUE(FS.addHardLink(Link, Target));
1101 EXPECT_FALSE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(LinkContent)));
1104 TEST_F(InMemoryFileSystemTest, AddHardLinkToADirectory) {
1105 StringRef Dir = "path/to/dummy/dir";
1106 StringRef Link = "/path/to/link";
1107 StringRef File = "path/to/dummy/dir/target";
1108 StringRef Content = "content of target";
1109 EXPECT_TRUE(FS.addFile(File, 0, MemoryBuffer::getMemBuffer(Content)));
1110 EXPECT_FALSE(FS.addHardLink(Link, Dir));
1113 TEST_F(InMemoryFileSystemTest, AddHardLinkFromADirectory) {
1114 StringRef Dir = "path/to/dummy/dir";
1115 StringRef Target = "path/to/dummy/dir/target";
1116 StringRef Content = "content of target";
1117 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1118 EXPECT_FALSE(FS.addHardLink(Dir, Target));
1121 TEST_F(InMemoryFileSystemTest, AddHardLinkUnderAFile) {
1122 StringRef CommonContent = "content string";
1123 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer(CommonContent));
1124 FS.addFile("/c/d", 0, MemoryBuffer::getMemBuffer(CommonContent));
1125 EXPECT_FALSE(FS.addHardLink("/c/d/e", "/a/b"));
1128 TEST_F(InMemoryFileSystemTest, RecursiveIterationWithHardLink) {
1129 std::error_code EC;
1130 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("content string"));
1131 EXPECT_TRUE(FS.addHardLink("/c/d", "/a/b"));
1132 auto I = vfs::recursive_directory_iterator(FS, "/", EC);
1133 ASSERT_FALSE(EC);
1134 std::vector<std::string> Nodes;
1135 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
1136 I.increment(EC)) {
1137 Nodes.push_back(getPosixPath(I->path()));
1139 EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d"));
1142 // NOTE: in the tests below, we use '//root/' as our root directory, since it is
1143 // a legal *absolute* path on Windows as well as *nix.
1144 class VFSFromYAMLTest : public ::testing::Test {
1145 public:
1146 int NumDiagnostics;
1148 void SetUp() override { NumDiagnostics = 0; }
1150 static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
1151 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
1152 ++Test->NumDiagnostics;
1155 IntrusiveRefCntPtr<vfs::FileSystem>
1156 getFromYAMLRawString(StringRef Content,
1157 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
1158 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
1159 return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
1160 ExternalFS);
1163 IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
1164 StringRef Content,
1165 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
1166 std::string VersionPlusContent("{\n 'version':0,\n");
1167 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
1168 return getFromYAMLRawString(VersionPlusContent, ExternalFS);
1171 // This is intended as a "XFAIL" for windows hosts.
1172 bool supportsSameDirMultipleYAMLEntries() {
1173 Triple Host(Triple::normalize(sys::getProcessTriple()));
1174 return !Host.isOSWindows();
1178 TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
1179 IntrusiveRefCntPtr<vfs::FileSystem> FS;
1180 FS = getFromYAMLString("");
1181 EXPECT_EQ(nullptr, FS.get());
1182 FS = getFromYAMLString("[]");
1183 EXPECT_EQ(nullptr, FS.get());
1184 FS = getFromYAMLString("'string'");
1185 EXPECT_EQ(nullptr, FS.get());
1186 EXPECT_EQ(3, NumDiagnostics);
1189 TEST_F(VFSFromYAMLTest, MappedFiles) {
1190 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1191 Lower->addRegularFile("//root/foo/bar/a");
1192 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1193 "{ 'roots': [\n"
1194 "{\n"
1195 " 'type': 'directory',\n"
1196 " 'name': '//root/',\n"
1197 " 'contents': [ {\n"
1198 " 'type': 'file',\n"
1199 " 'name': 'file1',\n"
1200 " 'external-contents': '//root/foo/bar/a'\n"
1201 " },\n"
1202 " {\n"
1203 " 'type': 'file',\n"
1204 " 'name': 'file2',\n"
1205 " 'external-contents': '//root/foo/b'\n"
1206 " }\n"
1207 " ]\n"
1208 "}\n"
1209 "]\n"
1210 "}",
1211 Lower);
1212 ASSERT_TRUE(FS.get() != nullptr);
1214 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1215 new vfs::OverlayFileSystem(Lower));
1216 O->pushOverlay(FS);
1218 // file
1219 ErrorOr<vfs::Status> S = O->status("//root/file1");
1220 ASSERT_FALSE(S.getError());
1221 EXPECT_EQ("//root/foo/bar/a", S->getName());
1222 EXPECT_TRUE(S->IsVFSMapped);
1224 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
1225 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
1226 EXPECT_TRUE(S->equivalent(*SLower));
1227 EXPECT_FALSE(SLower->IsVFSMapped);
1229 // file after opening
1230 auto OpenedF = O->openFileForRead("//root/file1");
1231 ASSERT_FALSE(OpenedF.getError());
1232 auto OpenedS = (*OpenedF)->status();
1233 ASSERT_FALSE(OpenedS.getError());
1234 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
1235 EXPECT_TRUE(OpenedS->IsVFSMapped);
1237 // directory
1238 S = O->status("//root/");
1239 ASSERT_FALSE(S.getError());
1240 EXPECT_TRUE(S->isDirectory());
1241 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
1243 // broken mapping
1244 EXPECT_EQ(O->status("//root/file2").getError(),
1245 llvm::errc::no_such_file_or_directory);
1246 EXPECT_EQ(0, NumDiagnostics);
1249 TEST_F(VFSFromYAMLTest, CaseInsensitive) {
1250 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1251 Lower->addRegularFile("//root/foo/bar/a");
1252 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1253 "{ 'case-sensitive': 'false',\n"
1254 " 'roots': [\n"
1255 "{\n"
1256 " 'type': 'directory',\n"
1257 " 'name': '//root/',\n"
1258 " 'contents': [ {\n"
1259 " 'type': 'file',\n"
1260 " 'name': 'XX',\n"
1261 " 'external-contents': '//root/foo/bar/a'\n"
1262 " }\n"
1263 " ]\n"
1264 "}]}",
1265 Lower);
1266 ASSERT_TRUE(FS.get() != nullptr);
1268 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1269 new vfs::OverlayFileSystem(Lower));
1270 O->pushOverlay(FS);
1272 ErrorOr<vfs::Status> S = O->status("//root/XX");
1273 ASSERT_FALSE(S.getError());
1275 ErrorOr<vfs::Status> SS = O->status("//root/xx");
1276 ASSERT_FALSE(SS.getError());
1277 EXPECT_TRUE(S->equivalent(*SS));
1278 SS = O->status("//root/xX");
1279 EXPECT_TRUE(S->equivalent(*SS));
1280 SS = O->status("//root/Xx");
1281 EXPECT_TRUE(S->equivalent(*SS));
1282 EXPECT_EQ(0, NumDiagnostics);
1285 TEST_F(VFSFromYAMLTest, CaseSensitive) {
1286 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1287 Lower->addRegularFile("//root/foo/bar/a");
1288 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1289 "{ 'case-sensitive': 'true',\n"
1290 " 'roots': [\n"
1291 "{\n"
1292 " 'type': 'directory',\n"
1293 " 'name': '//root/',\n"
1294 " 'contents': [ {\n"
1295 " 'type': 'file',\n"
1296 " 'name': 'XX',\n"
1297 " 'external-contents': '//root/foo/bar/a'\n"
1298 " }\n"
1299 " ]\n"
1300 "}]}",
1301 Lower);
1302 ASSERT_TRUE(FS.get() != nullptr);
1304 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1305 new vfs::OverlayFileSystem(Lower));
1306 O->pushOverlay(FS);
1308 ErrorOr<vfs::Status> SS = O->status("//root/xx");
1309 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1310 SS = O->status("//root/xX");
1311 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1312 SS = O->status("//root/Xx");
1313 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1314 EXPECT_EQ(0, NumDiagnostics);
1317 TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
1318 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1320 // invalid YAML at top-level
1321 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
1322 EXPECT_EQ(nullptr, FS.get());
1323 // invalid YAML in roots
1324 FS = getFromYAMLString("{ 'roots':[}", Lower);
1325 // invalid YAML in directory
1326 FS = getFromYAMLString(
1327 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
1328 Lower);
1329 EXPECT_EQ(nullptr, FS.get());
1331 // invalid configuration
1332 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
1333 EXPECT_EQ(nullptr, FS.get());
1334 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
1335 EXPECT_EQ(nullptr, FS.get());
1337 // invalid roots
1338 FS = getFromYAMLString("{ 'roots':'' }", Lower);
1339 EXPECT_EQ(nullptr, FS.get());
1340 FS = getFromYAMLString("{ 'roots':{} }", Lower);
1341 EXPECT_EQ(nullptr, FS.get());
1343 // invalid entries
1344 FS = getFromYAMLString(
1345 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
1346 EXPECT_EQ(nullptr, FS.get());
1347 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
1348 "'external-contents': 'other' }",
1349 Lower);
1350 EXPECT_EQ(nullptr, FS.get());
1351 FS = getFromYAMLString(
1352 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1353 Lower);
1354 EXPECT_EQ(nullptr, FS.get());
1355 FS = getFromYAMLString(
1356 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
1357 Lower);
1358 EXPECT_EQ(nullptr, FS.get());
1359 FS = getFromYAMLString(
1360 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
1361 Lower);
1362 EXPECT_EQ(nullptr, FS.get());
1363 FS = getFromYAMLString(
1364 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
1365 Lower);
1366 EXPECT_EQ(nullptr, FS.get());
1367 FS = getFromYAMLString(
1368 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
1369 Lower);
1370 EXPECT_EQ(nullptr, FS.get());
1372 // missing mandatory fields
1373 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
1374 EXPECT_EQ(nullptr, FS.get());
1375 FS = getFromYAMLString(
1376 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
1377 EXPECT_EQ(nullptr, FS.get());
1378 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
1379 EXPECT_EQ(nullptr, FS.get());
1381 // duplicate keys
1382 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
1383 EXPECT_EQ(nullptr, FS.get());
1384 FS = getFromYAMLString(
1385 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1386 Lower);
1387 EXPECT_EQ(nullptr, FS.get());
1388 FS =
1389 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1390 "'external-contents':'blah' } ] }",
1391 Lower);
1392 EXPECT_EQ(nullptr, FS.get());
1394 // missing version
1395 FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
1396 EXPECT_EQ(nullptr, FS.get());
1398 // bad version number
1399 FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
1400 EXPECT_EQ(nullptr, FS.get());
1401 FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
1402 EXPECT_EQ(nullptr, FS.get());
1403 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
1404 EXPECT_EQ(nullptr, FS.get());
1405 EXPECT_EQ(24, NumDiagnostics);
1408 TEST_F(VFSFromYAMLTest, UseExternalName) {
1409 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1410 Lower->addRegularFile("//root/external/file");
1412 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1413 getFromYAMLString("{ 'roots': [\n"
1414 " { 'type': 'file', 'name': '//root/A',\n"
1415 " 'external-contents': '//root/external/file'\n"
1416 " },\n"
1417 " { 'type': 'file', 'name': '//root/B',\n"
1418 " 'use-external-name': true,\n"
1419 " 'external-contents': '//root/external/file'\n"
1420 " },\n"
1421 " { 'type': 'file', 'name': '//root/C',\n"
1422 " 'use-external-name': false,\n"
1423 " 'external-contents': '//root/external/file'\n"
1424 " }\n"
1425 "] }",
1426 Lower);
1427 ASSERT_TRUE(nullptr != FS.get());
1429 // default true
1430 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
1431 // explicit
1432 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1433 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
1435 // global configuration
1436 FS = getFromYAMLString("{ 'use-external-names': false,\n"
1437 " 'roots': [\n"
1438 " { 'type': 'file', 'name': '//root/A',\n"
1439 " 'external-contents': '//root/external/file'\n"
1440 " },\n"
1441 " { 'type': 'file', 'name': '//root/B',\n"
1442 " 'use-external-name': true,\n"
1443 " 'external-contents': '//root/external/file'\n"
1444 " },\n"
1445 " { 'type': 'file', 'name': '//root/C',\n"
1446 " 'use-external-name': false,\n"
1447 " 'external-contents': '//root/external/file'\n"
1448 " }\n"
1449 "] }",
1450 Lower);
1451 ASSERT_TRUE(nullptr != FS.get());
1453 // default
1454 EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
1455 // explicit
1456 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1457 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
1460 TEST_F(VFSFromYAMLTest, MultiComponentPath) {
1461 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1462 Lower->addRegularFile("//root/other");
1464 // file in roots
1465 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1466 getFromYAMLString("{ 'roots': [\n"
1467 " { 'type': 'file', 'name': '//root/path/to/file',\n"
1468 " 'external-contents': '//root/other' }]\n"
1469 "}",
1470 Lower);
1471 ASSERT_TRUE(nullptr != FS.get());
1472 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1473 EXPECT_FALSE(FS->status("//root/path/to").getError());
1474 EXPECT_FALSE(FS->status("//root/path").getError());
1475 EXPECT_FALSE(FS->status("//root/").getError());
1477 // at the start
1478 FS = getFromYAMLString(
1479 "{ 'roots': [\n"
1480 " { 'type': 'directory', 'name': '//root/path/to',\n"
1481 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
1482 " 'external-contents': '//root/other' }]}]\n"
1483 "}",
1484 Lower);
1485 ASSERT_TRUE(nullptr != FS.get());
1486 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1487 EXPECT_FALSE(FS->status("//root/path/to").getError());
1488 EXPECT_FALSE(FS->status("//root/path").getError());
1489 EXPECT_FALSE(FS->status("//root/").getError());
1491 // at the end
1492 FS = getFromYAMLString(
1493 "{ 'roots': [\n"
1494 " { 'type': 'directory', 'name': '//root/',\n"
1495 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
1496 " 'external-contents': '//root/other' }]}]\n"
1497 "}",
1498 Lower);
1499 ASSERT_TRUE(nullptr != FS.get());
1500 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1501 EXPECT_FALSE(FS->status("//root/path/to").getError());
1502 EXPECT_FALSE(FS->status("//root/path").getError());
1503 EXPECT_FALSE(FS->status("//root/").getError());
1506 TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1507 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1508 Lower->addRegularFile("//root/other");
1510 // file in roots
1511 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1512 "{ 'roots': [\n"
1513 " { 'type': 'directory', 'name': '//root/path/to////',\n"
1514 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
1515 " 'external-contents': '//root/other' }]}]\n"
1516 "}",
1517 Lower);
1518 ASSERT_TRUE(nullptr != FS.get());
1519 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1520 EXPECT_FALSE(FS->status("//root/path/to").getError());
1521 EXPECT_FALSE(FS->status("//root/path").getError());
1522 EXPECT_FALSE(FS->status("//root/").getError());
1525 TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1526 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1527 Lower->addDirectory("//root/");
1528 Lower->addDirectory("//root/foo");
1529 Lower->addDirectory("//root/foo/bar");
1530 Lower->addRegularFile("//root/foo/bar/a");
1531 Lower->addRegularFile("//root/foo/bar/b");
1532 Lower->addRegularFile("//root/file3");
1533 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1534 "{ 'use-external-names': false,\n"
1535 " 'roots': [\n"
1536 "{\n"
1537 " 'type': 'directory',\n"
1538 " 'name': '//root/',\n"
1539 " 'contents': [ {\n"
1540 " 'type': 'file',\n"
1541 " 'name': 'file1',\n"
1542 " 'external-contents': '//root/foo/bar/a'\n"
1543 " },\n"
1544 " {\n"
1545 " 'type': 'file',\n"
1546 " 'name': 'file2',\n"
1547 " 'external-contents': '//root/foo/bar/b'\n"
1548 " }\n"
1549 " ]\n"
1550 "}\n"
1551 "]\n"
1552 "}",
1553 Lower);
1554 ASSERT_TRUE(FS.get() != nullptr);
1556 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1557 new vfs::OverlayFileSystem(Lower));
1558 O->pushOverlay(FS);
1560 std::error_code EC;
1561 checkContents(O->dir_begin("//root/", EC),
1562 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
1564 checkContents(O->dir_begin("//root/foo/bar", EC),
1565 {"//root/foo/bar/a", "//root/foo/bar/b"});
1568 TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1569 // https://llvm.org/bugs/show_bug.cgi?id=27725
1570 if (!supportsSameDirMultipleYAMLEntries())
1571 return;
1573 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1574 Lower->addDirectory("//root/zab");
1575 Lower->addDirectory("//root/baz");
1576 Lower->addRegularFile("//root/zab/a");
1577 Lower->addRegularFile("//root/zab/b");
1578 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1579 "{ 'use-external-names': false,\n"
1580 " 'roots': [\n"
1581 "{\n"
1582 " 'type': 'directory',\n"
1583 " 'name': '//root/baz/',\n"
1584 " 'contents': [ {\n"
1585 " 'type': 'file',\n"
1586 " 'name': 'x',\n"
1587 " 'external-contents': '//root/zab/a'\n"
1588 " }\n"
1589 " ]\n"
1590 "},\n"
1591 "{\n"
1592 " 'type': 'directory',\n"
1593 " 'name': '//root/baz/',\n"
1594 " 'contents': [ {\n"
1595 " 'type': 'file',\n"
1596 " 'name': 'y',\n"
1597 " 'external-contents': '//root/zab/b'\n"
1598 " }\n"
1599 " ]\n"
1600 "}\n"
1601 "]\n"
1602 "}",
1603 Lower);
1604 ASSERT_TRUE(FS.get() != nullptr);
1606 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1607 new vfs::OverlayFileSystem(Lower));
1608 O->pushOverlay(FS);
1610 std::error_code EC;
1612 checkContents(O->dir_begin("//root/baz/", EC),
1613 {"//root/baz/x", "//root/baz/y"});
1616 TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1618 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1619 Lower->addDirectory("//root/a");
1620 Lower->addDirectory("//root/a/b");
1621 Lower->addDirectory("//root/a/b/c");
1622 Lower->addRegularFile("//root/a/b/c/file");
1623 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1624 "{ 'use-external-names': false,\n"
1625 " 'roots': [\n"
1626 "{\n"
1627 " 'type': 'directory',\n"
1628 " 'name': '//root/a/b/c/',\n"
1629 " 'contents': [ {\n"
1630 " 'type': 'file',\n"
1631 " 'name': 'file',\n"
1632 " 'external-contents': '//root/a/b/c/file'\n"
1633 " }\n"
1634 " ]\n"
1635 "},\n"
1636 "]\n"
1637 "}",
1638 Lower);
1639 ASSERT_TRUE(FS.get() != nullptr);
1641 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1642 new vfs::OverlayFileSystem(Lower));
1643 O->pushOverlay(FS);
1645 std::error_code EC;
1647 // Test recursive_directory_iterator level()
1648 vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
1649 *O, "//root", EC),
1651 ASSERT_FALSE(EC);
1652 for (int l = 0; I != E; I.increment(EC), ++l) {
1653 ASSERT_FALSE(EC);
1654 EXPECT_EQ(I.level(), l);
1656 EXPECT_EQ(I, E);
1659 TEST_F(VFSFromYAMLTest, RelativePaths) {
1660 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1661 // Filename at root level without a parent directory.
1662 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1663 "{ 'roots': [\n"
1664 " { 'type': 'file', 'name': 'file-not-in-directory.h',\n"
1665 " 'external-contents': '//root/external/file'\n"
1666 " }\n"
1667 "] }",
1668 Lower);
1669 EXPECT_EQ(nullptr, FS.get());
1671 // Relative file path.
1672 FS = getFromYAMLString("{ 'roots': [\n"
1673 " { 'type': 'file', 'name': 'relative/file/path.h',\n"
1674 " 'external-contents': '//root/external/file'\n"
1675 " }\n"
1676 "] }",
1677 Lower);
1678 EXPECT_EQ(nullptr, FS.get());
1680 // Relative directory path.
1681 FS = getFromYAMLString(
1682 "{ 'roots': [\n"
1683 " { 'type': 'directory', 'name': 'relative/directory/path.h',\n"
1684 " 'contents': []\n"
1685 " }\n"
1686 "] }",
1687 Lower);
1688 EXPECT_EQ(nullptr, FS.get());
1690 EXPECT_EQ(3, NumDiagnostics);
1693 TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) {
1694 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1695 Lower->addDirectory("//root/");
1696 Lower->addRegularFile("//root/a");
1697 Lower->addRegularFile("//root/b");
1698 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1699 "{ 'use-external-names': false,\n"
1700 " 'fallthrough': false,\n"
1701 " 'roots': [\n"
1702 "{\n"
1703 " 'type': 'directory',\n"
1704 " 'name': '//root/',\n"
1705 " 'contents': [ {\n"
1706 " 'type': 'file',\n"
1707 " 'name': 'c',\n"
1708 " 'external-contents': '//root/a'\n"
1709 " }\n"
1710 " ]\n"
1711 "}\n"
1712 "]\n"
1713 "}",
1714 Lower);
1715 ASSERT_TRUE(FS.get() != nullptr);
1717 std::error_code EC;
1718 checkContents(FS->dir_begin("//root/", EC),
1719 {"//root/c"});
1722 TEST_F(VFSFromYAMLTest, DirectoryIterationWithDuplicates) {
1723 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1724 Lower->addDirectory("//root/");
1725 Lower->addRegularFile("//root/a");
1726 Lower->addRegularFile("//root/b");
1727 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1728 "{ 'use-external-names': false,\n"
1729 " 'roots': [\n"
1730 "{\n"
1731 " 'type': 'directory',\n"
1732 " 'name': '//root/',\n"
1733 " 'contents': [ {\n"
1734 " 'type': 'file',\n"
1735 " 'name': 'a',\n"
1736 " 'external-contents': '//root/a'\n"
1737 " }\n"
1738 " ]\n"
1739 "}\n"
1740 "]\n"
1741 "}",
1742 Lower);
1743 ASSERT_TRUE(FS.get() != nullptr);
1745 std::error_code EC;
1746 checkContents(FS->dir_begin("//root/", EC),
1747 {"//root/a", "//root/b"});
1750 TEST_F(VFSFromYAMLTest, DirectoryIterationErrorInVFSLayer) {
1751 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1752 Lower->addDirectory("//root/");
1753 Lower->addDirectory("//root/foo");
1754 Lower->addRegularFile("//root/foo/a");
1755 Lower->addRegularFile("//root/foo/b");
1756 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1757 "{ 'use-external-names': false,\n"
1758 " 'roots': [\n"
1759 "{\n"
1760 " 'type': 'directory',\n"
1761 " 'name': '//root/',\n"
1762 " 'contents': [ {\n"
1763 " 'type': 'file',\n"
1764 " 'name': 'bar/a',\n"
1765 " 'external-contents': '//root/foo/a'\n"
1766 " }\n"
1767 " ]\n"
1768 "}\n"
1769 "]\n"
1770 "}",
1771 Lower);
1772 ASSERT_TRUE(FS.get() != nullptr);
1774 std::error_code EC;
1775 checkContents(FS->dir_begin("//root/foo", EC),
1776 {"//root/foo/a", "//root/foo/b"});
1779 TEST_F(VFSFromYAMLTest, GetRealPath) {
1780 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1781 Lower->addDirectory("//dir/");
1782 Lower->addRegularFile("/foo");
1783 Lower->addSymlink("/link");
1784 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1785 "{ 'use-external-names': false,\n"
1786 " 'roots': [\n"
1787 "{\n"
1788 " 'type': 'directory',\n"
1789 " 'name': '//root/',\n"
1790 " 'contents': [ {\n"
1791 " 'type': 'file',\n"
1792 " 'name': 'bar',\n"
1793 " 'external-contents': '/link'\n"
1794 " }\n"
1795 " ]\n"
1796 "},\n"
1797 "{\n"
1798 " 'type': 'directory',\n"
1799 " 'name': '//dir/',\n"
1800 " 'contents': []\n"
1801 "}\n"
1802 "]\n"
1803 "}",
1804 Lower);
1805 ASSERT_TRUE(FS.get() != nullptr);
1807 // Regular file present in underlying file system.
1808 SmallString<16> RealPath;
1809 EXPECT_FALSE(FS->getRealPath("/foo", RealPath));
1810 EXPECT_EQ(RealPath.str(), "/foo");
1812 // File present in YAML pointing to symlink in underlying file system.
1813 EXPECT_FALSE(FS->getRealPath("//root/bar", RealPath));
1814 EXPECT_EQ(RealPath.str(), "/symlink");
1816 // Directories should fall back to the underlying file system is possible.
1817 EXPECT_FALSE(FS->getRealPath("//dir/", RealPath));
1818 EXPECT_EQ(RealPath.str(), "//dir/");
1820 // Try a non-existing file.
1821 EXPECT_EQ(FS->getRealPath("/non_existing", RealPath),
1822 errc::no_such_file_or_directory);