diff options
-rw-r--r-- | llvm/include/llvm/Testing/Support/Error.h | 64 | ||||
-rw-r--r-- | llvm/include/llvm/Testing/Support/SupportHelpers.h | 20 | ||||
-rw-r--r-- | llvm/lib/Testing/Support/Error.cpp | 11 | ||||
-rw-r--r-- | llvm/unittests/Support/ErrorTest.cpp | 24 |
4 files changed, 105 insertions, 14 deletions
diff --git a/llvm/include/llvm/Testing/Support/Error.h b/llvm/include/llvm/Testing/Support/Error.h index 50889b9c66f..9f0237a0946 100644 --- a/llvm/include/llvm/Testing/Support/Error.h +++ b/llvm/include/llvm/Testing/Support/Error.h @@ -38,7 +38,7 @@ public: 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); @@ -82,6 +82,53 @@ 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) \ @@ -94,8 +141,19 @@ private: #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) { diff --git a/llvm/include/llvm/Testing/Support/SupportHelpers.h b/llvm/include/llvm/Testing/Support/SupportHelpers.h index d7f0c7142b2..96264ac81dc 100644 --- a/llvm/include/llvm/Testing/Support/SupportHelpers.h +++ b/llvm/include/llvm/Testing/Support/SupportHelpers.h @@ -17,8 +17,9 @@ 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 { @@ -29,15 +30,22 @@ 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); diff --git a/llvm/lib/Testing/Support/Error.cpp b/llvm/lib/Testing/Support/Error.cpp index ce0da44da40..5692cdfcdf7 100644 --- a/llvm/lib/Testing/Support/Error.cpp +++ b/llvm/lib/Testing/Support/Error.cpp @@ -14,9 +14,10 @@ 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)}; } diff --git a/llvm/unittests/Support/ErrorTest.cpp b/llvm/unittests/Support/ErrorTest.cpp index 2629e640f79..d03db26df39 100644 --- a/llvm/unittests/Support/ErrorTest.cpp +++ b/llvm/unittests/Support/ErrorTest.cpp @@ -726,6 +726,30 @@ TEST(Error, ErrorMatchers) { 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)), |