diff options
author | Ben Barham <ben_barham@apple.com> | 2022-02-03 12:53:22 -0800 |
---|---|---|
committer | Keith Smiley <keithbsmiley@gmail.com> | 2022-02-03 13:10:23 -0800 |
commit | 502f14d6f2eee10d2993ed22d820f12cf52462d6 (patch) | |
tree | 6a2c0331daecbba60c480bf974dd198c3413d26f /llvm/unittests/Support/VirtualFileSystemTest.cpp | |
parent | 95d609b549bbdc3c1b7368eac427b9e6628f4ace (diff) | |
download | llvm-502f14d6f2eee10d2993ed22d820f12cf52462d6.zip llvm-502f14d6f2eee10d2993ed22d820f12cf52462d6.tar.gz llvm-502f14d6f2eee10d2993ed22d820f12cf52462d6.tar.bz2 |
[VFS] Add a "redirecting-with" field to overlays
Extend "fallthrough" to allow a third option: "fallback". Fallthrough
allows the original path to used if the redirected (or mapped) path
fails. Fallback is the reverse of this, ie. use the original path and
fallback to the mapped path otherwise.
While this result *can* be achieved today using multiple overlays, this
adds a much more intuitive option. As an example, take two directories
"A" and "B". We would like files from "A" to be used, unless they don't
exist, in which case the VFS should fallback to those in "B".
With the current fallthrough option this is possible by adding two
overlays: one mapping from A -> B and another mapping from B -> A. Since
the frontend *nests* the two RedirectingFileSystems, the result will
be that "A" is mapped to "B" and back to "A", unless it isn't in "A" in
which case it fallsthrough to "B" (or fails if it exists in neither).
Using "fallback" semantics allows a single overlay instead: one mapping
from "A" to "B" but only using that mapping if the operation in "A"
fails first.
"redirect-only" is used to represent the current "fallthrough: false"
case.
Differential Revision: https://reviews.llvm.org/D117937
Diffstat (limited to 'llvm/unittests/Support/VirtualFileSystemTest.cpp')
-rw-r--r-- | llvm/unittests/Support/VirtualFileSystemTest.cpp | 135 |
1 files changed, 134 insertions, 1 deletions
diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp index 6b191c6..657fc0a 100644 --- a/llvm/unittests/Support/VirtualFileSystemTest.cpp +++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -1910,7 +1910,25 @@ TEST_F(VFSFromYAMLTest, IllegalVFSFile) { Lower); EXPECT_EQ(nullptr, FS.get()); - EXPECT_EQ(26, NumDiagnostics); + // invalid redirect kind + FS = getFromYAMLString("{ 'redirecting-with': 'none', 'roots': [{\n" + " 'type': 'directory-remap',\n" + " 'name': '//root/A',\n" + " 'external-contents': '//root/B' }]}", + Lower); + EXPECT_EQ(nullptr, FS.get()); + + // redirect and fallthrough passed + FS = getFromYAMLString("{ 'redirecting-with': 'fallthrough',\n" + " 'fallthrough': true,\n" + " 'roots': [{\n" + " 'type': 'directory-remap',\n" + " 'name': '//root/A',\n" + " 'external-contents': '//root/B' }]}", + Lower); + EXPECT_EQ(nullptr, FS.get()); + + EXPECT_EQ(28, NumDiagnostics); } TEST_F(VFSFromYAMLTest, UseExternalName) { @@ -2710,6 +2728,121 @@ TEST_F(VFSFromYAMLTest, YAMLVFSWriterTestHandleDirs) { EXPECT_FALSE(FS->exists(_c.path("c"))); } +TEST_F(VFSFromYAMLTest, RedirectingWith) { + IntrusiveRefCntPtr<DummyFileSystem> Both(new DummyFileSystem()); + Both->addDirectory("//root/a"); + Both->addRegularFile("//root/a/f"); + Both->addDirectory("//root/b"); + Both->addRegularFile("//root/b/f"); + + IntrusiveRefCntPtr<DummyFileSystem> AOnly(new DummyFileSystem()); + AOnly->addDirectory("//root/a"); + AOnly->addRegularFile("//root/a/f"); + + IntrusiveRefCntPtr<DummyFileSystem> BOnly(new DummyFileSystem()); + BOnly->addDirectory("//root/b"); + BOnly->addRegularFile("//root/b/f"); + + auto BaseStr = std::string(" 'roots': [\n" + " {\n" + " 'type': 'directory-remap',\n" + " 'name': '//root/a',\n" + " 'external-contents': '//root/b'\n" + " }\n" + " ]\n" + "}"); + auto FallthroughStr = "{ 'redirecting-with': 'fallthrough',\n" + BaseStr; + auto FallbackStr = "{ 'redirecting-with': 'fallback',\n" + BaseStr; + auto RedirectOnlyStr = "{ 'redirecting-with': 'redirect-only',\n" + BaseStr; + + auto ExpectPath = [&](vfs::FileSystem &FS, StringRef Expected, + StringRef Message) { + auto AF = FS.openFileForRead("//root/a/f"); + ASSERT_FALSE(AF.getError()) << Message; + auto AFName = (*AF)->getName(); + ASSERT_FALSE(AFName.getError()) << Message; + EXPECT_EQ(Expected.str(), AFName.get()) << Message; + + auto AS = FS.status("//root/a/f"); + ASSERT_FALSE(AS.getError()) << Message; + EXPECT_EQ(Expected.str(), AS->getName()) << Message; + }; + + auto ExpectFailure = [&](vfs::FileSystem &FS, StringRef Message) { + EXPECT_TRUE(FS.openFileForRead("//root/a/f").getError()) << Message; + EXPECT_TRUE(FS.status("//root/a/f").getError()) << Message; + }; + + { + // `f` in both `a` and `b` + + // `fallthrough` tries `external-name` first, so should be `b` + IntrusiveRefCntPtr<vfs::FileSystem> Fallthrough = + getFromYAMLString(FallthroughStr, Both); + ASSERT_TRUE(Fallthrough.get() != nullptr); + ExpectPath(*Fallthrough, "//root/b/f", "fallthrough, both exist"); + + // `fallback` tries the original name first, so should be `a` + IntrusiveRefCntPtr<vfs::FileSystem> Fallback = + getFromYAMLString(FallbackStr, Both); + ASSERT_TRUE(Fallback.get() != nullptr); + ExpectPath(*Fallback, "//root/a/f", "fallback, both exist"); + + // `redirect-only` is the same as `fallthrough` but doesn't try the + // original on failure, so no change here (ie. `b`) + IntrusiveRefCntPtr<vfs::FileSystem> Redirect = + getFromYAMLString(RedirectOnlyStr, Both); + ASSERT_TRUE(Redirect.get() != nullptr); + ExpectPath(*Redirect, "//root/b/f", "redirect-only, both exist"); + } + + { + // `f` in `a` only + + // Fallthrough to the original path, `a` + IntrusiveRefCntPtr<vfs::FileSystem> Fallthrough = + getFromYAMLString(FallthroughStr, AOnly); + ASSERT_TRUE(Fallthrough.get() != nullptr); + ExpectPath(*Fallthrough, "//root/a/f", "fallthrough, a only"); + + // Original first, so still `a` + IntrusiveRefCntPtr<vfs::FileSystem> Fallback = + getFromYAMLString(FallbackStr, AOnly); + ASSERT_TRUE(Fallback.get() != nullptr); + ExpectPath(*Fallback, "//root/a/f", "fallback, a only"); + + // Fails since no fallthrough + IntrusiveRefCntPtr<vfs::FileSystem> Redirect = + getFromYAMLString(RedirectOnlyStr, AOnly); + ASSERT_TRUE(Redirect.get() != nullptr); + ExpectFailure(*Redirect, "redirect-only, a only"); + } + + { + // `f` in `b` only + + // Tries `b` first (no fallthrough) + IntrusiveRefCntPtr<vfs::FileSystem> Fallthrough = + getFromYAMLString(FallthroughStr, BOnly); + ASSERT_TRUE(Fallthrough.get() != nullptr); + ExpectPath(*Fallthrough, "//root/b/f", "fallthrough, b only"); + + // Tries original first but then fallsback to `b` + IntrusiveRefCntPtr<vfs::FileSystem> Fallback = + getFromYAMLString(FallbackStr, BOnly); + ASSERT_TRUE(Fallback.get() != nullptr); + ExpectPath(*Fallback, "//root/b/f", "fallback, b only"); + + // Redirect exists, so uses it (`b`) + IntrusiveRefCntPtr<vfs::FileSystem> Redirect = + getFromYAMLString(RedirectOnlyStr, BOnly); + ASSERT_TRUE(Redirect.get() != nullptr); + ExpectPath(*Redirect, "//root/b/f", "redirect-only, b only"); + } + + EXPECT_EQ(0, NumDiagnostics); +} + TEST(VFSFromRemappedFilesTest, Basic) { IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS = new vfs::InMemoryFileSystem; |