1//===- llvm/Testing/Support/Error.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_ERROR_H
10#define LLVM_TESTING_SUPPORT_ERROR_H
11
12#include "llvm/ADT/Optional.h"
13#include "llvm/Support/Error.h"
14#include "llvm/Testing/Support/SupportHelpers.h"
15
16#include "gmock/gmock.h"
17#include <ostream>
18
19namespace llvm {
20namespace detail {
21ErrorHolder TakeError(Error Err);
22
23template <typename T> ExpectedHolder<T> TakeExpected(Expected<T> &Exp) {
24  return {TakeError(Exp.takeError()), Exp};
25}
26
27template <typename T> ExpectedHolder<T> TakeExpected(Expected<T> &&Exp) {
28  return TakeExpected(Exp);
29}
30
31template <typename T>
32class ValueMatchesMono
33    : public testing::MatcherInterface<const ExpectedHolder<T> &> {
34public:
35  explicit ValueMatchesMono(const testing::Matcher<T> &Matcher)
36      : Matcher(Matcher) {}
37
38  bool MatchAndExplain(const ExpectedHolder<T> &Holder,
39                       testing::MatchResultListener *listener) const override {
40    if (!Holder.Success())
41      return false;
42
43    bool result = Matcher.MatchAndExplain(*Holder.Exp, listener);
44
45    if (result)
46      return result;
47    *listener << "(";
48    Matcher.DescribeNegationTo(listener->stream());
49    *listener << ")";
50    return result;
51  }
52
53  void DescribeTo(std::ostream *OS) const override {
54    *OS << "succeeded with value (";
55    Matcher.DescribeTo(OS);
56    *OS << ")";
57  }
58
59  void DescribeNegationTo(std::ostream *OS) const override {
60    *OS << "did not succeed or value (";
61    Matcher.DescribeNegationTo(OS);
62    *OS << ")";
63  }
64
65private:
66  testing::Matcher<T> Matcher;
67};
68
69template<typename M>
70class ValueMatchesPoly {
71public:
72  explicit ValueMatchesPoly(const M &Matcher) : Matcher(Matcher) {}
73
74  template <typename T>
75  operator testing::Matcher<const ExpectedHolder<T> &>() const {
76    return MakeMatcher(
77        new ValueMatchesMono<T>(testing::SafeMatcherCast<T>(Matcher)));
78  }
79
80private:
81  M Matcher;
82};
83
84template <typename InfoT>
85class ErrorMatchesMono : public testing::MatcherInterface<const ErrorHolder &> {
86public:
87  explicit ErrorMatchesMono(Optional<testing::Matcher<InfoT &>> Matcher)
88      : Matcher(std::move(Matcher)) {}
89
90  bool MatchAndExplain(const ErrorHolder &Holder,
91                       testing::MatchResultListener *listener) const override {
92    if (Holder.Success())
93      return false;
94
95    if (Holder.Infos.size() > 1) {
96      *listener << "multiple errors";
97      return false;
98    }
99
100    auto &Info = *Holder.Infos[0];
101    if (!Info.isA<InfoT>()) {
102      *listener << "Error was not of given type";
103      return false;
104    }
105
106    if (!Matcher)
107      return true;
108
109    return Matcher->MatchAndExplain(static_cast<InfoT &>(Info), listener);
110  }
111
112  void DescribeTo(std::ostream *OS) const override {
113    *OS << "failed with Error of given type";
114    if (Matcher) {
115      *OS << " and the error ";
116      Matcher->DescribeTo(OS);
117    }
118  }
119
120  void DescribeNegationTo(std::ostream *OS) const override {
121    *OS << "succeeded or did not fail with the error of given type";
122    if (Matcher) {
123      *OS << " or the error ";
124      Matcher->DescribeNegationTo(OS);
125    }
126  }
127
128private:
129  Optional<testing::Matcher<InfoT &>> Matcher;
130};
131
132class ErrorMessageMatches
133    : public testing::MatcherInterface<const ErrorHolder &> {
134public:
135  explicit ErrorMessageMatches(
136      testing::Matcher<std::vector<std::string>> Matcher)
137      : Matcher(std::move(Matcher)) {}
138
139  bool MatchAndExplain(const ErrorHolder &Holder,
140                       testing::MatchResultListener *listener) const override {
141    std::vector<std::string> Messages;
142    for (const std::shared_ptr<ErrorInfoBase> &Info: Holder.Infos)
143      Messages.push_back(Info->message());
144
145    return Matcher.MatchAndExplain(Messages, listener);
146  }
147
148  void DescribeTo(std::ostream *OS) const override {
149    *OS << "failed with Error whose message ";
150    Matcher.DescribeTo(OS);
151  }
152
153  void DescribeNegationTo(std::ostream *OS) const override {
154    *OS << "failed with an Error whose message ";
155    Matcher.DescribeNegationTo(OS);
156  }
157
158private:
159  testing::Matcher<std::vector<std::string>> Matcher;
160};
161} // namespace detail
162
163#define EXPECT_THAT_ERROR(Err, Matcher)                                        \
164  EXPECT_THAT(llvm::detail::TakeError(Err), Matcher)
165#define ASSERT_THAT_ERROR(Err, Matcher)                                        \
166  ASSERT_THAT(llvm::detail::TakeError(Err), Matcher)
167
168#define EXPECT_THAT_EXPECTED(Err, Matcher)                                     \
169  EXPECT_THAT(llvm::detail::TakeExpected(Err), Matcher)
170#define ASSERT_THAT_EXPECTED(Err, Matcher)                                     \
171  ASSERT_THAT(llvm::detail::TakeExpected(Err), Matcher)
172
173MATCHER(Succeeded, "") { return arg.Success(); }
174MATCHER(Failed, "") { return !arg.Success(); }
175
176template <typename InfoT>
177testing::Matcher<const detail::ErrorHolder &> Failed() {
178  return MakeMatcher(new detail::ErrorMatchesMono<InfoT>(None));
179}
180
181template <typename InfoT, typename M>
182testing::Matcher<const detail::ErrorHolder &> Failed(M Matcher) {
183  return MakeMatcher(new detail::ErrorMatchesMono<InfoT>(
184      testing::SafeMatcherCast<InfoT &>(Matcher)));
185}
186
187template <typename... M>
188testing::Matcher<const detail::ErrorHolder &> FailedWithMessage(M... Matcher) {
189  static_assert(sizeof...(M) > 0, "");
190  return MakeMatcher(
191      new detail::ErrorMessageMatches(testing::ElementsAre(Matcher...)));
192}
193
194template <typename M>
195testing::Matcher<const detail::ErrorHolder &> FailedWithMessageArray(M Matcher) {
196  return MakeMatcher(new detail::ErrorMessageMatches(Matcher));
197}
198
199template <typename M>
200detail::ValueMatchesPoly<M> HasValue(M Matcher) {
201  return detail::ValueMatchesPoly<M>(Matcher);
202}
203
204} // namespace llvm
205
206#endif
207