From 0d2830b283f9e883e88650d3b33ebac6b9184f16 Mon Sep 17 00:00:00 2001 From: Vladimir Goncharov Date: Fri, 19 Jun 2020 23:27:14 +0300 Subject: [PATCH] Make EXPECT_THROW and EXPECT_NO_THROW macros more informative EXPECT_THROW and EXPECT_NO_THROW will now print exception type and message when an unexpected std::exception-derived error is thrown. Fixes #2878 --- .../include/gtest/internal/gtest-internal.h | 43 +++++++++++++++-- googletest/test/gtest_unittest.cc | 47 +++++++++++++++---- 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index 028f21eb..423601f7 100644 --- a/googletest/include/gtest/internal/gtest-internal.h +++ b/googletest/include/gtest/internal/gtest-internal.h @@ -1291,9 +1291,41 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } } else /* NOLINT */ \ static_assert(true, "") // User must have a semicolon after expansion. +#if GTEST_HAS_EXCEPTIONS + +#if GTEST_HAS_RTTI + +#define GTEST_EXCEPTION_TYPE_(e) \ + ::testing::internal::GetTypeName(typeid(e)) + +#else // GTEST_HAS_RTTI + +#define GTEST_EXCEPTION_TYPE_(e) \ + std::string{"an std::exception-derived error"} + +#endif // GTEST_HAS_RTTI + +#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \ + catch (std::exception const& e) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws "; \ + gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \ + gtest_msg.value += " with description \""; \ + gtest_msg.value += e.what(); \ + gtest_msg.value += "\"."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } + +#else // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) + +#endif // GTEST_HAS_EXCEPTIONS + #define GTEST_TEST_THROW_(statement, expected_exception, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::ConstCharPtr gtest_msg = "") { \ + if (::testing::internal::TrueWithString gtest_msg{}) { \ bool gtest_caught_expected = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ @@ -1301,6 +1333,7 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } catch (expected_exception const&) { \ gtest_caught_expected = true; \ } \ + GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \ catch (...) { \ gtest_msg.value = \ "Expected: " #statement " throws an exception of type " \ @@ -1315,15 +1348,15 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ - fail(gtest_msg.value) + fail(gtest_msg.value.c_str()) #if GTEST_HAS_EXCEPTIONS #define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ catch (std::exception const& e) { \ - gtest_msg.value = ( \ - "it throws std::exception-derived exception with description: \"" \ - ); \ + gtest_msg.value = "it throws "; \ + gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \ + gtest_msg.value += " with description \""; \ gtest_msg.value += e.what(); \ gtest_msg.value += "\"."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index a6d44abd..e9f87eb9 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -3345,6 +3345,16 @@ TEST_F(SingleEvaluationTest, OtherCases) { #if GTEST_HAS_EXCEPTIONS +#if GTEST_HAS_RTTI + +#define ERROR_DESC "std::runtime_error" + +#else // GTEST_HAS_RTTI + +#define ERROR_DESC "an std::exception-derived error" + +#endif // GTEST_HAS_RTTI + void ThrowAnInteger() { throw 1; } @@ -3368,31 +3378,38 @@ TEST_F(SingleEvaluationTest, ExceptionTests) { }, bool), "throws a different type"); EXPECT_EQ(2, a_); + // failed EXPECT_THROW, throws runtime error + EXPECT_NONFATAL_FAILURE(EXPECT_THROW({ // NOLINT + a_++; + ThrowRuntimeError("A description"); + }, bool), "throws " ERROR_DESC " with description \"A description\""); + EXPECT_EQ(3, a_); + // failed EXPECT_THROW, throws nothing EXPECT_NONFATAL_FAILURE(EXPECT_THROW(a_++, bool), "throws nothing"); - EXPECT_EQ(3, a_); + EXPECT_EQ(4, a_); // successful EXPECT_NO_THROW EXPECT_NO_THROW(a_++); - EXPECT_EQ(4, a_); + EXPECT_EQ(5, a_); // failed EXPECT_NO_THROW EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW({ // NOLINT a_++; ThrowAnInteger(); }), "it throws"); - EXPECT_EQ(5, a_); + EXPECT_EQ(6, a_); // successful EXPECT_ANY_THROW EXPECT_ANY_THROW({ // NOLINT a_++; ThrowAnInteger(); }); - EXPECT_EQ(6, a_); + EXPECT_EQ(7, a_); // failed EXPECT_ANY_THROW EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(a_++), "it doesn't"); - EXPECT_EQ(7, a_); + EXPECT_EQ(8, a_); } #endif // GTEST_HAS_EXCEPTIONS @@ -3812,6 +3829,12 @@ TEST(AssertionTest, ASSERT_THROW) { ASSERT_THROW(ThrowAnInteger(), bool), "Expected: ThrowAnInteger() throws an exception of type bool.\n" " Actual: it throws a different type."); + EXPECT_FATAL_FAILURE( + ASSERT_THROW(ThrowRuntimeError("A description"), std::logic_error), + "Expected: ThrowRuntimeError(\"A description\") " + "throws an exception of type std::logic_error.\n " + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); # endif EXPECT_FATAL_FAILURE( @@ -3829,8 +3852,8 @@ TEST(AssertionTest, ASSERT_NO_THROW) { EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowRuntimeError("A description")), "Expected: ThrowRuntimeError(\"A description\") " "doesn't throw an exception.\n " - "Actual: it throws std::exception-derived exception " - "with description: \"A description\"."); + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); } // Tests ASSERT_ANY_THROW. @@ -4550,6 +4573,12 @@ TEST(ExpectTest, EXPECT_THROW) { EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool), "Expected: ThrowAnInteger() throws an exception of " "type bool.\n Actual: it throws a different type."); + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowRuntimeError("A description"), + std::logic_error), + "Expected: ThrowRuntimeError(\"A description\") " + "throws an exception of type std::logic_error.\n " + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); EXPECT_NONFATAL_FAILURE( EXPECT_THROW(ThrowNothing(), bool), "Expected: ThrowNothing() throws an exception of type bool.\n" @@ -4565,8 +4594,8 @@ TEST(ExpectTest, EXPECT_NO_THROW) { EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowRuntimeError("A description")), "Expected: ThrowRuntimeError(\"A description\") " "doesn't throw an exception.\n " - "Actual: it throws std::exception-derived exception " - "with description: \"A description\"."); + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); } // Tests EXPECT_ANY_THROW.