148 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Support/VirtualOutputBackend.h"10#include "llvm/Testing/Support/Error.h"11#include "gtest/gtest.h"12 13using namespace llvm;14using namespace llvm::vfs;15 16namespace {17 18struct MockOutputBackendData {19 int Cloned = 0;20 int FilesCreated = 0;21 std::optional<OutputConfig> LastConfig;22 unique_function<Error()> FileCreator;23};24 25struct MockOutputBackend final : public OutputBackend {26 struct MockFile final : public OutputFileImpl {27 Error keep() override { return Error::success(); }28 Error discard() override { return Error::success(); }29 raw_pwrite_stream &getOS() override { return OS; }30 raw_null_ostream OS;31 };32 33 IntrusiveRefCntPtr<OutputBackend> cloneImpl() const override {34 ++Data.Cloned;35 return const_cast<MockOutputBackend *>(this);36 }37 38 Expected<std::unique_ptr<OutputFileImpl>>39 createFileImpl(StringRef, std::optional<OutputConfig> Config) override {40 ++Data.FilesCreated;41 Data.LastConfig = Config;42 if (Data.FileCreator)43 return Data.FileCreator();44 return std::make_unique<MockFile>();45 }46 47 Expected<OutputFile>48 createAutoDiscardFile(const Twine &OutputPath,49 std::optional<OutputConfig> Config = std::nullopt) {50 return consumeDiscardOnDestroy(createFile(OutputPath, Config));51 }52 53 MockOutputBackend(MockOutputBackendData &Data) : Data(Data) {}54 MockOutputBackendData &Data;55};56 57static IntrusiveRefCntPtr<MockOutputBackend>58createMockBackend(MockOutputBackendData &Data) {59 return makeIntrusiveRefCnt<MockOutputBackend>(Data);60}61 62static Error createCustomError() {63 return createStringError(inconvertibleErrorCode(), "custom error");64}65 66TEST(VirtualOutputBackendTest, construct) {67 MockOutputBackendData Data;68 auto B = createMockBackend(Data);69 EXPECT_EQ(0, Data.Cloned);70 EXPECT_EQ(0, Data.FilesCreated);71}72 73TEST(VirtualOutputBackendTest, clone) {74 MockOutputBackendData Data;75 auto Backend = createMockBackend(Data);76 auto Clone = Backend->clone();77 EXPECT_EQ(1, Data.Cloned);78 79 // Confirm the clone matches what the mock's cloneImpl() does.80 EXPECT_EQ(Backend.get(), Clone.get());81 82 // Make another clone.83 Backend->clone();84 EXPECT_EQ(2, Data.Cloned);85}86 87TEST(VirtualOutputBackendTest, createFile) {88 MockOutputBackendData Data;89 auto Backend = createMockBackend(Data);90 91 StringRef FilePath = "dir/file";92 OutputFile F;93 EXPECT_THAT_ERROR(Backend->createFile(Twine(FilePath)).moveInto(F),94 Succeeded());95 EXPECT_EQ(1, Data.FilesCreated);96 EXPECT_EQ(FilePath, F.getPath());97 EXPECT_EQ(std::nullopt, Data.LastConfig);98 99 // Confirm OutputBackend has not installed a discard handler.100#if GTEST_HAS_DEATH_TEST101 EXPECT_DEATH(F = OutputFile(), "output not closed");102#endif103 consumeError(F.discard());104 105 // Create more files and specify configs.106 for (OutputConfig Config : {107 OutputConfig(),108 OutputConfig().setNoAtomicWrite().setDiscardOnSignal(),109 OutputConfig().setAtomicWrite().setNoDiscardOnSignal(),110 OutputConfig().setText(),111 OutputConfig().setTextWithCRLF(),112 }) {113 int CreatedAlready = Data.FilesCreated;114 EXPECT_THAT_ERROR(115 Backend->createAutoDiscardFile(Twine(FilePath), Config).takeError(),116 Succeeded());117 EXPECT_EQ(Config, Data.LastConfig);118 EXPECT_EQ(1 + CreatedAlready, Data.FilesCreated);119 }120}121 122TEST(VirtualOutputBackendTest, createFileInvalidConfigCRLF) {123 MockOutputBackendData Data;124 auto Backend = createMockBackend(Data);125 126 // Check that invalid configs don't make it to the backend.127 EXPECT_THAT_ERROR(128 Backend129 ->createAutoDiscardFile(Twine("dir/file"), OutputConfig().setCRLF())130 .takeError(),131 FailedWithMessage("dir/file: invalid config: {CRLF}"));132 EXPECT_EQ(0, Data.FilesCreated);133}134 135TEST(VirtualOutputBackendTest, createFileError) {136 MockOutputBackendData Data;137 Data.FileCreator = createCustomError;138 auto Backend = createMockBackend(Data);139 140 // Check that invalid configs don't make it to the backend.141 EXPECT_THAT_ERROR(142 Backend->createAutoDiscardFile(Twine("dir/file")).takeError(),143 FailedWithMessage("custom error"));144 EXPECT_EQ(1, Data.FilesCreated);145}146 147} // end namespace148