From dbd55366c8b010b558795223db6036747eb1c388 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 4 Sep 2018 17:00:34 -0400 Subject: [PATCH] Googletest export Make EXPECT_THROW print the actual exception type on the "threw the wrong exception type" case if the actual exception is a std::exception PiperOrigin-RevId: 211519873 --- .../include/gtest/internal/gtest-internal.h | 75 +++++++++++-------- googletest/test/gtest_unittest.cc | 9 +++ 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index b762f61f..60c79647 100644 --- a/googletest/include/gtest/internal/gtest-internal.h +++ b/googletest/include/gtest/internal/gtest-internal.h @@ -771,13 +771,12 @@ GTEST_API_ bool AlwaysTrue(); // Always returns false. inline bool AlwaysFalse() { return !AlwaysTrue(); } -// Helper for suppressing false warning from Clang on a const char* -// variable declared in a conditional expression always being NULL in -// the else branch. -struct GTEST_API_ ConstCharPtr { - ConstCharPtr(const char* str) : value(str) {} +// Helper for creating strings in if() statement branches. Always converts to +// true. +struct GTEST_API_ TrueString { + TrueString() {} operator bool() const { return true; } - const char* value; + std::string value; }; // A simple Linear Congruential Generator for generating random @@ -1214,31 +1213,45 @@ class NativeArray { #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ if (::testing::internal::AlwaysTrue()) { statement; } -#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::ConstCharPtr gtest_msg = "") { \ - bool gtest_caught_expected = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (expected_exception const&) { \ - gtest_caught_expected = true; \ - } \ - catch (...) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws a different type."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - if (!gtest_caught_expected) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws nothing."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ - fail(gtest_msg.value) +#define GTEST_WRONG_EXCEPTION_MESSAGE_(statement, expected_exception) \ + "Expected: " #statement " throws an exception of type " #expected_exception \ + ".\n Actual: it throws " + +// The nested try-catch block allows us to catch erroneous exceptions which +// inherit from std::exception and feed what() to the failure description. If +// there was no nested try-catch and expected_exception was std::exception, then +// this would fail to build due to two blocks both catching std::exceptions. +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::TrueString gtest_msg = \ + ::testing::internal::TrueString()) { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } catch (...) { \ + try { \ + throw; \ + } catch (const std::exception& e) { \ + gtest_msg.value = std::string(GTEST_WRONG_EXCEPTION_MESSAGE_( \ + statement, expected_expression)) + \ + e.what() + "."; \ + } catch (...) { \ + gtest_msg.value = GTEST_WRONG_EXCEPTION_MESSAGE_( \ + statement, expected_exception) "a different type."; \ + } \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \ + : fail(gtest_msg.value.c_str()) #define GTEST_TEST_NO_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index f7213fbf..3965f46b 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -4541,12 +4541,21 @@ 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."); + std::string expected = "what() arg"; + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(throw std::out_of_range(expected), bool), + expected); EXPECT_NONFATAL_FAILURE( EXPECT_THROW(ThrowNothing(), bool), "Expected: ThrowNothing() throws an exception of type bool.\n" " Actual: it throws nothing."); } +// We need to make sure always to avoid having multiple blocks which catch a +// std::exception +TEST(ExpectTest, EXPECT_THROW_STD_EXCEPTION) { + EXPECT_THROW(throw std::exception(), std::exception); +} + // Tests EXPECT_NO_THROW. TEST(ExpectTest, EXPECT_NO_THROW) { EXPECT_NO_THROW(ThrowNothing());