summaryrefslogtreecommitdiff
path: root/llvm/unittests/Support/VirtualOutputBackendTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/unittests/Support/VirtualOutputBackendTest.cpp')
-rw-r--r--llvm/unittests/Support/VirtualOutputBackendTest.cpp147
1 files changed, 147 insertions, 0 deletions
diff --git a/llvm/unittests/Support/VirtualOutputBackendTest.cpp b/llvm/unittests/Support/VirtualOutputBackendTest.cpp
new file mode 100644
index 000000000000..3adb671d9777
--- /dev/null
+++ b/llvm/unittests/Support/VirtualOutputBackendTest.cpp
@@ -0,0 +1,147 @@
+//===- VirtualOutputBackendTest.cpp - Tests for vfs::OutputBackend --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/VirtualOutputBackend.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::vfs;
+
+namespace {
+
+struct MockOutputBackendData {
+ int Cloned = 0;
+ int FilesCreated = 0;
+ std::optional<OutputConfig> LastConfig;
+ unique_function<Error()> FileCreator;
+};
+
+struct MockOutputBackend final : public OutputBackend {
+ struct MockFile final : public OutputFileImpl {
+ Error keep() override { return Error::success(); }
+ Error discard() override { return Error::success(); }
+ raw_pwrite_stream &getOS() override { return OS; }
+ raw_null_ostream OS;
+ };
+
+ IntrusiveRefCntPtr<OutputBackend> cloneImpl() const override {
+ ++Data.Cloned;
+ return const_cast<MockOutputBackend *>(this);
+ }
+
+ Expected<std::unique_ptr<OutputFileImpl>>
+ createFileImpl(StringRef, std::optional<OutputConfig> Config) override {
+ ++Data.FilesCreated;
+ Data.LastConfig = Config;
+ if (Data.FileCreator)
+ return Data.FileCreator();
+ return std::make_unique<MockFile>();
+ }
+
+ Expected<OutputFile>
+ createAutoDiscardFile(const Twine &OutputPath,
+ std::optional<OutputConfig> Config = std::nullopt) {
+ return consumeDiscardOnDestroy(createFile(OutputPath, Config));
+ }
+
+ MockOutputBackend(MockOutputBackendData &Data) : Data(Data) {}
+ MockOutputBackendData &Data;
+};
+
+static IntrusiveRefCntPtr<MockOutputBackend>
+createMockBackend(MockOutputBackendData &Data) {
+ return makeIntrusiveRefCnt<MockOutputBackend>(Data);
+}
+
+static Error createCustomError() {
+ return createStringError(inconvertibleErrorCode(), "custom error");
+}
+
+TEST(VirtualOutputBackendTest, construct) {
+ MockOutputBackendData Data;
+ auto B = createMockBackend(Data);
+ EXPECT_EQ(0, Data.Cloned);
+ EXPECT_EQ(0, Data.FilesCreated);
+}
+
+TEST(VirtualOutputBackendTest, clone) {
+ MockOutputBackendData Data;
+ auto Backend = createMockBackend(Data);
+ auto Clone = Backend->clone();
+ EXPECT_EQ(1, Data.Cloned);
+
+ // Confirm the clone matches what the mock's cloneImpl() does.
+ EXPECT_EQ(Backend.get(), Clone.get());
+
+ // Make another clone.
+ Backend->clone();
+ EXPECT_EQ(2, Data.Cloned);
+}
+
+TEST(VirtualOutputBackendTest, createFile) {
+ MockOutputBackendData Data;
+ auto Backend = createMockBackend(Data);
+
+ StringRef FilePath = "dir/file";
+ OutputFile F;
+ EXPECT_THAT_ERROR(Backend->createFile(Twine(FilePath)).moveInto(F),
+ Succeeded());
+ EXPECT_EQ(1, Data.FilesCreated);
+ EXPECT_EQ(FilePath, F.getPath());
+ EXPECT_EQ(std::nullopt, Data.LastConfig);
+
+ // Confirm OutputBackend has not installed a discard handler.
+#if GTEST_HAS_DEATH_TEST
+ EXPECT_DEATH(F = OutputFile(), "output not closed");
+#endif
+ consumeError(F.discard());
+
+ // Create more files and specify configs.
+ for (OutputConfig Config : {
+ OutputConfig(),
+ OutputConfig().setNoAtomicWrite().setDiscardOnSignal(),
+ OutputConfig().setAtomicWrite().setNoDiscardOnSignal(),
+ OutputConfig().setText(),
+ OutputConfig().setTextWithCRLF(),
+ }) {
+ int CreatedAlready = Data.FilesCreated;
+ EXPECT_THAT_ERROR(
+ Backend->createAutoDiscardFile(Twine(FilePath), Config).takeError(),
+ Succeeded());
+ EXPECT_EQ(Config, Data.LastConfig);
+ EXPECT_EQ(1 + CreatedAlready, Data.FilesCreated);
+ }
+}
+
+TEST(VirtualOutputBackendTest, createFileInvalidConfigCRLF) {
+ MockOutputBackendData Data;
+ auto Backend = createMockBackend(Data);
+
+ // Check that invalid configs don't make it to the backend.
+ EXPECT_THAT_ERROR(
+ Backend
+ ->createAutoDiscardFile(Twine("dir/file"), OutputConfig().setCRLF())
+ .takeError(),
+ FailedWithMessage("dir/file: invalid config: {CRLF}"));
+ EXPECT_EQ(0, Data.FilesCreated);
+}
+
+TEST(VirtualOutputBackendTest, createFileError) {
+ MockOutputBackendData Data;
+ Data.FileCreator = createCustomError;
+ auto Backend = createMockBackend(Data);
+
+ // Check that invalid configs don't make it to the backend.
+ EXPECT_THAT_ERROR(
+ Backend->createAutoDiscardFile(Twine("dir/file")).takeError(),
+ FailedWithMessage("custom error"));
+ EXPECT_EQ(1, Data.FilesCreated);
+}
+
+} // end namespace