1 //===- unittests/Support/VirtualFileSystem.cpp -------------- VFS tests ---===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
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"
24 using llvm::sys::fs::UniqueID
;
25 using testing::ElementsAre
;
27 using testing::UnorderedElementsAre
;
30 struct DummyFile
: public vfs::File
{
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() {
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
);
62 ErrorOr
<std::unique_ptr
<vfs::File
>>
63 openFileForRead(const Twine
&Path
) override
{
64 auto S
= status(Path
);
66 return std::unique_ptr
<vfs::File
>(new DummyFile
{*S
});
69 llvm::ErrorOr
<std::string
> getCurrentWorkingDirectory() const override
{
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()) {
83 Twine("/symlink").toVector(Output
);
84 return std::error_code();
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
;
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)
103 DirIterImpl(std::map
<std::string
, vfs::Status
> &FilesAndDirs
,
105 : FilesAndDirs(FilesAndDirs
), I(FilesAndDirs
.begin()),
107 for (; I
!= FilesAndDirs
.end(); ++I
) {
108 if (isInPath(I
->first
)) {
110 vfs::directory_entry(I
->second
.getName(), I
->second
.getType());
115 std::error_code
increment() override
{
117 for (; I
!= FilesAndDirs
.end(); ++I
) {
118 if (isInPath(I
->first
)) {
120 vfs::directory_entry(I
->second
.getName(), I
->second
.getType());
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
);
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
);
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
);
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
);
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
);
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
);
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());
348 SmallString
<128> Path
;
349 ScopedDir(const Twine
&Name
, bool Unique
= false) {
352 EC
= llvm::sys::fs::createUniqueDirectory(Name
, Path
);
355 EC
= llvm::sys::fs::create_directory(Twine(Path
));
363 EXPECT_FALSE(llvm::sys::fs::remove(Path
.str()));
366 operator StringRef() { return Path
.str(); }
370 SmallString
<128> Path
;
371 ScopedLink(const Twine
&To
, const Twine
&From
) {
373 std::error_code EC
= sys::fs::create_link(To
, From
);
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();
392 vfs::directory_iterator I
= FS
->dir_begin(Twine(TestDirectory
), 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
);
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"));
408 ASSERT_NE(vfs::directory_iterator(), I
);
409 EXPECT_TRUE(I
->path().endswith("a") || I
->path().endswith("c"));
411 EXPECT_EQ(vfs::directory_iterator(), I
);
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
;
426 for (vfs::directory_iterator I
= FS
->dir_begin(Twine(TestDirectory
), EC
), E
;
427 I
!= E
; I
.increment(EC
)) {
429 StatResults
[sys::path::filename(I
->path())] =
430 FS
->status(I
->path()).getError();
435 Pair("a", std::make_error_code(std::errc::no_such_file_or_directory
)),
436 Pair("b", std::error_code()),
438 std::make_error_code(std::errc::no_such_file_or_directory
))));
442 TEST(VirtualFileSystemTest
, BasicRealFSRecursiveIteration
) {
443 ScopedDir
TestDirectory("virtual-file-system-test", /*Unique*/ true);
444 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= vfs::getRealFileSystem();
447 auto I
= vfs::recursive_directory_iterator(*FS
, Twine(TestDirectory
), 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
);
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
;
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);
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.
497 auto I
= vfs::recursive_directory_iterator(*FS
, Twine(TestDirectory
), EC
);
500 std::vector
<std::string
> Contents
;
501 for (auto E
= vfs::recursive_directory_iterator(); !EC
&& I
!= E
;
503 Contents
.push_back(I
->path());
504 char last
= I
->path().back();
516 EXPECT_EQ(7U, Contents
.size());
519 // Test that calling no_push skips subdirectories.
522 auto I
= vfs::recursive_directory_iterator(*FS
, Twine(TestDirectory
), EC
);
525 std::vector
<std::string
> Contents
;
526 for (auto E
= vfs::recursive_directory_iterator(); !EC
&& I
!= E
;
528 Contents
.push_back(I
->path());
529 char last
= I
->path().back();
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);
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
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
;
579 for (vfs::recursive_directory_iterator
I(*FS
, Twine(TestDirectory
), EC
), E
;
580 I
!= E
; I
.increment(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
),
591 EXPECT_THAT(VisitedNonBrokenSymlinks
,
592 UnorderedElementsAre(StringRef(_b
), StringRef(_bb
), StringRef(_d
),
593 StringRef(_dd
), StringRef(_ddd
)));
597 template <typename DirIter
>
598 static void checkContents(DirIter I
, ArrayRef
<StringRef
> ExpectedOut
) {
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
);
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
);
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
);
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
);
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");
722 O
->dir_begin("/", EC
),
723 {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
725 // Make sure we get the top-most entry
728 vfs::directory_iterator I
= O
->dir_begin("/", EC
), E
;
729 for (; !EC
&& I
!= E
; I
.increment(EC
))
730 if (I
->path() == "/hiddenByUp")
733 EXPECT_EQ(sys::fs::file_type::regular_file
, I
->type());
737 vfs::directory_iterator I
= O
->dir_begin("/", EC
), E
;
738 for (; !EC
&& I
!= E
; I
.increment(EC
))
739 if (I
->path() == "/hiddenByMid")
742 EXPECT_EQ(sys::fs::file_type::regular_file
, I
->type());
746 class InMemoryFileSystemTest
: public ::testing::Test
{
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:");
777 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << FS
.toString();
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("/.");
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");
827 File
= FS
.openFileForRead("e/../d");
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(""));
847 vfs::directory_iterator I
= FS
.dir_begin("/", EC
);
849 ASSERT_EQ("/a", I
->path());
852 ASSERT_EQ("/b", I
->path());
855 ASSERT_EQ(vfs::directory_iterator(), I
);
857 I
= FS
.dir_begin("/b", 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()));
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(".");
882 getPosixPath(NormalizedFS
.getCurrentWorkingDirectory().get()));
883 NormalizedFS
.setCurrentWorkingDirectory("..");
885 getPosixPath(NormalizedFS
.getCurrentWorkingDirectory().get()));
888 TEST_F(InMemoryFileSystemTest
, IsLocal
) {
889 FS
.setCurrentWorkingDirectory("/b");
890 FS
.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
894 EC
= FS
.isLocal("c", IsLocal
);
896 ASSERT_FALSE(IsLocal
);
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
);
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");
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"),
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.
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
) {
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
);
1134 std::vector
<std::string
> Nodes
;
1135 for (auto E
= vfs::recursive_directory_iterator(); !EC
&& I
!= E
;
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
{
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,
1163 IntrusiveRefCntPtr
<vfs::FileSystem
> getFromYAMLString(
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(
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"
1203 " 'type': 'file',\n"
1204 " 'name': 'file2',\n"
1205 " 'external-contents': '//root/foo/b'\n"
1212 ASSERT_TRUE(FS
.get() != nullptr);
1214 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
1215 new vfs::OverlayFileSystem(Lower
));
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
);
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
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"
1256 " 'type': 'directory',\n"
1257 " 'name': '//root/',\n"
1258 " 'contents': [ {\n"
1259 " 'type': 'file',\n"
1261 " 'external-contents': '//root/foo/bar/a'\n"
1266 ASSERT_TRUE(FS
.get() != nullptr);
1268 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
1269 new vfs::OverlayFileSystem(Lower
));
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"
1292 " 'type': 'directory',\n"
1293 " 'name': '//root/',\n"
1294 " 'contents': [ {\n"
1295 " 'type': 'file',\n"
1297 " 'external-contents': '//root/foo/bar/a'\n"
1302 ASSERT_TRUE(FS
.get() != nullptr);
1304 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
1305 new vfs::OverlayFileSystem(Lower
));
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': [}",
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());
1338 FS
= getFromYAMLString("{ 'roots':'' }", Lower
);
1339 EXPECT_EQ(nullptr, FS
.get());
1340 FS
= getFromYAMLString("{ 'roots':{} }", Lower
);
1341 EXPECT_EQ(nullptr, FS
.get());
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' }",
1350 EXPECT_EQ(nullptr, FS
.get());
1351 FS
= getFromYAMLString(
1352 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1354 EXPECT_EQ(nullptr, FS
.get());
1355 FS
= getFromYAMLString(
1356 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
1358 EXPECT_EQ(nullptr, FS
.get());
1359 FS
= getFromYAMLString(
1360 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
1362 EXPECT_EQ(nullptr, FS
.get());
1363 FS
= getFromYAMLString(
1364 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
1366 EXPECT_EQ(nullptr, FS
.get());
1367 FS
= getFromYAMLString(
1368 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
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());
1382 FS
= getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower
);
1383 EXPECT_EQ(nullptr, FS
.get());
1384 FS
= getFromYAMLString(
1385 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1387 EXPECT_EQ(nullptr, FS
.get());
1389 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1390 "'external-contents':'blah' } ] }",
1392 EXPECT_EQ(nullptr, FS
.get());
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"
1417 " { 'type': 'file', 'name': '//root/B',\n"
1418 " 'use-external-name': true,\n"
1419 " 'external-contents': '//root/external/file'\n"
1421 " { 'type': 'file', 'name': '//root/C',\n"
1422 " 'use-external-name': false,\n"
1423 " 'external-contents': '//root/external/file'\n"
1427 ASSERT_TRUE(nullptr != FS
.get());
1430 EXPECT_EQ("//root/external/file", FS
->status("//root/A")->getName());
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"
1438 " { 'type': 'file', 'name': '//root/A',\n"
1439 " 'external-contents': '//root/external/file'\n"
1441 " { 'type': 'file', 'name': '//root/B',\n"
1442 " 'use-external-name': true,\n"
1443 " 'external-contents': '//root/external/file'\n"
1445 " { 'type': 'file', 'name': '//root/C',\n"
1446 " 'use-external-name': false,\n"
1447 " 'external-contents': '//root/external/file'\n"
1451 ASSERT_TRUE(nullptr != FS
.get());
1454 EXPECT_EQ("//root/A", FS
->status("//root/A")->getName());
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");
1465 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
=
1466 getFromYAMLString("{ 'roots': [\n"
1467 " { 'type': 'file', 'name': '//root/path/to/file',\n"
1468 " 'external-contents': '//root/other' }]\n"
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());
1478 FS
= getFromYAMLString(
1480 " { 'type': 'directory', 'name': '//root/path/to',\n"
1481 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
1482 " 'external-contents': '//root/other' }]}]\n"
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());
1492 FS
= getFromYAMLString(
1494 " { 'type': 'directory', 'name': '//root/',\n"
1495 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
1496 " 'external-contents': '//root/other' }]}]\n"
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");
1511 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
1513 " { 'type': 'directory', 'name': '//root/path/to////',\n"
1514 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
1515 " 'external-contents': '//root/other' }]}]\n"
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"
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"
1545 " 'type': 'file',\n"
1546 " 'name': 'file2',\n"
1547 " 'external-contents': '//root/foo/bar/b'\n"
1554 ASSERT_TRUE(FS
.get() != nullptr);
1556 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
1557 new vfs::OverlayFileSystem(Lower
));
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())
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"
1582 " 'type': 'directory',\n"
1583 " 'name': '//root/baz/',\n"
1584 " 'contents': [ {\n"
1585 " 'type': 'file',\n"
1587 " 'external-contents': '//root/zab/a'\n"
1592 " 'type': 'directory',\n"
1593 " 'name': '//root/baz/',\n"
1594 " 'contents': [ {\n"
1595 " 'type': 'file',\n"
1597 " 'external-contents': '//root/zab/b'\n"
1604 ASSERT_TRUE(FS
.get() != nullptr);
1606 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
1607 new vfs::OverlayFileSystem(Lower
));
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"
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"
1639 ASSERT_TRUE(FS
.get() != nullptr);
1641 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
1642 new vfs::OverlayFileSystem(Lower
));
1647 // Test recursive_directory_iterator level()
1648 vfs::recursive_directory_iterator I
= vfs::recursive_directory_iterator(
1652 for (int l
= 0; I
!= E
; I
.increment(EC
), ++l
) {
1654 EXPECT_EQ(I
.level(), l
);
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(
1664 " { 'type': 'file', 'name': 'file-not-in-directory.h',\n"
1665 " 'external-contents': '//root/external/file'\n"
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"
1678 EXPECT_EQ(nullptr, FS
.get());
1680 // Relative directory path.
1681 FS
= getFromYAMLString(
1683 " { 'type': 'directory', 'name': 'relative/directory/path.h',\n"
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"
1703 " 'type': 'directory',\n"
1704 " 'name': '//root/',\n"
1705 " 'contents': [ {\n"
1706 " 'type': 'file',\n"
1708 " 'external-contents': '//root/a'\n"
1715 ASSERT_TRUE(FS
.get() != nullptr);
1718 checkContents(FS
->dir_begin("//root/", EC
),
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"
1731 " 'type': 'directory',\n"
1732 " 'name': '//root/',\n"
1733 " 'contents': [ {\n"
1734 " 'type': 'file',\n"
1736 " 'external-contents': '//root/a'\n"
1743 ASSERT_TRUE(FS
.get() != nullptr);
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"
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"
1772 ASSERT_TRUE(FS
.get() != nullptr);
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"
1788 " 'type': 'directory',\n"
1789 " 'name': '//root/',\n"
1790 " 'contents': [ {\n"
1791 " 'type': 'file',\n"
1793 " 'external-contents': '/link'\n"
1798 " 'type': 'directory',\n"
1799 " 'name': '//dir/',\n"
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
);