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/Optional.h" 13#include "llvm/ADT/SmallString.h" 14#include "llvm/Support/Error.h" 15#include "llvm/Support/raw_os_ostream.h" 16#include "gmock/gmock-matchers.h" 17#include "gtest/gtest-printers.h" 18 19#include <string> 20 21namespace llvm { 22namespace detail { 23struct ErrorHolder { 24 std::vector<std::shared_ptr<ErrorInfoBase>> Infos; 25 26 bool Success() const { return Infos.empty(); } 27}; 28 29template <typename T> struct ExpectedHolder : public ErrorHolder { 30 ExpectedHolder(ErrorHolder Err, Expected<T> &Exp) 31 : ErrorHolder(std::move(Err)), Exp(Exp) {} 32 33 Expected<T> &Exp; 34}; 35 36inline void PrintTo(const ErrorHolder &Err, std::ostream *Out) { 37 raw_os_ostream OS(*Out); 38 OS << (Err.Success() ? "succeeded" : "failed"); 39 if (!Err.Success()) { 40 const char *Delim = " ("; 41 for (const auto &Info : Err.Infos) { 42 OS << Delim; 43 Delim = "; "; 44 Info->log(OS); 45 } 46 OS << ")"; 47 } 48} 49 50template <typename T> 51void PrintTo(const ExpectedHolder<T> &Item, std::ostream *Out) { 52 if (Item.Success()) { 53 *Out << "succeeded with value " << ::testing::PrintToString(*Item.Exp); 54 } else { 55 PrintTo(static_cast<const ErrorHolder &>(Item), Out); 56 } 57} 58 59template <class InnerMatcher> class ValueIsMatcher { 60public: 61 explicit ValueIsMatcher(InnerMatcher ValueMatcher) 62 : ValueMatcher(ValueMatcher) {} 63 64 template <class T> 65 operator ::testing::Matcher<const llvm::Optional<T> &>() const { 66 return ::testing::MakeMatcher( 67 new Impl<T>(::testing::SafeMatcherCast<T>(ValueMatcher))); 68 } 69 70 template <class T> 71 class Impl : public ::testing::MatcherInterface<const llvm::Optional<T> &> { 72 public: 73 explicit Impl(const ::testing::Matcher<T> &ValueMatcher) 74 : ValueMatcher(ValueMatcher) {} 75 76 bool MatchAndExplain(const llvm::Optional<T> &Input, 77 testing::MatchResultListener *L) const override { 78 return Input && ValueMatcher.MatchAndExplain(Input.getValue(), L); 79 } 80 81 void DescribeTo(std::ostream *OS) const override { 82 *OS << "has a value that "; 83 ValueMatcher.DescribeTo(OS); 84 } 85 void DescribeNegationTo(std::ostream *OS) const override { 86 *OS << "does not have a value that "; 87 ValueMatcher.DescribeTo(OS); 88 } 89 90 private: 91 testing::Matcher<T> ValueMatcher; 92 }; 93 94private: 95 InnerMatcher ValueMatcher; 96}; 97} // namespace detail 98 99/// Matches an llvm::Optional<T> with a value that conforms to an inner matcher. 100/// To match llvm::None you could use Eq(llvm::None). 101template <class InnerMatcher> 102detail::ValueIsMatcher<InnerMatcher> ValueIs(const InnerMatcher &ValueMatcher) { 103 return detail::ValueIsMatcher<InnerMatcher>(ValueMatcher); 104} 105namespace unittest { 106SmallString<128> getInputFileDirectory(const char *Argv0); 107} // namespace unittest 108} // namespace llvm 109 110#endif 111