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/Support/Error.h"
13 #include "llvm/Testing/Support/SupportHelpers.h"
14 
15 #include "gmock/gmock.h"
16 #include <ostream>
17 
18 namespace llvm {
19 namespace detail {
20 ErrorHolder TakeError(Error Err);
21 
TakeExpected(Expected<T> & Exp)22 template <typename T> ExpectedHolder<T> TakeExpected(Expected<T> &Exp) {
23   return {TakeError(Exp.takeError()), Exp};
24 }
25 
TakeExpected(Expected<T> && Exp)26 template <typename T> ExpectedHolder<T> TakeExpected(Expected<T> &&Exp) {
27   return TakeExpected(Exp);
28 }
29 
30 template <typename T>
31 class ValueMatchesMono
32     : public testing::MatcherInterface<const ExpectedHolder<T> &> {
33 public:
ValueMatchesMono(const testing::Matcher<T> & Matcher)34   explicit ValueMatchesMono(const testing::Matcher<T> &Matcher)
35       : Matcher(Matcher) {}
36 
MatchAndExplain(const ExpectedHolder<T> & Holder,testing::MatchResultListener * listener)37   bool MatchAndExplain(const ExpectedHolder<T> &Holder,
38                        testing::MatchResultListener *listener) const override {
39     if (!Holder.Success())
40       return false;
41 
42     bool result = Matcher.MatchAndExplain(*Holder.Exp, listener);
43 
44     if (result || !listener->IsInterested())
45       return result;
46     *listener << "(";
47     Matcher.DescribeNegationTo(listener->stream());
48     *listener << ")";
49     return result;
50   }
51 
DescribeTo(std::ostream * OS)52   void DescribeTo(std::ostream *OS) const override {
53     *OS << "succeeded with value (";
54     Matcher.DescribeTo(OS);
55     *OS << ")";
56   }
57 
DescribeNegationTo(std::ostream * OS)58   void DescribeNegationTo(std::ostream *OS) const override {
59     *OS << "did not succeed or value (";
60     Matcher.DescribeNegationTo(OS);
61     *OS << ")";
62   }
63 
64 private:
65   testing::Matcher<T> Matcher;
66 };
67 
68 template<typename M>
69 class ValueMatchesPoly {
70 public:
ValueMatchesPoly(const M & Matcher)71   explicit ValueMatchesPoly(const M &Matcher) : Matcher(Matcher) {}
72 
73   template <typename T>
74   operator testing::Matcher<const ExpectedHolder<T> &>() const {
75     return MakeMatcher(
76         new ValueMatchesMono<T>(testing::SafeMatcherCast<T>(Matcher)));
77   }
78 
79 private:
80   M Matcher;
81 };
82 
83 template <typename InfoT>
84 class ErrorMatchesMono : public testing::MatcherInterface<const ErrorHolder &> {
85 public:
ErrorMatchesMono(std::optional<testing::Matcher<InfoT &>> Matcher)86   explicit ErrorMatchesMono(std::optional<testing::Matcher<InfoT &>> Matcher)
87       : Matcher(std::move(Matcher)) {}
88 
MatchAndExplain(const ErrorHolder & Holder,testing::MatchResultListener * listener)89   bool MatchAndExplain(const ErrorHolder &Holder,
90                        testing::MatchResultListener *listener) const override {
91     if (Holder.Success())
92       return false;
93 
94     if (Holder.Infos.size() > 1) {
95       *listener << "multiple errors";
96       return false;
97     }
98 
99     auto &Info = *Holder.Infos[0];
100     if (!Info.isA<InfoT>()) {
101       *listener << "Error was not of given type";
102       return false;
103     }
104 
105     if (!Matcher)
106       return true;
107 
108     return Matcher->MatchAndExplain(static_cast<InfoT &>(Info), listener);
109   }
110 
DescribeTo(std::ostream * OS)111   void DescribeTo(std::ostream *OS) const override {
112     *OS << "failed with Error of given type";
113     if (Matcher) {
114       *OS << " and the error ";
115       Matcher->DescribeTo(OS);
116     }
117   }
118 
DescribeNegationTo(std::ostream * OS)119   void DescribeNegationTo(std::ostream *OS) const override {
120     *OS << "succeeded or did not fail with the error of given type";
121     if (Matcher) {
122       *OS << " or the error ";
123       Matcher->DescribeNegationTo(OS);
124     }
125   }
126 
127 private:
128   std::optional<testing::Matcher<InfoT &>> Matcher;
129 };
130 
131 class ErrorMessageMatches
132     : public testing::MatcherInterface<const ErrorHolder &> {
133 public:
ErrorMessageMatches(testing::Matcher<std::vector<std::string>> Matcher)134   explicit ErrorMessageMatches(
135       testing::Matcher<std::vector<std::string>> Matcher)
136       : Matcher(std::move(Matcher)) {}
137 
MatchAndExplain(const ErrorHolder & Holder,testing::MatchResultListener * listener)138   bool MatchAndExplain(const ErrorHolder &Holder,
139                        testing::MatchResultListener *listener) const override {
140     std::vector<std::string> Messages;
141     Messages.reserve(Holder.Infos.size());
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 
DescribeTo(std::ostream * OS)148   void DescribeTo(std::ostream *OS) const override {
149     *OS << "failed with Error whose message ";
150     Matcher.DescribeTo(OS);
151   }
152 
DescribeNegationTo(std::ostream * OS)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 /// Helper macro for checking the result of an 'Expected<T>'
169 ///
170 ///   @code{.cpp}
171 ///     // function to be tested
172 ///     Expected<int> myDivide(int A, int B);
173 ///
174 ///     TEST(myDivideTests, GoodAndBad) {
175 ///       // test good case
176 ///       // if you only care about success or failure:
177 ///       EXPECT_THAT_EXPECTED(myDivide(10, 5), Succeeded());
178 ///       // if you also care about the value:
179 ///       EXPECT_THAT_EXPECTED(myDivide(10, 5), HasValue(2));
180 ///
181 ///       // test the error case
182 ///       EXPECT_THAT_EXPECTED(myDivide(10, 0), Failed());
183 ///       // also check the error message
184 ///       EXPECT_THAT_EXPECTED(myDivide(10, 0),
185 ///           FailedWithMessage("B must not be zero!"));
186 ///     }
187 ///   @endcode
188 
189 #define EXPECT_THAT_EXPECTED(Err, Matcher)                                     \
190   EXPECT_THAT(llvm::detail::TakeExpected(Err), Matcher)
191 #define ASSERT_THAT_EXPECTED(Err, Matcher)                                     \
192   ASSERT_THAT(llvm::detail::TakeExpected(Err), Matcher)
193 
194 MATCHER(Succeeded, "") { return arg.Success(); }
195 MATCHER(Failed, "") { return !arg.Success(); }
196 
197 template <typename InfoT>
Failed()198 testing::Matcher<const detail::ErrorHolder &> Failed() {
199   return MakeMatcher(new detail::ErrorMatchesMono<InfoT>(std::nullopt));
200 }
201 
202 template <typename InfoT, typename M>
Failed(M Matcher)203 testing::Matcher<const detail::ErrorHolder &> Failed(M Matcher) {
204   return MakeMatcher(new detail::ErrorMatchesMono<InfoT>(
205       testing::SafeMatcherCast<InfoT &>(Matcher)));
206 }
207 
208 template <typename... M>
FailedWithMessage(M...Matcher)209 testing::Matcher<const detail::ErrorHolder &> FailedWithMessage(M... Matcher) {
210   static_assert(sizeof...(M) > 0);
211   return MakeMatcher(
212       new detail::ErrorMessageMatches(testing::ElementsAre(Matcher...)));
213 }
214 
215 template <typename M>
FailedWithMessageArray(M Matcher)216 testing::Matcher<const detail::ErrorHolder &> FailedWithMessageArray(M Matcher) {
217   return MakeMatcher(new detail::ErrorMessageMatches(Matcher));
218 }
219 
220 template <typename M>
HasValue(M Matcher)221 detail::ValueMatchesPoly<M> HasValue(M Matcher) {
222   return detail::ValueMatchesPoly<M>(Matcher);
223 }
224 
225 } // namespace llvm
226 
227 #endif
228