1 //===- unittests/Support/VirtualFileSystem.cpp -------------- VFS tests ---===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Support/VirtualFileSystem.h" 10 #include "llvm/ADT/Triple.h" 11 #include "llvm/Config/llvm-config.h" 12 #include "llvm/Support/Errc.h" 13 #include "llvm/Support/Host.h" 14 #include "llvm/Support/MemoryBuffer.h" 15 #include "llvm/Support/Path.h" 16 #include "llvm/Support/SourceMgr.h" 17 #include "llvm/Testing/Support/SupportHelpers.h" 18 #include "gmock/gmock.h" 19 #include "gtest/gtest.h" 20 #include <map> 21 #include <string> 22 23 using namespace llvm; 24 using llvm::sys::fs::UniqueID; 25 using llvm::unittest::TempDir; 26 using llvm::unittest::TempFile; 27 using llvm::unittest::TempLink; 28 using testing::ElementsAre; 29 using testing::Pair; 30 using testing::UnorderedElementsAre; 31 32 namespace { 33 struct DummyFile : public vfs::File { 34 vfs::Status S; 35 explicit DummyFile(vfs::Status S) : S(S) {} 36 llvm::ErrorOr<vfs::Status> status() override { return S; } 37 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> 38 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, 39 bool IsVolatile) override { 40 llvm_unreachable("unimplemented"); 41 } 42 std::error_code close() override { return std::error_code(); } 43 }; 44 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; 51 52 static int getNextFSID() { 53 static int Count = 0; 54 return Count++; 55 } 56 57 public: 58 DummyFileSystem() : FSID(getNextFSID()), FileID(0) {} 59 60 ErrorOr<vfs::Status> status(const Twine &Path) override { 61 auto I = findEntry(Path); 62 if (I == FilesAndDirs.end()) 63 return make_error_code(llvm::errc::no_such_file_or_directory); 64 return I->second; 65 } 66 ErrorOr<std::unique_ptr<vfs::File>> 67 openFileForRead(const Twine &Path) override { 68 auto S = status(Path); 69 if (S) 70 return std::unique_ptr<vfs::File>(new DummyFile{*S}); 71 return S.getError(); 72 } 73 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { 74 return WorkingDirectory; 75 } 76 std::error_code setCurrentWorkingDirectory(const Twine &Path) override { 77 WorkingDirectory = Path.str(); 78 return std::error_code(); 79 } 80 // Map any symlink to "/symlink". 81 std::error_code getRealPath(const Twine &Path, 82 SmallVectorImpl<char> &Output) const override { 83 auto I = findEntry(Path); 84 if (I == FilesAndDirs.end()) 85 return make_error_code(llvm::errc::no_such_file_or_directory); 86 if (I->second.isSymlink()) { 87 Output.clear(); 88 Twine("/symlink").toVector(Output); 89 return std::error_code(); 90 } 91 Output.clear(); 92 Path.toVector(Output); 93 return std::error_code(); 94 } 95 96 struct DirIterImpl : public llvm::vfs::detail::DirIterImpl { 97 std::map<std::string, vfs::Status> &FilesAndDirs; 98 std::map<std::string, vfs::Status>::iterator I; 99 std::string Path; 100 bool isInPath(StringRef S) { 101 if (Path.size() < S.size() && S.find(Path) == 0) { 102 auto LastSep = S.find_last_of('/'); 103 if (LastSep == Path.size() || LastSep == Path.size() - 1) 104 return true; 105 } 106 return false; 107 } 108 DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs, 109 const Twine &_Path) 110 : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()), 111 Path(_Path.str()) { 112 for (; I != FilesAndDirs.end(); ++I) { 113 if (isInPath(I->first)) { 114 CurrentEntry = vfs::directory_entry(std::string(I->second.getName()), 115 I->second.getType()); 116 break; 117 } 118 } 119 } 120 std::error_code increment() override { 121 ++I; 122 for (; I != FilesAndDirs.end(); ++I) { 123 if (isInPath(I->first)) { 124 CurrentEntry = vfs::directory_entry(std::string(I->second.getName()), 125 I->second.getType()); 126 break; 127 } 128 } 129 if (I == FilesAndDirs.end()) 130 CurrentEntry = vfs::directory_entry(); 131 return std::error_code(); 132 } 133 }; 134 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)); 139 } 140 141 void addEntry(StringRef Path, const vfs::Status &Status) { 142 FilesAndDirs[std::string(Path)] = Status; 143 } 144 145 const_iterator findEntry(const Twine &Path) const { 146 SmallString<128> P; 147 Path.toVector(P); 148 std::error_code EC = makeAbsolute(P); 149 assert(!EC); 150 (void)EC; 151 return FilesAndDirs.find(std::string(P.str())); 152 } 153 154 void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) { 155 vfs::Status S(Path, UniqueID(FSID, FileID++), 156 std::chrono::system_clock::now(), 0, 0, 1024, 157 sys::fs::file_type::regular_file, Perms); 158 addEntry(Path, S); 159 } 160 161 void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) { 162 vfs::Status S(Path, UniqueID(FSID, FileID++), 163 std::chrono::system_clock::now(), 0, 0, 0, 164 sys::fs::file_type::directory_file, Perms); 165 addEntry(Path, S); 166 } 167 168 void addSymlink(StringRef Path) { 169 vfs::Status S(Path, UniqueID(FSID, FileID++), 170 std::chrono::system_clock::now(), 0, 0, 0, 171 sys::fs::file_type::symlink_file, sys::fs::all_all); 172 addEntry(Path, S); 173 } 174 }; 175 176 class ErrorDummyFileSystem : public DummyFileSystem { 177 std::error_code setCurrentWorkingDirectory(const Twine &Path) override { 178 return llvm::errc::no_such_file_or_directory; 179 } 180 }; 181 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()); 187 } 188 } // end anonymous namespace 189 190 TEST(VirtualFileSystemTest, StatusQueries) { 191 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem()); 192 ErrorOr<vfs::Status> Status((std::error_code())); 193 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()); 203 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()); 213 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()); 223 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)); 228 } 229 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")); 234 235 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D)); 236 EXPECT_FALSE(Status = O->status("/foo")); 237 238 D->addRegularFile("/foo"); 239 Status = D->status("/foo"); 240 EXPECT_FALSE(Status.getError()); 241 242 ErrorOr<vfs::Status> Status2((std::error_code())); 243 Status2 = O->status("/foo"); 244 EXPECT_FALSE(Status2.getError()); 245 EXPECT_TRUE(Status->equivalent(*Status2)); 246 } 247 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()); 253 254 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O( 255 new vfs::OverlayFileSystem(Lower)); 256 O->pushOverlay(Upper); 257 258 // Regular file. 259 SmallString<16> RealPath; 260 EXPECT_FALSE(O->getRealPath("/foo", RealPath)); 261 EXPECT_EQ(RealPath.str(), "/foo"); 262 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"); 266 267 // Try a non-existing link. 268 EXPECT_EQ(O->getRealPath("/upper_link", RealPath), 269 errc::no_such_file_or_directory); 270 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"); 275 } 276 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); 284 O->pushOverlay(Top); 285 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())); 290 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()); 306 307 EXPECT_TRUE(Status1->equivalent(*StatusB)); 308 EXPECT_TRUE(Status2->equivalent(*StatusM)); 309 EXPECT_TRUE(Status3->equivalent(*StatusT)); 310 311 EXPECT_FALSE(Status1->equivalent(*Status2)); 312 EXPECT_FALSE(Status2->equivalent(*Status3)); 313 EXPECT_FALSE(Status1->equivalent(*Status3)); 314 } 315 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); 322 323 Lower->addDirectory("/lower-only"); 324 Upper->addDirectory("/upper-only"); 325 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)); 332 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)); 338 } 339 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); 347 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()); 354 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()); 364 } 365 366 TEST(VirtualFileSystemTest, OverlayIterator) { 367 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 368 Lower->addRegularFile("/foo"); 369 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem()); 370 371 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O( 372 new vfs::OverlayFileSystem(Lower)); 373 O->pushOverlay(Upper); 374 375 ErrorOr<vfs::Status> Status((std::error_code())); 376 { 377 auto it = O->overlays_begin(); 378 auto end = O->overlays_end(); 379 380 EXPECT_NE(it, end); 381 382 Status = (*it)->status("/foo"); 383 ASSERT_TRUE(Status.getError()); 384 385 it++; 386 EXPECT_NE(it, end); 387 388 Status = (*it)->status("/foo"); 389 ASSERT_FALSE(Status.getError()); 390 EXPECT_TRUE(Status->exists()); 391 392 it++; 393 EXPECT_EQ(it, end); 394 } 395 396 { 397 auto it = O->overlays_rbegin(); 398 auto end = O->overlays_rend(); 399 400 EXPECT_NE(it, end); 401 402 Status = (*it)->status("/foo"); 403 ASSERT_FALSE(Status.getError()); 404 EXPECT_TRUE(Status->exists()); 405 406 it++; 407 EXPECT_NE(it, end); 408 409 Status = (*it)->status("/foo"); 410 ASSERT_TRUE(Status.getError()); 411 412 it++; 413 EXPECT_EQ(it, end); 414 } 415 } 416 417 TEST(VirtualFileSystemTest, BasicRealFSIteration) { 418 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true); 419 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem(); 420 421 std::error_code EC; 422 vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory.path()), EC); 423 ASSERT_FALSE(EC); 424 EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty 425 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")); 430 431 I = FS->dir_begin(Twine(TestDirectory.path()), EC); 432 ASSERT_FALSE(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")); 436 I.increment(EC); 437 ASSERT_FALSE(EC); 438 ASSERT_NE(vfs::directory_iterator(), I); 439 EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c")); 440 I.increment(EC); 441 EXPECT_EQ(vfs::directory_iterator(), I); 442 } 443 444 #ifdef LLVM_ON_UNIX 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(); 457 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()); 462 463 // openFileForRead(), indirectly. 464 auto BBuf = BFS->getBufferForFile("bb"); 465 ASSERT_TRUE(BBuf); 466 EXPECT_EQ("bbbb", (*BBuf)->getBuffer()); 467 468 auto ABuf = CFS->getBufferForFile("aa"); 469 ASSERT_TRUE(ABuf); 470 EXPECT_EQ("aaaa", (*ABuf)->getBuffer()); 471 472 // status() 473 auto BStat = BFS->status("bb"); 474 ASSERT_TRUE(BStat); 475 EXPECT_EQ("bb", BStat->getName()); 476 477 auto AStat = CFS->status("aa"); 478 ASSERT_TRUE(AStat); 479 EXPECT_EQ("aa", AStat->getName()); // unresolved name 480 481 // getRealPath() 482 SmallString<128> BPath; 483 ASSERT_FALSE(BFS->getRealPath("bb", BPath)); 484 EXPECT_EQ(BB.path(), BPath); 485 486 SmallString<128> APath; 487 ASSERT_FALSE(CFS->getRealPath("aa", APath)); 488 EXPECT_EQ(AA.path(), APath); // Reports resolved name. 489 490 // dir_begin 491 std::error_code EC; 492 auto BIt = BFS->dir_begin(".", EC); 493 ASSERT_FALSE(EC); 494 ASSERT_NE(BIt, vfs::directory_iterator()); 495 EXPECT_EQ((BDir.path() + "/./bb").str(), BIt->path()); 496 BIt.increment(EC); 497 ASSERT_FALSE(EC); 498 ASSERT_EQ(BIt, vfs::directory_iterator()); 499 500 auto CIt = CFS->dir_begin(".", EC); 501 ASSERT_FALSE(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. 506 ASSERT_FALSE(EC); 507 ASSERT_EQ(CIt, vfs::directory_iterator()); 508 } 509 510 TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) { 511 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true); 512 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem(); 513 514 TempLink _a("no_such_file", TestDirectory.path("a")); 515 TempDir _b(TestDirectory.path("b")); 516 TempLink _c("no_such_file", TestDirectory.path("c")); 517 518 // Should get no iteration error, but a stat error for the broken symlinks. 519 std::map<std::string, std::error_code> StatResults; 520 std::error_code EC; 521 for (vfs::directory_iterator 522 I = FS->dir_begin(Twine(TestDirectory.path()), EC), 523 E; 524 I != E; I.increment(EC)) { 525 EXPECT_FALSE(EC); 526 StatResults[std::string(sys::path::filename(I->path()))] = 527 FS->status(I->path()).getError(); 528 } 529 EXPECT_THAT( 530 StatResults, 531 ElementsAre( 532 Pair("a", std::make_error_code(std::errc::no_such_file_or_directory)), 533 Pair("b", std::error_code()), 534 Pair("c", 535 std::make_error_code(std::errc::no_such_file_or_directory)))); 536 } 537 #endif 538 539 TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) { 540 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true); 541 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem(); 542 543 std::error_code EC; 544 auto I = 545 vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC); 546 ASSERT_FALSE(EC); 547 EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty 548 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")); 553 554 I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC); 555 ASSERT_FALSE(EC); 556 ASSERT_NE(vfs::recursive_directory_iterator(), I); 557 558 std::vector<std::string> Contents; 559 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E; 560 I.increment(EC)) { 561 Contents.push_back(std::string(I->path())); 562 } 563 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); 571 Counts[Index]++; 572 } 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 577 } 578 579 TEST(VirtualFileSystemTest, BasicRealFSRecursiveIterationNoPush) { 580 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true); 581 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")); 589 590 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem(); 591 592 // Test that calling no_push on entries without subdirectories has no effect. 593 { 594 std::error_code EC; 595 auto I = 596 vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC); 597 ASSERT_FALSE(EC); 598 599 std::vector<std::string> Contents; 600 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E; 601 I.increment(EC)) { 602 Contents.push_back(std::string(I->path())); 603 char last = I->path().back(); 604 switch (last) { 605 case 'b': 606 case 'd': 607 case 'f': 608 case 'g': 609 I.no_push(); 610 break; 611 default: 612 break; 613 } 614 } 615 EXPECT_EQ(7U, Contents.size()); 616 } 617 618 // Test that calling no_push skips subdirectories. 619 { 620 std::error_code EC; 621 auto I = 622 vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC); 623 ASSERT_FALSE(EC); 624 625 std::vector<std::string> Contents; 626 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E; 627 I.increment(EC)) { 628 Contents.push_back(std::string(I->path())); 629 char last = I->path().back(); 630 switch (last) { 631 case 'a': 632 case 'c': 633 case 'e': 634 I.no_push(); 635 break; 636 default: 637 break; 638 } 639 } 640 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); 648 Counts[Index]++; 649 } 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 657 } 658 } 659 660 #ifdef LLVM_ON_UNIX 661 TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) { 662 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true); 663 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem(); 664 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")); 675 676 std::vector<std::string> VisitedBrokenSymlinks; 677 std::vector<std::string> VisitedNonBrokenSymlinks; 678 std::error_code EC; 679 for (vfs::recursive_directory_iterator 680 I(*FS, Twine(TestDirectory.path()), EC), 681 E; 682 I != E; I.increment(EC)) { 683 EXPECT_FALSE(EC); 684 (FS->status(I->path()) ? VisitedNonBrokenSymlinks : VisitedBrokenSymlinks) 685 .push_back(std::string(I->path())); 686 } 687 688 // Check visited file names. 689 EXPECT_THAT(VisitedBrokenSymlinks, 690 UnorderedElementsAre(_a.path().str(), _ba.path().str(), 691 _bc.path().str(), _c.path().str(), 692 _e.path().str())); 693 EXPECT_THAT(VisitedNonBrokenSymlinks, 694 UnorderedElementsAre(_b.path().str(), _bb.path().str(), 695 _d.path().str(), _dd.path().str(), 696 _ddd.path().str())); 697 } 698 #endif 699 700 template <typename DirIter> 701 static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) { 702 std::error_code EC; 703 SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end()); 704 SmallVector<std::string, 4> InputToCheck; 705 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())); 710 711 llvm::sort(InputToCheck); 712 llvm::sort(Expected); 713 EXPECT_EQ(InputToCheck.size(), Expected.size()); 714 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]); 718 } 719 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); 726 727 std::error_code EC; 728 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>()); 729 730 Lower->addRegularFile("/file1"); 731 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1")); 732 733 Upper->addRegularFile("/file2"); 734 checkContents(O->dir_begin("/", EC), {"/file2", "/file1"}); 735 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"}); 742 } 743 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); 752 753 std::error_code EC; 754 checkContents(vfs::recursive_directory_iterator(*O, "/", EC), 755 ArrayRef<StringRef>()); 756 757 Lower->addRegularFile("/file1"); 758 checkContents(vfs::recursive_directory_iterator(*O, "/", EC), 759 ArrayRef<StringRef>("/file1")); 760 761 Upper->addDirectory("/dir"); 762 Upper->addRegularFile("/dir/file2"); 763 checkContents(vfs::recursive_directory_iterator(*O, "/", EC), 764 {"/dir", "/dir/file2", "/file1"}); 765 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"}); 784 } 785 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); 794 795 std::error_code EC; 796 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>()); 797 798 Middle->addRegularFile("/file2"); 799 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2")); 800 801 Lower->addRegularFile("/file1"); 802 Upper->addRegularFile("/file3"); 803 checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"}); 804 } 805 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); 814 815 std::error_code EC; 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"); 824 checkContents( 825 O->dir_begin("/", EC), 826 {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"}); 827 828 // Make sure we get the top-most entry 829 { 830 std::error_code EC; 831 vfs::directory_iterator I = O->dir_begin("/", EC), E; 832 for (; !EC && I != E; I.increment(EC)) 833 if (I->path() == "/hiddenByUp") 834 break; 835 ASSERT_NE(E, I); 836 EXPECT_EQ(sys::fs::file_type::regular_file, I->type()); 837 } 838 { 839 std::error_code EC; 840 vfs::directory_iterator I = O->dir_begin("/", EC), E; 841 for (; !EC && I != E; I.increment(EC)) 842 if (I->path() == "/hiddenByMid") 843 break; 844 ASSERT_NE(E, I); 845 EXPECT_EQ(sys::fs::file_type::regular_file, I->type()); 846 } 847 } 848 849 TEST(ProxyFileSystemTest, Basic) { 850 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> Base( 851 new vfs::InMemoryFileSystem()); 852 vfs::ProxyFileSystem PFS(Base); 853 854 Base->addFile("/a", 0, MemoryBuffer::getMemBuffer("test")); 855 856 auto Stat = PFS.status("/a"); 857 ASSERT_FALSE(Stat.getError()); 858 859 auto File = PFS.openFileForRead("/a"); 860 ASSERT_FALSE(File.getError()); 861 EXPECT_EQ("test", (*(*File)->getBuffer("ignored"))->getBuffer()); 862 863 std::error_code EC; 864 vfs::directory_iterator I = PFS.dir_begin("/", EC); 865 ASSERT_FALSE(EC); 866 ASSERT_EQ("/a", I->path()); 867 I.increment(EC); 868 ASSERT_FALSE(EC); 869 ASSERT_EQ(vfs::directory_iterator(), I); 870 871 ASSERT_FALSE(PFS.setCurrentWorkingDirectory("/")); 872 873 auto PWD = PFS.getCurrentWorkingDirectory(); 874 ASSERT_FALSE(PWD.getError()); 875 ASSERT_EQ("/", *PWD); 876 877 SmallString<16> Path; 878 ASSERT_FALSE(PFS.getRealPath("a", Path)); 879 ASSERT_EQ("/a", Path); 880 881 bool Local = true; 882 ASSERT_FALSE(PFS.isLocal("/a", Local)); 883 EXPECT_FALSE(Local); 884 } 885 886 class InMemoryFileSystemTest : public ::testing::Test { 887 protected: 888 llvm::vfs::InMemoryFileSystem FS; 889 llvm::vfs::InMemoryFileSystem NormalizedFS; 890 891 InMemoryFileSystemTest() 892 : FS(/*UseNormalizedPaths=*/false), 893 NormalizedFS(/*UseNormalizedPaths=*/true) {} 894 }; 895 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(); 904 } 905 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(); 911 } 912 913 TEST_F(InMemoryFileSystemTest, WindowsPath) { 914 FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer("")); 915 auto Stat = FS.status("c:"); 916 #if !defined(_WIN32) 917 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString(); 918 #endif 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(); 924 } 925 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("/."); 932 ASSERT_FALSE(Stat); 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()); 938 } 939 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()); 946 } 947 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"); 966 ASSERT_FALSE(File); 967 File = FS.openFileForRead("e/../d"); 968 ASSERT_FALSE(File); 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()); 973 } 974 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"))); 980 } 981 982 TEST_F(InMemoryFileSystemTest, DirectoryIteration) { 983 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("")); 984 FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer("")); 985 986 std::error_code EC; 987 vfs::directory_iterator I = FS.dir_begin("/", EC); 988 ASSERT_FALSE(EC); 989 ASSERT_EQ("/a", I->path()); 990 I.increment(EC); 991 ASSERT_FALSE(EC); 992 ASSERT_EQ("/b", I->path()); 993 I.increment(EC); 994 ASSERT_FALSE(EC); 995 ASSERT_EQ(vfs::directory_iterator(), I); 996 997 I = FS.dir_begin("/b", EC); 998 ASSERT_FALSE(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()))); 1002 I.increment(EC); 1003 ASSERT_FALSE(EC); 1004 ASSERT_EQ(vfs::directory_iterator(), I); 1005 } 1006 1007 TEST_F(InMemoryFileSystemTest, WorkingDirectory) { 1008 FS.setCurrentWorkingDirectory("/b"); 1009 FS.addFile("c", 0, MemoryBuffer::getMemBuffer("")); 1010 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()); 1015 1016 Stat = FS.status("c"); 1017 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); 1018 1019 NormalizedFS.setCurrentWorkingDirectory("/b/c"); 1020 NormalizedFS.setCurrentWorkingDirectory("."); 1021 ASSERT_EQ("/b/c", 1022 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get())); 1023 NormalizedFS.setCurrentWorkingDirectory(".."); 1024 ASSERT_EQ("/b", 1025 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get())); 1026 } 1027 1028 TEST_F(InMemoryFileSystemTest, IsLocal) { 1029 FS.setCurrentWorkingDirectory("/b"); 1030 FS.addFile("c", 0, MemoryBuffer::getMemBuffer("")); 1031 1032 std::error_code EC; 1033 bool IsLocal = true; 1034 EC = FS.isLocal("c", IsLocal); 1035 ASSERT_FALSE(EC); 1036 ASSERT_FALSE(IsLocal); 1037 } 1038 1039 #if !defined(_WIN32) 1040 TEST_F(InMemoryFileSystemTest, GetRealPath) { 1041 SmallString<16> Path; 1042 EXPECT_EQ(FS.getRealPath("b", Path), errc::operation_not_permitted); 1043 1044 auto GetRealPath = [this](StringRef P) { 1045 SmallString<16> Output; 1046 auto EC = FS.getRealPath(P, Output); 1047 EXPECT_FALSE(EC); 1048 return std::string(Output); 1049 }; 1050 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"); 1055 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"); 1060 } 1061 #endif // _WIN32 1062 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()); 1078 } 1079 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()); 1095 } 1096 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()); 1110 } 1111 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()); 1132 } 1133 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()); 1145 } 1146 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"), 1151 /*User=*/None, 1152 /*Group=*/None, sys::fs::file_type::regular_file); 1153 NormalizedFS.setCurrentWorkingDirectory("/a/b"); 1154 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()); 1161 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()); 1171 1172 // Access using a directory iterator. 1173 std::error_code EC; 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()))); 1178 } 1179 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()); 1189 } 1190 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)); 1203 } 1204 1205 TEST_F(InMemoryFileSystemTest, AddHardLinkToAFileThatWasNotAddedBefore) { 1206 EXPECT_FALSE(FS.addHardLink("/path/to/link", "/path/to/target")); 1207 } 1208 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)); 1215 } 1216 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)); 1223 } 1224 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))); 1232 } 1233 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))); 1242 } 1243 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)); 1251 } 1252 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)); 1259 } 1260 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")); 1266 } 1267 1268 TEST_F(InMemoryFileSystemTest, RecursiveIterationWithHardLink) { 1269 std::error_code EC; 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); 1273 ASSERT_FALSE(EC); 1274 std::vector<std::string> Nodes; 1275 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E; 1276 I.increment(EC)) { 1277 Nodes.push_back(getPosixPath(std::string(I->path()))); 1278 } 1279 EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d")); 1280 } 1281 1282 // NOTE: in the tests below, we use '//root/' as our root directory, since it is 1283 // a legal *absolute* path on Windows as well as *nix. 1284 class VFSFromYAMLTest : public ::testing::Test { 1285 public: 1286 int NumDiagnostics; 1287 1288 void SetUp() override { NumDiagnostics = 0; } 1289 1290 static void CountingDiagHandler(const SMDiagnostic &, void *Context) { 1291 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context); 1292 ++Test->NumDiagnostics; 1293 } 1294 1295 std::unique_ptr<vfs::FileSystem> 1296 getFromYAMLRawString(StringRef Content, 1297 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) { 1298 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content); 1299 return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this, 1300 ExternalFS); 1301 } 1302 1303 std::unique_ptr<vfs::FileSystem> getFromYAMLString( 1304 StringRef Content, 1305 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) { 1306 std::string VersionPlusContent("{\n 'version':0,\n"); 1307 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos); 1308 return getFromYAMLRawString(VersionPlusContent, ExternalFS); 1309 } 1310 1311 // This is intended as a "XFAIL" for windows hosts. 1312 bool supportsSameDirMultipleYAMLEntries() { 1313 Triple Host(Triple::normalize(sys::getProcessTriple())); 1314 return !Host.isOSWindows(); 1315 } 1316 }; 1317 1318 TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) { 1319 IntrusiveRefCntPtr<vfs::FileSystem> FS; 1320 FS = getFromYAMLString(""); 1321 EXPECT_EQ(nullptr, FS.get()); 1322 FS = getFromYAMLString("[]"); 1323 EXPECT_EQ(nullptr, FS.get()); 1324 FS = getFromYAMLString("'string'"); 1325 EXPECT_EQ(nullptr, FS.get()); 1326 EXPECT_EQ(3, NumDiagnostics); 1327 } 1328 1329 TEST_F(VFSFromYAMLTest, MappedFiles) { 1330 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1331 Lower->addDirectory("//root/foo/bar"); 1332 Lower->addRegularFile("//root/foo/bar/a"); 1333 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 1334 "{ 'roots': [\n" 1335 "{\n" 1336 " 'type': 'directory',\n" 1337 " 'name': '//root/',\n" 1338 " 'contents': [ {\n" 1339 " 'type': 'file',\n" 1340 " 'name': 'file1',\n" 1341 " 'external-contents': '//root/foo/bar/a'\n" 1342 " },\n" 1343 " {\n" 1344 " 'type': 'file',\n" 1345 " 'name': 'file2',\n" 1346 " 'external-contents': '//root/foo/b'\n" 1347 " },\n" 1348 " {\n" 1349 " 'type': 'directory-remap',\n" 1350 " 'name': 'mappeddir',\n" 1351 " 'external-contents': '//root/foo/bar'\n" 1352 " },\n" 1353 " {\n" 1354 " 'type': 'directory-remap',\n" 1355 " 'name': 'mappeddir2',\n" 1356 " 'use-external-name': false,\n" 1357 " 'external-contents': '//root/foo/bar'\n" 1358 " }\n" 1359 " ]\n" 1360 "}\n" 1361 "]\n" 1362 "}", 1363 Lower); 1364 ASSERT_TRUE(FS.get() != nullptr); 1365 1366 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O( 1367 new vfs::OverlayFileSystem(Lower)); 1368 O->pushOverlay(FS); 1369 1370 // file 1371 ErrorOr<vfs::Status> S = O->status("//root/file1"); 1372 ASSERT_FALSE(S.getError()); 1373 EXPECT_EQ("//root/foo/bar/a", S->getName()); 1374 EXPECT_TRUE(S->IsVFSMapped); 1375 1376 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a"); 1377 EXPECT_EQ("//root/foo/bar/a", SLower->getName()); 1378 EXPECT_TRUE(S->equivalent(*SLower)); 1379 EXPECT_FALSE(SLower->IsVFSMapped); 1380 1381 // file after opening 1382 auto OpenedF = O->openFileForRead("//root/file1"); 1383 ASSERT_FALSE(OpenedF.getError()); 1384 auto OpenedS = (*OpenedF)->status(); 1385 ASSERT_FALSE(OpenedS.getError()); 1386 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName()); 1387 EXPECT_TRUE(OpenedS->IsVFSMapped); 1388 1389 // directory 1390 S = O->status("//root/"); 1391 ASSERT_FALSE(S.getError()); 1392 EXPECT_TRUE(S->isDirectory()); 1393 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID 1394 1395 // remapped directory 1396 S = O->status("//root/mappeddir"); 1397 ASSERT_FALSE(S.getError()); 1398 EXPECT_TRUE(S->isDirectory()); 1399 EXPECT_TRUE(S->IsVFSMapped); 1400 EXPECT_TRUE(S->equivalent(*O->status("//root/foo/bar"))); 1401 1402 SLower = O->status("//root/foo/bar"); 1403 EXPECT_EQ("//root/foo/bar", SLower->getName()); 1404 EXPECT_TRUE(S->equivalent(*SLower)); 1405 EXPECT_FALSE(SLower->IsVFSMapped); 1406 1407 // file in remapped directory 1408 S = O->status("//root/mappeddir/a"); 1409 ASSERT_FALSE(S.getError()); 1410 ASSERT_FALSE(S->isDirectory()); 1411 ASSERT_TRUE(S->IsVFSMapped); 1412 ASSERT_EQ("//root/foo/bar/a", S->getName()); 1413 1414 // file in remapped directory, with use-external-name=false 1415 S = O->status("//root/mappeddir2/a"); 1416 ASSERT_FALSE(S.getError()); 1417 ASSERT_FALSE(S->isDirectory()); 1418 ASSERT_TRUE(S->IsVFSMapped); 1419 ASSERT_EQ("//root/mappeddir2/a", S->getName()); 1420 1421 // file contents in remapped directory 1422 OpenedF = O->openFileForRead("//root/mappeddir/a"); 1423 ASSERT_FALSE(OpenedF.getError()); 1424 OpenedS = (*OpenedF)->status(); 1425 ASSERT_FALSE(OpenedS.getError()); 1426 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName()); 1427 EXPECT_TRUE(OpenedS->IsVFSMapped); 1428 1429 // file contents in remapped directory, with use-external-name=false 1430 OpenedF = O->openFileForRead("//root/mappeddir2/a"); 1431 ASSERT_FALSE(OpenedF.getError()); 1432 OpenedS = (*OpenedF)->status(); 1433 ASSERT_FALSE(OpenedS.getError()); 1434 EXPECT_EQ("//root/mappeddir2/a", OpenedS->getName()); 1435 EXPECT_TRUE(OpenedS->IsVFSMapped); 1436 1437 // broken mapping 1438 EXPECT_EQ(O->status("//root/file2").getError(), 1439 llvm::errc::no_such_file_or_directory); 1440 EXPECT_EQ(0, NumDiagnostics); 1441 } 1442 1443 TEST_F(VFSFromYAMLTest, MappedRoot) { 1444 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1445 Lower->addDirectory("//root/foo/bar"); 1446 Lower->addRegularFile("//root/foo/bar/a"); 1447 IntrusiveRefCntPtr<vfs::FileSystem> FS = 1448 getFromYAMLString("{ 'roots': [\n" 1449 "{\n" 1450 " 'type': 'directory-remap',\n" 1451 " 'name': '//mappedroot/',\n" 1452 " 'external-contents': '//root/foo/bar'\n" 1453 "}\n" 1454 "]\n" 1455 "}", 1456 Lower); 1457 ASSERT_TRUE(FS.get() != nullptr); 1458 1459 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O( 1460 new vfs::OverlayFileSystem(Lower)); 1461 O->pushOverlay(FS); 1462 1463 // file 1464 ErrorOr<vfs::Status> S = O->status("//mappedroot/a"); 1465 ASSERT_FALSE(S.getError()); 1466 EXPECT_EQ("//root/foo/bar/a", S->getName()); 1467 EXPECT_TRUE(S->IsVFSMapped); 1468 1469 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a"); 1470 EXPECT_EQ("//root/foo/bar/a", SLower->getName()); 1471 EXPECT_TRUE(S->equivalent(*SLower)); 1472 EXPECT_FALSE(SLower->IsVFSMapped); 1473 1474 // file after opening 1475 auto OpenedF = O->openFileForRead("//mappedroot/a"); 1476 ASSERT_FALSE(OpenedF.getError()); 1477 auto OpenedS = (*OpenedF)->status(); 1478 ASSERT_FALSE(OpenedS.getError()); 1479 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName()); 1480 EXPECT_TRUE(OpenedS->IsVFSMapped); 1481 1482 EXPECT_EQ(0, NumDiagnostics); 1483 } 1484 1485 TEST_F(VFSFromYAMLTest, RemappedDirectoryOverlay) { 1486 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1487 Lower->addDirectory("//root/foo"); 1488 Lower->addRegularFile("//root/foo/a"); 1489 Lower->addDirectory("//root/bar"); 1490 Lower->addRegularFile("//root/bar/b"); 1491 Lower->addRegularFile("//root/bar/c"); 1492 IntrusiveRefCntPtr<vfs::FileSystem> FS = 1493 getFromYAMLString("{ 'roots': [\n" 1494 "{\n" 1495 " 'type': 'directory',\n" 1496 " 'name': '//root/',\n" 1497 " 'contents': [ {\n" 1498 " 'type': 'directory-remap',\n" 1499 " 'name': 'bar',\n" 1500 " 'external-contents': '//root/foo'\n" 1501 " }\n" 1502 " ]\n" 1503 "}]}", 1504 Lower); 1505 ASSERT_TRUE(FS.get() != nullptr); 1506 1507 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O( 1508 new vfs::OverlayFileSystem(Lower)); 1509 O->pushOverlay(FS); 1510 1511 ErrorOr<vfs::Status> S = O->status("//root/foo"); 1512 ASSERT_FALSE(S.getError()); 1513 1514 ErrorOr<vfs::Status> SS = O->status("//root/bar"); 1515 ASSERT_FALSE(SS.getError()); 1516 EXPECT_TRUE(S->equivalent(*SS)); 1517 1518 std::error_code EC; 1519 checkContents(O->dir_begin("//root/bar", EC), 1520 {"//root/foo/a", "//root/bar/b", "//root/bar/c"}); 1521 1522 Lower->addRegularFile("//root/foo/b"); 1523 checkContents(O->dir_begin("//root/bar", EC), 1524 {"//root/foo/a", "//root/foo/b", "//root/bar/c"}); 1525 1526 EXPECT_EQ(0, NumDiagnostics); 1527 } 1528 1529 TEST_F(VFSFromYAMLTest, RemappedDirectoryOverlayNoExternalNames) { 1530 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1531 Lower->addDirectory("//root/foo"); 1532 Lower->addRegularFile("//root/foo/a"); 1533 Lower->addDirectory("//root/bar"); 1534 Lower->addRegularFile("//root/bar/b"); 1535 Lower->addRegularFile("//root/bar/c"); 1536 IntrusiveRefCntPtr<vfs::FileSystem> FS = 1537 getFromYAMLString("{ 'use-external-names': false,\n" 1538 " 'roots': [\n" 1539 "{\n" 1540 " 'type': 'directory',\n" 1541 " 'name': '//root/',\n" 1542 " 'contents': [ {\n" 1543 " 'type': 'directory-remap',\n" 1544 " 'name': 'bar',\n" 1545 " 'external-contents': '//root/foo'\n" 1546 " }\n" 1547 " ]\n" 1548 "}]}", 1549 Lower); 1550 ASSERT_TRUE(FS.get() != nullptr); 1551 1552 ErrorOr<vfs::Status> S = FS->status("//root/foo"); 1553 ASSERT_FALSE(S.getError()); 1554 1555 ErrorOr<vfs::Status> SS = FS->status("//root/bar"); 1556 ASSERT_FALSE(SS.getError()); 1557 EXPECT_TRUE(S->equivalent(*SS)); 1558 1559 std::error_code EC; 1560 checkContents(FS->dir_begin("//root/bar", EC), 1561 {"//root/bar/a", "//root/bar/b", "//root/bar/c"}); 1562 1563 Lower->addRegularFile("//root/foo/b"); 1564 checkContents(FS->dir_begin("//root/bar", EC), 1565 {"//root/bar/a", "//root/bar/b", "//root/bar/c"}); 1566 1567 EXPECT_EQ(0, NumDiagnostics); 1568 } 1569 1570 TEST_F(VFSFromYAMLTest, RemappedDirectoryOverlayNoFallthrough) { 1571 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1572 Lower->addDirectory("//root/foo"); 1573 Lower->addRegularFile("//root/foo/a"); 1574 Lower->addDirectory("//root/bar"); 1575 Lower->addRegularFile("//root/bar/b"); 1576 Lower->addRegularFile("//root/bar/c"); 1577 IntrusiveRefCntPtr<vfs::FileSystem> FS = 1578 getFromYAMLString("{ 'fallthrough': false,\n" 1579 " 'roots': [\n" 1580 "{\n" 1581 " 'type': 'directory',\n" 1582 " 'name': '//root/',\n" 1583 " 'contents': [ {\n" 1584 " 'type': 'directory-remap',\n" 1585 " 'name': 'bar',\n" 1586 " 'external-contents': '//root/foo'\n" 1587 " }\n" 1588 " ]\n" 1589 "}]}", 1590 Lower); 1591 ASSERT_TRUE(FS.get() != nullptr); 1592 1593 ErrorOr<vfs::Status> S = Lower->status("//root/foo"); 1594 ASSERT_FALSE(S.getError()); 1595 1596 ErrorOr<vfs::Status> SS = FS->status("//root/bar"); 1597 ASSERT_FALSE(SS.getError()); 1598 EXPECT_TRUE(S->equivalent(*SS)); 1599 1600 std::error_code EC; 1601 checkContents(FS->dir_begin("//root/bar", EC), {"//root/foo/a"}); 1602 1603 Lower->addRegularFile("//root/foo/b"); 1604 checkContents(FS->dir_begin("//root/bar", EC), 1605 {"//root/foo/a", "//root/foo/b"}); 1606 1607 EXPECT_EQ(0, NumDiagnostics); 1608 } 1609 1610 TEST_F(VFSFromYAMLTest, CaseInsensitive) { 1611 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1612 Lower->addRegularFile("//root/foo/bar/a"); 1613 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 1614 "{ 'case-sensitive': 'false',\n" 1615 " 'roots': [\n" 1616 "{\n" 1617 " 'type': 'directory',\n" 1618 " 'name': '//root/',\n" 1619 " 'contents': [ {\n" 1620 " 'type': 'file',\n" 1621 " 'name': 'XX',\n" 1622 " 'external-contents': '//root/foo/bar/a'\n" 1623 " }\n" 1624 " ]\n" 1625 "}]}", 1626 Lower); 1627 ASSERT_TRUE(FS.get() != nullptr); 1628 1629 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O( 1630 new vfs::OverlayFileSystem(Lower)); 1631 O->pushOverlay(FS); 1632 1633 ErrorOr<vfs::Status> S = O->status("//root/XX"); 1634 ASSERT_FALSE(S.getError()); 1635 1636 ErrorOr<vfs::Status> SS = O->status("//root/xx"); 1637 ASSERT_FALSE(SS.getError()); 1638 EXPECT_TRUE(S->equivalent(*SS)); 1639 SS = O->status("//root/xX"); 1640 EXPECT_TRUE(S->equivalent(*SS)); 1641 SS = O->status("//root/Xx"); 1642 EXPECT_TRUE(S->equivalent(*SS)); 1643 EXPECT_EQ(0, NumDiagnostics); 1644 } 1645 1646 TEST_F(VFSFromYAMLTest, CaseSensitive) { 1647 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1648 Lower->addRegularFile("//root/foo/bar/a"); 1649 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 1650 "{ 'case-sensitive': 'true',\n" 1651 " 'roots': [\n" 1652 "{\n" 1653 " 'type': 'directory',\n" 1654 " 'name': '//root/',\n" 1655 " 'contents': [ {\n" 1656 " 'type': 'file',\n" 1657 " 'name': 'XX',\n" 1658 " 'external-contents': '//root/foo/bar/a'\n" 1659 " }\n" 1660 " ]\n" 1661 "}]}", 1662 Lower); 1663 ASSERT_TRUE(FS.get() != nullptr); 1664 1665 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O( 1666 new vfs::OverlayFileSystem(Lower)); 1667 O->pushOverlay(FS); 1668 1669 ErrorOr<vfs::Status> SS = O->status("//root/xx"); 1670 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory); 1671 SS = O->status("//root/xX"); 1672 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory); 1673 SS = O->status("//root/Xx"); 1674 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory); 1675 EXPECT_EQ(0, NumDiagnostics); 1676 } 1677 1678 TEST_F(VFSFromYAMLTest, IllegalVFSFile) { 1679 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1680 1681 // invalid YAML at top-level 1682 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower); 1683 EXPECT_EQ(nullptr, FS.get()); 1684 // invalid YAML in roots 1685 FS = getFromYAMLString("{ 'roots':[}", Lower); 1686 // invalid YAML in directory 1687 FS = getFromYAMLString( 1688 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}", 1689 Lower); 1690 EXPECT_EQ(nullptr, FS.get()); 1691 1692 // invalid configuration 1693 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower); 1694 EXPECT_EQ(nullptr, FS.get()); 1695 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower); 1696 EXPECT_EQ(nullptr, FS.get()); 1697 1698 // invalid roots 1699 FS = getFromYAMLString("{ 'roots':'' }", Lower); 1700 EXPECT_EQ(nullptr, FS.get()); 1701 FS = getFromYAMLString("{ 'roots':{} }", Lower); 1702 EXPECT_EQ(nullptr, FS.get()); 1703 1704 // invalid entries 1705 FS = getFromYAMLString( 1706 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower); 1707 EXPECT_EQ(nullptr, FS.get()); 1708 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], " 1709 "'external-contents': 'other' }", 1710 Lower); 1711 EXPECT_EQ(nullptr, FS.get()); 1712 FS = getFromYAMLString( 1713 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }", 1714 Lower); 1715 EXPECT_EQ(nullptr, FS.get()); 1716 FS = getFromYAMLString( 1717 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }", 1718 Lower); 1719 EXPECT_EQ(nullptr, FS.get()); 1720 FS = getFromYAMLString( 1721 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }", 1722 Lower); 1723 EXPECT_EQ(nullptr, FS.get()); 1724 FS = getFromYAMLString( 1725 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }", 1726 Lower); 1727 EXPECT_EQ(nullptr, FS.get()); 1728 FS = getFromYAMLString( 1729 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }", 1730 Lower); 1731 EXPECT_EQ(nullptr, FS.get()); 1732 1733 // missing mandatory fields 1734 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower); 1735 EXPECT_EQ(nullptr, FS.get()); 1736 FS = getFromYAMLString( 1737 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower); 1738 EXPECT_EQ(nullptr, FS.get()); 1739 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower); 1740 EXPECT_EQ(nullptr, FS.get()); 1741 1742 // duplicate keys 1743 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower); 1744 EXPECT_EQ(nullptr, FS.get()); 1745 FS = getFromYAMLString( 1746 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }", 1747 Lower); 1748 EXPECT_EQ(nullptr, FS.get()); 1749 FS = 1750 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', " 1751 "'external-contents':'blah' } ] }", 1752 Lower); 1753 EXPECT_EQ(nullptr, FS.get()); 1754 1755 // missing version 1756 FS = getFromYAMLRawString("{ 'roots':[] }", Lower); 1757 EXPECT_EQ(nullptr, FS.get()); 1758 1759 // bad version number 1760 FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower); 1761 EXPECT_EQ(nullptr, FS.get()); 1762 FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower); 1763 EXPECT_EQ(nullptr, FS.get()); 1764 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower); 1765 EXPECT_EQ(nullptr, FS.get()); 1766 1767 // both 'external-contents' and 'contents' specified 1768 Lower->addDirectory("//root/external/dir"); 1769 FS = getFromYAMLString( 1770 "{ 'roots':[ \n" 1771 "{ 'type': 'directory', 'name': '//root/A', 'contents': [],\n" 1772 " 'external-contents': '//root/external/dir'}]}", 1773 Lower); 1774 EXPECT_EQ(nullptr, FS.get()); 1775 1776 // 'directory-remap' with 'contents' 1777 FS = getFromYAMLString( 1778 "{ 'roots':[ \n" 1779 "{ 'type': 'directory-remap', 'name': '//root/A', 'contents': [] }]}", 1780 Lower); 1781 EXPECT_EQ(nullptr, FS.get()); 1782 1783 EXPECT_EQ(26, NumDiagnostics); 1784 } 1785 1786 TEST_F(VFSFromYAMLTest, UseExternalName) { 1787 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1788 Lower->addRegularFile("//root/external/file"); 1789 1790 IntrusiveRefCntPtr<vfs::FileSystem> FS = 1791 getFromYAMLString("{ 'roots': [\n" 1792 " { 'type': 'file', 'name': '//root/A',\n" 1793 " 'external-contents': '//root/external/file'\n" 1794 " },\n" 1795 " { 'type': 'file', 'name': '//root/B',\n" 1796 " 'use-external-name': true,\n" 1797 " 'external-contents': '//root/external/file'\n" 1798 " },\n" 1799 " { 'type': 'file', 'name': '//root/C',\n" 1800 " 'use-external-name': false,\n" 1801 " 'external-contents': '//root/external/file'\n" 1802 " }\n" 1803 "] }", 1804 Lower); 1805 ASSERT_TRUE(nullptr != FS.get()); 1806 1807 // default true 1808 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName()); 1809 // explicit 1810 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName()); 1811 EXPECT_EQ("//root/C", FS->status("//root/C")->getName()); 1812 1813 // global configuration 1814 FS = getFromYAMLString("{ 'use-external-names': false,\n" 1815 " 'roots': [\n" 1816 " { 'type': 'file', 'name': '//root/A',\n" 1817 " 'external-contents': '//root/external/file'\n" 1818 " },\n" 1819 " { 'type': 'file', 'name': '//root/B',\n" 1820 " 'use-external-name': true,\n" 1821 " 'external-contents': '//root/external/file'\n" 1822 " },\n" 1823 " { 'type': 'file', 'name': '//root/C',\n" 1824 " 'use-external-name': false,\n" 1825 " 'external-contents': '//root/external/file'\n" 1826 " }\n" 1827 "] }", 1828 Lower); 1829 ASSERT_TRUE(nullptr != FS.get()); 1830 1831 // default 1832 EXPECT_EQ("//root/A", FS->status("//root/A")->getName()); 1833 // explicit 1834 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName()); 1835 EXPECT_EQ("//root/C", FS->status("//root/C")->getName()); 1836 } 1837 1838 TEST_F(VFSFromYAMLTest, MultiComponentPath) { 1839 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1840 Lower->addRegularFile("//root/other"); 1841 1842 // file in roots 1843 IntrusiveRefCntPtr<vfs::FileSystem> FS = 1844 getFromYAMLString("{ 'roots': [\n" 1845 " { 'type': 'file', 'name': '//root/path/to/file',\n" 1846 " 'external-contents': '//root/other' }]\n" 1847 "}", 1848 Lower); 1849 ASSERT_TRUE(nullptr != FS.get()); 1850 EXPECT_FALSE(FS->status("//root/path/to/file").getError()); 1851 EXPECT_FALSE(FS->status("//root/path/to").getError()); 1852 EXPECT_FALSE(FS->status("//root/path").getError()); 1853 EXPECT_FALSE(FS->status("//root/").getError()); 1854 1855 // at the start 1856 FS = getFromYAMLString( 1857 "{ 'roots': [\n" 1858 " { 'type': 'directory', 'name': '//root/path/to',\n" 1859 " 'contents': [ { 'type': 'file', 'name': 'file',\n" 1860 " 'external-contents': '//root/other' }]}]\n" 1861 "}", 1862 Lower); 1863 ASSERT_TRUE(nullptr != FS.get()); 1864 EXPECT_FALSE(FS->status("//root/path/to/file").getError()); 1865 EXPECT_FALSE(FS->status("//root/path/to").getError()); 1866 EXPECT_FALSE(FS->status("//root/path").getError()); 1867 EXPECT_FALSE(FS->status("//root/").getError()); 1868 1869 // at the end 1870 FS = getFromYAMLString( 1871 "{ 'roots': [\n" 1872 " { 'type': 'directory', 'name': '//root/',\n" 1873 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n" 1874 " 'external-contents': '//root/other' }]}]\n" 1875 "}", 1876 Lower); 1877 ASSERT_TRUE(nullptr != FS.get()); 1878 EXPECT_FALSE(FS->status("//root/path/to/file").getError()); 1879 EXPECT_FALSE(FS->status("//root/path/to").getError()); 1880 EXPECT_FALSE(FS->status("//root/path").getError()); 1881 EXPECT_FALSE(FS->status("//root/").getError()); 1882 } 1883 1884 TEST_F(VFSFromYAMLTest, TrailingSlashes) { 1885 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1886 Lower->addRegularFile("//root/other"); 1887 1888 // file in roots 1889 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 1890 "{ 'roots': [\n" 1891 " { 'type': 'directory', 'name': '//root/path/to////',\n" 1892 " 'contents': [ { 'type': 'file', 'name': 'file',\n" 1893 " 'external-contents': '//root/other' }]}]\n" 1894 "}", 1895 Lower); 1896 ASSERT_TRUE(nullptr != FS.get()); 1897 EXPECT_FALSE(FS->status("//root/path/to/file").getError()); 1898 EXPECT_FALSE(FS->status("//root/path/to").getError()); 1899 EXPECT_FALSE(FS->status("//root/path").getError()); 1900 EXPECT_FALSE(FS->status("//root/").getError()); 1901 } 1902 1903 TEST_F(VFSFromYAMLTest, DirectoryIteration) { 1904 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1905 Lower->addDirectory("//root/"); 1906 Lower->addDirectory("//root/foo"); 1907 Lower->addDirectory("//root/foo/bar"); 1908 Lower->addRegularFile("//root/foo/bar/a"); 1909 Lower->addRegularFile("//root/foo/bar/b"); 1910 Lower->addRegularFile("//root/file3"); 1911 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 1912 "{ 'use-external-names': false,\n" 1913 " 'roots': [\n" 1914 "{\n" 1915 " 'type': 'directory',\n" 1916 " 'name': '//root/',\n" 1917 " 'contents': [ {\n" 1918 " 'type': 'file',\n" 1919 " 'name': 'file1',\n" 1920 " 'external-contents': '//root/foo/bar/a'\n" 1921 " },\n" 1922 " {\n" 1923 " 'type': 'file',\n" 1924 " 'name': 'file2',\n" 1925 " 'external-contents': '//root/foo/bar/b'\n" 1926 " }\n" 1927 " ]\n" 1928 "}\n" 1929 "]\n" 1930 "}", 1931 Lower); 1932 ASSERT_TRUE(FS.get() != nullptr); 1933 1934 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O( 1935 new vfs::OverlayFileSystem(Lower)); 1936 O->pushOverlay(FS); 1937 1938 std::error_code EC; 1939 checkContents(O->dir_begin("//root/", EC), 1940 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"}); 1941 1942 checkContents(O->dir_begin("//root/foo/bar", EC), 1943 {"//root/foo/bar/a", "//root/foo/bar/b"}); 1944 } 1945 1946 TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) { 1947 // https://llvm.org/bugs/show_bug.cgi?id=27725 1948 if (!supportsSameDirMultipleYAMLEntries()) 1949 return; 1950 1951 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1952 Lower->addDirectory("//root/zab"); 1953 Lower->addDirectory("//root/baz"); 1954 Lower->addRegularFile("//root/zab/a"); 1955 Lower->addRegularFile("//root/zab/b"); 1956 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 1957 "{ 'use-external-names': false,\n" 1958 " 'roots': [\n" 1959 "{\n" 1960 " 'type': 'directory',\n" 1961 " 'name': '//root/baz/',\n" 1962 " 'contents': [ {\n" 1963 " 'type': 'file',\n" 1964 " 'name': 'x',\n" 1965 " 'external-contents': '//root/zab/a'\n" 1966 " }\n" 1967 " ]\n" 1968 "},\n" 1969 "{\n" 1970 " 'type': 'directory',\n" 1971 " 'name': '//root/baz/',\n" 1972 " 'contents': [ {\n" 1973 " 'type': 'file',\n" 1974 " 'name': 'y',\n" 1975 " 'external-contents': '//root/zab/b'\n" 1976 " }\n" 1977 " ]\n" 1978 "}\n" 1979 "]\n" 1980 "}", 1981 Lower); 1982 ASSERT_TRUE(FS.get() != nullptr); 1983 1984 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O( 1985 new vfs::OverlayFileSystem(Lower)); 1986 O->pushOverlay(FS); 1987 1988 std::error_code EC; 1989 1990 checkContents(O->dir_begin("//root/baz/", EC), 1991 {"//root/baz/x", "//root/baz/y"}); 1992 } 1993 1994 TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) { 1995 1996 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 1997 Lower->addDirectory("//root/a"); 1998 Lower->addDirectory("//root/a/b"); 1999 Lower->addDirectory("//root/a/b/c"); 2000 Lower->addRegularFile("//root/a/b/c/file"); 2001 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 2002 "{ 'use-external-names': false,\n" 2003 " 'roots': [\n" 2004 "{\n" 2005 " 'type': 'directory',\n" 2006 " 'name': '//root/a/b/c/',\n" 2007 " 'contents': [ {\n" 2008 " 'type': 'file',\n" 2009 " 'name': 'file',\n" 2010 " 'external-contents': '//root/a/b/c/file'\n" 2011 " }\n" 2012 " ]\n" 2013 "},\n" 2014 "]\n" 2015 "}", 2016 Lower); 2017 ASSERT_TRUE(FS.get() != nullptr); 2018 2019 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O( 2020 new vfs::OverlayFileSystem(Lower)); 2021 O->pushOverlay(FS); 2022 2023 std::error_code EC; 2024 2025 // Test recursive_directory_iterator level() 2026 vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator( 2027 *O, "//root", EC), 2028 E; 2029 ASSERT_FALSE(EC); 2030 for (int l = 0; I != E; I.increment(EC), ++l) { 2031 ASSERT_FALSE(EC); 2032 EXPECT_EQ(I.level(), l); 2033 } 2034 EXPECT_EQ(I, E); 2035 } 2036 2037 TEST_F(VFSFromYAMLTest, RelativePaths) { 2038 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 2039 // Filename at root level without a parent directory. 2040 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 2041 "{ 'roots': [\n" 2042 " { 'type': 'file', 'name': 'file-not-in-directory.h',\n" 2043 " 'external-contents': '//root/external/file'\n" 2044 " }\n" 2045 "] }", 2046 Lower); 2047 EXPECT_EQ(nullptr, FS.get()); 2048 2049 // Relative file path. 2050 FS = getFromYAMLString("{ 'roots': [\n" 2051 " { 'type': 'file', 'name': 'relative/file/path.h',\n" 2052 " 'external-contents': '//root/external/file'\n" 2053 " }\n" 2054 "] }", 2055 Lower); 2056 EXPECT_EQ(nullptr, FS.get()); 2057 2058 // Relative directory path. 2059 FS = getFromYAMLString( 2060 "{ 'roots': [\n" 2061 " { 'type': 'directory', 'name': 'relative/directory/path.h',\n" 2062 " 'contents': []\n" 2063 " }\n" 2064 "] }", 2065 Lower); 2066 EXPECT_EQ(nullptr, FS.get()); 2067 2068 EXPECT_EQ(3, NumDiagnostics); 2069 } 2070 2071 TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) { 2072 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 2073 Lower->addDirectory("//root/"); 2074 Lower->addRegularFile("//root/a"); 2075 Lower->addRegularFile("//root/b"); 2076 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 2077 "{ 'use-external-names': false,\n" 2078 " 'fallthrough': false,\n" 2079 " 'roots': [\n" 2080 "{\n" 2081 " 'type': 'directory',\n" 2082 " 'name': '//root/',\n" 2083 " 'contents': [ {\n" 2084 " 'type': 'file',\n" 2085 " 'name': 'c',\n" 2086 " 'external-contents': '//root/a'\n" 2087 " }\n" 2088 " ]\n" 2089 "}\n" 2090 "]\n" 2091 "}", 2092 Lower); 2093 ASSERT_TRUE(FS.get() != nullptr); 2094 2095 std::error_code EC; 2096 checkContents(FS->dir_begin("//root/", EC), 2097 {"//root/c"}); 2098 } 2099 2100 TEST_F(VFSFromYAMLTest, DirectoryIterationWithDuplicates) { 2101 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 2102 Lower->addDirectory("//root/"); 2103 Lower->addRegularFile("//root/a"); 2104 Lower->addRegularFile("//root/b"); 2105 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 2106 "{ 'use-external-names': false,\n" 2107 " 'roots': [\n" 2108 "{\n" 2109 " 'type': 'directory',\n" 2110 " 'name': '//root/',\n" 2111 " 'contents': [ {\n" 2112 " 'type': 'file',\n" 2113 " 'name': 'a',\n" 2114 " 'external-contents': '//root/a'\n" 2115 " }\n" 2116 " ]\n" 2117 "}\n" 2118 "]\n" 2119 "}", 2120 Lower); 2121 ASSERT_TRUE(FS.get() != nullptr); 2122 2123 std::error_code EC; 2124 checkContents(FS->dir_begin("//root/", EC), 2125 {"//root/a", "//root/b"}); 2126 } 2127 2128 TEST_F(VFSFromYAMLTest, DirectoryIterationErrorInVFSLayer) { 2129 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 2130 Lower->addDirectory("//root/"); 2131 Lower->addDirectory("//root/foo"); 2132 Lower->addRegularFile("//root/foo/a"); 2133 Lower->addRegularFile("//root/foo/b"); 2134 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 2135 "{ 'use-external-names': false,\n" 2136 " 'roots': [\n" 2137 "{\n" 2138 " 'type': 'directory',\n" 2139 " 'name': '//root/',\n" 2140 " 'contents': [ {\n" 2141 " 'type': 'file',\n" 2142 " 'name': 'bar/a',\n" 2143 " 'external-contents': '//root/foo/a'\n" 2144 " }\n" 2145 " ]\n" 2146 "}\n" 2147 "]\n" 2148 "}", 2149 Lower); 2150 ASSERT_TRUE(FS.get() != nullptr); 2151 2152 std::error_code EC; 2153 checkContents(FS->dir_begin("//root/foo", EC), 2154 {"//root/foo/a", "//root/foo/b"}); 2155 } 2156 2157 TEST_F(VFSFromYAMLTest, GetRealPath) { 2158 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 2159 Lower->addDirectory("//dir/"); 2160 Lower->addRegularFile("/foo"); 2161 Lower->addSymlink("/link"); 2162 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 2163 "{ 'use-external-names': false,\n" 2164 " 'roots': [\n" 2165 "{\n" 2166 " 'type': 'directory',\n" 2167 " 'name': '//root/',\n" 2168 " 'contents': [ {\n" 2169 " 'type': 'file',\n" 2170 " 'name': 'bar',\n" 2171 " 'external-contents': '/link'\n" 2172 " }\n" 2173 " ]\n" 2174 "},\n" 2175 "{\n" 2176 " 'type': 'directory',\n" 2177 " 'name': '//dir/',\n" 2178 " 'contents': []\n" 2179 "}\n" 2180 "]\n" 2181 "}", 2182 Lower); 2183 ASSERT_TRUE(FS.get() != nullptr); 2184 2185 // Regular file present in underlying file system. 2186 SmallString<16> RealPath; 2187 EXPECT_FALSE(FS->getRealPath("/foo", RealPath)); 2188 EXPECT_EQ(RealPath.str(), "/foo"); 2189 2190 // File present in YAML pointing to symlink in underlying file system. 2191 EXPECT_FALSE(FS->getRealPath("//root/bar", RealPath)); 2192 EXPECT_EQ(RealPath.str(), "/symlink"); 2193 2194 // Directories should fall back to the underlying file system is possible. 2195 EXPECT_FALSE(FS->getRealPath("//dir/", RealPath)); 2196 EXPECT_EQ(RealPath.str(), "//dir/"); 2197 2198 // Try a non-existing file. 2199 EXPECT_EQ(FS->getRealPath("/non_existing", RealPath), 2200 errc::no_such_file_or_directory); 2201 } 2202 2203 TEST_F(VFSFromYAMLTest, WorkingDirectory) { 2204 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 2205 Lower->addDirectory("//root/"); 2206 Lower->addDirectory("//root/foo"); 2207 Lower->addRegularFile("//root/foo/a"); 2208 Lower->addRegularFile("//root/foo/b"); 2209 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 2210 "{ 'use-external-names': false,\n" 2211 " 'roots': [\n" 2212 "{\n" 2213 " 'type': 'directory',\n" 2214 " 'name': '//root/bar',\n" 2215 " 'contents': [ {\n" 2216 " 'type': 'file',\n" 2217 " 'name': 'a',\n" 2218 " 'external-contents': '//root/foo/a'\n" 2219 " }\n" 2220 " ]\n" 2221 "}\n" 2222 "]\n" 2223 "}", 2224 Lower); 2225 ASSERT_TRUE(FS.get() != nullptr); 2226 std::error_code EC = FS->setCurrentWorkingDirectory("//root/bar"); 2227 ASSERT_FALSE(EC); 2228 2229 llvm::ErrorOr<std::string> WorkingDir = FS->getCurrentWorkingDirectory(); 2230 ASSERT_TRUE(WorkingDir); 2231 EXPECT_EQ(*WorkingDir, "//root/bar"); 2232 2233 llvm::ErrorOr<vfs::Status> Status = FS->status("./a"); 2234 ASSERT_FALSE(Status.getError()); 2235 EXPECT_TRUE(Status->isStatusKnown()); 2236 EXPECT_FALSE(Status->isDirectory()); 2237 EXPECT_TRUE(Status->isRegularFile()); 2238 EXPECT_FALSE(Status->isSymlink()); 2239 EXPECT_FALSE(Status->isOther()); 2240 EXPECT_TRUE(Status->exists()); 2241 2242 EC = FS->setCurrentWorkingDirectory("bogus"); 2243 ASSERT_TRUE(EC); 2244 WorkingDir = FS->getCurrentWorkingDirectory(); 2245 ASSERT_TRUE(WorkingDir); 2246 EXPECT_EQ(*WorkingDir, "//root/bar"); 2247 2248 EC = FS->setCurrentWorkingDirectory("//root/"); 2249 ASSERT_FALSE(EC); 2250 WorkingDir = FS->getCurrentWorkingDirectory(); 2251 ASSERT_TRUE(WorkingDir); 2252 EXPECT_EQ(*WorkingDir, "//root/"); 2253 2254 EC = FS->setCurrentWorkingDirectory("bar"); 2255 ASSERT_FALSE(EC); 2256 WorkingDir = FS->getCurrentWorkingDirectory(); 2257 ASSERT_TRUE(WorkingDir); 2258 EXPECT_EQ(*WorkingDir, "//root/bar"); 2259 } 2260 2261 TEST_F(VFSFromYAMLTest, WorkingDirectoryFallthrough) { 2262 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); 2263 Lower->addDirectory("//root/"); 2264 Lower->addDirectory("//root/foo"); 2265 Lower->addRegularFile("//root/foo/a"); 2266 Lower->addRegularFile("//root/foo/b"); 2267 Lower->addRegularFile("//root/c"); 2268 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 2269 "{ 'use-external-names': false,\n" 2270 " 'roots': [\n" 2271 "{\n" 2272 " 'type': 'directory',\n" 2273 " 'name': '//root/bar',\n" 2274 " 'contents': [ {\n" 2275 " 'type': 'file',\n" 2276 " 'name': 'a',\n" 2277 " 'external-contents': '//root/foo/a'\n" 2278 " }\n" 2279 " ]\n" 2280 "},\n" 2281 "{\n" 2282 " 'type': 'directory',\n" 2283 " 'name': '//root/bar/baz',\n" 2284 " 'contents': [ {\n" 2285 " 'type': 'file',\n" 2286 " 'name': 'a',\n" 2287 " 'external-contents': '//root/foo/a'\n" 2288 " }\n" 2289 " ]\n" 2290 "}\n" 2291 "]\n" 2292 "}", 2293 Lower); 2294 ASSERT_TRUE(FS.get() != nullptr); 2295 std::error_code EC = FS->setCurrentWorkingDirectory("//root/"); 2296 ASSERT_FALSE(EC); 2297 ASSERT_TRUE(FS.get() != nullptr); 2298 2299 llvm::ErrorOr<vfs::Status> Status = FS->status("bar/a"); 2300 ASSERT_FALSE(Status.getError()); 2301 EXPECT_TRUE(Status->exists()); 2302 2303 Status = FS->status("foo/a"); 2304 ASSERT_FALSE(Status.getError()); 2305 EXPECT_TRUE(Status->exists()); 2306 2307 EC = FS->setCurrentWorkingDirectory("//root/bar"); 2308 ASSERT_FALSE(EC); 2309 2310 Status = FS->status("./a"); 2311 ASSERT_FALSE(Status.getError()); 2312 EXPECT_TRUE(Status->exists()); 2313 2314 Status = FS->status("./b"); 2315 ASSERT_TRUE(Status.getError()); 2316 2317 Status = FS->status("./c"); 2318 ASSERT_TRUE(Status.getError()); 2319 2320 EC = FS->setCurrentWorkingDirectory("//root/"); 2321 ASSERT_FALSE(EC); 2322 2323 Status = FS->status("c"); 2324 ASSERT_FALSE(Status.getError()); 2325 EXPECT_TRUE(Status->exists()); 2326 2327 Status = FS->status("./bar/baz/a"); 2328 ASSERT_FALSE(Status.getError()); 2329 EXPECT_TRUE(Status->exists()); 2330 2331 EC = FS->setCurrentWorkingDirectory("//root/bar"); 2332 ASSERT_FALSE(EC); 2333 2334 Status = FS->status("./baz/a"); 2335 ASSERT_FALSE(Status.getError()); 2336 EXPECT_TRUE(Status->exists()); 2337 2338 Status = FS->status("../bar/baz/a"); 2339 ASSERT_FALSE(Status.getError()); 2340 EXPECT_TRUE(Status->exists()); 2341 } 2342 2343 TEST_F(VFSFromYAMLTest, WorkingDirectoryFallthroughInvalid) { 2344 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem()); 2345 Lower->addDirectory("//root/"); 2346 Lower->addDirectory("//root/foo"); 2347 Lower->addRegularFile("//root/foo/a"); 2348 Lower->addRegularFile("//root/foo/b"); 2349 Lower->addRegularFile("//root/c"); 2350 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 2351 "{ 'use-external-names': false,\n" 2352 " 'roots': [\n" 2353 "{\n" 2354 " 'type': 'directory',\n" 2355 " 'name': '//root/bar',\n" 2356 " 'contents': [ {\n" 2357 " 'type': 'file',\n" 2358 " 'name': 'a',\n" 2359 " 'external-contents': '//root/foo/a'\n" 2360 " }\n" 2361 " ]\n" 2362 "}\n" 2363 "]\n" 2364 "}", 2365 Lower); 2366 ASSERT_TRUE(FS.get() != nullptr); 2367 std::error_code EC = FS->setCurrentWorkingDirectory("//root/"); 2368 ASSERT_FALSE(EC); 2369 ASSERT_TRUE(FS.get() != nullptr); 2370 2371 llvm::ErrorOr<vfs::Status> Status = FS->status("bar/a"); 2372 ASSERT_FALSE(Status.getError()); 2373 EXPECT_TRUE(Status->exists()); 2374 2375 Status = FS->status("foo/a"); 2376 ASSERT_FALSE(Status.getError()); 2377 EXPECT_TRUE(Status->exists()); 2378 } 2379 2380 TEST_F(VFSFromYAMLTest, VirtualWorkingDirectory) { 2381 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem()); 2382 Lower->addDirectory("//root/"); 2383 Lower->addDirectory("//root/foo"); 2384 Lower->addRegularFile("//root/foo/a"); 2385 Lower->addRegularFile("//root/foo/b"); 2386 Lower->addRegularFile("//root/c"); 2387 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( 2388 "{ 'use-external-names': false,\n" 2389 " 'roots': [\n" 2390 "{\n" 2391 " 'type': 'directory',\n" 2392 " 'name': '//root/bar',\n" 2393 " 'contents': [ {\n" 2394 " 'type': 'file',\n" 2395 " 'name': 'a',\n" 2396 " 'external-contents': '//root/foo/a'\n" 2397 " }\n" 2398 " ]\n" 2399 "}\n" 2400 "]\n" 2401 "}", 2402 Lower); 2403 ASSERT_TRUE(FS.get() != nullptr); 2404 std::error_code EC = FS->setCurrentWorkingDirectory("//root/bar"); 2405 ASSERT_FALSE(EC); 2406 ASSERT_TRUE(FS.get() != nullptr); 2407 2408 llvm::ErrorOr<vfs::Status> Status = FS->status("a"); 2409 ASSERT_FALSE(Status.getError()); 2410 EXPECT_TRUE(Status->exists()); 2411 } 2412 2413 TEST_F(VFSFromYAMLTest, YAMLVFSWriterTest) { 2414 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true); 2415 TempDir _a(TestDirectory.path("a")); 2416 TempFile _ab(TestDirectory.path("a, b")); 2417 TempDir _c(TestDirectory.path("c")); 2418 TempFile _cd(TestDirectory.path("c/d")); 2419 TempDir _e(TestDirectory.path("e")); 2420 TempDir _ef(TestDirectory.path("e/f")); 2421 TempFile _g(TestDirectory.path("g")); 2422 TempDir _h(TestDirectory.path("h")); 2423 2424 vfs::YAMLVFSWriter VFSWriter; 2425 VFSWriter.addDirectoryMapping(_a.path(), "//root/a"); 2426 VFSWriter.addFileMapping(_ab.path(), "//root/a/b"); 2427 VFSWriter.addFileMapping(_cd.path(), "//root/c/d"); 2428 VFSWriter.addDirectoryMapping(_e.path(), "//root/e"); 2429 VFSWriter.addDirectoryMapping(_ef.path(), "//root/e/f"); 2430 VFSWriter.addFileMapping(_g.path(), "//root/g"); 2431 VFSWriter.addDirectoryMapping(_h.path(), "//root/h"); 2432 2433 std::string Buffer; 2434 raw_string_ostream OS(Buffer); 2435 VFSWriter.write(OS); 2436 OS.flush(); 2437 2438 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem()); 2439 Lower->addDirectory("//root/"); 2440 Lower->addDirectory("//root/a"); 2441 Lower->addRegularFile("//root/a/b"); 2442 Lower->addDirectory("//root/b"); 2443 Lower->addDirectory("//root/c"); 2444 Lower->addRegularFile("//root/c/d"); 2445 Lower->addDirectory("//root/e"); 2446 Lower->addDirectory("//root/e/f"); 2447 Lower->addRegularFile("//root/g"); 2448 Lower->addDirectory("//root/h"); 2449 2450 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower); 2451 ASSERT_TRUE(FS.get() != nullptr); 2452 2453 EXPECT_TRUE(FS->exists(_a.path())); 2454 EXPECT_TRUE(FS->exists(_ab.path())); 2455 EXPECT_TRUE(FS->exists(_c.path())); 2456 EXPECT_TRUE(FS->exists(_cd.path())); 2457 EXPECT_TRUE(FS->exists(_e.path())); 2458 EXPECT_TRUE(FS->exists(_ef.path())); 2459 EXPECT_TRUE(FS->exists(_g.path())); 2460 EXPECT_TRUE(FS->exists(_h.path())); 2461 } 2462 2463 TEST_F(VFSFromYAMLTest, YAMLVFSWriterTest2) { 2464 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true); 2465 TempDir _a(TestDirectory.path("a")); 2466 TempFile _ab(TestDirectory.path("a/b")); 2467 TempDir _ac(TestDirectory.path("a/c")); 2468 TempFile _acd(TestDirectory.path("a/c/d")); 2469 TempFile _ace(TestDirectory.path("a/c/e")); 2470 TempFile _acf(TestDirectory.path("a/c/f")); 2471 TempDir _ag(TestDirectory.path("a/g")); 2472 TempFile _agh(TestDirectory.path("a/g/h")); 2473 2474 vfs::YAMLVFSWriter VFSWriter; 2475 VFSWriter.addDirectoryMapping(_a.path(), "//root/a"); 2476 VFSWriter.addFileMapping(_ab.path(), "//root/a/b"); 2477 VFSWriter.addDirectoryMapping(_ac.path(), "//root/a/c"); 2478 VFSWriter.addFileMapping(_acd.path(), "//root/a/c/d"); 2479 VFSWriter.addFileMapping(_ace.path(), "//root/a/c/e"); 2480 VFSWriter.addFileMapping(_acf.path(), "//root/a/c/f"); 2481 VFSWriter.addDirectoryMapping(_ag.path(), "//root/a/g"); 2482 VFSWriter.addFileMapping(_agh.path(), "//root/a/g/h"); 2483 2484 std::string Buffer; 2485 raw_string_ostream OS(Buffer); 2486 VFSWriter.write(OS); 2487 OS.flush(); 2488 2489 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem()); 2490 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower); 2491 EXPECT_TRUE(FS.get() != nullptr); 2492 } 2493 2494 TEST_F(VFSFromYAMLTest, YAMLVFSWriterTest3) { 2495 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true); 2496 TempDir _a(TestDirectory.path("a")); 2497 TempFile _ab(TestDirectory.path("a/b")); 2498 TempDir _ac(TestDirectory.path("a/c")); 2499 TempDir _acd(TestDirectory.path("a/c/d")); 2500 TempDir _acde(TestDirectory.path("a/c/d/e")); 2501 TempFile _acdef(TestDirectory.path("a/c/d/e/f")); 2502 TempFile _acdeg(TestDirectory.path("a/c/d/e/g")); 2503 TempDir _ah(TestDirectory.path("a/h")); 2504 TempFile _ahi(TestDirectory.path("a/h/i")); 2505 2506 vfs::YAMLVFSWriter VFSWriter; 2507 VFSWriter.addDirectoryMapping(_a.path(), "//root/a"); 2508 VFSWriter.addFileMapping(_ab.path(), "//root/a/b"); 2509 VFSWriter.addDirectoryMapping(_ac.path(), "//root/a/c"); 2510 VFSWriter.addDirectoryMapping(_acd.path(), "//root/a/c/d"); 2511 VFSWriter.addDirectoryMapping(_acde.path(), "//root/a/c/d/e"); 2512 VFSWriter.addFileMapping(_acdef.path(), "//root/a/c/d/e/f"); 2513 VFSWriter.addFileMapping(_acdeg.path(), "//root/a/c/d/e/g"); 2514 VFSWriter.addDirectoryMapping(_ahi.path(), "//root/a/h"); 2515 VFSWriter.addFileMapping(_ahi.path(), "//root/a/h/i"); 2516 2517 std::string Buffer; 2518 raw_string_ostream OS(Buffer); 2519 VFSWriter.write(OS); 2520 OS.flush(); 2521 2522 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem()); 2523 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower); 2524 EXPECT_TRUE(FS.get() != nullptr); 2525 } 2526 2527 TEST_F(VFSFromYAMLTest, YAMLVFSWriterTestHandleDirs) { 2528 TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true); 2529 TempDir _a(TestDirectory.path("a")); 2530 TempDir _b(TestDirectory.path("b")); 2531 TempDir _c(TestDirectory.path("c")); 2532 2533 vfs::YAMLVFSWriter VFSWriter; 2534 VFSWriter.addDirectoryMapping(_a.path(), "//root/a"); 2535 VFSWriter.addDirectoryMapping(_b.path(), "//root/b"); 2536 VFSWriter.addDirectoryMapping(_c.path(), "//root/c"); 2537 2538 std::string Buffer; 2539 raw_string_ostream OS(Buffer); 2540 VFSWriter.write(OS); 2541 OS.flush(); 2542 2543 // We didn't add a single file - only directories. 2544 EXPECT_TRUE(Buffer.find("'type': 'file'") == std::string::npos); 2545 2546 IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem()); 2547 Lower->addDirectory("//root/a"); 2548 Lower->addDirectory("//root/b"); 2549 Lower->addDirectory("//root/c"); 2550 // canaries 2551 Lower->addRegularFile("//root/a/a"); 2552 Lower->addRegularFile("//root/b/b"); 2553 Lower->addRegularFile("//root/c/c"); 2554 2555 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower); 2556 ASSERT_TRUE(FS.get() != nullptr); 2557 2558 EXPECT_FALSE(FS->exists(_a.path("a"))); 2559 EXPECT_FALSE(FS->exists(_b.path("b"))); 2560 EXPECT_FALSE(FS->exists(_c.path("c"))); 2561 } 2562 2563 TEST(VFSFromRemappedFilesTest, Basic) { 2564 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS = 2565 new vfs::InMemoryFileSystem; 2566 BaseFS->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b")); 2567 BaseFS->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c")); 2568 2569 std::vector<std::pair<std::string, std::string>> RemappedFiles = { 2570 {"//root/a/a", "//root/b"}, 2571 {"//root/a/b/c", "//root/c"}, 2572 }; 2573 auto RemappedFS = vfs::RedirectingFileSystem::create( 2574 RemappedFiles, /*UseExternalNames=*/false, *BaseFS); 2575 2576 auto StatA = RemappedFS->status("//root/a/a"); 2577 auto StatB = RemappedFS->status("//root/a/b/c"); 2578 ASSERT_TRUE(StatA); 2579 ASSERT_TRUE(StatB); 2580 EXPECT_EQ("//root/a/a", StatA->getName()); 2581 EXPECT_EQ("//root/a/b/c", StatB->getName()); 2582 2583 auto BufferA = RemappedFS->getBufferForFile("//root/a/a"); 2584 auto BufferB = RemappedFS->getBufferForFile("//root/a/b/c"); 2585 ASSERT_TRUE(BufferA); 2586 ASSERT_TRUE(BufferB); 2587 EXPECT_EQ("contents of b", (*BufferA)->getBuffer()); 2588 EXPECT_EQ("contents of c", (*BufferB)->getBuffer()); 2589 } 2590 2591 TEST(VFSFromRemappedFilesTest, UseExternalNames) { 2592 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS = 2593 new vfs::InMemoryFileSystem; 2594 BaseFS->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b")); 2595 BaseFS->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c")); 2596 2597 std::vector<std::pair<std::string, std::string>> RemappedFiles = { 2598 {"//root/a/a", "//root/b"}, 2599 {"//root/a/b/c", "//root/c"}, 2600 }; 2601 auto RemappedFS = vfs::RedirectingFileSystem::create( 2602 RemappedFiles, /*UseExternalNames=*/true, *BaseFS); 2603 2604 auto StatA = RemappedFS->status("//root/a/a"); 2605 auto StatB = RemappedFS->status("//root/a/b/c"); 2606 ASSERT_TRUE(StatA); 2607 ASSERT_TRUE(StatB); 2608 EXPECT_EQ("//root/b", StatA->getName()); 2609 EXPECT_EQ("//root/c", StatB->getName()); 2610 2611 auto BufferA = RemappedFS->getBufferForFile("//root/a/a"); 2612 auto BufferB = RemappedFS->getBufferForFile("//root/a/b/c"); 2613 ASSERT_TRUE(BufferA); 2614 ASSERT_TRUE(BufferB); 2615 EXPECT_EQ("contents of b", (*BufferA)->getBuffer()); 2616 EXPECT_EQ("contents of c", (*BufferB)->getBuffer()); 2617 } 2618 2619 TEST(VFSFromRemappedFilesTest, LastMappingWins) { 2620 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS = 2621 new vfs::InMemoryFileSystem; 2622 BaseFS->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b")); 2623 BaseFS->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c")); 2624 2625 std::vector<std::pair<std::string, std::string>> RemappedFiles = { 2626 {"//root/a", "//root/b"}, 2627 {"//root/a", "//root/c"}, 2628 }; 2629 auto RemappedFSKeepName = vfs::RedirectingFileSystem::create( 2630 RemappedFiles, /*UseExternalNames=*/false, *BaseFS); 2631 auto RemappedFSExternalName = vfs::RedirectingFileSystem::create( 2632 RemappedFiles, /*UseExternalNames=*/true, *BaseFS); 2633 2634 auto StatKeepA = RemappedFSKeepName->status("//root/a"); 2635 auto StatExternalA = RemappedFSExternalName->status("//root/a"); 2636 ASSERT_TRUE(StatKeepA); 2637 ASSERT_TRUE(StatExternalA); 2638 EXPECT_EQ("//root/a", StatKeepA->getName()); 2639 EXPECT_EQ("//root/c", StatExternalA->getName()); 2640 2641 auto BufferKeepA = RemappedFSKeepName->getBufferForFile("//root/a"); 2642 auto BufferExternalA = RemappedFSExternalName->getBufferForFile("//root/a"); 2643 ASSERT_TRUE(BufferKeepA); 2644 ASSERT_TRUE(BufferExternalA); 2645 EXPECT_EQ("contents of c", (*BufferKeepA)->getBuffer()); 2646 EXPECT_EQ("contents of c", (*BufferExternalA)->getBuffer()); 2647 } 2648