SupportHelpers.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- Testing/Support/SupportHelpers.h -----------------------------------===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_TESTING_SUPPORT_SUPPORTHELPERS_H
  14. #define LLVM_TESTING_SUPPORT_SUPPORTHELPERS_H
  15. #include "llvm/ADT/SmallString.h"
  16. #include "llvm/Support/Error.h"
  17. #include "llvm/Support/FileSystem.h"
  18. #include "llvm/Support/Path.h"
  19. #include "llvm/Support/raw_os_ostream.h"
  20. #include "gmock/gmock-matchers.h"
  21. #include "gtest/gtest-printers.h"
  22. #include <optional>
  23. #include <string>
  24. namespace llvm {
  25. namespace detail {
  26. struct ErrorHolder {
  27. std::vector<std::shared_ptr<ErrorInfoBase>> Infos;
  28. bool Success() const { return Infos.empty(); }
  29. };
  30. template <typename T> struct ExpectedHolder : public ErrorHolder {
  31. ExpectedHolder(ErrorHolder Err, Expected<T> &Exp)
  32. : ErrorHolder(std::move(Err)), Exp(Exp) {}
  33. Expected<T> &Exp;
  34. };
  35. inline void PrintTo(const ErrorHolder &Err, std::ostream *Out) {
  36. raw_os_ostream OS(*Out);
  37. OS << (Err.Success() ? "succeeded" : "failed");
  38. if (!Err.Success()) {
  39. const char *Delim = " (";
  40. for (const auto &Info : Err.Infos) {
  41. OS << Delim;
  42. Delim = "; ";
  43. Info->log(OS);
  44. }
  45. OS << ")";
  46. }
  47. }
  48. template <typename T>
  49. void PrintTo(const ExpectedHolder<T> &Item, std::ostream *Out) {
  50. if (Item.Success()) {
  51. *Out << "succeeded with value " << ::testing::PrintToString(*Item.Exp);
  52. } else {
  53. PrintTo(static_cast<const ErrorHolder &>(Item), Out);
  54. }
  55. }
  56. template <class InnerMatcher> class ValueIsMatcher {
  57. public:
  58. explicit ValueIsMatcher(InnerMatcher ValueMatcher)
  59. : ValueMatcher(ValueMatcher) {}
  60. template <class T>
  61. operator ::testing::Matcher<const std::optional<T> &>() const {
  62. return ::testing::MakeMatcher(
  63. new Impl<T>(::testing::SafeMatcherCast<T>(ValueMatcher)));
  64. }
  65. template <class T, class O = std::optional<T>>
  66. class Impl : public ::testing::MatcherInterface<const O &> {
  67. public:
  68. explicit Impl(const ::testing::Matcher<T> &ValueMatcher)
  69. : ValueMatcher(ValueMatcher) {}
  70. bool MatchAndExplain(const O &Input,
  71. testing::MatchResultListener *L) const override {
  72. return Input && ValueMatcher.MatchAndExplain(*Input, L);
  73. }
  74. void DescribeTo(std::ostream *OS) const override {
  75. *OS << "has a value that ";
  76. ValueMatcher.DescribeTo(OS);
  77. }
  78. void DescribeNegationTo(std::ostream *OS) const override {
  79. *OS << "does not have a value that ";
  80. ValueMatcher.DescribeTo(OS);
  81. }
  82. private:
  83. testing::Matcher<T> ValueMatcher;
  84. };
  85. private:
  86. InnerMatcher ValueMatcher;
  87. };
  88. } // namespace detail
  89. /// Matches an std::optional<T> with a value that conforms to an inner matcher.
  90. /// To match std::nullopt you could use Eq(std::nullopt).
  91. template <class InnerMatcher>
  92. detail::ValueIsMatcher<InnerMatcher> ValueIs(const InnerMatcher &ValueMatcher) {
  93. return detail::ValueIsMatcher<InnerMatcher>(ValueMatcher);
  94. }
  95. namespace unittest {
  96. SmallString<128> getInputFileDirectory(const char *Argv0);
  97. /// A RAII object that creates a temporary directory upon initialization and
  98. /// removes it upon destruction.
  99. class TempDir {
  100. SmallString<128> Path;
  101. public:
  102. /// Creates a managed temporary directory.
  103. ///
  104. /// @param Name The name of the directory to create.
  105. /// @param Unique If true, the directory will be created using
  106. /// llvm::sys::fs::createUniqueDirectory.
  107. explicit TempDir(StringRef Name, bool Unique = false) {
  108. std::error_code EC;
  109. if (Unique) {
  110. EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
  111. if (!EC) {
  112. // Resolve any symlinks in the new directory.
  113. std::string UnresolvedPath(Path.str());
  114. EC = llvm::sys::fs::real_path(UnresolvedPath, Path);
  115. }
  116. } else {
  117. Path = Name;
  118. EC = llvm::sys::fs::create_directory(Path);
  119. }
  120. if (EC)
  121. Path.clear();
  122. EXPECT_FALSE(EC) << EC.message();
  123. }
  124. ~TempDir() {
  125. if (!Path.empty()) {
  126. EXPECT_FALSE(llvm::sys::fs::remove_directories(Path.str()));
  127. }
  128. }
  129. TempDir(const TempDir &) = delete;
  130. TempDir &operator=(const TempDir &) = delete;
  131. TempDir(TempDir &&) = default;
  132. TempDir &operator=(TempDir &&) = default;
  133. /// The path to the temporary directory.
  134. StringRef path() const { return Path; }
  135. /// The null-terminated C string pointing to the path.
  136. const char *c_str() { return Path.c_str(); }
  137. /// Creates a new path by appending the argument to the path of the managed
  138. /// directory using the native path separator.
  139. SmallString<128> path(StringRef component) const {
  140. SmallString<128> Result(Path);
  141. SmallString<128> ComponentToAppend(component);
  142. llvm::sys::path::native(ComponentToAppend);
  143. llvm::sys::path::append(Result, Twine(ComponentToAppend));
  144. return Result;
  145. }
  146. };
  147. /// A RAII object that creates a link upon initialization and
  148. /// removes it upon destruction.
  149. ///
  150. /// The link may be a soft or a hard link, depending on the platform.
  151. class TempLink {
  152. SmallString<128> Path;
  153. public:
  154. /// Creates a managed link at path Link pointing to Target.
  155. TempLink(StringRef Target, StringRef Link) {
  156. Path = Link;
  157. std::error_code EC = sys::fs::create_link(Target, Link);
  158. if (EC)
  159. Path.clear();
  160. EXPECT_FALSE(EC);
  161. }
  162. ~TempLink() {
  163. if (!Path.empty()) {
  164. EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
  165. }
  166. }
  167. TempLink(const TempLink &) = delete;
  168. TempLink &operator=(const TempLink &) = delete;
  169. TempLink(TempLink &&) = default;
  170. TempLink &operator=(TempLink &&) = default;
  171. /// The path to the link.
  172. StringRef path() const { return Path; }
  173. };
  174. /// A RAII object that creates a file upon initialization and
  175. /// removes it upon destruction.
  176. class TempFile {
  177. SmallString<128> Path;
  178. public:
  179. /// Creates a managed file.
  180. ///
  181. /// @param Name The name of the file to create.
  182. /// @param Contents The string to write to the file.
  183. /// @param Unique If true, the file will be created using
  184. /// llvm::sys::fs::createTemporaryFile.
  185. TempFile(StringRef Name, StringRef Suffix = "", StringRef Contents = "",
  186. bool Unique = false) {
  187. std::error_code EC;
  188. int fd;
  189. if (Unique) {
  190. EC = llvm::sys::fs::createTemporaryFile(Name, Suffix, fd, Path);
  191. } else {
  192. Path = Name;
  193. if (!Suffix.empty()) {
  194. Path.append(".");
  195. Path.append(Suffix);
  196. }
  197. EC = llvm::sys::fs::openFileForWrite(Path, fd);
  198. }
  199. EXPECT_FALSE(EC);
  200. raw_fd_ostream OS(fd, /*shouldClose*/ true);
  201. OS << Contents;
  202. OS.flush();
  203. EXPECT_FALSE(OS.error());
  204. if (EC || OS.error())
  205. Path.clear();
  206. }
  207. ~TempFile() {
  208. if (!Path.empty()) {
  209. EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
  210. }
  211. }
  212. TempFile(const TempFile &) = delete;
  213. TempFile &operator=(const TempFile &) = delete;
  214. TempFile(TempFile &&) = default;
  215. TempFile &operator=(TempFile &&) = default;
  216. /// The path to the file.
  217. StringRef path() const { return Path; }
  218. };
  219. } // namespace unittest
  220. } // namespace llvm
  221. #endif
  222. #ifdef __GNUC__
  223. #pragma GCC diagnostic pop
  224. #endif