diff options
author | Jonas Devlieghere <jonas@devlieghere.com> | 2019-10-15 17:14:24 +0000 |
---|---|---|
committer | Jonas Devlieghere <jonas@devlieghere.com> | 2019-10-15 17:14:24 +0000 |
commit | 0b9981b180ef2f08d2a97cfda2fb6ca35ad5e93c (patch) | |
tree | 43455e702c7c2c9721b611272cfc2a5d092c0149 /llvm/unittests/Support | |
parent | d3bd5b3d71ae9fc3a3a45e05d5dba6b1ecbcb2f5 (diff) | |
download | bcm5719-llvm-0b9981b180ef2f08d2a97cfda2fb6ca35ad5e93c.tar.gz bcm5719-llvm-0b9981b180ef2f08d2a97cfda2fb6ca35ad5e93c.zip |
[VirtualFileSystem] Support virtual working directory in the RedirectingFS
Before this patch, changing the working directory of the RedirectingFS
would just forward to its external file system. This prevented us from
having a working directory that only existed in the VFS mapping.
This patch adds support for a virtual working directory in the
RedirectingFileSystem. It now keeps track of its own WD in addition to
updating the WD of the external file system. This ensures that we can
still fall through for relative paths.
This change was originally motivated by the reproducer infrastructure in
LLDB where we want to deal transparently with relative paths.
Differential revision: https://reviews.llvm.org/D65677
llvm-svn: 374917
Diffstat (limited to 'llvm/unittests/Support')
-rw-r--r-- | llvm/unittests/Support/VirtualFileSystemTest.cpp | 175 |
1 files changed, 171 insertions, 4 deletions
diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp index a867bc57e94..b81cb86f0b6 100644 --- a/llvm/unittests/Support/VirtualFileSystemTest.cpp +++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -41,7 +41,9 @@ struct DummyFile : public vfs::File { class DummyFileSystem : public vfs::FileSystem { int FSID; // used to produce UniqueIDs int FileID; // used to produce UniqueIDs + std::string WorkingDirectory; std::map<std::string, vfs::Status> FilesAndDirs; + typedef std::map<std::string, vfs::Status>::const_iterator const_iterator; static int getNextFSID() { static int Count = 0; @@ -52,8 +54,7 @@ public: DummyFileSystem() : FSID(getNextFSID()), FileID(0) {} ErrorOr<vfs::Status> status(const Twine &Path) override { - std::map<std::string, vfs::Status>::iterator I = - FilesAndDirs.find(Path.str()); + auto I = findEntry(Path); if (I == FilesAndDirs.end()) return make_error_code(llvm::errc::no_such_file_or_directory); return I->second; @@ -66,15 +67,16 @@ public: return S.getError(); } llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { - return std::string(); + return WorkingDirectory; } std::error_code setCurrentWorkingDirectory(const Twine &Path) override { + WorkingDirectory = Path.str(); return std::error_code(); } // Map any symlink to "/symlink". std::error_code getRealPath(const Twine &Path, SmallVectorImpl<char> &Output) const override { - auto I = FilesAndDirs.find(Path.str()); + auto I = findEntry(Path); if (I == FilesAndDirs.end()) return make_error_code(llvm::errc::no_such_file_or_directory); if (I->second.isSymlink()) { @@ -136,6 +138,14 @@ public: FilesAndDirs[Path] = Status; } + const_iterator findEntry(const Twine &Path) const { + SmallString<128> P; + Path.toVector(P); + std::error_code EC = makeAbsolute(P); + assert(!EC); + return FilesAndDirs.find(P.str()); + } + void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) { vfs::Status S(Path, UniqueID(FSID, FileID++), std::chrono::system_clock::now(), 0, 0, 1024, @@ -158,6 +168,12 @@ public: } }; +class ErrorDummyFileSystem : public DummyFileSystem { + std::error_code setCurrentWorkingDirectory(const Twine &Path) override { + return llvm::errc::no_such_file_or_directory; + } +}; + /// Replace back-slashes by front-slashes. std::string getPosixPath(std::string S) { SmallString<128> Result; @@ -1994,3 +2010,154 @@ TEST_F(VFSFromYAMLTest, GetRealPath) { EXPECT_EQ(FS->getRealPath("/non_existing", RealPath), errc::no_such_file_or_directory); } + +TEST_F(VFSFromYAMLTest, WorkingDirectory) { + IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); + Lower->addDirectory("//root/"); + Lower->addDirectory("//root/foo"); + Lower->addRegularFile("//root/foo/a"); + Lower->addRegularFile("//root/foo/b"); + IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( + "{ 'use-external-names': false,\n" + " 'roots': [\n" + "{\n" + " 'type': 'directory',\n" + " 'name': '//root/',\n" + " 'contents': [ {\n" + " 'type': 'file',\n" + " 'name': 'bar/a',\n" + " 'external-contents': '//root/foo/a'\n" + " }\n" + " ]\n" + "}\n" + "]\n" + "}", + Lower); + ASSERT_TRUE(FS.get() != nullptr); + std::error_code EC = FS->setCurrentWorkingDirectory("//root/bar/"); + ASSERT_FALSE(EC); + + llvm::ErrorOr<std::string> WorkingDir = FS->getCurrentWorkingDirectory(); + ASSERT_TRUE(WorkingDir); + EXPECT_EQ(*WorkingDir, "//root/bar/"); + + llvm::ErrorOr<vfs::Status> Status = FS->status("./a"); + ASSERT_FALSE(Status.getError()); + EXPECT_TRUE(Status->isStatusKnown()); + EXPECT_FALSE(Status->isDirectory()); + EXPECT_TRUE(Status->isRegularFile()); + EXPECT_FALSE(Status->isSymlink()); + EXPECT_FALSE(Status->isOther()); + EXPECT_TRUE(Status->exists()); + + EC = FS->setCurrentWorkingDirectory("bogus"); + ASSERT_TRUE(EC); + WorkingDir = FS->getCurrentWorkingDirectory(); + ASSERT_TRUE(WorkingDir); + EXPECT_EQ(*WorkingDir, "//root/bar/"); + + EC = FS->setCurrentWorkingDirectory("//root/"); + ASSERT_FALSE(EC); + WorkingDir = FS->getCurrentWorkingDirectory(); + ASSERT_TRUE(WorkingDir); + EXPECT_EQ(*WorkingDir, "//root/"); + + EC = FS->setCurrentWorkingDirectory("bar/"); + ASSERT_FALSE(EC); + WorkingDir = FS->getCurrentWorkingDirectory(); + ASSERT_TRUE(WorkingDir); + EXPECT_EQ(*WorkingDir, "//root/bar/"); +} + +TEST_F(VFSFromYAMLTest, WorkingDirectoryFallthrough) { + IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem()); + Lower->addDirectory("//root/"); + Lower->addDirectory("//root/foo"); + Lower->addRegularFile("//root/foo/a"); + Lower->addRegularFile("//root/foo/b"); + Lower->addRegularFile("//root/c"); + IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( + "{ 'use-external-names': false,\n" + " 'roots': [\n" + "{\n" + " 'type': 'directory',\n" + " 'name': '//root/',\n" + " 'contents': [ {\n" + " 'type': 'file',\n" + " 'name': 'bar/a',\n" + " 'external-contents': '//root/foo/a'\n" + " }\n" + " ]\n" + "}\n" + "]\n" + "}", + Lower); + ASSERT_TRUE(FS.get() != nullptr); + std::error_code EC = FS->setCurrentWorkingDirectory("//root/"); + ASSERT_FALSE(EC); + ASSERT_TRUE(FS.get() != nullptr); + + llvm::ErrorOr<vfs::Status> Status = FS->status("bar/a"); + ASSERT_FALSE(Status.getError()); + EXPECT_TRUE(Status->exists()); + + Status = FS->status("foo/a"); + ASSERT_FALSE(Status.getError()); + EXPECT_TRUE(Status->exists()); + + EC = FS->setCurrentWorkingDirectory("//root/bar/"); + ASSERT_FALSE(EC); + + Status = FS->status("./a"); + ASSERT_FALSE(Status.getError()); + EXPECT_TRUE(Status->exists()); + + Status = FS->status("./b"); + ASSERT_TRUE(Status.getError()); + + Status = FS->status("./c"); + ASSERT_TRUE(Status.getError()); + + EC = FS->setCurrentWorkingDirectory("//root/"); + ASSERT_FALSE(EC); + + Status = FS->status("c"); + ASSERT_FALSE(Status.getError()); + EXPECT_TRUE(Status->exists()); +} + +TEST_F(VFSFromYAMLTest, WorkingDirectoryFallthroughInvalid) { + IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem()); + Lower->addDirectory("//root/"); + Lower->addDirectory("//root/foo"); + Lower->addRegularFile("//root/foo/a"); + Lower->addRegularFile("//root/foo/b"); + Lower->addRegularFile("//root/c"); + IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString( + "{ 'use-external-names': false,\n" + " 'roots': [\n" + "{\n" + " 'type': 'directory',\n" + " 'name': '//root/',\n" + " 'contents': [ {\n" + " 'type': 'file',\n" + " 'name': 'bar/a',\n" + " 'external-contents': '//root/foo/a'\n" + " }\n" + " ]\n" + "}\n" + "]\n" + "}", + Lower); + ASSERT_TRUE(FS.get() != nullptr); + std::error_code EC = FS->setCurrentWorkingDirectory("//root/"); + ASSERT_FALSE(EC); + ASSERT_TRUE(FS.get() != nullptr); + + llvm::ErrorOr<vfs::Status> Status = FS->status("bar/a"); + ASSERT_FALSE(Status.getError()); + EXPECT_TRUE(Status->exists()); + + Status = FS->status("foo/a"); + ASSERT_TRUE(Status.getError()); +} |