File indexing completed on 2026-05-10 08:44:37
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLVM_TESTING_SUPPORT_SUPPORTHELPERS_H
0010 #define LLVM_TESTING_SUPPORT_SUPPORTHELPERS_H
0011
0012 #include "llvm/ADT/SmallString.h"
0013 #include "llvm/Support/Error.h"
0014 #include "llvm/Support/FileSystem.h"
0015 #include "llvm/Support/Path.h"
0016 #include "llvm/Support/raw_os_ostream.h"
0017 #include "gmock/gmock-matchers.h"
0018 #include "gtest/gtest-printers.h"
0019
0020 #include <optional>
0021 #include <string>
0022
0023 namespace llvm {
0024 namespace detail {
0025 struct ErrorHolder {
0026 std::vector<std::shared_ptr<ErrorInfoBase>> Infos;
0027
0028 bool Success() const { return Infos.empty(); }
0029 };
0030
0031 template <typename T> struct ExpectedHolder : public ErrorHolder {
0032 ExpectedHolder(ErrorHolder Err, Expected<T> &Exp)
0033 : ErrorHolder(std::move(Err)), Exp(Exp) {}
0034
0035 Expected<T> &Exp;
0036 };
0037
0038 inline void PrintTo(const ErrorHolder &Err, std::ostream *Out) {
0039 raw_os_ostream OS(*Out);
0040 OS << (Err.Success() ? "succeeded" : "failed");
0041 if (!Err.Success()) {
0042 const char *Delim = " (";
0043 for (const auto &Info : Err.Infos) {
0044 OS << Delim;
0045 Delim = "; ";
0046 Info->log(OS);
0047 }
0048 OS << ")";
0049 }
0050 }
0051
0052 template <typename T>
0053 void PrintTo(const ExpectedHolder<T> &Item, std::ostream *Out) {
0054 if (Item.Success()) {
0055 *Out << "succeeded with value " << ::testing::PrintToString(*Item.Exp);
0056 } else {
0057 PrintTo(static_cast<const ErrorHolder &>(Item), Out);
0058 }
0059 }
0060
0061 template <class InnerMatcher> class ValueIsMatcher {
0062 public:
0063 explicit ValueIsMatcher(InnerMatcher ValueMatcher)
0064 : ValueMatcher(ValueMatcher) {}
0065
0066 template <class T>
0067 operator ::testing::Matcher<const std::optional<T> &>() const {
0068 return ::testing::MakeMatcher(
0069 new Impl<T>(::testing::SafeMatcherCast<T>(ValueMatcher)));
0070 }
0071
0072 template <class T, class O = std::optional<T>>
0073 class Impl : public ::testing::MatcherInterface<const O &> {
0074 public:
0075 explicit Impl(const ::testing::Matcher<T> &ValueMatcher)
0076 : ValueMatcher(ValueMatcher) {}
0077
0078 bool MatchAndExplain(const O &Input,
0079 testing::MatchResultListener *L) const override {
0080 return Input && ValueMatcher.MatchAndExplain(*Input, L);
0081 }
0082
0083 void DescribeTo(std::ostream *OS) const override {
0084 *OS << "has a value that ";
0085 ValueMatcher.DescribeTo(OS);
0086 }
0087 void DescribeNegationTo(std::ostream *OS) const override {
0088 *OS << "does not have a value that ";
0089 ValueMatcher.DescribeTo(OS);
0090 }
0091
0092 private:
0093 testing::Matcher<T> ValueMatcher;
0094 };
0095
0096 private:
0097 InnerMatcher ValueMatcher;
0098 };
0099 }
0100
0101
0102
0103 template <class InnerMatcher>
0104 detail::ValueIsMatcher<InnerMatcher> ValueIs(const InnerMatcher &ValueMatcher) {
0105 return detail::ValueIsMatcher<InnerMatcher>(ValueMatcher);
0106 }
0107 namespace unittest {
0108
0109 SmallString<128> getInputFileDirectory(const char *Argv0);
0110
0111
0112
0113 class TempDir {
0114 SmallString<128> Path;
0115
0116 public:
0117
0118
0119
0120
0121
0122 explicit TempDir(StringRef Name, bool Unique = false) {
0123 std::error_code EC;
0124 if (Unique) {
0125 EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
0126 if (!EC) {
0127
0128 std::string UnresolvedPath(Path.str());
0129 EC = llvm::sys::fs::real_path(UnresolvedPath, Path);
0130 }
0131 } else {
0132 Path = Name;
0133 EC = llvm::sys::fs::create_directory(Path);
0134 }
0135 if (EC)
0136 Path.clear();
0137 EXPECT_FALSE(EC) << EC.message();
0138 }
0139
0140 ~TempDir() {
0141 if (!Path.empty()) {
0142 EXPECT_FALSE(llvm::sys::fs::remove_directories(Path.str()));
0143 }
0144 }
0145
0146 TempDir(const TempDir &) = delete;
0147 TempDir &operator=(const TempDir &) = delete;
0148
0149 TempDir(TempDir &&) = default;
0150 TempDir &operator=(TempDir &&) = default;
0151
0152
0153 StringRef path() const { return Path; }
0154
0155
0156 const char *c_str() { return Path.c_str(); }
0157
0158
0159
0160 SmallString<128> path(StringRef component) const {
0161 SmallString<128> Result(Path);
0162 SmallString<128> ComponentToAppend(component);
0163 llvm::sys::path::native(ComponentToAppend);
0164 llvm::sys::path::append(Result, Twine(ComponentToAppend));
0165 return Result;
0166 }
0167 };
0168
0169
0170
0171
0172
0173 class TempLink {
0174 SmallString<128> Path;
0175
0176 public:
0177
0178 TempLink(StringRef Target, StringRef Link) {
0179 Path = Link;
0180 std::error_code EC = sys::fs::create_link(Target, Link);
0181 if (EC)
0182 Path.clear();
0183 EXPECT_FALSE(EC);
0184 }
0185 ~TempLink() {
0186 if (!Path.empty()) {
0187 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
0188 }
0189 }
0190
0191 TempLink(const TempLink &) = delete;
0192 TempLink &operator=(const TempLink &) = delete;
0193
0194 TempLink(TempLink &&) = default;
0195 TempLink &operator=(TempLink &&) = default;
0196
0197
0198 StringRef path() const { return Path; }
0199 };
0200
0201
0202
0203 class TempFile {
0204 SmallString<128> Path;
0205
0206 public:
0207
0208
0209
0210
0211
0212
0213 TempFile(StringRef Name, StringRef Suffix = "", StringRef Contents = "",
0214 bool Unique = false) {
0215 std::error_code EC;
0216 int fd;
0217 if (Unique) {
0218 EC = llvm::sys::fs::createTemporaryFile(Name, Suffix, fd, Path);
0219 } else {
0220 Path = Name;
0221 if (!Suffix.empty()) {
0222 Path.append(".");
0223 Path.append(Suffix);
0224 }
0225 EC = llvm::sys::fs::openFileForWrite(Path, fd);
0226 }
0227 EXPECT_FALSE(EC);
0228 raw_fd_ostream OS(fd, true);
0229 OS << Contents;
0230 OS.flush();
0231 EXPECT_FALSE(OS.error());
0232 if (EC || OS.error())
0233 Path.clear();
0234 }
0235 ~TempFile() {
0236 if (!Path.empty()) {
0237 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
0238 }
0239 }
0240
0241 TempFile(const TempFile &) = delete;
0242 TempFile &operator=(const TempFile &) = delete;
0243
0244 TempFile(TempFile &&) = default;
0245 TempFile &operator=(TempFile &&) = default;
0246
0247
0248 StringRef path() const { return Path; }
0249 };
0250
0251 }
0252 }
0253
0254 #endif