| //===- llvm/Testing/Support/Error.h ---------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_TESTING_SUPPORT_ERROR_H |
| #define LLVM_TESTING_SUPPORT_ERROR_H |
| |
| #include "llvm/ADT/Optional.h" |
| #include "llvm/Support/Error.h" |
| #include "llvm/Testing/Support/SupportHelpers.h" |
| |
| #include "gmock/gmock.h" |
| #include <ostream> |
| |
| namespace llvm { |
| namespace detail { |
| ErrorHolder TakeError(Error Err); |
| |
| template <typename T> ExpectedHolder<T> TakeExpected(Expected<T> &Exp) { |
| return {TakeError(Exp.takeError()), Exp}; |
| } |
| |
| template <typename T> ExpectedHolder<T> TakeExpected(Expected<T> &&Exp) { |
| return TakeExpected(Exp); |
| } |
| |
| template <typename T> |
| class ValueMatchesMono |
| : public testing::MatcherInterface<const ExpectedHolder<T> &> { |
| public: |
| explicit ValueMatchesMono(const testing::Matcher<T> &Matcher) |
| : Matcher(Matcher) {} |
| |
| bool MatchAndExplain(const ExpectedHolder<T> &Holder, |
| testing::MatchResultListener *listener) const override { |
| if (!Holder.Success()) |
| return false; |
| |
| bool result = Matcher.MatchAndExplain(*Holder.Exp, listener); |
| |
| if (result) |
| return result; |
| *listener << "("; |
| Matcher.DescribeNegationTo(listener->stream()); |
| *listener << ")"; |
| return result; |
| } |
| |
| void DescribeTo(std::ostream *OS) const override { |
| *OS << "succeeded with value ("; |
| Matcher.DescribeTo(OS); |
| *OS << ")"; |
| } |
| |
| void DescribeNegationTo(std::ostream *OS) const override { |
| *OS << "did not succeed or value ("; |
| Matcher.DescribeNegationTo(OS); |
| *OS << ")"; |
| } |
| |
| private: |
| testing::Matcher<T> Matcher; |
| }; |
| |
| template<typename M> |
| class ValueMatchesPoly { |
| public: |
| explicit ValueMatchesPoly(const M &Matcher) : Matcher(Matcher) {} |
| |
| template <typename T> |
| operator testing::Matcher<const ExpectedHolder<T> &>() const { |
| return MakeMatcher( |
| new ValueMatchesMono<T>(testing::SafeMatcherCast<T>(Matcher))); |
| } |
| |
| private: |
| M Matcher; |
| }; |
| |
| template <typename InfoT> |
| class ErrorMatchesMono : public testing::MatcherInterface<const ErrorHolder &> { |
| public: |
| explicit ErrorMatchesMono(Optional<testing::Matcher<InfoT &>> Matcher) |
| : Matcher(std::move(Matcher)) {} |
| |
| bool MatchAndExplain(const ErrorHolder &Holder, |
| testing::MatchResultListener *listener) const override { |
| if (Holder.Success()) |
| return false; |
| |
| if (Holder.Infos.size() > 1) { |
| *listener << "multiple errors"; |
| return false; |
| } |
| |
| auto &Info = *Holder.Infos[0]; |
| if (!Info.isA<InfoT>()) { |
| *listener << "Error was not of given type"; |
| return false; |
| } |
| |
| if (!Matcher) |
| return true; |
| |
| return Matcher->MatchAndExplain(static_cast<InfoT &>(Info), listener); |
| } |
| |
| void DescribeTo(std::ostream *OS) const override { |
| *OS << "failed with Error of given type"; |
| if (Matcher) { |
| *OS << " and the error "; |
| Matcher->DescribeTo(OS); |
| } |
| } |
| |
| void DescribeNegationTo(std::ostream *OS) const override { |
| *OS << "succeeded or did not fail with the error of given type"; |
| if (Matcher) { |
| *OS << " or the error "; |
| Matcher->DescribeNegationTo(OS); |
| } |
| } |
| |
| private: |
| Optional<testing::Matcher<InfoT &>> Matcher; |
| }; |
| } // namespace detail |
| |
| #define EXPECT_THAT_ERROR(Err, Matcher) \ |
| EXPECT_THAT(llvm::detail::TakeError(Err), Matcher) |
| #define ASSERT_THAT_ERROR(Err, Matcher) \ |
| ASSERT_THAT(llvm::detail::TakeError(Err), Matcher) |
| |
| #define EXPECT_THAT_EXPECTED(Err, Matcher) \ |
| EXPECT_THAT(llvm::detail::TakeExpected(Err), Matcher) |
| #define ASSERT_THAT_EXPECTED(Err, Matcher) \ |
| ASSERT_THAT(llvm::detail::TakeExpected(Err), Matcher) |
| |
| MATCHER(Succeeded, "") { return arg.Success(); } |
| MATCHER(Failed, "") { return !arg.Success(); } |
| |
| template <typename InfoT> |
| testing::Matcher<const detail::ErrorHolder &> Failed() { |
| return MakeMatcher(new detail::ErrorMatchesMono<InfoT>(None)); |
| } |
| |
| template <typename InfoT, typename M> |
| testing::Matcher<const detail::ErrorHolder &> Failed(M Matcher) { |
| return MakeMatcher(new detail::ErrorMatchesMono<InfoT>( |
| testing::SafeMatcherCast<InfoT &>(Matcher))); |
| } |
| |
| template <typename M> |
| detail::ValueMatchesPoly<M> HasValue(M Matcher) { |
| return detail::ValueMatchesPoly<M>(Matcher); |
| } |
| |
| } // namespace llvm |
| |
| #endif |