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 
19 namespace llvm {
20 namespace detail {
21 ErrorHolder TakeError(Error Err);
22 
23 template <typename T> ExpectedHolder<T> TakeExpected(Expected<T> &Exp) {
24   return {TakeError(Exp.takeError()), Exp};
25 }
26 
27 template <typename T> ExpectedHolder<T> TakeExpected(Expected<T> &&Exp) {
28   return TakeExpected(Exp);
29 }
30 
31 template <typename T>
32 class ValueMatchesMono
33     : public testing::MatcherInterface<const ExpectedHolder<T> &> {
34 public:
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 
65 private:
66   testing::Matcher<T> Matcher;
67 };
68 
69 template<typename M>
70 class ValueMatchesPoly {
71 public:
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 
80 private:
81   M Matcher;
82 };
83 
84 template <typename InfoT>
85 class ErrorMatchesMono : public testing::MatcherInterface<const ErrorHolder &> {
86 public:
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 
128 private:
129   Optional<testing::Matcher<InfoT &>> Matcher;
130 };
131 
132 class ErrorMessageMatches
133     : public testing::MatcherInterface<const ErrorHolder &> {
134 public:
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 
158 private:
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 
173 MATCHER(Succeeded, "") { return arg.Success(); }
174 MATCHER(Failed, "") { return !arg.Success(); }
175 
176 template <typename InfoT>
177 testing::Matcher<const detail::ErrorHolder &> Failed() {
178   return MakeMatcher(new detail::ErrorMatchesMono<InfoT>(None));
179 }
180 
181 template <typename InfoT, typename M>
182 testing::Matcher<const detail::ErrorHolder &> Failed(M Matcher) {
183   return MakeMatcher(new detail::ErrorMatchesMono<InfoT>(
184       testing::SafeMatcherCast<InfoT &>(Matcher)));
185 }
186 
187 template <typename... M>
188 testing::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 
194 template <typename M>
195 testing::Matcher<const detail::ErrorHolder &> FailedWithMessageArray(M Matcher) {
196   return MakeMatcher(new detail::ErrorMessageMatches(Matcher));
197 }
198 
199 template <typename M>
200 detail::ValueMatchesPoly<M> HasValue(M Matcher) {
201   return detail::ValueMatchesPoly<M>(Matcher);
202 }
203 
204 } // namespace llvm
205 
206 #endif
207