1 //===- unittests/Support/VirtualFileSystem.cpp -------------- VFS tests ---===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Support/VirtualFileSystem.h"
10 #include "llvm/ADT/Triple.h"
11 #include "llvm/Config/llvm-config.h"
12 #include "llvm/Support/Errc.h"
13 #include "llvm/Support/Host.h"
14 #include "llvm/Support/MemoryBuffer.h"
15 #include "llvm/Support/Path.h"
16 #include "llvm/Support/SourceMgr.h"
17 #include "llvm/Testing/Support/SupportHelpers.h"
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
24 using llvm::sys::fs::UniqueID
;
25 using llvm::unittest::TempDir
;
26 using llvm::unittest::TempFile
;
27 using llvm::unittest::TempLink
;
28 using testing::ElementsAre
;
30 using testing::UnorderedElementsAre
;
33 struct DummyFile
: public vfs::File
{
35 explicit DummyFile(vfs::Status S
) : S(S
) {}
36 llvm::ErrorOr
<vfs::Status
> status() override
{ return S
; }
37 llvm::ErrorOr
<std::unique_ptr
<llvm::MemoryBuffer
>>
38 getBuffer(const Twine
&Name
, int64_t FileSize
, bool RequiresNullTerminator
,
39 bool IsVolatile
) override
{
40 llvm_unreachable("unimplemented");
42 std::error_code
close() override
{ return std::error_code(); }
45 class DummyFileSystem
: public vfs::FileSystem
{
46 int FSID
; // used to produce UniqueIDs
47 int FileID
; // used to produce UniqueIDs
48 std::string WorkingDirectory
;
49 std::map
<std::string
, vfs::Status
> FilesAndDirs
;
50 typedef std::map
<std::string
, vfs::Status
>::const_iterator const_iterator
;
52 static int getNextFSID() {
58 DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
60 ErrorOr
<vfs::Status
> status(const Twine
&Path
) override
{
61 auto I
= findEntry(Path
);
62 if (I
== FilesAndDirs
.end())
63 return make_error_code(llvm::errc::no_such_file_or_directory
);
66 ErrorOr
<std::unique_ptr
<vfs::File
>>
67 openFileForRead(const Twine
&Path
) override
{
68 auto S
= status(Path
);
70 return std::unique_ptr
<vfs::File
>(new DummyFile
{*S
});
73 llvm::ErrorOr
<std::string
> getCurrentWorkingDirectory() const override
{
74 return WorkingDirectory
;
76 std::error_code
setCurrentWorkingDirectory(const Twine
&Path
) override
{
77 WorkingDirectory
= Path
.str();
78 return std::error_code();
80 // Map any symlink to "/symlink".
81 std::error_code
getRealPath(const Twine
&Path
,
82 SmallVectorImpl
<char> &Output
) const override
{
83 auto I
= findEntry(Path
);
84 if (I
== FilesAndDirs
.end())
85 return make_error_code(llvm::errc::no_such_file_or_directory
);
86 if (I
->second
.isSymlink()) {
88 Twine("/symlink").toVector(Output
);
89 return std::error_code();
92 Path
.toVector(Output
);
93 return std::error_code();
96 struct DirIterImpl
: public llvm::vfs::detail::DirIterImpl
{
97 std::map
<std::string
, vfs::Status
> &FilesAndDirs
;
98 std::map
<std::string
, vfs::Status
>::iterator I
;
100 bool isInPath(StringRef S
) {
101 if (Path
.size() < S
.size() && S
.find(Path
) == 0) {
102 auto LastSep
= S
.find_last_of('/');
103 if (LastSep
== Path
.size() || LastSep
== Path
.size() - 1)
108 DirIterImpl(std::map
<std::string
, vfs::Status
> &FilesAndDirs
,
110 : FilesAndDirs(FilesAndDirs
), I(FilesAndDirs
.begin()),
112 for (; I
!= FilesAndDirs
.end(); ++I
) {
113 if (isInPath(I
->first
)) {
114 CurrentEntry
= vfs::directory_entry(std::string(I
->second
.getName()),
115 I
->second
.getType());
120 std::error_code
increment() override
{
122 for (; I
!= FilesAndDirs
.end(); ++I
) {
123 if (isInPath(I
->first
)) {
124 CurrentEntry
= vfs::directory_entry(std::string(I
->second
.getName()),
125 I
->second
.getType());
129 if (I
== FilesAndDirs
.end())
130 CurrentEntry
= vfs::directory_entry();
131 return std::error_code();
135 vfs::directory_iterator
dir_begin(const Twine
&Dir
,
136 std::error_code
&EC
) override
{
137 return vfs::directory_iterator(
138 std::make_shared
<DirIterImpl
>(FilesAndDirs
, Dir
));
141 void addEntry(StringRef Path
, const vfs::Status
&Status
) {
142 FilesAndDirs
[std::string(Path
)] = Status
;
145 const_iterator
findEntry(const Twine
&Path
) const {
148 std::error_code EC
= makeAbsolute(P
);
151 return FilesAndDirs
.find(std::string(P
.str()));
154 void addRegularFile(StringRef Path
, sys::fs::perms Perms
= sys::fs::all_all
) {
155 vfs::Status
S(Path
, UniqueID(FSID
, FileID
++),
156 std::chrono::system_clock::now(), 0, 0, 1024,
157 sys::fs::file_type::regular_file
, Perms
);
161 void addDirectory(StringRef Path
, sys::fs::perms Perms
= sys::fs::all_all
) {
162 vfs::Status
S(Path
, UniqueID(FSID
, FileID
++),
163 std::chrono::system_clock::now(), 0, 0, 0,
164 sys::fs::file_type::directory_file
, Perms
);
168 void addSymlink(StringRef Path
) {
169 vfs::Status
S(Path
, UniqueID(FSID
, FileID
++),
170 std::chrono::system_clock::now(), 0, 0, 0,
171 sys::fs::file_type::symlink_file
, sys::fs::all_all
);
176 class ErrorDummyFileSystem
: public DummyFileSystem
{
177 std::error_code
setCurrentWorkingDirectory(const Twine
&Path
) override
{
178 return llvm::errc::no_such_file_or_directory
;
182 /// Replace back-slashes by front-slashes.
183 std::string
getPosixPath(std::string S
) {
184 SmallString
<128> Result
;
185 llvm::sys::path::native(S
, Result
, llvm::sys::path::Style::posix
);
186 return std::string(Result
.str());
188 } // end anonymous namespace
190 TEST(VirtualFileSystemTest
, StatusQueries
) {
191 IntrusiveRefCntPtr
<DummyFileSystem
> D(new DummyFileSystem());
192 ErrorOr
<vfs::Status
> Status((std::error_code()));
194 D
->addRegularFile("/foo");
195 Status
= D
->status("/foo");
196 ASSERT_FALSE(Status
.getError());
197 EXPECT_TRUE(Status
->isStatusKnown());
198 EXPECT_FALSE(Status
->isDirectory());
199 EXPECT_TRUE(Status
->isRegularFile());
200 EXPECT_FALSE(Status
->isSymlink());
201 EXPECT_FALSE(Status
->isOther());
202 EXPECT_TRUE(Status
->exists());
204 D
->addDirectory("/bar");
205 Status
= D
->status("/bar");
206 ASSERT_FALSE(Status
.getError());
207 EXPECT_TRUE(Status
->isStatusKnown());
208 EXPECT_TRUE(Status
->isDirectory());
209 EXPECT_FALSE(Status
->isRegularFile());
210 EXPECT_FALSE(Status
->isSymlink());
211 EXPECT_FALSE(Status
->isOther());
212 EXPECT_TRUE(Status
->exists());
214 D
->addSymlink("/baz");
215 Status
= D
->status("/baz");
216 ASSERT_FALSE(Status
.getError());
217 EXPECT_TRUE(Status
->isStatusKnown());
218 EXPECT_FALSE(Status
->isDirectory());
219 EXPECT_FALSE(Status
->isRegularFile());
220 EXPECT_TRUE(Status
->isSymlink());
221 EXPECT_FALSE(Status
->isOther());
222 EXPECT_TRUE(Status
->exists());
224 EXPECT_TRUE(Status
->equivalent(*Status
));
225 ErrorOr
<vfs::Status
> Status2
= D
->status("/foo");
226 ASSERT_FALSE(Status2
.getError());
227 EXPECT_FALSE(Status
->equivalent(*Status2
));
230 TEST(VirtualFileSystemTest
, BaseOnlyOverlay
) {
231 IntrusiveRefCntPtr
<DummyFileSystem
> D(new DummyFileSystem());
232 ErrorOr
<vfs::Status
> Status((std::error_code()));
233 EXPECT_FALSE(Status
= D
->status("/foo"));
235 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(new vfs::OverlayFileSystem(D
));
236 EXPECT_FALSE(Status
= O
->status("/foo"));
238 D
->addRegularFile("/foo");
239 Status
= D
->status("/foo");
240 EXPECT_FALSE(Status
.getError());
242 ErrorOr
<vfs::Status
> Status2((std::error_code()));
243 Status2
= O
->status("/foo");
244 EXPECT_FALSE(Status2
.getError());
245 EXPECT_TRUE(Status
->equivalent(*Status2
));
248 TEST(VirtualFileSystemTest
, GetRealPathInOverlay
) {
249 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
250 Lower
->addRegularFile("/foo");
251 Lower
->addSymlink("/lower_link");
252 IntrusiveRefCntPtr
<DummyFileSystem
> Upper(new DummyFileSystem());
254 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
255 new vfs::OverlayFileSystem(Lower
));
256 O
->pushOverlay(Upper
);
259 SmallString
<16> RealPath
;
260 EXPECT_FALSE(O
->getRealPath("/foo", RealPath
));
261 EXPECT_EQ(RealPath
.str(), "/foo");
263 // Expect no error getting real path for symlink in lower overlay.
264 EXPECT_FALSE(O
->getRealPath("/lower_link", RealPath
));
265 EXPECT_EQ(RealPath
.str(), "/symlink");
267 // Try a non-existing link.
268 EXPECT_EQ(O
->getRealPath("/upper_link", RealPath
),
269 errc::no_such_file_or_directory
);
271 // Add a new symlink in upper.
272 Upper
->addSymlink("/upper_link");
273 EXPECT_FALSE(O
->getRealPath("/upper_link", RealPath
));
274 EXPECT_EQ(RealPath
.str(), "/symlink");
277 TEST(VirtualFileSystemTest
, OverlayFiles
) {
278 IntrusiveRefCntPtr
<DummyFileSystem
> Base(new DummyFileSystem());
279 IntrusiveRefCntPtr
<DummyFileSystem
> Middle(new DummyFileSystem());
280 IntrusiveRefCntPtr
<DummyFileSystem
> Top(new DummyFileSystem());
281 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
282 new vfs::OverlayFileSystem(Base
));
283 O
->pushOverlay(Middle
);
286 ErrorOr
<vfs::Status
> Status1((std::error_code())),
287 Status2((std::error_code())), Status3((std::error_code())),
288 StatusB((std::error_code())), StatusM((std::error_code())),
289 StatusT((std::error_code()));
291 Base
->addRegularFile("/foo");
292 StatusB
= Base
->status("/foo");
293 ASSERT_FALSE(StatusB
.getError());
294 Status1
= O
->status("/foo");
295 ASSERT_FALSE(Status1
.getError());
296 Middle
->addRegularFile("/foo");
297 StatusM
= Middle
->status("/foo");
298 ASSERT_FALSE(StatusM
.getError());
299 Status2
= O
->status("/foo");
300 ASSERT_FALSE(Status2
.getError());
301 Top
->addRegularFile("/foo");
302 StatusT
= Top
->status("/foo");
303 ASSERT_FALSE(StatusT
.getError());
304 Status3
= O
->status("/foo");
305 ASSERT_FALSE(Status3
.getError());
307 EXPECT_TRUE(Status1
->equivalent(*StatusB
));
308 EXPECT_TRUE(Status2
->equivalent(*StatusM
));
309 EXPECT_TRUE(Status3
->equivalent(*StatusT
));
311 EXPECT_FALSE(Status1
->equivalent(*Status2
));
312 EXPECT_FALSE(Status2
->equivalent(*Status3
));
313 EXPECT_FALSE(Status1
->equivalent(*Status3
));
316 TEST(VirtualFileSystemTest
, OverlayDirsNonMerged
) {
317 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
318 IntrusiveRefCntPtr
<DummyFileSystem
> Upper(new DummyFileSystem());
319 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
320 new vfs::OverlayFileSystem(Lower
));
321 O
->pushOverlay(Upper
);
323 Lower
->addDirectory("/lower-only");
324 Upper
->addDirectory("/upper-only");
326 // non-merged paths should be the same
327 ErrorOr
<vfs::Status
> Status1
= Lower
->status("/lower-only");
328 ASSERT_FALSE(Status1
.getError());
329 ErrorOr
<vfs::Status
> Status2
= O
->status("/lower-only");
330 ASSERT_FALSE(Status2
.getError());
331 EXPECT_TRUE(Status1
->equivalent(*Status2
));
333 Status1
= Upper
->status("/upper-only");
334 ASSERT_FALSE(Status1
.getError());
335 Status2
= O
->status("/upper-only");
336 ASSERT_FALSE(Status2
.getError());
337 EXPECT_TRUE(Status1
->equivalent(*Status2
));
340 TEST(VirtualFileSystemTest
, MergedDirPermissions
) {
341 // merged directories get the permissions of the upper dir
342 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
343 IntrusiveRefCntPtr
<DummyFileSystem
> Upper(new DummyFileSystem());
344 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
345 new vfs::OverlayFileSystem(Lower
));
346 O
->pushOverlay(Upper
);
348 ErrorOr
<vfs::Status
> Status((std::error_code()));
349 Lower
->addDirectory("/both", sys::fs::owner_read
);
350 Upper
->addDirectory("/both", sys::fs::owner_all
| sys::fs::group_read
);
351 Status
= O
->status("/both");
352 ASSERT_FALSE(Status
.getError());
353 EXPECT_EQ(0740, Status
->getPermissions());
355 // permissions (as usual) are not recursively applied
356 Lower
->addRegularFile("/both/foo", sys::fs::owner_read
);
357 Upper
->addRegularFile("/both/bar", sys::fs::owner_write
);
358 Status
= O
->status("/both/foo");
359 ASSERT_FALSE(Status
.getError());
360 EXPECT_EQ(0400, Status
->getPermissions());
361 Status
= O
->status("/both/bar");
362 ASSERT_FALSE(Status
.getError());
363 EXPECT_EQ(0200, Status
->getPermissions());
366 TEST(VirtualFileSystemTest
, OverlayIterator
) {
367 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
368 Lower
->addRegularFile("/foo");
369 IntrusiveRefCntPtr
<DummyFileSystem
> Upper(new DummyFileSystem());
371 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
372 new vfs::OverlayFileSystem(Lower
));
373 O
->pushOverlay(Upper
);
375 ErrorOr
<vfs::Status
> Status((std::error_code()));
377 auto it
= O
->overlays_begin();
378 auto end
= O
->overlays_end();
382 Status
= (*it
)->status("/foo");
383 ASSERT_TRUE(Status
.getError());
388 Status
= (*it
)->status("/foo");
389 ASSERT_FALSE(Status
.getError());
390 EXPECT_TRUE(Status
->exists());
397 auto it
= O
->overlays_rbegin();
398 auto end
= O
->overlays_rend();
402 Status
= (*it
)->status("/foo");
403 ASSERT_FALSE(Status
.getError());
404 EXPECT_TRUE(Status
->exists());
409 Status
= (*it
)->status("/foo");
410 ASSERT_TRUE(Status
.getError());
417 TEST(VirtualFileSystemTest
, BasicRealFSIteration
) {
418 TempDir
TestDirectory("virtual-file-system-test", /*Unique*/ true);
419 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= vfs::getRealFileSystem();
422 vfs::directory_iterator I
= FS
->dir_begin(Twine(TestDirectory
.path()), EC
);
424 EXPECT_EQ(vfs::directory_iterator(), I
); // empty directory is empty
426 TempDir
_a(TestDirectory
.path("a"));
427 TempDir
_ab(TestDirectory
.path("a/b"));
428 TempDir
_c(TestDirectory
.path("c"));
429 TempDir
_cd(TestDirectory
.path("c/d"));
431 I
= FS
->dir_begin(Twine(TestDirectory
.path()), EC
);
433 ASSERT_NE(vfs::directory_iterator(), I
);
434 // Check either a or c, since we can't rely on the iteration order.
435 EXPECT_TRUE(I
->path().endswith("a") || I
->path().endswith("c"));
438 ASSERT_NE(vfs::directory_iterator(), I
);
439 EXPECT_TRUE(I
->path().endswith("a") || I
->path().endswith("c"));
441 EXPECT_EQ(vfs::directory_iterator(), I
);
445 TEST(VirtualFileSystemTest
, MultipleWorkingDirs
) {
446 // Our root contains a/aa, b/bb, c, where c is a link to a/.
447 // Run tests both in root/b/ and root/c/ (to test "normal" and symlink dirs).
448 // Interleave operations to show the working directories are independent.
449 TempDir
Root("r", /*Unique*/ true);
450 TempDir
ADir(Root
.path("a"));
451 TempDir
BDir(Root
.path("b"));
452 TempLink
C(ADir
.path(), Root
.path("c"));
453 TempFile
AA(ADir
.path("aa"), "", "aaaa");
454 TempFile
BB(BDir
.path("bb"), "", "bbbb");
455 std::unique_ptr
<vfs::FileSystem
> BFS
= vfs::createPhysicalFileSystem(),
456 CFS
= vfs::createPhysicalFileSystem();
458 ASSERT_FALSE(BFS
->setCurrentWorkingDirectory(BDir
.path()));
459 ASSERT_FALSE(CFS
->setCurrentWorkingDirectory(C
.path()));
460 EXPECT_EQ(BDir
.path(), *BFS
->getCurrentWorkingDirectory());
461 EXPECT_EQ(C
.path(), *CFS
->getCurrentWorkingDirectory());
463 // openFileForRead(), indirectly.
464 auto BBuf
= BFS
->getBufferForFile("bb");
466 EXPECT_EQ("bbbb", (*BBuf
)->getBuffer());
468 auto ABuf
= CFS
->getBufferForFile("aa");
470 EXPECT_EQ("aaaa", (*ABuf
)->getBuffer());
473 auto BStat
= BFS
->status("bb");
475 EXPECT_EQ("bb", BStat
->getName());
477 auto AStat
= CFS
->status("aa");
479 EXPECT_EQ("aa", AStat
->getName()); // unresolved name
482 SmallString
<128> BPath
;
483 ASSERT_FALSE(BFS
->getRealPath("bb", BPath
));
484 EXPECT_EQ(BB
.path(), BPath
);
486 SmallString
<128> APath
;
487 ASSERT_FALSE(CFS
->getRealPath("aa", APath
));
488 EXPECT_EQ(AA
.path(), APath
); // Reports resolved name.
492 auto BIt
= BFS
->dir_begin(".", EC
);
494 ASSERT_NE(BIt
, vfs::directory_iterator());
495 EXPECT_EQ((BDir
.path() + "/./bb").str(), BIt
->path());
498 ASSERT_EQ(BIt
, vfs::directory_iterator());
500 auto CIt
= CFS
->dir_begin(".", EC
);
502 ASSERT_NE(CIt
, vfs::directory_iterator());
503 EXPECT_EQ((ADir
.path() + "/./aa").str(),
504 CIt
->path()); // Partly resolved name!
505 CIt
.increment(EC
); // Because likely to read through this path.
507 ASSERT_EQ(CIt
, vfs::directory_iterator());
510 TEST(VirtualFileSystemTest
, BrokenSymlinkRealFSIteration
) {
511 TempDir
TestDirectory("virtual-file-system-test", /*Unique*/ true);
512 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= vfs::getRealFileSystem();
514 TempLink
_a("no_such_file", TestDirectory
.path("a"));
515 TempDir
_b(TestDirectory
.path("b"));
516 TempLink
_c("no_such_file", TestDirectory
.path("c"));
518 // Should get no iteration error, but a stat error for the broken symlinks.
519 std::map
<std::string
, std::error_code
> StatResults
;
521 for (vfs::directory_iterator
522 I
= FS
->dir_begin(Twine(TestDirectory
.path()), EC
),
524 I
!= E
; I
.increment(EC
)) {
526 StatResults
[std::string(sys::path::filename(I
->path()))] =
527 FS
->status(I
->path()).getError();
532 Pair("a", std::make_error_code(std::errc::no_such_file_or_directory
)),
533 Pair("b", std::error_code()),
535 std::make_error_code(std::errc::no_such_file_or_directory
))));
539 TEST(VirtualFileSystemTest
, BasicRealFSRecursiveIteration
) {
540 TempDir
TestDirectory("virtual-file-system-test", /*Unique*/ true);
541 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= vfs::getRealFileSystem();
545 vfs::recursive_directory_iterator(*FS
, Twine(TestDirectory
.path()), EC
);
547 EXPECT_EQ(vfs::recursive_directory_iterator(), I
); // empty directory is empty
549 TempDir
_a(TestDirectory
.path("a"));
550 TempDir
_ab(TestDirectory
.path("a/b"));
551 TempDir
_c(TestDirectory
.path("c"));
552 TempDir
_cd(TestDirectory
.path("c/d"));
554 I
= vfs::recursive_directory_iterator(*FS
, Twine(TestDirectory
.path()), EC
);
556 ASSERT_NE(vfs::recursive_directory_iterator(), I
);
558 std::vector
<std::string
> Contents
;
559 for (auto E
= vfs::recursive_directory_iterator(); !EC
&& I
!= E
;
561 Contents
.push_back(std::string(I
->path()));
564 // Check contents, which may be in any order
565 EXPECT_EQ(4U, Contents
.size());
566 int Counts
[4] = {0, 0, 0, 0};
567 for (const std::string
&Name
: Contents
) {
568 ASSERT_FALSE(Name
.empty());
569 int Index
= Name
[Name
.size() - 1] - 'a';
570 ASSERT_TRUE(Index
>= 0 && Index
< 4);
573 EXPECT_EQ(1, Counts
[0]); // a
574 EXPECT_EQ(1, Counts
[1]); // b
575 EXPECT_EQ(1, Counts
[2]); // c
576 EXPECT_EQ(1, Counts
[3]); // d
579 TEST(VirtualFileSystemTest
, BasicRealFSRecursiveIterationNoPush
) {
580 TempDir
TestDirectory("virtual-file-system-test", /*Unique*/ true);
582 TempDir
_a(TestDirectory
.path("a"));
583 TempDir
_ab(TestDirectory
.path("a/b"));
584 TempDir
_c(TestDirectory
.path("c"));
585 TempDir
_cd(TestDirectory
.path("c/d"));
586 TempDir
_e(TestDirectory
.path("e"));
587 TempDir
_ef(TestDirectory
.path("e/f"));
588 TempDir
_g(TestDirectory
.path("g"));
590 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= vfs::getRealFileSystem();
592 // Test that calling no_push on entries without subdirectories has no effect.
596 vfs::recursive_directory_iterator(*FS
, Twine(TestDirectory
.path()), EC
);
599 std::vector
<std::string
> Contents
;
600 for (auto E
= vfs::recursive_directory_iterator(); !EC
&& I
!= E
;
602 Contents
.push_back(std::string(I
->path()));
603 char last
= I
->path().back();
615 EXPECT_EQ(7U, Contents
.size());
618 // Test that calling no_push skips subdirectories.
622 vfs::recursive_directory_iterator(*FS
, Twine(TestDirectory
.path()), EC
);
625 std::vector
<std::string
> Contents
;
626 for (auto E
= vfs::recursive_directory_iterator(); !EC
&& I
!= E
;
628 Contents
.push_back(std::string(I
->path()));
629 char last
= I
->path().back();
641 // Check contents, which may be in any order
642 EXPECT_EQ(4U, Contents
.size());
643 int Counts
[7] = {0, 0, 0, 0, 0, 0, 0};
644 for (const std::string
&Name
: Contents
) {
645 ASSERT_FALSE(Name
.empty());
646 int Index
= Name
[Name
.size() - 1] - 'a';
647 ASSERT_TRUE(Index
>= 0 && Index
< 7);
650 EXPECT_EQ(1, Counts
[0]); // a
651 EXPECT_EQ(0, Counts
[1]); // b
652 EXPECT_EQ(1, Counts
[2]); // c
653 EXPECT_EQ(0, Counts
[3]); // d
654 EXPECT_EQ(1, Counts
[4]); // e
655 EXPECT_EQ(0, Counts
[5]); // f
656 EXPECT_EQ(1, Counts
[6]); // g
661 TEST(VirtualFileSystemTest
, BrokenSymlinkRealFSRecursiveIteration
) {
662 TempDir
TestDirectory("virtual-file-system-test", /*Unique*/ true);
663 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= vfs::getRealFileSystem();
665 TempLink
_a("no_such_file", TestDirectory
.path("a"));
666 TempDir
_b(TestDirectory
.path("b"));
667 TempLink
_ba("no_such_file", TestDirectory
.path("b/a"));
668 TempDir
_bb(TestDirectory
.path("b/b"));
669 TempLink
_bc("no_such_file", TestDirectory
.path("b/c"));
670 TempLink
_c("no_such_file", TestDirectory
.path("c"));
671 TempDir
_d(TestDirectory
.path("d"));
672 TempDir
_dd(TestDirectory
.path("d/d"));
673 TempDir
_ddd(TestDirectory
.path("d/d/d"));
674 TempLink
_e("no_such_file", TestDirectory
.path("e"));
676 std::vector
<std::string
> VisitedBrokenSymlinks
;
677 std::vector
<std::string
> VisitedNonBrokenSymlinks
;
679 for (vfs::recursive_directory_iterator
680 I(*FS
, Twine(TestDirectory
.path()), EC
),
682 I
!= E
; I
.increment(EC
)) {
684 (FS
->status(I
->path()) ? VisitedNonBrokenSymlinks
: VisitedBrokenSymlinks
)
685 .push_back(std::string(I
->path()));
688 // Check visited file names.
689 EXPECT_THAT(VisitedBrokenSymlinks
,
690 UnorderedElementsAre(_a
.path().str(), _ba
.path().str(),
691 _bc
.path().str(), _c
.path().str(),
693 EXPECT_THAT(VisitedNonBrokenSymlinks
,
694 UnorderedElementsAre(_b
.path().str(), _bb
.path().str(),
695 _d
.path().str(), _dd
.path().str(),
700 template <typename DirIter
>
701 static void checkContents(DirIter I
, ArrayRef
<StringRef
> ExpectedOut
) {
703 SmallVector
<StringRef
, 4> Expected(ExpectedOut
.begin(), ExpectedOut
.end());
704 SmallVector
<std::string
, 4> InputToCheck
;
706 // Do not rely on iteration order to check for contents, sort both
707 // content vectors before comparison.
708 for (DirIter E
; !EC
&& I
!= E
; I
.increment(EC
))
709 InputToCheck
.push_back(std::string(I
->path()));
711 llvm::sort(InputToCheck
);
712 llvm::sort(Expected
);
713 EXPECT_EQ(InputToCheck
.size(), Expected
.size());
715 unsigned LastElt
= std::min(InputToCheck
.size(), Expected
.size());
716 for (unsigned Idx
= 0; Idx
!= LastElt
; ++Idx
)
717 EXPECT_EQ(StringRef(InputToCheck
[Idx
]), Expected
[Idx
]);
720 TEST(VirtualFileSystemTest
, OverlayIteration
) {
721 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
722 IntrusiveRefCntPtr
<DummyFileSystem
> Upper(new DummyFileSystem());
723 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
724 new vfs::OverlayFileSystem(Lower
));
725 O
->pushOverlay(Upper
);
728 checkContents(O
->dir_begin("/", EC
), ArrayRef
<StringRef
>());
730 Lower
->addRegularFile("/file1");
731 checkContents(O
->dir_begin("/", EC
), ArrayRef
<StringRef
>("/file1"));
733 Upper
->addRegularFile("/file2");
734 checkContents(O
->dir_begin("/", EC
), {"/file2", "/file1"});
736 Lower
->addDirectory("/dir1");
737 Lower
->addRegularFile("/dir1/foo");
738 Upper
->addDirectory("/dir2");
739 Upper
->addRegularFile("/dir2/foo");
740 checkContents(O
->dir_begin("/dir2", EC
), ArrayRef
<StringRef
>("/dir2/foo"));
741 checkContents(O
->dir_begin("/", EC
), {"/dir2", "/file2", "/dir1", "/file1"});
744 TEST(VirtualFileSystemTest
, OverlayRecursiveIteration
) {
745 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
746 IntrusiveRefCntPtr
<DummyFileSystem
> Middle(new DummyFileSystem());
747 IntrusiveRefCntPtr
<DummyFileSystem
> Upper(new DummyFileSystem());
748 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
749 new vfs::OverlayFileSystem(Lower
));
750 O
->pushOverlay(Middle
);
751 O
->pushOverlay(Upper
);
754 checkContents(vfs::recursive_directory_iterator(*O
, "/", EC
),
755 ArrayRef
<StringRef
>());
757 Lower
->addRegularFile("/file1");
758 checkContents(vfs::recursive_directory_iterator(*O
, "/", EC
),
759 ArrayRef
<StringRef
>("/file1"));
761 Upper
->addDirectory("/dir");
762 Upper
->addRegularFile("/dir/file2");
763 checkContents(vfs::recursive_directory_iterator(*O
, "/", EC
),
764 {"/dir", "/dir/file2", "/file1"});
766 Lower
->addDirectory("/dir1");
767 Lower
->addRegularFile("/dir1/foo");
768 Lower
->addDirectory("/dir1/a");
769 Lower
->addRegularFile("/dir1/a/b");
770 Middle
->addDirectory("/a");
771 Middle
->addDirectory("/a/b");
772 Middle
->addDirectory("/a/b/c");
773 Middle
->addRegularFile("/a/b/c/d");
774 Middle
->addRegularFile("/hiddenByUp");
775 Upper
->addDirectory("/dir2");
776 Upper
->addRegularFile("/dir2/foo");
777 Upper
->addRegularFile("/hiddenByUp");
778 checkContents(vfs::recursive_directory_iterator(*O
, "/dir2", EC
),
779 ArrayRef
<StringRef
>("/dir2/foo"));
780 checkContents(vfs::recursive_directory_iterator(*O
, "/", EC
),
781 {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
782 "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
783 "/dir1/a/b", "/dir1/foo", "/file1"});
786 TEST(VirtualFileSystemTest
, ThreeLevelIteration
) {
787 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
788 IntrusiveRefCntPtr
<DummyFileSystem
> Middle(new DummyFileSystem());
789 IntrusiveRefCntPtr
<DummyFileSystem
> Upper(new DummyFileSystem());
790 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
791 new vfs::OverlayFileSystem(Lower
));
792 O
->pushOverlay(Middle
);
793 O
->pushOverlay(Upper
);
796 checkContents(O
->dir_begin("/", EC
), ArrayRef
<StringRef
>());
798 Middle
->addRegularFile("/file2");
799 checkContents(O
->dir_begin("/", EC
), ArrayRef
<StringRef
>("/file2"));
801 Lower
->addRegularFile("/file1");
802 Upper
->addRegularFile("/file3");
803 checkContents(O
->dir_begin("/", EC
), {"/file3", "/file2", "/file1"});
806 TEST(VirtualFileSystemTest
, HiddenInIteration
) {
807 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
808 IntrusiveRefCntPtr
<DummyFileSystem
> Middle(new DummyFileSystem());
809 IntrusiveRefCntPtr
<DummyFileSystem
> Upper(new DummyFileSystem());
810 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
811 new vfs::OverlayFileSystem(Lower
));
812 O
->pushOverlay(Middle
);
813 O
->pushOverlay(Upper
);
816 Lower
->addRegularFile("/onlyInLow");
817 Lower
->addDirectory("/hiddenByMid");
818 Lower
->addDirectory("/hiddenByUp");
819 Middle
->addRegularFile("/onlyInMid");
820 Middle
->addRegularFile("/hiddenByMid");
821 Middle
->addDirectory("/hiddenByUp");
822 Upper
->addRegularFile("/onlyInUp");
823 Upper
->addRegularFile("/hiddenByUp");
825 O
->dir_begin("/", EC
),
826 {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
828 // Make sure we get the top-most entry
831 vfs::directory_iterator I
= O
->dir_begin("/", EC
), E
;
832 for (; !EC
&& I
!= E
; I
.increment(EC
))
833 if (I
->path() == "/hiddenByUp")
836 EXPECT_EQ(sys::fs::file_type::regular_file
, I
->type());
840 vfs::directory_iterator I
= O
->dir_begin("/", EC
), E
;
841 for (; !EC
&& I
!= E
; I
.increment(EC
))
842 if (I
->path() == "/hiddenByMid")
845 EXPECT_EQ(sys::fs::file_type::regular_file
, I
->type());
849 TEST(ProxyFileSystemTest
, Basic
) {
850 IntrusiveRefCntPtr
<vfs::InMemoryFileSystem
> Base(
851 new vfs::InMemoryFileSystem());
852 vfs::ProxyFileSystem
PFS(Base
);
854 Base
->addFile("/a", 0, MemoryBuffer::getMemBuffer("test"));
856 auto Stat
= PFS
.status("/a");
857 ASSERT_FALSE(Stat
.getError());
859 auto File
= PFS
.openFileForRead("/a");
860 ASSERT_FALSE(File
.getError());
861 EXPECT_EQ("test", (*(*File
)->getBuffer("ignored"))->getBuffer());
864 vfs::directory_iterator I
= PFS
.dir_begin("/", EC
);
866 ASSERT_EQ("/a", I
->path());
869 ASSERT_EQ(vfs::directory_iterator(), I
);
871 ASSERT_FALSE(PFS
.setCurrentWorkingDirectory("/"));
873 auto PWD
= PFS
.getCurrentWorkingDirectory();
874 ASSERT_FALSE(PWD
.getError());
875 ASSERT_EQ("/", *PWD
);
877 SmallString
<16> Path
;
878 ASSERT_FALSE(PFS
.getRealPath("a", Path
));
879 ASSERT_EQ("/a", Path
);
882 ASSERT_FALSE(PFS
.isLocal("/a", Local
));
886 class InMemoryFileSystemTest
: public ::testing::Test
{
888 llvm::vfs::InMemoryFileSystem FS
;
889 llvm::vfs::InMemoryFileSystem NormalizedFS
;
891 InMemoryFileSystemTest()
892 : FS(/*UseNormalizedPaths=*/false),
893 NormalizedFS(/*UseNormalizedPaths=*/true) {}
896 MATCHER_P2(IsHardLinkTo
, FS
, Target
, "") {
897 StringRef From
= arg
;
898 StringRef To
= Target
;
899 auto OpenedFrom
= FS
->openFileForRead(From
);
900 auto OpenedTo
= FS
->openFileForRead(To
);
901 return !OpenedFrom
.getError() && !OpenedTo
.getError() &&
902 (*OpenedFrom
)->status()->getUniqueID() ==
903 (*OpenedTo
)->status()->getUniqueID();
906 TEST_F(InMemoryFileSystemTest
, IsEmpty
) {
907 auto Stat
= FS
.status("/a");
908 ASSERT_EQ(Stat
.getError(), errc::no_such_file_or_directory
) << FS
.toString();
909 Stat
= FS
.status("/");
910 ASSERT_EQ(Stat
.getError(), errc::no_such_file_or_directory
) << FS
.toString();
913 TEST_F(InMemoryFileSystemTest
, WindowsPath
) {
914 FS
.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
915 auto Stat
= FS
.status("c:");
917 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << FS
.toString();
919 Stat
= FS
.status("c:/windows/system128/foo.cpp");
920 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << FS
.toString();
921 FS
.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
922 Stat
= FS
.status("d:/windows/foo.cpp");
923 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << FS
.toString();
926 TEST_F(InMemoryFileSystemTest
, OverlayFile
) {
927 FS
.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
928 NormalizedFS
.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
929 auto Stat
= FS
.status("/");
930 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << FS
.toString();
931 Stat
= FS
.status("/.");
933 Stat
= NormalizedFS
.status("/.");
934 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << FS
.toString();
935 Stat
= FS
.status("/a");
936 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
937 ASSERT_EQ("/a", Stat
->getName());
940 TEST_F(InMemoryFileSystemTest
, OverlayFileNoOwn
) {
941 auto Buf
= MemoryBuffer::getMemBuffer("a");
942 FS
.addFileNoOwn("/a", 0, *Buf
);
943 auto Stat
= FS
.status("/a");
944 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
945 ASSERT_EQ("/a", Stat
->getName());
948 TEST_F(InMemoryFileSystemTest
, OpenFileForRead
) {
949 FS
.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
950 FS
.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
951 FS
.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
952 NormalizedFS
.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
953 NormalizedFS
.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
954 NormalizedFS
.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
955 auto File
= FS
.openFileForRead("/a");
956 ASSERT_EQ("a", (*(*File
)->getBuffer("ignored"))->getBuffer());
957 File
= FS
.openFileForRead("/a"); // Open again.
958 ASSERT_EQ("a", (*(*File
)->getBuffer("ignored"))->getBuffer());
959 File
= NormalizedFS
.openFileForRead("/././a"); // Open again.
960 ASSERT_EQ("a", (*(*File
)->getBuffer("ignored"))->getBuffer());
961 File
= FS
.openFileForRead("/");
962 ASSERT_EQ(File
.getError(), errc::invalid_argument
) << FS
.toString();
963 File
= FS
.openFileForRead("/b");
964 ASSERT_EQ(File
.getError(), errc::no_such_file_or_directory
) << FS
.toString();
965 File
= FS
.openFileForRead("./c");
967 File
= FS
.openFileForRead("e/../d");
969 File
= NormalizedFS
.openFileForRead("./c");
970 ASSERT_EQ("c", (*(*File
)->getBuffer("ignored"))->getBuffer());
971 File
= NormalizedFS
.openFileForRead("e/../d");
972 ASSERT_EQ("d", (*(*File
)->getBuffer("ignored"))->getBuffer());
975 TEST_F(InMemoryFileSystemTest
, DuplicatedFile
) {
976 ASSERT_TRUE(FS
.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
977 ASSERT_FALSE(FS
.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
978 ASSERT_TRUE(FS
.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
979 ASSERT_FALSE(FS
.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
982 TEST_F(InMemoryFileSystemTest
, DirectoryIteration
) {
983 FS
.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
984 FS
.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
987 vfs::directory_iterator I
= FS
.dir_begin("/", EC
);
989 ASSERT_EQ("/a", I
->path());
992 ASSERT_EQ("/b", I
->path());
995 ASSERT_EQ(vfs::directory_iterator(), I
);
997 I
= FS
.dir_begin("/b", EC
);
999 // When on Windows, we end up with "/b\\c" as the name. Convert to Posix
1000 // path for the sake of the comparison.
1001 ASSERT_EQ("/b/c", getPosixPath(std::string(I
->path())));
1004 ASSERT_EQ(vfs::directory_iterator(), I
);
1007 TEST_F(InMemoryFileSystemTest
, WorkingDirectory
) {
1008 FS
.setCurrentWorkingDirectory("/b");
1009 FS
.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
1011 auto Stat
= FS
.status("/b/c");
1012 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1013 ASSERT_EQ("/b/c", Stat
->getName());
1014 ASSERT_EQ("/b", *FS
.getCurrentWorkingDirectory());
1016 Stat
= FS
.status("c");
1017 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1019 NormalizedFS
.setCurrentWorkingDirectory("/b/c");
1020 NormalizedFS
.setCurrentWorkingDirectory(".");
1022 getPosixPath(NormalizedFS
.getCurrentWorkingDirectory().get()));
1023 NormalizedFS
.setCurrentWorkingDirectory("..");
1025 getPosixPath(NormalizedFS
.getCurrentWorkingDirectory().get()));
1028 TEST_F(InMemoryFileSystemTest
, IsLocal
) {
1029 FS
.setCurrentWorkingDirectory("/b");
1030 FS
.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
1033 bool IsLocal
= true;
1034 EC
= FS
.isLocal("c", IsLocal
);
1036 ASSERT_FALSE(IsLocal
);
1039 #if !defined(_WIN32)
1040 TEST_F(InMemoryFileSystemTest
, GetRealPath
) {
1041 SmallString
<16> Path
;
1042 EXPECT_EQ(FS
.getRealPath("b", Path
), errc::operation_not_permitted
);
1044 auto GetRealPath
= [this](StringRef P
) {
1045 SmallString
<16> Output
;
1046 auto EC
= FS
.getRealPath(P
, Output
);
1048 return std::string(Output
);
1051 FS
.setCurrentWorkingDirectory("a");
1052 EXPECT_EQ(GetRealPath("b"), "a/b");
1053 EXPECT_EQ(GetRealPath("../b"), "b");
1054 EXPECT_EQ(GetRealPath("b/./c"), "a/b/c");
1056 FS
.setCurrentWorkingDirectory("/a");
1057 EXPECT_EQ(GetRealPath("b"), "/a/b");
1058 EXPECT_EQ(GetRealPath("../b"), "/b");
1059 EXPECT_EQ(GetRealPath("b/./c"), "/a/b/c");
1063 TEST_F(InMemoryFileSystemTest
, AddFileWithUser
) {
1064 FS
.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
1065 auto Stat
= FS
.status("/a");
1066 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1067 ASSERT_TRUE(Stat
->isDirectory());
1068 ASSERT_EQ(0xFEEDFACE, Stat
->getUser());
1069 Stat
= FS
.status("/a/b");
1070 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1071 ASSERT_TRUE(Stat
->isDirectory());
1072 ASSERT_EQ(0xFEEDFACE, Stat
->getUser());
1073 Stat
= FS
.status("/a/b/c");
1074 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1075 ASSERT_TRUE(Stat
->isRegularFile());
1076 ASSERT_EQ(sys::fs::perms::all_all
, Stat
->getPermissions());
1077 ASSERT_EQ(0xFEEDFACE, Stat
->getUser());
1080 TEST_F(InMemoryFileSystemTest
, AddFileWithGroup
) {
1081 FS
.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None
, 0xDABBAD00);
1082 auto Stat
= FS
.status("/a");
1083 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1084 ASSERT_TRUE(Stat
->isDirectory());
1085 ASSERT_EQ(0xDABBAD00, Stat
->getGroup());
1086 Stat
= FS
.status("/a/b");
1087 ASSERT_TRUE(Stat
->isDirectory());
1088 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1089 ASSERT_EQ(0xDABBAD00, Stat
->getGroup());
1090 Stat
= FS
.status("/a/b/c");
1091 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1092 ASSERT_TRUE(Stat
->isRegularFile());
1093 ASSERT_EQ(sys::fs::perms::all_all
, Stat
->getPermissions());
1094 ASSERT_EQ(0xDABBAD00, Stat
->getGroup());
1097 TEST_F(InMemoryFileSystemTest
, AddFileWithFileType
) {
1098 FS
.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None
, None
,
1099 sys::fs::file_type::socket_file
);
1100 auto Stat
= FS
.status("/a");
1101 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1102 ASSERT_TRUE(Stat
->isDirectory());
1103 Stat
= FS
.status("/a/b");
1104 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1105 ASSERT_TRUE(Stat
->isDirectory());
1106 Stat
= FS
.status("/a/b/c");
1107 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1108 ASSERT_EQ(sys::fs::file_type::socket_file
, Stat
->getType());
1109 ASSERT_EQ(sys::fs::perms::all_all
, Stat
->getPermissions());
1112 TEST_F(InMemoryFileSystemTest
, AddFileWithPerms
) {
1113 FS
.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None
, None
, None
,
1114 sys::fs::perms::owner_read
| sys::fs::perms::owner_write
);
1115 auto Stat
= FS
.status("/a");
1116 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1117 ASSERT_TRUE(Stat
->isDirectory());
1118 ASSERT_EQ(sys::fs::perms::owner_read
| sys::fs::perms::owner_write
|
1119 sys::fs::perms::owner_exe
,
1120 Stat
->getPermissions());
1121 Stat
= FS
.status("/a/b");
1122 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1123 ASSERT_TRUE(Stat
->isDirectory());
1124 ASSERT_EQ(sys::fs::perms::owner_read
| sys::fs::perms::owner_write
|
1125 sys::fs::perms::owner_exe
,
1126 Stat
->getPermissions());
1127 Stat
= FS
.status("/a/b/c");
1128 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1129 ASSERT_TRUE(Stat
->isRegularFile());
1130 ASSERT_EQ(sys::fs::perms::owner_read
| sys::fs::perms::owner_write
,
1131 Stat
->getPermissions());
1134 TEST_F(InMemoryFileSystemTest
, AddDirectoryThenAddChild
) {
1135 FS
.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None
,
1136 /*Group=*/None
, sys::fs::file_type::directory_file
);
1137 FS
.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None
,
1138 /*Group=*/None
, sys::fs::file_type::regular_file
);
1139 auto Stat
= FS
.status("/a");
1140 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1141 ASSERT_TRUE(Stat
->isDirectory());
1142 Stat
= FS
.status("/a/b");
1143 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n" << FS
.toString();
1144 ASSERT_TRUE(Stat
->isRegularFile());
1147 // Test that the name returned by status() is in the same form as the path that
1148 // was requested (to match the behavior of RealFileSystem).
1149 TEST_F(InMemoryFileSystemTest
, StatusName
) {
1150 NormalizedFS
.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"),
1152 /*Group=*/None
, sys::fs::file_type::regular_file
);
1153 NormalizedFS
.setCurrentWorkingDirectory("/a/b");
1155 // Access using InMemoryFileSystem::status.
1156 auto Stat
= NormalizedFS
.status("../b/c");
1157 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n"
1158 << NormalizedFS
.toString();
1159 ASSERT_TRUE(Stat
->isRegularFile());
1160 ASSERT_EQ("../b/c", Stat
->getName());
1162 // Access using InMemoryFileAdaptor::status.
1163 auto File
= NormalizedFS
.openFileForRead("../b/c");
1164 ASSERT_FALSE(File
.getError()) << File
.getError() << "\n"
1165 << NormalizedFS
.toString();
1166 Stat
= (*File
)->status();
1167 ASSERT_FALSE(Stat
.getError()) << Stat
.getError() << "\n"
1168 << NormalizedFS
.toString();
1169 ASSERT_TRUE(Stat
->isRegularFile());
1170 ASSERT_EQ("../b/c", Stat
->getName());
1172 // Access using a directory iterator.
1174 llvm::vfs::directory_iterator It
= NormalizedFS
.dir_begin("../b", EC
);
1175 // When on Windows, we end up with "../b\\c" as the name. Convert to Posix
1176 // path for the sake of the comparison.
1177 ASSERT_EQ("../b/c", getPosixPath(std::string(It
->path())));
1180 TEST_F(InMemoryFileSystemTest
, AddHardLinkToFile
) {
1181 StringRef FromLink
= "/path/to/FROM/link";
1182 StringRef Target
= "/path/to/TO/file";
1183 FS
.addFile(Target
, 0, MemoryBuffer::getMemBuffer("content of target"));
1184 EXPECT_TRUE(FS
.addHardLink(FromLink
, Target
));
1185 EXPECT_THAT(FromLink
, IsHardLinkTo(&FS
, Target
));
1186 EXPECT_TRUE(FS
.status(FromLink
)->getSize() == FS
.status(Target
)->getSize());
1187 EXPECT_TRUE(FS
.getBufferForFile(FromLink
)->get()->getBuffer() ==
1188 FS
.getBufferForFile(Target
)->get()->getBuffer());
1191 TEST_F(InMemoryFileSystemTest
, AddHardLinkInChainPattern
) {
1192 StringRef Link0
= "/path/to/0/link";
1193 StringRef Link1
= "/path/to/1/link";
1194 StringRef Link2
= "/path/to/2/link";
1195 StringRef Target
= "/path/to/target";
1196 FS
.addFile(Target
, 0, MemoryBuffer::getMemBuffer("content of target file"));
1197 EXPECT_TRUE(FS
.addHardLink(Link2
, Target
));
1198 EXPECT_TRUE(FS
.addHardLink(Link1
, Link2
));
1199 EXPECT_TRUE(FS
.addHardLink(Link0
, Link1
));
1200 EXPECT_THAT(Link0
, IsHardLinkTo(&FS
, Target
));
1201 EXPECT_THAT(Link1
, IsHardLinkTo(&FS
, Target
));
1202 EXPECT_THAT(Link2
, IsHardLinkTo(&FS
, Target
));
1205 TEST_F(InMemoryFileSystemTest
, AddHardLinkToAFileThatWasNotAddedBefore
) {
1206 EXPECT_FALSE(FS
.addHardLink("/path/to/link", "/path/to/target"));
1209 TEST_F(InMemoryFileSystemTest
, AddHardLinkFromAFileThatWasAddedBefore
) {
1210 StringRef Link
= "/path/to/link";
1211 StringRef Target
= "/path/to/target";
1212 FS
.addFile(Target
, 0, MemoryBuffer::getMemBuffer("content of target"));
1213 FS
.addFile(Link
, 0, MemoryBuffer::getMemBuffer("content of link"));
1214 EXPECT_FALSE(FS
.addHardLink(Link
, Target
));
1217 TEST_F(InMemoryFileSystemTest
, AddSameHardLinkMoreThanOnce
) {
1218 StringRef Link
= "/path/to/link";
1219 StringRef Target
= "/path/to/target";
1220 FS
.addFile(Target
, 0, MemoryBuffer::getMemBuffer("content of target"));
1221 EXPECT_TRUE(FS
.addHardLink(Link
, Target
));
1222 EXPECT_FALSE(FS
.addHardLink(Link
, Target
));
1225 TEST_F(InMemoryFileSystemTest
, AddFileInPlaceOfAHardLinkWithSameContent
) {
1226 StringRef Link
= "/path/to/link";
1227 StringRef Target
= "/path/to/target";
1228 StringRef Content
= "content of target";
1229 EXPECT_TRUE(FS
.addFile(Target
, 0, MemoryBuffer::getMemBuffer(Content
)));
1230 EXPECT_TRUE(FS
.addHardLink(Link
, Target
));
1231 EXPECT_TRUE(FS
.addFile(Link
, 0, MemoryBuffer::getMemBuffer(Content
)));
1234 TEST_F(InMemoryFileSystemTest
, AddFileInPlaceOfAHardLinkWithDifferentContent
) {
1235 StringRef Link
= "/path/to/link";
1236 StringRef Target
= "/path/to/target";
1237 StringRef Content
= "content of target";
1238 StringRef LinkContent
= "different content of link";
1239 EXPECT_TRUE(FS
.addFile(Target
, 0, MemoryBuffer::getMemBuffer(Content
)));
1240 EXPECT_TRUE(FS
.addHardLink(Link
, Target
));
1241 EXPECT_FALSE(FS
.addFile(Link
, 0, MemoryBuffer::getMemBuffer(LinkContent
)));
1244 TEST_F(InMemoryFileSystemTest
, AddHardLinkToADirectory
) {
1245 StringRef Dir
= "path/to/dummy/dir";
1246 StringRef Link
= "/path/to/link";
1247 StringRef File
= "path/to/dummy/dir/target";
1248 StringRef Content
= "content of target";
1249 EXPECT_TRUE(FS
.addFile(File
, 0, MemoryBuffer::getMemBuffer(Content
)));
1250 EXPECT_FALSE(FS
.addHardLink(Link
, Dir
));
1253 TEST_F(InMemoryFileSystemTest
, AddHardLinkFromADirectory
) {
1254 StringRef Dir
= "path/to/dummy/dir";
1255 StringRef Target
= "path/to/dummy/dir/target";
1256 StringRef Content
= "content of target";
1257 EXPECT_TRUE(FS
.addFile(Target
, 0, MemoryBuffer::getMemBuffer(Content
)));
1258 EXPECT_FALSE(FS
.addHardLink(Dir
, Target
));
1261 TEST_F(InMemoryFileSystemTest
, AddHardLinkUnderAFile
) {
1262 StringRef CommonContent
= "content string";
1263 FS
.addFile("/a/b", 0, MemoryBuffer::getMemBuffer(CommonContent
));
1264 FS
.addFile("/c/d", 0, MemoryBuffer::getMemBuffer(CommonContent
));
1265 EXPECT_FALSE(FS
.addHardLink("/c/d/e", "/a/b"));
1268 TEST_F(InMemoryFileSystemTest
, RecursiveIterationWithHardLink
) {
1270 FS
.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("content string"));
1271 EXPECT_TRUE(FS
.addHardLink("/c/d", "/a/b"));
1272 auto I
= vfs::recursive_directory_iterator(FS
, "/", EC
);
1274 std::vector
<std::string
> Nodes
;
1275 for (auto E
= vfs::recursive_directory_iterator(); !EC
&& I
!= E
;
1277 Nodes
.push_back(getPosixPath(std::string(I
->path())));
1279 EXPECT_THAT(Nodes
, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d"));
1282 TEST_F(InMemoryFileSystemTest
, UniqueID
) {
1283 ASSERT_TRUE(FS
.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("text")));
1284 ASSERT_TRUE(FS
.addFile("/c/d", 0, MemoryBuffer::getMemBuffer("text")));
1285 ASSERT_TRUE(FS
.addHardLink("/e/f", "/a/b"));
1287 EXPECT_EQ(FS
.status("/a/b")->getUniqueID(), FS
.status("/a/b")->getUniqueID());
1288 EXPECT_NE(FS
.status("/a/b")->getUniqueID(), FS
.status("/c/d")->getUniqueID());
1289 EXPECT_EQ(FS
.status("/a/b")->getUniqueID(), FS
.status("/e/f")->getUniqueID());
1290 EXPECT_EQ(FS
.status("/a")->getUniqueID(), FS
.status("/a")->getUniqueID());
1291 EXPECT_NE(FS
.status("/a")->getUniqueID(), FS
.status("/c")->getUniqueID());
1292 EXPECT_NE(FS
.status("/a")->getUniqueID(), FS
.status("/e")->getUniqueID());
1294 // Recreating the "same" FS yields the same UniqueIDs.
1295 vfs::InMemoryFileSystem FS2
;
1296 ASSERT_TRUE(FS2
.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("text")));
1297 EXPECT_EQ(FS
.status("/a/b")->getUniqueID(),
1298 FS2
.status("/a/b")->getUniqueID());
1299 EXPECT_EQ(FS
.status("/a")->getUniqueID(), FS2
.status("/a")->getUniqueID());
1302 // NOTE: in the tests below, we use '//root/' as our root directory, since it is
1303 // a legal *absolute* path on Windows as well as *nix.
1304 class VFSFromYAMLTest
: public ::testing::Test
{
1308 void SetUp() override
{ NumDiagnostics
= 0; }
1310 static void CountingDiagHandler(const SMDiagnostic
&, void *Context
) {
1311 VFSFromYAMLTest
*Test
= static_cast<VFSFromYAMLTest
*>(Context
);
1312 ++Test
->NumDiagnostics
;
1315 std::unique_ptr
<vfs::FileSystem
>
1316 getFromYAMLRawString(StringRef Content
,
1317 IntrusiveRefCntPtr
<vfs::FileSystem
> ExternalFS
) {
1318 std::unique_ptr
<MemoryBuffer
> Buffer
= MemoryBuffer::getMemBuffer(Content
);
1319 return getVFSFromYAML(std::move(Buffer
), CountingDiagHandler
, "", this,
1323 std::unique_ptr
<vfs::FileSystem
> getFromYAMLString(
1325 IntrusiveRefCntPtr
<vfs::FileSystem
> ExternalFS
= new DummyFileSystem()) {
1326 std::string
VersionPlusContent("{\n 'version':0,\n");
1327 VersionPlusContent
+= Content
.slice(Content
.find('{') + 1, StringRef::npos
);
1328 return getFromYAMLRawString(VersionPlusContent
, ExternalFS
);
1331 // This is intended as a "XFAIL" for windows hosts.
1332 bool supportsSameDirMultipleYAMLEntries() {
1333 Triple
Host(Triple::normalize(sys::getProcessTriple()));
1334 return !Host
.isOSWindows();
1338 TEST_F(VFSFromYAMLTest
, BasicVFSFromYAML
) {
1339 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
;
1340 FS
= getFromYAMLString("");
1341 EXPECT_EQ(nullptr, FS
.get());
1342 FS
= getFromYAMLString("[]");
1343 EXPECT_EQ(nullptr, FS
.get());
1344 FS
= getFromYAMLString("'string'");
1345 EXPECT_EQ(nullptr, FS
.get());
1346 EXPECT_EQ(3, NumDiagnostics
);
1349 TEST_F(VFSFromYAMLTest
, MappedFiles
) {
1350 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
1351 Lower
->addDirectory("//root/foo/bar");
1352 Lower
->addRegularFile("//root/foo/bar/a");
1353 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
1356 " 'type': 'directory',\n"
1357 " 'name': '//root/',\n"
1358 " 'contents': [ {\n"
1359 " 'type': 'file',\n"
1360 " 'name': 'file1',\n"
1361 " 'external-contents': '//root/foo/bar/a'\n"
1364 " 'type': 'file',\n"
1365 " 'name': 'file2',\n"
1366 " 'external-contents': '//root/foo/b'\n"
1369 " 'type': 'directory-remap',\n"
1370 " 'name': 'mappeddir',\n"
1371 " 'external-contents': '//root/foo/bar'\n"
1374 " 'type': 'directory-remap',\n"
1375 " 'name': 'mappeddir2',\n"
1376 " 'use-external-name': false,\n"
1377 " 'external-contents': '//root/foo/bar'\n"
1384 ASSERT_TRUE(FS
.get() != nullptr);
1386 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
1387 new vfs::OverlayFileSystem(Lower
));
1391 ErrorOr
<vfs::Status
> S
= O
->status("//root/file1");
1392 ASSERT_FALSE(S
.getError());
1393 EXPECT_EQ("//root/foo/bar/a", S
->getName());
1394 EXPECT_TRUE(S
->IsVFSMapped
);
1396 ErrorOr
<vfs::Status
> SLower
= O
->status("//root/foo/bar/a");
1397 EXPECT_EQ("//root/foo/bar/a", SLower
->getName());
1398 EXPECT_TRUE(S
->equivalent(*SLower
));
1399 EXPECT_FALSE(SLower
->IsVFSMapped
);
1401 // file after opening
1402 auto OpenedF
= O
->openFileForRead("//root/file1");
1403 ASSERT_FALSE(OpenedF
.getError());
1404 auto OpenedS
= (*OpenedF
)->status();
1405 ASSERT_FALSE(OpenedS
.getError());
1406 EXPECT_EQ("//root/foo/bar/a", OpenedS
->getName());
1407 EXPECT_TRUE(OpenedS
->IsVFSMapped
);
1410 S
= O
->status("//root/");
1411 ASSERT_FALSE(S
.getError());
1412 EXPECT_TRUE(S
->isDirectory());
1413 EXPECT_TRUE(S
->equivalent(*O
->status("//root/"))); // non-volatile UniqueID
1415 // remapped directory
1416 S
= O
->status("//root/mappeddir");
1417 ASSERT_FALSE(S
.getError());
1418 EXPECT_TRUE(S
->isDirectory());
1419 EXPECT_TRUE(S
->IsVFSMapped
);
1420 EXPECT_TRUE(S
->equivalent(*O
->status("//root/foo/bar")));
1422 SLower
= O
->status("//root/foo/bar");
1423 EXPECT_EQ("//root/foo/bar", SLower
->getName());
1424 EXPECT_TRUE(S
->equivalent(*SLower
));
1425 EXPECT_FALSE(SLower
->IsVFSMapped
);
1427 // file in remapped directory
1428 S
= O
->status("//root/mappeddir/a");
1429 ASSERT_FALSE(S
.getError());
1430 ASSERT_FALSE(S
->isDirectory());
1431 ASSERT_TRUE(S
->IsVFSMapped
);
1432 ASSERT_EQ("//root/foo/bar/a", S
->getName());
1434 // file in remapped directory, with use-external-name=false
1435 S
= O
->status("//root/mappeddir2/a");
1436 ASSERT_FALSE(S
.getError());
1437 ASSERT_FALSE(S
->isDirectory());
1438 ASSERT_TRUE(S
->IsVFSMapped
);
1439 ASSERT_EQ("//root/mappeddir2/a", S
->getName());
1441 // file contents in remapped directory
1442 OpenedF
= O
->openFileForRead("//root/mappeddir/a");
1443 ASSERT_FALSE(OpenedF
.getError());
1444 OpenedS
= (*OpenedF
)->status();
1445 ASSERT_FALSE(OpenedS
.getError());
1446 EXPECT_EQ("//root/foo/bar/a", OpenedS
->getName());
1447 EXPECT_TRUE(OpenedS
->IsVFSMapped
);
1449 // file contents in remapped directory, with use-external-name=false
1450 OpenedF
= O
->openFileForRead("//root/mappeddir2/a");
1451 ASSERT_FALSE(OpenedF
.getError());
1452 OpenedS
= (*OpenedF
)->status();
1453 ASSERT_FALSE(OpenedS
.getError());
1454 EXPECT_EQ("//root/mappeddir2/a", OpenedS
->getName());
1455 EXPECT_TRUE(OpenedS
->IsVFSMapped
);
1458 EXPECT_EQ(O
->status("//root/file2").getError(),
1459 llvm::errc::no_such_file_or_directory
);
1460 EXPECT_EQ(0, NumDiagnostics
);
1463 TEST_F(VFSFromYAMLTest
, MappedRoot
) {
1464 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
1465 Lower
->addDirectory("//root/foo/bar");
1466 Lower
->addRegularFile("//root/foo/bar/a");
1467 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
=
1468 getFromYAMLString("{ 'roots': [\n"
1470 " 'type': 'directory-remap',\n"
1471 " 'name': '//mappedroot/',\n"
1472 " 'external-contents': '//root/foo/bar'\n"
1477 ASSERT_TRUE(FS
.get() != nullptr);
1479 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
1480 new vfs::OverlayFileSystem(Lower
));
1484 ErrorOr
<vfs::Status
> S
= O
->status("//mappedroot/a");
1485 ASSERT_FALSE(S
.getError());
1486 EXPECT_EQ("//root/foo/bar/a", S
->getName());
1487 EXPECT_TRUE(S
->IsVFSMapped
);
1489 ErrorOr
<vfs::Status
> SLower
= O
->status("//root/foo/bar/a");
1490 EXPECT_EQ("//root/foo/bar/a", SLower
->getName());
1491 EXPECT_TRUE(S
->equivalent(*SLower
));
1492 EXPECT_FALSE(SLower
->IsVFSMapped
);
1494 // file after opening
1495 auto OpenedF
= O
->openFileForRead("//mappedroot/a");
1496 ASSERT_FALSE(OpenedF
.getError());
1497 auto OpenedS
= (*OpenedF
)->status();
1498 ASSERT_FALSE(OpenedS
.getError());
1499 EXPECT_EQ("//root/foo/bar/a", OpenedS
->getName());
1500 EXPECT_TRUE(OpenedS
->IsVFSMapped
);
1502 EXPECT_EQ(0, NumDiagnostics
);
1505 TEST_F(VFSFromYAMLTest
, RemappedDirectoryOverlay
) {
1506 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
1507 Lower
->addDirectory("//root/foo");
1508 Lower
->addRegularFile("//root/foo/a");
1509 Lower
->addDirectory("//root/bar");
1510 Lower
->addRegularFile("//root/bar/b");
1511 Lower
->addRegularFile("//root/bar/c");
1512 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
=
1513 getFromYAMLString("{ 'roots': [\n"
1515 " 'type': 'directory',\n"
1516 " 'name': '//root/',\n"
1517 " 'contents': [ {\n"
1518 " 'type': 'directory-remap',\n"
1520 " 'external-contents': '//root/foo'\n"
1525 ASSERT_TRUE(FS
.get() != nullptr);
1527 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
1528 new vfs::OverlayFileSystem(Lower
));
1531 ErrorOr
<vfs::Status
> S
= O
->status("//root/foo");
1532 ASSERT_FALSE(S
.getError());
1534 ErrorOr
<vfs::Status
> SS
= O
->status("//root/bar");
1535 ASSERT_FALSE(SS
.getError());
1536 EXPECT_TRUE(S
->equivalent(*SS
));
1539 checkContents(O
->dir_begin("//root/bar", EC
),
1540 {"//root/foo/a", "//root/bar/b", "//root/bar/c"});
1542 Lower
->addRegularFile("//root/foo/b");
1543 checkContents(O
->dir_begin("//root/bar", EC
),
1544 {"//root/foo/a", "//root/foo/b", "//root/bar/c"});
1546 EXPECT_EQ(0, NumDiagnostics
);
1549 TEST_F(VFSFromYAMLTest
, RemappedDirectoryOverlayNoExternalNames
) {
1550 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
1551 Lower
->addDirectory("//root/foo");
1552 Lower
->addRegularFile("//root/foo/a");
1553 Lower
->addDirectory("//root/bar");
1554 Lower
->addRegularFile("//root/bar/b");
1555 Lower
->addRegularFile("//root/bar/c");
1556 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
=
1557 getFromYAMLString("{ 'use-external-names': false,\n"
1560 " 'type': 'directory',\n"
1561 " 'name': '//root/',\n"
1562 " 'contents': [ {\n"
1563 " 'type': 'directory-remap',\n"
1565 " 'external-contents': '//root/foo'\n"
1570 ASSERT_TRUE(FS
.get() != nullptr);
1572 ErrorOr
<vfs::Status
> S
= FS
->status("//root/foo");
1573 ASSERT_FALSE(S
.getError());
1575 ErrorOr
<vfs::Status
> SS
= FS
->status("//root/bar");
1576 ASSERT_FALSE(SS
.getError());
1577 EXPECT_TRUE(S
->equivalent(*SS
));
1580 checkContents(FS
->dir_begin("//root/bar", EC
),
1581 {"//root/bar/a", "//root/bar/b", "//root/bar/c"});
1583 Lower
->addRegularFile("//root/foo/b");
1584 checkContents(FS
->dir_begin("//root/bar", EC
),
1585 {"//root/bar/a", "//root/bar/b", "//root/bar/c"});
1587 EXPECT_EQ(0, NumDiagnostics
);
1590 TEST_F(VFSFromYAMLTest
, RemappedDirectoryOverlayNoFallthrough
) {
1591 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
1592 Lower
->addDirectory("//root/foo");
1593 Lower
->addRegularFile("//root/foo/a");
1594 Lower
->addDirectory("//root/bar");
1595 Lower
->addRegularFile("//root/bar/b");
1596 Lower
->addRegularFile("//root/bar/c");
1597 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
=
1598 getFromYAMLString("{ 'fallthrough': false,\n"
1601 " 'type': 'directory',\n"
1602 " 'name': '//root/',\n"
1603 " 'contents': [ {\n"
1604 " 'type': 'directory-remap',\n"
1606 " 'external-contents': '//root/foo'\n"
1611 ASSERT_TRUE(FS
.get() != nullptr);
1613 ErrorOr
<vfs::Status
> S
= Lower
->status("//root/foo");
1614 ASSERT_FALSE(S
.getError());
1616 ErrorOr
<vfs::Status
> SS
= FS
->status("//root/bar");
1617 ASSERT_FALSE(SS
.getError());
1618 EXPECT_TRUE(S
->equivalent(*SS
));
1621 checkContents(FS
->dir_begin("//root/bar", EC
), {"//root/foo/a"});
1623 Lower
->addRegularFile("//root/foo/b");
1624 checkContents(FS
->dir_begin("//root/bar", EC
),
1625 {"//root/foo/a", "//root/foo/b"});
1627 EXPECT_EQ(0, NumDiagnostics
);
1630 TEST_F(VFSFromYAMLTest
, ReturnsRequestedPathVFSMiss
) {
1631 IntrusiveRefCntPtr
<vfs::InMemoryFileSystem
> BaseFS(
1632 new vfs::InMemoryFileSystem
);
1633 BaseFS
->addFile("//root/foo/a", 0,
1634 MemoryBuffer::getMemBuffer("contents of a"));
1635 ASSERT_FALSE(BaseFS
->setCurrentWorkingDirectory("//root/foo"));
1636 auto RemappedFS
= vfs::RedirectingFileSystem::create(
1637 {}, /*UseExternalNames=*/false, *BaseFS
);
1639 auto OpenedF
= RemappedFS
->openFileForRead("a");
1640 ASSERT_FALSE(OpenedF
.getError());
1641 llvm::ErrorOr
<std::string
> Name
= (*OpenedF
)->getName();
1642 ASSERT_FALSE(Name
.getError());
1643 EXPECT_EQ("a", Name
.get());
1645 auto OpenedS
= (*OpenedF
)->status();
1646 ASSERT_FALSE(OpenedS
.getError());
1647 EXPECT_EQ("a", OpenedS
->getName());
1648 EXPECT_FALSE(OpenedS
->IsVFSMapped
);
1650 auto DirectS
= RemappedFS
->status("a");
1651 ASSERT_FALSE(DirectS
.getError());
1652 EXPECT_EQ("a", DirectS
->getName());
1653 EXPECT_FALSE(DirectS
->IsVFSMapped
);
1655 EXPECT_EQ(0, NumDiagnostics
);
1658 TEST_F(VFSFromYAMLTest
, ReturnsExternalPathVFSHit
) {
1659 IntrusiveRefCntPtr
<vfs::InMemoryFileSystem
> BaseFS(
1660 new vfs::InMemoryFileSystem
);
1661 BaseFS
->addFile("//root/foo/realname", 0,
1662 MemoryBuffer::getMemBuffer("contents of a"));
1664 getFromYAMLString("{ 'use-external-names': true,\n"
1667 " 'type': 'directory',\n"
1668 " 'name': '//root/foo',\n"
1669 " 'contents': [ {\n"
1670 " 'type': 'file',\n"
1671 " 'name': 'vfsname',\n"
1672 " 'external-contents': 'realname'\n"
1677 ASSERT_FALSE(FS
->setCurrentWorkingDirectory("//root/foo"));
1679 auto OpenedF
= FS
->openFileForRead("vfsname");
1680 ASSERT_FALSE(OpenedF
.getError());
1681 llvm::ErrorOr
<std::string
> Name
= (*OpenedF
)->getName();
1682 ASSERT_FALSE(Name
.getError());
1683 EXPECT_EQ("realname", Name
.get());
1685 auto OpenedS
= (*OpenedF
)->status();
1686 ASSERT_FALSE(OpenedS
.getError());
1687 EXPECT_EQ("realname", OpenedS
->getName());
1688 EXPECT_TRUE(OpenedS
->IsVFSMapped
);
1690 auto DirectS
= FS
->status("vfsname");
1691 ASSERT_FALSE(DirectS
.getError());
1692 EXPECT_EQ("realname", DirectS
->getName());
1693 EXPECT_TRUE(DirectS
->IsVFSMapped
);
1695 EXPECT_EQ(0, NumDiagnostics
);
1698 TEST_F(VFSFromYAMLTest
, ReturnsInternalPathVFSHit
) {
1699 IntrusiveRefCntPtr
<vfs::InMemoryFileSystem
> BaseFS(
1700 new vfs::InMemoryFileSystem
);
1701 BaseFS
->addFile("//root/foo/realname", 0,
1702 MemoryBuffer::getMemBuffer("contents of a"));
1704 getFromYAMLString("{ 'use-external-names': false,\n"
1707 " 'type': 'directory',\n"
1708 " 'name': '//root/foo',\n"
1709 " 'contents': [ {\n"
1710 " 'type': 'file',\n"
1711 " 'name': 'vfsname',\n"
1712 " 'external-contents': 'realname'\n"
1717 ASSERT_FALSE(FS
->setCurrentWorkingDirectory("//root/foo"));
1719 auto OpenedF
= FS
->openFileForRead("vfsname");
1720 ASSERT_FALSE(OpenedF
.getError());
1721 llvm::ErrorOr
<std::string
> Name
= (*OpenedF
)->getName();
1722 ASSERT_FALSE(Name
.getError());
1723 EXPECT_EQ("vfsname", Name
.get());
1725 auto OpenedS
= (*OpenedF
)->status();
1726 ASSERT_FALSE(OpenedS
.getError());
1727 EXPECT_EQ("vfsname", OpenedS
->getName());
1728 EXPECT_TRUE(OpenedS
->IsVFSMapped
);
1730 auto DirectS
= FS
->status("vfsname");
1731 ASSERT_FALSE(DirectS
.getError());
1732 EXPECT_EQ("vfsname", DirectS
->getName());
1733 EXPECT_TRUE(DirectS
->IsVFSMapped
);
1735 EXPECT_EQ(0, NumDiagnostics
);
1738 TEST_F(VFSFromYAMLTest
, CaseInsensitive
) {
1739 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
1740 Lower
->addRegularFile("//root/foo/bar/a");
1741 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
1742 "{ 'case-sensitive': 'false',\n"
1745 " 'type': 'directory',\n"
1746 " 'name': '//root/',\n"
1747 " 'contents': [ {\n"
1748 " 'type': 'file',\n"
1750 " 'external-contents': '//root/foo/bar/a'\n"
1755 ASSERT_TRUE(FS
.get() != nullptr);
1757 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
1758 new vfs::OverlayFileSystem(Lower
));
1761 ErrorOr
<vfs::Status
> S
= O
->status("//root/XX");
1762 ASSERT_FALSE(S
.getError());
1764 ErrorOr
<vfs::Status
> SS
= O
->status("//root/xx");
1765 ASSERT_FALSE(SS
.getError());
1766 EXPECT_TRUE(S
->equivalent(*SS
));
1767 SS
= O
->status("//root/xX");
1768 EXPECT_TRUE(S
->equivalent(*SS
));
1769 SS
= O
->status("//root/Xx");
1770 EXPECT_TRUE(S
->equivalent(*SS
));
1771 EXPECT_EQ(0, NumDiagnostics
);
1774 TEST_F(VFSFromYAMLTest
, CaseSensitive
) {
1775 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
1776 Lower
->addRegularFile("//root/foo/bar/a");
1777 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
1778 "{ 'case-sensitive': 'true',\n"
1781 " 'type': 'directory',\n"
1782 " 'name': '//root/',\n"
1783 " 'contents': [ {\n"
1784 " 'type': 'file',\n"
1786 " 'external-contents': '//root/foo/bar/a'\n"
1791 ASSERT_TRUE(FS
.get() != nullptr);
1793 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
1794 new vfs::OverlayFileSystem(Lower
));
1797 ErrorOr
<vfs::Status
> SS
= O
->status("//root/xx");
1798 EXPECT_EQ(SS
.getError(), llvm::errc::no_such_file_or_directory
);
1799 SS
= O
->status("//root/xX");
1800 EXPECT_EQ(SS
.getError(), llvm::errc::no_such_file_or_directory
);
1801 SS
= O
->status("//root/Xx");
1802 EXPECT_EQ(SS
.getError(), llvm::errc::no_such_file_or_directory
);
1803 EXPECT_EQ(0, NumDiagnostics
);
1806 TEST_F(VFSFromYAMLTest
, IllegalVFSFile
) {
1807 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
1809 // invalid YAML at top-level
1810 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString("{]", Lower
);
1811 EXPECT_EQ(nullptr, FS
.get());
1812 // invalid YAML in roots
1813 FS
= getFromYAMLString("{ 'roots':[}", Lower
);
1814 // invalid YAML in directory
1815 FS
= getFromYAMLString(
1816 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
1818 EXPECT_EQ(nullptr, FS
.get());
1820 // invalid configuration
1821 FS
= getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower
);
1822 EXPECT_EQ(nullptr, FS
.get());
1823 FS
= getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower
);
1824 EXPECT_EQ(nullptr, FS
.get());
1827 FS
= getFromYAMLString("{ 'roots':'' }", Lower
);
1828 EXPECT_EQ(nullptr, FS
.get());
1829 FS
= getFromYAMLString("{ 'roots':{} }", Lower
);
1830 EXPECT_EQ(nullptr, FS
.get());
1833 FS
= getFromYAMLString(
1834 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower
);
1835 EXPECT_EQ(nullptr, FS
.get());
1836 FS
= getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
1837 "'external-contents': 'other' }",
1839 EXPECT_EQ(nullptr, FS
.get());
1840 FS
= getFromYAMLString(
1841 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1843 EXPECT_EQ(nullptr, FS
.get());
1844 FS
= getFromYAMLString(
1845 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
1847 EXPECT_EQ(nullptr, FS
.get());
1848 FS
= getFromYAMLString(
1849 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
1851 EXPECT_EQ(nullptr, FS
.get());
1852 FS
= getFromYAMLString(
1853 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
1855 EXPECT_EQ(nullptr, FS
.get());
1856 FS
= getFromYAMLString(
1857 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
1859 EXPECT_EQ(nullptr, FS
.get());
1861 // missing mandatory fields
1862 FS
= getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower
);
1863 EXPECT_EQ(nullptr, FS
.get());
1864 FS
= getFromYAMLString(
1865 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower
);
1866 EXPECT_EQ(nullptr, FS
.get());
1867 FS
= getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower
);
1868 EXPECT_EQ(nullptr, FS
.get());
1871 FS
= getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower
);
1872 EXPECT_EQ(nullptr, FS
.get());
1873 FS
= getFromYAMLString(
1874 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1876 EXPECT_EQ(nullptr, FS
.get());
1878 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1879 "'external-contents':'blah' } ] }",
1881 EXPECT_EQ(nullptr, FS
.get());
1884 FS
= getFromYAMLRawString("{ 'roots':[] }", Lower
);
1885 EXPECT_EQ(nullptr, FS
.get());
1887 // bad version number
1888 FS
= getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower
);
1889 EXPECT_EQ(nullptr, FS
.get());
1890 FS
= getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower
);
1891 EXPECT_EQ(nullptr, FS
.get());
1892 FS
= getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower
);
1893 EXPECT_EQ(nullptr, FS
.get());
1895 // both 'external-contents' and 'contents' specified
1896 Lower
->addDirectory("//root/external/dir");
1897 FS
= getFromYAMLString(
1899 "{ 'type': 'directory', 'name': '//root/A', 'contents': [],\n"
1900 " 'external-contents': '//root/external/dir'}]}",
1902 EXPECT_EQ(nullptr, FS
.get());
1904 // 'directory-remap' with 'contents'
1905 FS
= getFromYAMLString(
1907 "{ 'type': 'directory-remap', 'name': '//root/A', 'contents': [] }]}",
1909 EXPECT_EQ(nullptr, FS
.get());
1911 EXPECT_EQ(26, NumDiagnostics
);
1914 TEST_F(VFSFromYAMLTest
, UseExternalName
) {
1915 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
1916 Lower
->addRegularFile("//root/external/file");
1918 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
=
1919 getFromYAMLString("{ 'roots': [\n"
1920 " { 'type': 'file', 'name': '//root/A',\n"
1921 " 'external-contents': '//root/external/file'\n"
1923 " { 'type': 'file', 'name': '//root/B',\n"
1924 " 'use-external-name': true,\n"
1925 " 'external-contents': '//root/external/file'\n"
1927 " { 'type': 'file', 'name': '//root/C',\n"
1928 " 'use-external-name': false,\n"
1929 " 'external-contents': '//root/external/file'\n"
1933 ASSERT_TRUE(nullptr != FS
.get());
1936 EXPECT_EQ("//root/external/file", FS
->status("//root/A")->getName());
1938 EXPECT_EQ("//root/external/file", FS
->status("//root/B")->getName());
1939 EXPECT_EQ("//root/C", FS
->status("//root/C")->getName());
1941 // global configuration
1942 FS
= getFromYAMLString("{ 'use-external-names': false,\n"
1944 " { 'type': 'file', 'name': '//root/A',\n"
1945 " 'external-contents': '//root/external/file'\n"
1947 " { 'type': 'file', 'name': '//root/B',\n"
1948 " 'use-external-name': true,\n"
1949 " 'external-contents': '//root/external/file'\n"
1951 " { 'type': 'file', 'name': '//root/C',\n"
1952 " 'use-external-name': false,\n"
1953 " 'external-contents': '//root/external/file'\n"
1957 ASSERT_TRUE(nullptr != FS
.get());
1960 EXPECT_EQ("//root/A", FS
->status("//root/A")->getName());
1962 EXPECT_EQ("//root/external/file", FS
->status("//root/B")->getName());
1963 EXPECT_EQ("//root/C", FS
->status("//root/C")->getName());
1966 TEST_F(VFSFromYAMLTest
, MultiComponentPath
) {
1967 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
1968 Lower
->addRegularFile("//root/other");
1971 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
=
1972 getFromYAMLString("{ 'roots': [\n"
1973 " { 'type': 'file', 'name': '//root/path/to/file',\n"
1974 " 'external-contents': '//root/other' }]\n"
1977 ASSERT_TRUE(nullptr != FS
.get());
1978 EXPECT_FALSE(FS
->status("//root/path/to/file").getError());
1979 EXPECT_FALSE(FS
->status("//root/path/to").getError());
1980 EXPECT_FALSE(FS
->status("//root/path").getError());
1981 EXPECT_FALSE(FS
->status("//root/").getError());
1984 FS
= getFromYAMLString(
1986 " { 'type': 'directory', 'name': '//root/path/to',\n"
1987 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
1988 " 'external-contents': '//root/other' }]}]\n"
1991 ASSERT_TRUE(nullptr != FS
.get());
1992 EXPECT_FALSE(FS
->status("//root/path/to/file").getError());
1993 EXPECT_FALSE(FS
->status("//root/path/to").getError());
1994 EXPECT_FALSE(FS
->status("//root/path").getError());
1995 EXPECT_FALSE(FS
->status("//root/").getError());
1998 FS
= getFromYAMLString(
2000 " { 'type': 'directory', 'name': '//root/',\n"
2001 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
2002 " 'external-contents': '//root/other' }]}]\n"
2005 ASSERT_TRUE(nullptr != FS
.get());
2006 EXPECT_FALSE(FS
->status("//root/path/to/file").getError());
2007 EXPECT_FALSE(FS
->status("//root/path/to").getError());
2008 EXPECT_FALSE(FS
->status("//root/path").getError());
2009 EXPECT_FALSE(FS
->status("//root/").getError());
2012 TEST_F(VFSFromYAMLTest
, TrailingSlashes
) {
2013 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
2014 Lower
->addRegularFile("//root/other");
2017 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2019 " { 'type': 'directory', 'name': '//root/path/to////',\n"
2020 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
2021 " 'external-contents': '//root/other' }]}]\n"
2024 ASSERT_TRUE(nullptr != FS
.get());
2025 EXPECT_FALSE(FS
->status("//root/path/to/file").getError());
2026 EXPECT_FALSE(FS
->status("//root/path/to").getError());
2027 EXPECT_FALSE(FS
->status("//root/path").getError());
2028 EXPECT_FALSE(FS
->status("//root/").getError());
2031 TEST_F(VFSFromYAMLTest
, DirectoryIteration
) {
2032 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
2033 Lower
->addDirectory("//root/");
2034 Lower
->addDirectory("//root/foo");
2035 Lower
->addDirectory("//root/foo/bar");
2036 Lower
->addRegularFile("//root/foo/bar/a");
2037 Lower
->addRegularFile("//root/foo/bar/b");
2038 Lower
->addRegularFile("//root/file3");
2039 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2040 "{ 'use-external-names': false,\n"
2043 " 'type': 'directory',\n"
2044 " 'name': '//root/',\n"
2045 " 'contents': [ {\n"
2046 " 'type': 'file',\n"
2047 " 'name': 'file1',\n"
2048 " 'external-contents': '//root/foo/bar/a'\n"
2051 " 'type': 'file',\n"
2052 " 'name': 'file2',\n"
2053 " 'external-contents': '//root/foo/bar/b'\n"
2060 ASSERT_TRUE(FS
.get() != nullptr);
2062 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
2063 new vfs::OverlayFileSystem(Lower
));
2067 checkContents(O
->dir_begin("//root/", EC
),
2068 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
2070 checkContents(O
->dir_begin("//root/foo/bar", EC
),
2071 {"//root/foo/bar/a", "//root/foo/bar/b"});
2074 TEST_F(VFSFromYAMLTest
, DirectoryIterationSameDirMultipleEntries
) {
2075 // https://llvm.org/bugs/show_bug.cgi?id=27725
2076 if (!supportsSameDirMultipleYAMLEntries())
2079 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
2080 Lower
->addDirectory("//root/zab");
2081 Lower
->addDirectory("//root/baz");
2082 Lower
->addRegularFile("//root/zab/a");
2083 Lower
->addRegularFile("//root/zab/b");
2084 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2085 "{ 'use-external-names': false,\n"
2088 " 'type': 'directory',\n"
2089 " 'name': '//root/baz/',\n"
2090 " 'contents': [ {\n"
2091 " 'type': 'file',\n"
2093 " 'external-contents': '//root/zab/a'\n"
2098 " 'type': 'directory',\n"
2099 " 'name': '//root/baz/',\n"
2100 " 'contents': [ {\n"
2101 " 'type': 'file',\n"
2103 " 'external-contents': '//root/zab/b'\n"
2110 ASSERT_TRUE(FS
.get() != nullptr);
2112 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
2113 new vfs::OverlayFileSystem(Lower
));
2118 checkContents(O
->dir_begin("//root/baz/", EC
),
2119 {"//root/baz/x", "//root/baz/y"});
2122 TEST_F(VFSFromYAMLTest
, RecursiveDirectoryIterationLevel
) {
2124 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
2125 Lower
->addDirectory("//root/a");
2126 Lower
->addDirectory("//root/a/b");
2127 Lower
->addDirectory("//root/a/b/c");
2128 Lower
->addRegularFile("//root/a/b/c/file");
2129 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2130 "{ 'use-external-names': false,\n"
2133 " 'type': 'directory',\n"
2134 " 'name': '//root/a/b/c/',\n"
2135 " 'contents': [ {\n"
2136 " 'type': 'file',\n"
2137 " 'name': 'file',\n"
2138 " 'external-contents': '//root/a/b/c/file'\n"
2145 ASSERT_TRUE(FS
.get() != nullptr);
2147 IntrusiveRefCntPtr
<vfs::OverlayFileSystem
> O(
2148 new vfs::OverlayFileSystem(Lower
));
2153 // Test recursive_directory_iterator level()
2154 vfs::recursive_directory_iterator I
= vfs::recursive_directory_iterator(
2158 for (int l
= 0; I
!= E
; I
.increment(EC
), ++l
) {
2160 EXPECT_EQ(I
.level(), l
);
2165 TEST_F(VFSFromYAMLTest
, RelativePaths
) {
2166 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
2167 // Filename at root level without a parent directory.
2168 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2170 " { 'type': 'file', 'name': 'file-not-in-directory.h',\n"
2171 " 'external-contents': '//root/external/file'\n"
2175 EXPECT_EQ(nullptr, FS
.get());
2177 // Relative file path.
2178 FS
= getFromYAMLString("{ 'roots': [\n"
2179 " { 'type': 'file', 'name': 'relative/file/path.h',\n"
2180 " 'external-contents': '//root/external/file'\n"
2184 EXPECT_EQ(nullptr, FS
.get());
2186 // Relative directory path.
2187 FS
= getFromYAMLString(
2189 " { 'type': 'directory', 'name': 'relative/directory/path.h',\n"
2194 EXPECT_EQ(nullptr, FS
.get());
2196 EXPECT_EQ(3, NumDiagnostics
);
2199 TEST_F(VFSFromYAMLTest
, NonFallthroughDirectoryIteration
) {
2200 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
2201 Lower
->addDirectory("//root/");
2202 Lower
->addRegularFile("//root/a");
2203 Lower
->addRegularFile("//root/b");
2204 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2205 "{ 'use-external-names': false,\n"
2206 " 'fallthrough': false,\n"
2209 " 'type': 'directory',\n"
2210 " 'name': '//root/',\n"
2211 " 'contents': [ {\n"
2212 " 'type': 'file',\n"
2214 " 'external-contents': '//root/a'\n"
2221 ASSERT_TRUE(FS
.get() != nullptr);
2224 checkContents(FS
->dir_begin("//root/", EC
),
2228 TEST_F(VFSFromYAMLTest
, DirectoryIterationWithDuplicates
) {
2229 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
2230 Lower
->addDirectory("//root/");
2231 Lower
->addRegularFile("//root/a");
2232 Lower
->addRegularFile("//root/b");
2233 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2234 "{ 'use-external-names': false,\n"
2237 " 'type': 'directory',\n"
2238 " 'name': '//root/',\n"
2239 " 'contents': [ {\n"
2240 " 'type': 'file',\n"
2242 " 'external-contents': '//root/a'\n"
2249 ASSERT_TRUE(FS
.get() != nullptr);
2252 checkContents(FS
->dir_begin("//root/", EC
),
2253 {"//root/a", "//root/b"});
2256 TEST_F(VFSFromYAMLTest
, DirectoryIterationErrorInVFSLayer
) {
2257 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
2258 Lower
->addDirectory("//root/");
2259 Lower
->addDirectory("//root/foo");
2260 Lower
->addRegularFile("//root/foo/a");
2261 Lower
->addRegularFile("//root/foo/b");
2262 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2263 "{ 'use-external-names': false,\n"
2266 " 'type': 'directory',\n"
2267 " 'name': '//root/',\n"
2268 " 'contents': [ {\n"
2269 " 'type': 'file',\n"
2270 " 'name': 'bar/a',\n"
2271 " 'external-contents': '//root/foo/a'\n"
2278 ASSERT_TRUE(FS
.get() != nullptr);
2281 checkContents(FS
->dir_begin("//root/foo", EC
),
2282 {"//root/foo/a", "//root/foo/b"});
2285 TEST_F(VFSFromYAMLTest
, GetRealPath
) {
2286 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
2287 Lower
->addDirectory("//dir/");
2288 Lower
->addRegularFile("/foo");
2289 Lower
->addSymlink("/link");
2290 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2291 "{ 'use-external-names': false,\n"
2294 " 'type': 'directory',\n"
2295 " 'name': '//root/',\n"
2296 " 'contents': [ {\n"
2297 " 'type': 'file',\n"
2299 " 'external-contents': '/link'\n"
2304 " 'type': 'directory',\n"
2305 " 'name': '//dir/',\n"
2311 ASSERT_TRUE(FS
.get() != nullptr);
2313 // Regular file present in underlying file system.
2314 SmallString
<16> RealPath
;
2315 EXPECT_FALSE(FS
->getRealPath("/foo", RealPath
));
2316 EXPECT_EQ(RealPath
.str(), "/foo");
2318 // File present in YAML pointing to symlink in underlying file system.
2319 EXPECT_FALSE(FS
->getRealPath("//root/bar", RealPath
));
2320 EXPECT_EQ(RealPath
.str(), "/symlink");
2322 // Directories should fall back to the underlying file system is possible.
2323 EXPECT_FALSE(FS
->getRealPath("//dir/", RealPath
));
2324 EXPECT_EQ(RealPath
.str(), "//dir/");
2326 // Try a non-existing file.
2327 EXPECT_EQ(FS
->getRealPath("/non_existing", RealPath
),
2328 errc::no_such_file_or_directory
);
2331 TEST_F(VFSFromYAMLTest
, WorkingDirectory
) {
2332 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
2333 Lower
->addDirectory("//root/");
2334 Lower
->addDirectory("//root/foo");
2335 Lower
->addRegularFile("//root/foo/a");
2336 Lower
->addRegularFile("//root/foo/b");
2337 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2338 "{ 'use-external-names': false,\n"
2341 " 'type': 'directory',\n"
2342 " 'name': '//root/bar',\n"
2343 " 'contents': [ {\n"
2344 " 'type': 'file',\n"
2346 " 'external-contents': '//root/foo/a'\n"
2353 ASSERT_TRUE(FS
.get() != nullptr);
2354 std::error_code EC
= FS
->setCurrentWorkingDirectory("//root/bar");
2357 llvm::ErrorOr
<std::string
> WorkingDir
= FS
->getCurrentWorkingDirectory();
2358 ASSERT_TRUE(WorkingDir
);
2359 EXPECT_EQ(*WorkingDir
, "//root/bar");
2361 llvm::ErrorOr
<vfs::Status
> Status
= FS
->status("./a");
2362 ASSERT_FALSE(Status
.getError());
2363 EXPECT_TRUE(Status
->isStatusKnown());
2364 EXPECT_FALSE(Status
->isDirectory());
2365 EXPECT_TRUE(Status
->isRegularFile());
2366 EXPECT_FALSE(Status
->isSymlink());
2367 EXPECT_FALSE(Status
->isOther());
2368 EXPECT_TRUE(Status
->exists());
2370 EC
= FS
->setCurrentWorkingDirectory("bogus");
2372 WorkingDir
= FS
->getCurrentWorkingDirectory();
2373 ASSERT_TRUE(WorkingDir
);
2374 EXPECT_EQ(*WorkingDir
, "//root/bar");
2376 EC
= FS
->setCurrentWorkingDirectory("//root/");
2378 WorkingDir
= FS
->getCurrentWorkingDirectory();
2379 ASSERT_TRUE(WorkingDir
);
2380 EXPECT_EQ(*WorkingDir
, "//root/");
2382 EC
= FS
->setCurrentWorkingDirectory("bar");
2384 WorkingDir
= FS
->getCurrentWorkingDirectory();
2385 ASSERT_TRUE(WorkingDir
);
2386 EXPECT_EQ(*WorkingDir
, "//root/bar");
2389 TEST_F(VFSFromYAMLTest
, WorkingDirectoryFallthrough
) {
2390 IntrusiveRefCntPtr
<DummyFileSystem
> Lower(new DummyFileSystem());
2391 Lower
->addDirectory("//root/");
2392 Lower
->addDirectory("//root/foo");
2393 Lower
->addRegularFile("//root/foo/a");
2394 Lower
->addRegularFile("//root/foo/b");
2395 Lower
->addRegularFile("//root/c");
2396 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2397 "{ 'use-external-names': false,\n"
2400 " 'type': 'directory',\n"
2401 " 'name': '//root/bar',\n"
2402 " 'contents': [ {\n"
2403 " 'type': 'file',\n"
2405 " 'external-contents': '//root/foo/a'\n"
2410 " 'type': 'directory',\n"
2411 " 'name': '//root/bar/baz',\n"
2412 " 'contents': [ {\n"
2413 " 'type': 'file',\n"
2415 " 'external-contents': '//root/foo/a'\n"
2422 ASSERT_TRUE(FS
.get() != nullptr);
2423 std::error_code EC
= FS
->setCurrentWorkingDirectory("//root/");
2425 ASSERT_TRUE(FS
.get() != nullptr);
2427 llvm::ErrorOr
<vfs::Status
> Status
= FS
->status("bar/a");
2428 ASSERT_FALSE(Status
.getError());
2429 EXPECT_TRUE(Status
->exists());
2431 Status
= FS
->status("foo/a");
2432 ASSERT_FALSE(Status
.getError());
2433 EXPECT_TRUE(Status
->exists());
2435 EC
= FS
->setCurrentWorkingDirectory("//root/bar");
2438 Status
= FS
->status("./a");
2439 ASSERT_FALSE(Status
.getError());
2440 EXPECT_TRUE(Status
->exists());
2442 Status
= FS
->status("./b");
2443 ASSERT_TRUE(Status
.getError());
2445 Status
= FS
->status("./c");
2446 ASSERT_TRUE(Status
.getError());
2448 EC
= FS
->setCurrentWorkingDirectory("//root/");
2451 Status
= FS
->status("c");
2452 ASSERT_FALSE(Status
.getError());
2453 EXPECT_TRUE(Status
->exists());
2455 Status
= FS
->status("./bar/baz/a");
2456 ASSERT_FALSE(Status
.getError());
2457 EXPECT_TRUE(Status
->exists());
2459 EC
= FS
->setCurrentWorkingDirectory("//root/bar");
2462 Status
= FS
->status("./baz/a");
2463 ASSERT_FALSE(Status
.getError());
2464 EXPECT_TRUE(Status
->exists());
2466 Status
= FS
->status("../bar/baz/a");
2467 ASSERT_FALSE(Status
.getError());
2468 EXPECT_TRUE(Status
->exists());
2471 TEST_F(VFSFromYAMLTest
, WorkingDirectoryFallthroughInvalid
) {
2472 IntrusiveRefCntPtr
<ErrorDummyFileSystem
> Lower(new ErrorDummyFileSystem());
2473 Lower
->addDirectory("//root/");
2474 Lower
->addDirectory("//root/foo");
2475 Lower
->addRegularFile("//root/foo/a");
2476 Lower
->addRegularFile("//root/foo/b");
2477 Lower
->addRegularFile("//root/c");
2478 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2479 "{ 'use-external-names': false,\n"
2482 " 'type': 'directory',\n"
2483 " 'name': '//root/bar',\n"
2484 " 'contents': [ {\n"
2485 " 'type': 'file',\n"
2487 " 'external-contents': '//root/foo/a'\n"
2494 ASSERT_TRUE(FS
.get() != nullptr);
2495 std::error_code EC
= FS
->setCurrentWorkingDirectory("//root/");
2497 ASSERT_TRUE(FS
.get() != nullptr);
2499 llvm::ErrorOr
<vfs::Status
> Status
= FS
->status("bar/a");
2500 ASSERT_FALSE(Status
.getError());
2501 EXPECT_TRUE(Status
->exists());
2503 Status
= FS
->status("foo/a");
2504 ASSERT_FALSE(Status
.getError());
2505 EXPECT_TRUE(Status
->exists());
2508 TEST_F(VFSFromYAMLTest
, VirtualWorkingDirectory
) {
2509 IntrusiveRefCntPtr
<ErrorDummyFileSystem
> Lower(new ErrorDummyFileSystem());
2510 Lower
->addDirectory("//root/");
2511 Lower
->addDirectory("//root/foo");
2512 Lower
->addRegularFile("//root/foo/a");
2513 Lower
->addRegularFile("//root/foo/b");
2514 Lower
->addRegularFile("//root/c");
2515 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLString(
2516 "{ 'use-external-names': false,\n"
2519 " 'type': 'directory',\n"
2520 " 'name': '//root/bar',\n"
2521 " 'contents': [ {\n"
2522 " 'type': 'file',\n"
2524 " 'external-contents': '//root/foo/a'\n"
2531 ASSERT_TRUE(FS
.get() != nullptr);
2532 std::error_code EC
= FS
->setCurrentWorkingDirectory("//root/bar");
2534 ASSERT_TRUE(FS
.get() != nullptr);
2536 llvm::ErrorOr
<vfs::Status
> Status
= FS
->status("a");
2537 ASSERT_FALSE(Status
.getError());
2538 EXPECT_TRUE(Status
->exists());
2541 TEST_F(VFSFromYAMLTest
, YAMLVFSWriterTest
) {
2542 TempDir
TestDirectory("virtual-file-system-test", /*Unique*/ true);
2543 TempDir
_a(TestDirectory
.path("a"));
2544 TempFile
_ab(TestDirectory
.path("a, b"));
2545 TempDir
_c(TestDirectory
.path("c"));
2546 TempFile
_cd(TestDirectory
.path("c/d"));
2547 TempDir
_e(TestDirectory
.path("e"));
2548 TempDir
_ef(TestDirectory
.path("e/f"));
2549 TempFile
_g(TestDirectory
.path("g"));
2550 TempDir
_h(TestDirectory
.path("h"));
2552 vfs::YAMLVFSWriter VFSWriter
;
2553 VFSWriter
.addDirectoryMapping(_a
.path(), "//root/a");
2554 VFSWriter
.addFileMapping(_ab
.path(), "//root/a/b");
2555 VFSWriter
.addFileMapping(_cd
.path(), "//root/c/d");
2556 VFSWriter
.addDirectoryMapping(_e
.path(), "//root/e");
2557 VFSWriter
.addDirectoryMapping(_ef
.path(), "//root/e/f");
2558 VFSWriter
.addFileMapping(_g
.path(), "//root/g");
2559 VFSWriter
.addDirectoryMapping(_h
.path(), "//root/h");
2562 raw_string_ostream
OS(Buffer
);
2563 VFSWriter
.write(OS
);
2566 IntrusiveRefCntPtr
<ErrorDummyFileSystem
> Lower(new ErrorDummyFileSystem());
2567 Lower
->addDirectory("//root/");
2568 Lower
->addDirectory("//root/a");
2569 Lower
->addRegularFile("//root/a/b");
2570 Lower
->addDirectory("//root/b");
2571 Lower
->addDirectory("//root/c");
2572 Lower
->addRegularFile("//root/c/d");
2573 Lower
->addDirectory("//root/e");
2574 Lower
->addDirectory("//root/e/f");
2575 Lower
->addRegularFile("//root/g");
2576 Lower
->addDirectory("//root/h");
2578 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLRawString(Buffer
, Lower
);
2579 ASSERT_TRUE(FS
.get() != nullptr);
2581 EXPECT_TRUE(FS
->exists(_a
.path()));
2582 EXPECT_TRUE(FS
->exists(_ab
.path()));
2583 EXPECT_TRUE(FS
->exists(_c
.path()));
2584 EXPECT_TRUE(FS
->exists(_cd
.path()));
2585 EXPECT_TRUE(FS
->exists(_e
.path()));
2586 EXPECT_TRUE(FS
->exists(_ef
.path()));
2587 EXPECT_TRUE(FS
->exists(_g
.path()));
2588 EXPECT_TRUE(FS
->exists(_h
.path()));
2591 TEST_F(VFSFromYAMLTest
, YAMLVFSWriterTest2
) {
2592 TempDir
TestDirectory("virtual-file-system-test", /*Unique*/ true);
2593 TempDir
_a(TestDirectory
.path("a"));
2594 TempFile
_ab(TestDirectory
.path("a/b"));
2595 TempDir
_ac(TestDirectory
.path("a/c"));
2596 TempFile
_acd(TestDirectory
.path("a/c/d"));
2597 TempFile
_ace(TestDirectory
.path("a/c/e"));
2598 TempFile
_acf(TestDirectory
.path("a/c/f"));
2599 TempDir
_ag(TestDirectory
.path("a/g"));
2600 TempFile
_agh(TestDirectory
.path("a/g/h"));
2602 vfs::YAMLVFSWriter VFSWriter
;
2603 VFSWriter
.addDirectoryMapping(_a
.path(), "//root/a");
2604 VFSWriter
.addFileMapping(_ab
.path(), "//root/a/b");
2605 VFSWriter
.addDirectoryMapping(_ac
.path(), "//root/a/c");
2606 VFSWriter
.addFileMapping(_acd
.path(), "//root/a/c/d");
2607 VFSWriter
.addFileMapping(_ace
.path(), "//root/a/c/e");
2608 VFSWriter
.addFileMapping(_acf
.path(), "//root/a/c/f");
2609 VFSWriter
.addDirectoryMapping(_ag
.path(), "//root/a/g");
2610 VFSWriter
.addFileMapping(_agh
.path(), "//root/a/g/h");
2613 raw_string_ostream
OS(Buffer
);
2614 VFSWriter
.write(OS
);
2617 IntrusiveRefCntPtr
<ErrorDummyFileSystem
> Lower(new ErrorDummyFileSystem());
2618 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLRawString(Buffer
, Lower
);
2619 EXPECT_TRUE(FS
.get() != nullptr);
2622 TEST_F(VFSFromYAMLTest
, YAMLVFSWriterTest3
) {
2623 TempDir
TestDirectory("virtual-file-system-test", /*Unique*/ true);
2624 TempDir
_a(TestDirectory
.path("a"));
2625 TempFile
_ab(TestDirectory
.path("a/b"));
2626 TempDir
_ac(TestDirectory
.path("a/c"));
2627 TempDir
_acd(TestDirectory
.path("a/c/d"));
2628 TempDir
_acde(TestDirectory
.path("a/c/d/e"));
2629 TempFile
_acdef(TestDirectory
.path("a/c/d/e/f"));
2630 TempFile
_acdeg(TestDirectory
.path("a/c/d/e/g"));
2631 TempDir
_ah(TestDirectory
.path("a/h"));
2632 TempFile
_ahi(TestDirectory
.path("a/h/i"));
2634 vfs::YAMLVFSWriter VFSWriter
;
2635 VFSWriter
.addDirectoryMapping(_a
.path(), "//root/a");
2636 VFSWriter
.addFileMapping(_ab
.path(), "//root/a/b");
2637 VFSWriter
.addDirectoryMapping(_ac
.path(), "//root/a/c");
2638 VFSWriter
.addDirectoryMapping(_acd
.path(), "//root/a/c/d");
2639 VFSWriter
.addDirectoryMapping(_acde
.path(), "//root/a/c/d/e");
2640 VFSWriter
.addFileMapping(_acdef
.path(), "//root/a/c/d/e/f");
2641 VFSWriter
.addFileMapping(_acdeg
.path(), "//root/a/c/d/e/g");
2642 VFSWriter
.addDirectoryMapping(_ahi
.path(), "//root/a/h");
2643 VFSWriter
.addFileMapping(_ahi
.path(), "//root/a/h/i");
2646 raw_string_ostream
OS(Buffer
);
2647 VFSWriter
.write(OS
);
2650 IntrusiveRefCntPtr
<ErrorDummyFileSystem
> Lower(new ErrorDummyFileSystem());
2651 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLRawString(Buffer
, Lower
);
2652 EXPECT_TRUE(FS
.get() != nullptr);
2655 TEST_F(VFSFromYAMLTest
, YAMLVFSWriterTestHandleDirs
) {
2656 TempDir
TestDirectory("virtual-file-system-test", /*Unique*/ true);
2657 TempDir
_a(TestDirectory
.path("a"));
2658 TempDir
_b(TestDirectory
.path("b"));
2659 TempDir
_c(TestDirectory
.path("c"));
2661 vfs::YAMLVFSWriter VFSWriter
;
2662 VFSWriter
.addDirectoryMapping(_a
.path(), "//root/a");
2663 VFSWriter
.addDirectoryMapping(_b
.path(), "//root/b");
2664 VFSWriter
.addDirectoryMapping(_c
.path(), "//root/c");
2667 raw_string_ostream
OS(Buffer
);
2668 VFSWriter
.write(OS
);
2671 // We didn't add a single file - only directories.
2672 EXPECT_TRUE(Buffer
.find("'type': 'file'") == std::string::npos
);
2674 IntrusiveRefCntPtr
<ErrorDummyFileSystem
> Lower(new ErrorDummyFileSystem());
2675 Lower
->addDirectory("//root/a");
2676 Lower
->addDirectory("//root/b");
2677 Lower
->addDirectory("//root/c");
2679 Lower
->addRegularFile("//root/a/a");
2680 Lower
->addRegularFile("//root/b/b");
2681 Lower
->addRegularFile("//root/c/c");
2683 IntrusiveRefCntPtr
<vfs::FileSystem
> FS
= getFromYAMLRawString(Buffer
, Lower
);
2684 ASSERT_TRUE(FS
.get() != nullptr);
2686 EXPECT_FALSE(FS
->exists(_a
.path("a")));
2687 EXPECT_FALSE(FS
->exists(_b
.path("b")));
2688 EXPECT_FALSE(FS
->exists(_c
.path("c")));
2691 TEST(VFSFromRemappedFilesTest
, Basic
) {
2692 IntrusiveRefCntPtr
<vfs::InMemoryFileSystem
> BaseFS
=
2693 new vfs::InMemoryFileSystem
;
2694 BaseFS
->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b"));
2695 BaseFS
->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c"));
2697 std::vector
<std::pair
<std::string
, std::string
>> RemappedFiles
= {
2698 {"//root/a/a", "//root/b"},
2699 {"//root/a/b/c", "//root/c"},
2701 auto RemappedFS
= vfs::RedirectingFileSystem::create(
2702 RemappedFiles
, /*UseExternalNames=*/false, *BaseFS
);
2704 auto StatA
= RemappedFS
->status("//root/a/a");
2705 auto StatB
= RemappedFS
->status("//root/a/b/c");
2708 EXPECT_EQ("//root/a/a", StatA
->getName());
2709 EXPECT_EQ("//root/a/b/c", StatB
->getName());
2711 auto BufferA
= RemappedFS
->getBufferForFile("//root/a/a");
2712 auto BufferB
= RemappedFS
->getBufferForFile("//root/a/b/c");
2713 ASSERT_TRUE(BufferA
);
2714 ASSERT_TRUE(BufferB
);
2715 EXPECT_EQ("contents of b", (*BufferA
)->getBuffer());
2716 EXPECT_EQ("contents of c", (*BufferB
)->getBuffer());
2719 TEST(VFSFromRemappedFilesTest
, UseExternalNames
) {
2720 IntrusiveRefCntPtr
<vfs::InMemoryFileSystem
> BaseFS
=
2721 new vfs::InMemoryFileSystem
;
2722 BaseFS
->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b"));
2723 BaseFS
->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c"));
2725 std::vector
<std::pair
<std::string
, std::string
>> RemappedFiles
= {
2726 {"//root/a/a", "//root/b"},
2727 {"//root/a/b/c", "//root/c"},
2729 auto RemappedFS
= vfs::RedirectingFileSystem::create(
2730 RemappedFiles
, /*UseExternalNames=*/true, *BaseFS
);
2732 auto StatA
= RemappedFS
->status("//root/a/a");
2733 auto StatB
= RemappedFS
->status("//root/a/b/c");
2736 EXPECT_EQ("//root/b", StatA
->getName());
2737 EXPECT_EQ("//root/c", StatB
->getName());
2739 auto BufferA
= RemappedFS
->getBufferForFile("//root/a/a");
2740 auto BufferB
= RemappedFS
->getBufferForFile("//root/a/b/c");
2741 ASSERT_TRUE(BufferA
);
2742 ASSERT_TRUE(BufferB
);
2743 EXPECT_EQ("contents of b", (*BufferA
)->getBuffer());
2744 EXPECT_EQ("contents of c", (*BufferB
)->getBuffer());
2747 TEST(VFSFromRemappedFilesTest
, LastMappingWins
) {
2748 IntrusiveRefCntPtr
<vfs::InMemoryFileSystem
> BaseFS
=
2749 new vfs::InMemoryFileSystem
;
2750 BaseFS
->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b"));
2751 BaseFS
->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c"));
2753 std::vector
<std::pair
<std::string
, std::string
>> RemappedFiles
= {
2754 {"//root/a", "//root/b"},
2755 {"//root/a", "//root/c"},
2757 auto RemappedFSKeepName
= vfs::RedirectingFileSystem::create(
2758 RemappedFiles
, /*UseExternalNames=*/false, *BaseFS
);
2759 auto RemappedFSExternalName
= vfs::RedirectingFileSystem::create(
2760 RemappedFiles
, /*UseExternalNames=*/true, *BaseFS
);
2762 auto StatKeepA
= RemappedFSKeepName
->status("//root/a");
2763 auto StatExternalA
= RemappedFSExternalName
->status("//root/a");
2764 ASSERT_TRUE(StatKeepA
);
2765 ASSERT_TRUE(StatExternalA
);
2766 EXPECT_EQ("//root/a", StatKeepA
->getName());
2767 EXPECT_EQ("//root/c", StatExternalA
->getName());
2769 auto BufferKeepA
= RemappedFSKeepName
->getBufferForFile("//root/a");
2770 auto BufferExternalA
= RemappedFSExternalName
->getBufferForFile("//root/a");
2771 ASSERT_TRUE(BufferKeepA
);
2772 ASSERT_TRUE(BufferExternalA
);
2773 EXPECT_EQ("contents of c", (*BufferKeepA
)->getBuffer());
2774 EXPECT_EQ("contents of c", (*BufferExternalA
)->getBuffer());