blob: 3adb671d977742b6d2d13efa3d08edc0de29a9f3 [file] [log] [blame]
//===- 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