From a44c6453fe3844de0efe8f490bb7a27c6f188dfd Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Tue, 21 Jun 2022 10:20:24 +0200 Subject: [llvm][vfs] Implement in-memory symlinks This patch implements symlinks for the in-memory VFS. Original author: @erik.pilkington. Depends on D117648 & D117649. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D117650 --- llvm/unittests/Support/VirtualFileSystemTest.cpp | 86 ++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'llvm/unittests/Support/VirtualFileSystemTest.cpp') diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp index e32b3d2..1e300ee 100644 --- a/llvm/unittests/Support/VirtualFileSystemTest.cpp +++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -1301,6 +1301,13 @@ TEST_F(InMemoryFileSystemTest, AddHardLinkToADirectory) { EXPECT_FALSE(FS.addHardLink(Link, Dir)); } +TEST_F(InMemoryFileSystemTest, AddHardLinkToASymlink) { + EXPECT_TRUE(FS.addFile("/file", 0, MemoryBuffer::getMemBuffer("content"))); + EXPECT_TRUE(FS.addSymbolicLink("/symlink", "/file", 0)); + EXPECT_TRUE(FS.addHardLink("/hardlink", "/symlink")); + EXPECT_EQ((*FS.getBufferForFile("/hardlink"))->getBuffer(), "content"); +} + TEST_F(InMemoryFileSystemTest, AddHardLinkFromADirectory) { StringRef Dir = "path/to/dummy/dir"; StringRef Target = "path/to/dummy/dir/target"; @@ -1351,6 +1358,85 @@ TEST_F(InMemoryFileSystemTest, UniqueID) { EXPECT_EQ(FS.status("/a")->getUniqueID(), FS2.status("/a")->getUniqueID()); } +TEST_F(InMemoryFileSystemTest, AddSymlinkToAFile) { + EXPECT_TRUE( + FS.addFile("/some/file", 0, MemoryBuffer::getMemBuffer("contents"))); + EXPECT_TRUE(FS.addSymbolicLink("/other/file/link", "/some/file", 0)); + ErrorOr Stat = FS.status("/some/file"); + EXPECT_TRUE(Stat->isRegularFile()); +} + +TEST_F(InMemoryFileSystemTest, AddSymlinkToADirectory) { + EXPECT_TRUE(FS.addSymbolicLink("/link", "/target", 0)); + EXPECT_TRUE( + FS.addFile("/target/foo.h", 0, MemoryBuffer::getMemBuffer("foo"))); + ErrorOr Stat = FS.status("/link/foo.h"); + EXPECT_TRUE(Stat); + EXPECT_EQ((*Stat).getName(), "/link/foo.h"); + EXPECT_TRUE(Stat->isRegularFile()); +} + +TEST_F(InMemoryFileSystemTest, AddSymlinkToASymlink) { + EXPECT_TRUE(FS.addSymbolicLink("/first", "/second", 0)); + EXPECT_TRUE(FS.addSymbolicLink("/second", "/third", 0)); + EXPECT_TRUE(FS.addFile("/third", 0, MemoryBuffer::getMemBuffer(""))); + ErrorOr Stat = FS.status("/first"); + EXPECT_TRUE(Stat); + EXPECT_EQ((*Stat).getName(), "/first"); + // Follow-through symlinks by default. This matches RealFileSystem's + // semantics. + EXPECT_TRUE(Stat->isRegularFile()); + Stat = FS.status("/second"); + EXPECT_TRUE(Stat); + EXPECT_EQ((*Stat).getName(), "/second"); + EXPECT_TRUE(Stat->isRegularFile()); + Stat = FS.status("/third"); + EXPECT_TRUE(Stat); + EXPECT_EQ((*Stat).getName(), "/third"); + EXPECT_TRUE(Stat->isRegularFile()); +} + +TEST_F(InMemoryFileSystemTest, AddRecursiveSymlink) { + EXPECT_TRUE(FS.addSymbolicLink("/link-a", "/link-b", 0)); + EXPECT_TRUE(FS.addSymbolicLink("/link-b", "/link-a", 0)); + ErrorOr Stat = FS.status("/link-a/foo"); + EXPECT_FALSE(Stat); + EXPECT_EQ(Stat.getError(), errc::no_such_file_or_directory); +} + +TEST_F(InMemoryFileSystemTest, DirectoryIteratorWithSymlinkToAFile) { + std::error_code EC; + + EXPECT_TRUE(FS.addFile("/file", 0, MemoryBuffer::getMemBuffer(""))); + EXPECT_TRUE(FS.addSymbolicLink("/symlink", "/file", 0)); + + vfs::directory_iterator I = FS.dir_begin("/", EC), E; + ASSERT_FALSE(EC); + + std::vector Nodes; + for (; !EC && I != E; I.increment(EC)) + Nodes.push_back(getPosixPath(std::string(I->path()))); + + EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/file", "/file")); +} + +TEST_F(InMemoryFileSystemTest, RecursiveDirectoryIteratorWithSymlinkToADir) { + std::error_code EC; + + EXPECT_TRUE(FS.addFile("/dir/file", 0, MemoryBuffer::getMemBuffer(""))); + EXPECT_TRUE(FS.addSymbolicLink("/dir_symlink", "/dir", 0)); + + vfs::recursive_directory_iterator I(FS, "/", EC), E; + ASSERT_FALSE(EC); + + std::vector Nodes; + for (; !EC && I != E; I.increment(EC)) + Nodes.push_back(getPosixPath(std::string(I->path()))); + + EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/dir", "/dir/file", "/dir", + "/dir/file")); +} + // NOTE: in the tests below, we use '//root/' as our root directory, since it is // a legal *absolute* path on Windows as well as *nix. class VFSFromYAMLTest : public ::testing::Test { -- cgit v1.1