summaryrefslogtreecommitdiffstats
path: root/llvm/unittests/Support
diff options
context:
space:
mode:
authorJonas Devlieghere <jonas@devlieghere.com>2019-10-15 17:14:24 +0000
committerJonas Devlieghere <jonas@devlieghere.com>2019-10-15 17:14:24 +0000
commit0b9981b180ef2f08d2a97cfda2fb6ca35ad5e93c (patch)
tree43455e702c7c2c9721b611272cfc2a5d092c0149 /llvm/unittests/Support
parentd3bd5b3d71ae9fc3a3a45e05d5dba6b1ecbcb2f5 (diff)
downloadbcm5719-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.cpp175
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());
+}
OpenPOWER on IntegriCloud