Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

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