bool MatchAndExplain(const ExpectedHolder<T> &Holder,
testing::MatchResultListener *listener) const override {
- if (!Holder.Success)
+ if (!Holder.Success())
return false;
bool result = Matcher.MatchAndExplain(*Holder.Exp, listener);
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) \
#define ASSERT_THAT_EXPECTED(Err, Matcher) \
ASSERT_THAT(llvm::detail::TakeExpected(Err), Matcher)
-MATCHER(Succeeded, "") { return arg.Success; }
-MATCHER(Failed, "") { return !arg.Success; }
+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) {
namespace llvm {
namespace detail {
struct ErrorHolder {
- bool Success;
- std::string Message;
+ std::vector<std::shared_ptr<ErrorInfoBase>> Infos;
+
+ bool Success() const { return Infos.empty(); }
};
template <typename T> struct ExpectedHolder : public ErrorHolder {
};
inline void PrintTo(const ErrorHolder &Err, std::ostream *Out) {
- *Out << (Err.Success ? "succeeded" : "failed");
- if (!Err.Success) {
- *Out << " (" << StringRef(Err.Message).trim().str() << ")";
+ raw_os_ostream OS(*Out);
+ OS << (Err.Success() ? "succeeded" : "failed");
+ if (!Err.Success()) {
+ const char *Delim = " (";
+ for (const auto &Info : Err.Infos) {
+ OS << Delim;
+ Delim = "; ";
+ Info->log(OS);
+ }
+ OS << ")";
}
}
template <typename T>
void PrintTo(const ExpectedHolder<T> &Item, std::ostream *Out) {
- if (Item.Success) {
+ if (Item.Success()) {
*Out << "succeeded with value " << ::testing::PrintToString(*Item.Exp);
} else {
PrintTo(static_cast<const ErrorHolder &>(Item), Out);
using namespace llvm;
llvm::detail::ErrorHolder llvm::detail::TakeError(llvm::Error Err) {
- bool Succeeded = !static_cast<bool>(Err);
- std::string Message;
- if (!Succeeded)
- Message = toString(std::move(Err));
- return {Succeeded, Message};
+ std::vector<std::shared_ptr<ErrorInfoBase>> Infos;
+ handleAllErrors(std::move(Err),
+ [&Infos](std::unique_ptr<ErrorInfoBase> Info) {
+ Infos.emplace_back(std::move(Info));
+ });
+ return {std::move(Infos)};
}
EXPECT_NONFATAL_FAILURE(EXPECT_THAT_ERROR(Error::success(), Failed()),
"Expected: failed\n Actual: succeeded");
+ EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<CustomError>());
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_ERROR(Error::success(), Failed<CustomError>()),
+ "Expected: failed with Error of given type\n Actual: succeeded");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<CustomSubError>()),
+ "Error was not of given type");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_ERROR(
+ joinErrors(make_error<CustomError>(0), make_error<CustomError>(1)),
+ Failed<CustomError>()),
+ "multiple errors");
+
+ EXPECT_THAT_ERROR(
+ make_error<CustomError>(0),
+ Failed<CustomError>(testing::Property(&CustomError::getInfo, 0)));
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_ERROR(
+ make_error<CustomError>(0),
+ Failed<CustomError>(testing::Property(&CustomError::getInfo, 1))),
+ "Expected: failed with Error of given type and the error is an object "
+ "whose given property is equal to 1\n"
+ " Actual: failed (CustomError { 0})");
+
EXPECT_THAT_EXPECTED(Expected<int>(0), Succeeded());
EXPECT_NONFATAL_FAILURE(
EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)),