1 //===- unittests/Basic/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 "clang/Basic/VirtualFileSystem.h"
11 #include "llvm/Support/Errc.h"
12 #include "llvm/Support/MemoryBuffer.h"
13 #include "llvm/Support/Path.h"
14 #include "llvm/Support/SourceMgr.h"
15 #include "gtest/gtest.h"
17 using namespace clang;
19 using llvm::sys::fs::UniqueID;
22 class DummyFileSystem : public vfs::FileSystem {
23 int FSID; // used to produce UniqueIDs
24 int FileID; // used to produce UniqueIDs
25 std::map<std::string, vfs::Status> FilesAndDirs;
27 static int getNextFSID() {
33 DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
35 ErrorOr<vfs::Status> status(const Twine &Path) {
36 std::map<std::string, vfs::Status>::iterator I =
37 FilesAndDirs.find(Path.str());
38 if (I == FilesAndDirs.end())
39 return make_error_code(llvm::errc::no_such_file_or_directory);
42 std::error_code openFileForRead(const Twine &Path,
43 std::unique_ptr<vfs::File> &Result) {
44 llvm_unreachable("unimplemented");
46 std::error_code getBufferForFile(const Twine &Name,
47 std::unique_ptr<MemoryBuffer> &Result,
48 int64_t FileSize = -1,
49 bool RequiresNullTerminator = true) {
50 llvm_unreachable("unimplemented");
53 struct DirIterImpl : public clang::vfs::detail::DirIterImpl {
54 std::map<std::string, vfs::Status> &FilesAndDirs;
55 std::map<std::string, vfs::Status>::iterator I;
57 DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
59 : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
61 for ( ; I != FilesAndDirs.end(); ++I) {
62 if (Path.size() < I->first.size() && I->first.find(Path) == 0 && I->first.find_last_of('/') <= Path.size()) {
63 CurrentEntry = I->second;
68 std::error_code increment() override {
70 for ( ; I != FilesAndDirs.end(); ++I) {
71 if (Path.size() < I->first.size() && I->first.find(Path) == 0 && I->first.find_last_of('/') <= Path.size()) {
72 CurrentEntry = I->second;
76 if (I == FilesAndDirs.end())
77 CurrentEntry = vfs::Status();
78 return std::error_code();
82 vfs::directory_iterator dir_begin(const Twine &Dir,
83 std::error_code &EC) override {
84 return vfs::directory_iterator(
85 std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
88 void addEntry(StringRef Path, const vfs::Status &Status) {
89 FilesAndDirs[Path] = Status;
92 void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
93 vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
94 0, 0, 1024, sys::fs::file_type::regular_file, Perms);
98 void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
99 vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
100 0, 0, 0, sys::fs::file_type::directory_file, Perms);
104 void addSymlink(StringRef Path) {
105 vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
106 0, 0, 0, sys::fs::file_type::symlink_file, sys::fs::all_all);
110 } // end anonymous namespace
112 TEST(VirtualFileSystemTest, StatusQueries) {
113 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
114 ErrorOr<vfs::Status> Status((std::error_code()));
116 D->addRegularFile("/foo");
117 Status = D->status("/foo");
118 ASSERT_FALSE(Status.getError());
119 EXPECT_TRUE(Status->isStatusKnown());
120 EXPECT_FALSE(Status->isDirectory());
121 EXPECT_TRUE(Status->isRegularFile());
122 EXPECT_FALSE(Status->isSymlink());
123 EXPECT_FALSE(Status->isOther());
124 EXPECT_TRUE(Status->exists());
126 D->addDirectory("/bar");
127 Status = D->status("/bar");
128 ASSERT_FALSE(Status.getError());
129 EXPECT_TRUE(Status->isStatusKnown());
130 EXPECT_TRUE(Status->isDirectory());
131 EXPECT_FALSE(Status->isRegularFile());
132 EXPECT_FALSE(Status->isSymlink());
133 EXPECT_FALSE(Status->isOther());
134 EXPECT_TRUE(Status->exists());
136 D->addSymlink("/baz");
137 Status = D->status("/baz");
138 ASSERT_FALSE(Status.getError());
139 EXPECT_TRUE(Status->isStatusKnown());
140 EXPECT_FALSE(Status->isDirectory());
141 EXPECT_FALSE(Status->isRegularFile());
142 EXPECT_TRUE(Status->isSymlink());
143 EXPECT_FALSE(Status->isOther());
144 EXPECT_TRUE(Status->exists());
146 EXPECT_TRUE(Status->equivalent(*Status));
147 ErrorOr<vfs::Status> Status2 = D->status("/foo");
148 ASSERT_FALSE(Status2.getError());
149 EXPECT_FALSE(Status->equivalent(*Status2));
152 TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
153 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
154 ErrorOr<vfs::Status> Status((std::error_code()));
155 EXPECT_FALSE(Status = D->status("/foo"));
157 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
158 EXPECT_FALSE(Status = O->status("/foo"));
160 D->addRegularFile("/foo");
161 Status = D->status("/foo");
162 EXPECT_FALSE(Status.getError());
164 ErrorOr<vfs::Status> Status2((std::error_code()));
165 Status2 = O->status("/foo");
166 EXPECT_FALSE(Status2.getError());
167 EXPECT_TRUE(Status->equivalent(*Status2));
170 TEST(VirtualFileSystemTest, OverlayFiles) {
171 IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
172 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
173 IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
174 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
175 new vfs::OverlayFileSystem(Base));
176 O->pushOverlay(Middle);
179 ErrorOr<vfs::Status> Status1((std::error_code())),
180 Status2((std::error_code())), Status3((std::error_code())),
181 StatusB((std::error_code())), StatusM((std::error_code())),
182 StatusT((std::error_code()));
184 Base->addRegularFile("/foo");
185 StatusB = Base->status("/foo");
186 ASSERT_FALSE(StatusB.getError());
187 Status1 = O->status("/foo");
188 ASSERT_FALSE(Status1.getError());
189 Middle->addRegularFile("/foo");
190 StatusM = Middle->status("/foo");
191 ASSERT_FALSE(StatusM.getError());
192 Status2 = O->status("/foo");
193 ASSERT_FALSE(Status2.getError());
194 Top->addRegularFile("/foo");
195 StatusT = Top->status("/foo");
196 ASSERT_FALSE(StatusT.getError());
197 Status3 = O->status("/foo");
198 ASSERT_FALSE(Status3.getError());
200 EXPECT_TRUE(Status1->equivalent(*StatusB));
201 EXPECT_TRUE(Status2->equivalent(*StatusM));
202 EXPECT_TRUE(Status3->equivalent(*StatusT));
204 EXPECT_FALSE(Status1->equivalent(*Status2));
205 EXPECT_FALSE(Status2->equivalent(*Status3));
206 EXPECT_FALSE(Status1->equivalent(*Status3));
209 TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
210 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
211 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
212 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
213 new vfs::OverlayFileSystem(Lower));
214 O->pushOverlay(Upper);
216 Lower->addDirectory("/lower-only");
217 Upper->addDirectory("/upper-only");
219 // non-merged paths should be the same
220 ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
221 ASSERT_FALSE(Status1.getError());
222 ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
223 ASSERT_FALSE(Status2.getError());
224 EXPECT_TRUE(Status1->equivalent(*Status2));
226 Status1 = Upper->status("/upper-only");
227 ASSERT_FALSE(Status1.getError());
228 Status2 = O->status("/upper-only");
229 ASSERT_FALSE(Status2.getError());
230 EXPECT_TRUE(Status1->equivalent(*Status2));
233 TEST(VirtualFileSystemTest, MergedDirPermissions) {
234 // merged directories get the permissions of the upper dir
235 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
236 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
237 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
238 new vfs::OverlayFileSystem(Lower));
239 O->pushOverlay(Upper);
241 ErrorOr<vfs::Status> Status((std::error_code()));
242 Lower->addDirectory("/both", sys::fs::owner_read);
243 Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
244 Status = O->status("/both");
245 ASSERT_FALSE(Status.getError());
246 EXPECT_EQ(0740, Status->getPermissions());
248 // permissions (as usual) are not recursively applied
249 Lower->addRegularFile("/both/foo", sys::fs::owner_read);
250 Upper->addRegularFile("/both/bar", sys::fs::owner_write);
251 Status = O->status("/both/foo");
252 ASSERT_FALSE( Status.getError());
253 EXPECT_EQ(0400, Status->getPermissions());
254 Status = O->status("/both/bar");
255 ASSERT_FALSE(Status.getError());
256 EXPECT_EQ(0200, Status->getPermissions());
261 SmallString<128> Path;
262 ScopedDir(const Twine &Name, bool Unique=false) {
265 EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
268 EC = llvm::sys::fs::create_directory(Twine(Path));
276 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
278 operator StringRef() { return Path.str(); }
282 TEST(VirtualFileSystemTest, BasicRealFSIteration) {
283 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
284 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
287 vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
289 EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
291 ScopedDir _a(TestDirectory+"/a");
292 ScopedDir _ab(TestDirectory+"/a/b");
293 ScopedDir _c(TestDirectory+"/c");
294 ScopedDir _cd(TestDirectory+"/c/d");
296 I = FS->dir_begin(Twine(TestDirectory), EC);
298 ASSERT_NE(vfs::directory_iterator(), I);
299 EXPECT_TRUE(I->getName().endswith("a"));
302 ASSERT_NE(vfs::directory_iterator(), I);
303 EXPECT_TRUE(I->getName().endswith("c"));
305 EXPECT_EQ(vfs::directory_iterator(), I);
308 static void checkContents(vfs::directory_iterator I,
309 ArrayRef<std::string> Expected) {
311 auto ExpectedIter = Expected.begin(), ExpectedEnd = Expected.end();
312 for (vfs::directory_iterator E;
313 !EC && I != E && ExpectedIter != ExpectedEnd;
314 I.increment(EC), ++ExpectedIter)
315 EXPECT_EQ(*ExpectedIter, I->getName());
317 EXPECT_EQ(ExpectedEnd, ExpectedIter);
318 EXPECT_EQ(vfs::directory_iterator(), I);
321 TEST(VirtualFileSystemTest, OverlayIteration) {
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);
329 checkContents(O->dir_begin("/", EC), ArrayRef<std::string>());
331 Lower->addRegularFile("/file1");
332 checkContents(O->dir_begin("/", EC), ArrayRef<std::string>("/file1"));
334 Upper->addRegularFile("/file2");
336 std::vector<std::string> Contents = { "/file2", "/file1" };
337 checkContents(O->dir_begin("/", EC), Contents);
340 Lower->addDirectory("/dir1");
341 Lower->addRegularFile("/dir1/foo");
342 Upper->addDirectory("/dir2");
343 Upper->addRegularFile("/dir2/foo");
344 checkContents(O->dir_begin("/dir2", EC), ArrayRef<std::string>("/dir2/foo"));
346 std::vector<std::string> Contents = { "/dir2", "/file2", "/dir1", "/file1" };
347 checkContents(O->dir_begin("/", EC), Contents);
351 TEST(VirtualFileSystemTest, ThreeLevelIteration) {
352 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
353 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
354 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
355 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
356 new vfs::OverlayFileSystem(Lower));
357 O->pushOverlay(Middle);
358 O->pushOverlay(Upper);
361 checkContents(O->dir_begin("/", EC), ArrayRef<std::string>());
363 Middle->addRegularFile("/file2");
364 checkContents(O->dir_begin("/", EC), ArrayRef<std::string>("/file2"));
366 Lower->addRegularFile("/file1");
367 Upper->addRegularFile("/file3");
369 std::vector<std::string> Contents = { "/file3", "/file2", "/file1" };
370 checkContents(O->dir_begin("/", EC), Contents);
374 TEST(VirtualFileSystemTest, HiddenInIteration) {
375 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
376 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
377 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
378 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
379 new vfs::OverlayFileSystem(Lower));
380 O->pushOverlay(Middle);
381 O->pushOverlay(Upper);
384 Lower->addRegularFile("/onlyInLow", sys::fs::owner_read);
385 Lower->addRegularFile("/hiddenByMid", sys::fs::owner_read);
386 Lower->addRegularFile("/hiddenByUp", sys::fs::owner_read);
387 Middle->addRegularFile("/onlyInMid", sys::fs::owner_write);
388 Middle->addRegularFile("/hiddenByMid", sys::fs::owner_write);
389 Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
390 Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
391 Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
393 std::vector<std::string> Contents = { "/hiddenByUp", "/onlyInUp",
394 "/hiddenByMid", "/onlyInMid", "/onlyInLow" };
395 checkContents(O->dir_begin("/", EC), Contents);
398 // Make sure we get the top-most entry
399 vfs::directory_iterator E;
401 auto I = std::find_if(O->dir_begin("/", EC), E, [](vfs::Status S){
402 return S.getName() == "/hiddenByUp";
405 EXPECT_EQ(sys::fs::owner_all, I->getPermissions());
408 auto I = std::find_if(O->dir_begin("/", EC), E, [](vfs::Status S){
409 return S.getName() == "/hiddenByMid";
412 EXPECT_EQ(sys::fs::owner_write, I->getPermissions());
416 // NOTE: in the tests below, we use '//root/' as our root directory, since it is
417 // a legal *absolute* path on Windows as well as *nix.
418 class VFSFromYAMLTest : public ::testing::Test {
426 static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
427 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
428 ++Test->NumDiagnostics;
431 IntrusiveRefCntPtr<vfs::FileSystem>
432 getFromYAMLRawString(StringRef Content,
433 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
434 MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(Content);
435 return getVFSFromYAML(Buffer, CountingDiagHandler, this, ExternalFS);
438 IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
440 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
441 std::string VersionPlusContent("{\n 'version':0,\n");
442 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
443 return getFromYAMLRawString(VersionPlusContent, ExternalFS);
447 TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
448 IntrusiveRefCntPtr<vfs::FileSystem> FS;
449 FS = getFromYAMLString("");
450 EXPECT_EQ(nullptr, FS.getPtr());
451 FS = getFromYAMLString("[]");
452 EXPECT_EQ(nullptr, FS.getPtr());
453 FS = getFromYAMLString("'string'");
454 EXPECT_EQ(nullptr, FS.getPtr());
455 EXPECT_EQ(3, NumDiagnostics);
458 TEST_F(VFSFromYAMLTest, MappedFiles) {
459 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
460 Lower->addRegularFile("//root/foo/bar/a");
461 IntrusiveRefCntPtr<vfs::FileSystem> FS =
462 getFromYAMLString("{ 'roots': [\n"
464 " 'type': 'directory',\n"
465 " 'name': '//root/',\n"
468 " 'name': 'file1',\n"
469 " 'external-contents': '//root/foo/bar/a'\n"
473 " 'name': 'file2',\n"
474 " 'external-contents': '//root/foo/b'\n"
481 ASSERT_TRUE(FS.getPtr() != nullptr);
483 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
484 new vfs::OverlayFileSystem(Lower));
488 ErrorOr<vfs::Status> S = O->status("//root/file1");
489 ASSERT_FALSE(S.getError());
490 EXPECT_EQ("//root/foo/bar/a", S->getName());
492 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
493 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
494 EXPECT_TRUE(S->equivalent(*SLower));
497 S = O->status("//root/");
498 ASSERT_FALSE(S.getError());
499 EXPECT_TRUE(S->isDirectory());
500 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
503 EXPECT_EQ(O->status("//root/file2").getError(),
504 llvm::errc::no_such_file_or_directory);
505 EXPECT_EQ(0, NumDiagnostics);
508 TEST_F(VFSFromYAMLTest, CaseInsensitive) {
509 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
510 Lower->addRegularFile("//root/foo/bar/a");
511 IntrusiveRefCntPtr<vfs::FileSystem> FS =
512 getFromYAMLString("{ 'case-sensitive': 'false',\n"
515 " 'type': 'directory',\n"
516 " 'name': '//root/',\n"
520 " 'external-contents': '//root/foo/bar/a'\n"
525 ASSERT_TRUE(FS.getPtr() != nullptr);
527 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
528 new vfs::OverlayFileSystem(Lower));
531 ErrorOr<vfs::Status> S = O->status("//root/XX");
532 ASSERT_FALSE(S.getError());
534 ErrorOr<vfs::Status> SS = O->status("//root/xx");
535 ASSERT_FALSE(SS.getError());
536 EXPECT_TRUE(S->equivalent(*SS));
537 SS = O->status("//root/xX");
538 EXPECT_TRUE(S->equivalent(*SS));
539 SS = O->status("//root/Xx");
540 EXPECT_TRUE(S->equivalent(*SS));
541 EXPECT_EQ(0, NumDiagnostics);
544 TEST_F(VFSFromYAMLTest, CaseSensitive) {
545 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
546 Lower->addRegularFile("//root/foo/bar/a");
547 IntrusiveRefCntPtr<vfs::FileSystem> FS =
548 getFromYAMLString("{ 'case-sensitive': 'true',\n"
551 " 'type': 'directory',\n"
552 " 'name': '//root/',\n"
556 " 'external-contents': '//root/foo/bar/a'\n"
561 ASSERT_TRUE(FS.getPtr() != nullptr);
563 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
564 new vfs::OverlayFileSystem(Lower));
567 ErrorOr<vfs::Status> SS = O->status("//root/xx");
568 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
569 SS = O->status("//root/xX");
570 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
571 SS = O->status("//root/Xx");
572 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
573 EXPECT_EQ(0, NumDiagnostics);
576 TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
577 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
579 // invalid YAML at top-level
580 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
581 EXPECT_EQ(nullptr, FS.getPtr());
582 // invalid YAML in roots
583 FS = getFromYAMLString("{ 'roots':[}", Lower);
584 // invalid YAML in directory
585 FS = getFromYAMLString(
586 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
588 EXPECT_EQ(nullptr, FS.getPtr());
590 // invalid configuration
591 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
592 EXPECT_EQ(nullptr, FS.getPtr());
593 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
594 EXPECT_EQ(nullptr, FS.getPtr());
597 FS = getFromYAMLString("{ 'roots':'' }", Lower);
598 EXPECT_EQ(nullptr, FS.getPtr());
599 FS = getFromYAMLString("{ 'roots':{} }", Lower);
600 EXPECT_EQ(nullptr, FS.getPtr());
603 FS = getFromYAMLString(
604 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
605 EXPECT_EQ(nullptr, FS.getPtr());
606 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
607 "'external-contents': 'other' }",
609 EXPECT_EQ(nullptr, FS.getPtr());
610 FS = getFromYAMLString(
611 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
613 EXPECT_EQ(nullptr, FS.getPtr());
614 FS = getFromYAMLString(
615 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
617 EXPECT_EQ(nullptr, FS.getPtr());
618 FS = getFromYAMLString(
619 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
621 EXPECT_EQ(nullptr, FS.getPtr());
622 FS = getFromYAMLString(
623 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
625 EXPECT_EQ(nullptr, FS.getPtr());
626 FS = getFromYAMLString(
627 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
629 EXPECT_EQ(nullptr, FS.getPtr());
631 // missing mandatory fields
632 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
633 EXPECT_EQ(nullptr, FS.getPtr());
634 FS = getFromYAMLString(
635 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
636 EXPECT_EQ(nullptr, FS.getPtr());
637 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
638 EXPECT_EQ(nullptr, FS.getPtr());
641 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
642 EXPECT_EQ(nullptr, FS.getPtr());
643 FS = getFromYAMLString(
644 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
646 EXPECT_EQ(nullptr, FS.getPtr());
648 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
649 "'external-contents':'blah' } ] }",
651 EXPECT_EQ(nullptr, FS.getPtr());
654 FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
655 EXPECT_EQ(nullptr, FS.getPtr());
657 // bad version number
658 FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
659 EXPECT_EQ(nullptr, FS.getPtr());
660 FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
661 EXPECT_EQ(nullptr, FS.getPtr());
662 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
663 EXPECT_EQ(nullptr, FS.getPtr());
664 EXPECT_EQ(24, NumDiagnostics);
667 TEST_F(VFSFromYAMLTest, UseExternalName) {
668 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
669 Lower->addRegularFile("//root/external/file");
671 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
673 " { 'type': 'file', 'name': '//root/A',\n"
674 " 'external-contents': '//root/external/file'\n"
676 " { 'type': 'file', 'name': '//root/B',\n"
677 " 'use-external-name': true,\n"
678 " 'external-contents': '//root/external/file'\n"
680 " { 'type': 'file', 'name': '//root/C',\n"
681 " 'use-external-name': false,\n"
682 " 'external-contents': '//root/external/file'\n"
685 ASSERT_TRUE(nullptr != FS.getPtr());
688 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
690 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
691 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
693 // global configuration
694 FS = getFromYAMLString(
695 "{ 'use-external-names': false,\n"
697 " { 'type': 'file', 'name': '//root/A',\n"
698 " 'external-contents': '//root/external/file'\n"
700 " { 'type': 'file', 'name': '//root/B',\n"
701 " 'use-external-name': true,\n"
702 " 'external-contents': '//root/external/file'\n"
704 " { 'type': 'file', 'name': '//root/C',\n"
705 " 'use-external-name': false,\n"
706 " 'external-contents': '//root/external/file'\n"
709 ASSERT_TRUE(nullptr != FS.getPtr());
712 EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
714 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
715 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
718 TEST_F(VFSFromYAMLTest, MultiComponentPath) {
719 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
720 Lower->addRegularFile("//root/other");
723 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
725 " { 'type': 'file', 'name': '//root/path/to/file',\n"
726 " 'external-contents': '//root/other' }]\n"
728 ASSERT_TRUE(nullptr != FS.getPtr());
729 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
730 EXPECT_FALSE(FS->status("//root/path/to").getError());
731 EXPECT_FALSE(FS->status("//root/path").getError());
732 EXPECT_FALSE(FS->status("//root/").getError());
735 FS = getFromYAMLString(
737 " { 'type': 'directory', 'name': '//root/path/to',\n"
738 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
739 " 'external-contents': '//root/other' }]}]\n"
741 ASSERT_TRUE(nullptr != FS.getPtr());
742 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
743 EXPECT_FALSE(FS->status("//root/path/to").getError());
744 EXPECT_FALSE(FS->status("//root/path").getError());
745 EXPECT_FALSE(FS->status("//root/").getError());
748 FS = getFromYAMLString(
750 " { 'type': 'directory', 'name': '//root/',\n"
751 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
752 " 'external-contents': '//root/other' }]}]\n"
754 ASSERT_TRUE(nullptr != FS.getPtr());
755 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
756 EXPECT_FALSE(FS->status("//root/path/to").getError());
757 EXPECT_FALSE(FS->status("//root/path").getError());
758 EXPECT_FALSE(FS->status("//root/").getError());
761 TEST_F(VFSFromYAMLTest, TrailingSlashes) {
762 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
763 Lower->addRegularFile("//root/other");
766 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
768 " { 'type': 'directory', 'name': '//root/path/to////',\n"
769 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
770 " 'external-contents': '//root/other' }]}]\n"
772 ASSERT_TRUE(nullptr != FS.getPtr());
773 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
774 EXPECT_FALSE(FS->status("//root/path/to").getError());
775 EXPECT_FALSE(FS->status("//root/path").getError());
776 EXPECT_FALSE(FS->status("//root/").getError());
779 TEST_F(VFSFromYAMLTest, DirectoryIteration) {
780 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
781 Lower->addDirectory("//root/");
782 Lower->addDirectory("//root/foo");
783 Lower->addDirectory("//root/foo/bar");
784 Lower->addRegularFile("//root/foo/bar/a");
785 Lower->addRegularFile("//root/foo/bar/b");
786 Lower->addRegularFile("//root/file3");
787 IntrusiveRefCntPtr<vfs::FileSystem> FS =
788 getFromYAMLString("{ 'use-external-names': false,\n"
791 " 'type': 'directory',\n"
792 " 'name': '//root/',\n"
795 " 'name': 'file1',\n"
796 " 'external-contents': '//root/foo/bar/a'\n"
800 " 'name': 'file2',\n"
801 " 'external-contents': '//root/foo/bar/b'\n"
808 ASSERT_TRUE(FS.getPtr() != NULL);
810 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
811 new vfs::OverlayFileSystem(Lower));
816 std::vector<std::string> Contents = { "//root/file1", "//root/file2",
817 "//root/file3", "//root/foo" };
818 checkContents(O->dir_begin("//root/", EC), Contents);
822 std::vector<std::string> Contents = {
823 "//root/foo/bar/a", "//root/foo/bar/b" };
824 checkContents(O->dir_begin("//root/foo/bar", EC), Contents);