Modifies handling of C++ exceptions in death tests to treat exceptions escaping them as failures.
This commit is contained in:
parent
2c81010523
commit
50f4deb1cf
@ -147,6 +147,13 @@ if (gtest_build_tests)
|
||||
cxx_library(gtest_main_no_rtti "${cxx_no_rtti}"
|
||||
src/gtest-all.cc src/gtest_main.cc)
|
||||
|
||||
cxx_test_with_flags(gtest-death-test_ex_nocatch_test
|
||||
"${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0"
|
||||
gtest test/gtest-death-test_ex_test.cc)
|
||||
cxx_test_with_flags(gtest-death-test_ex_catch_test
|
||||
"${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1"
|
||||
gtest test/gtest-death-test_ex_test.cc)
|
||||
|
||||
cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}"
|
||||
gtest_main_no_rtti test/gtest_unittest.cc)
|
||||
|
||||
|
@ -39,6 +39,8 @@
|
||||
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
@ -96,8 +98,12 @@ class GTEST_API_ DeathTest {
|
||||
// test, then wait for it to complete.
|
||||
enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
|
||||
|
||||
// An enumeration of the two reasons that a test might be aborted.
|
||||
enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE };
|
||||
// An enumeration of the three reasons that a test might be aborted.
|
||||
enum AbortReason {
|
||||
TEST_ENCOUNTERED_RETURN_STATEMENT,
|
||||
TEST_THREW_EXCEPTION,
|
||||
TEST_DID_NOT_DIE
|
||||
};
|
||||
|
||||
// Assumes one of the above roles.
|
||||
virtual TestRole AssumeRole() = 0;
|
||||
@ -149,6 +155,29 @@ class DefaultDeathTestFactory : public DeathTestFactory {
|
||||
// by a signal, or exited normally with a nonzero exit code.
|
||||
GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
||||
|
||||
// Traps C++ exceptions escaping statement and reports them as test
|
||||
// failures. Note that trapping SEH exceptions is not implemented here.
|
||||
#if GTEST_HAS_EXCEPTIONS
|
||||
#define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
|
||||
try { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} catch (const ::std::exception& gtest_exception) { \
|
||||
fprintf(\
|
||||
stderr, \
|
||||
"\n%s: Caught std::exception-derived exception escaping the " \
|
||||
"death test statement. Exception message: %s\n", \
|
||||
::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \
|
||||
gtest_exception.what()); \
|
||||
fflush(stderr); \
|
||||
death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
|
||||
} catch (...) { \
|
||||
death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
|
||||
}
|
||||
#else
|
||||
#define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
|
||||
#endif
|
||||
|
||||
// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
|
||||
// ASSERT_EXIT*, and EXPECT_EXIT*.
|
||||
#define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
|
||||
@ -172,7 +201,7 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
||||
case ::testing::internal::DeathTest::EXECUTE_TEST: { \
|
||||
::testing::internal::DeathTest::ReturnSentinel \
|
||||
gtest_sentinel(gtest_dt); \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
|
||||
gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
|
||||
break; \
|
||||
} \
|
||||
|
@ -182,15 +182,19 @@ static String DeathTestThreadWarning(size_t thread_count) {
|
||||
// Flag characters for reporting a death test that did not die.
|
||||
static const char kDeathTestLived = 'L';
|
||||
static const char kDeathTestReturned = 'R';
|
||||
static const char kDeathTestThrew = 'T';
|
||||
static const char kDeathTestInternalError = 'I';
|
||||
|
||||
// An enumeration describing all of the possible ways that a death test
|
||||
// can conclude. DIED means that the process died while executing the
|
||||
// test code; LIVED means that process lived beyond the end of the test
|
||||
// code; and RETURNED means that the test statement attempted a "return,"
|
||||
// which is not allowed. IN_PROGRESS means the test has not yet
|
||||
// concluded.
|
||||
enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED };
|
||||
// An enumeration describing all of the possible ways that a death test can
|
||||
// conclude. DIED means that the process died while executing the test
|
||||
// code; LIVED means that process lived beyond the end of the test code;
|
||||
// RETURNED means that the test statement attempted to execute a return
|
||||
// statement, which is not allowed; THREW means that the test statement
|
||||
// returned control by throwing an exception. IN_PROGRESS means the test
|
||||
// has not yet concluded.
|
||||
// TODO(vladl@google.com): Unify names and possibly values for
|
||||
// AbortReason, DeathTestOutcome, and flag characters above.
|
||||
enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
|
||||
|
||||
// Routine for aborting the program which is safe to call from an
|
||||
// exec-style death test child process, in which case the error
|
||||
@ -388,6 +392,9 @@ void DeathTestImpl::ReadAndInterpretStatusByte() {
|
||||
case kDeathTestReturned:
|
||||
set_outcome(RETURNED);
|
||||
break;
|
||||
case kDeathTestThrew:
|
||||
set_outcome(THREW);
|
||||
break;
|
||||
case kDeathTestLived:
|
||||
set_outcome(LIVED);
|
||||
break;
|
||||
@ -416,7 +423,9 @@ void DeathTestImpl::Abort(AbortReason reason) {
|
||||
// it finds any data in our pipe. So, here we write a single flag byte
|
||||
// to the pipe, then exit.
|
||||
const char status_ch =
|
||||
reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
|
||||
reason == TEST_DID_NOT_DIE ? kDeathTestLived :
|
||||
reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned;
|
||||
|
||||
GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
|
||||
// We are leaking the descriptor here because on some platforms (i.e.,
|
||||
// when built as Windows DLL), destructors of global objects will still
|
||||
@ -434,8 +443,8 @@ void DeathTestImpl::Abort(AbortReason reason) {
|
||||
//
|
||||
// Private data members:
|
||||
// outcome: An enumeration describing how the death test
|
||||
// concluded: DIED, LIVED, or RETURNED. The death test fails
|
||||
// in the latter two cases.
|
||||
// concluded: DIED, LIVED, THREW, or RETURNED. The death test
|
||||
// fails in the latter three cases.
|
||||
// status: The exit status of the child process. On *nix, it is in the
|
||||
// in the format specified by wait(2). On Windows, this is the
|
||||
// value supplied to the ExitProcess() API or a numeric code
|
||||
@ -466,6 +475,10 @@ bool DeathTestImpl::Passed(bool status_ok) {
|
||||
buffer << " Result: failed to die.\n"
|
||||
<< " Error msg: " << error_message;
|
||||
break;
|
||||
case THREW:
|
||||
buffer << " Result: threw an exception.\n"
|
||||
<< " Error msg: " << error_message;
|
||||
break;
|
||||
case RETURNED:
|
||||
buffer << " Result: illegal return in test statement.\n"
|
||||
<< " Error msg: " << error_message;
|
||||
|
93
test/gtest-death-test_ex_test.cc
Normal file
93
test/gtest-death-test_ex_test.cc
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: vladl@google.com (Vlad Losev)
|
||||
//
|
||||
// Tests that verify interaction of exceptions and death tests.
|
||||
|
||||
#include "gtest/gtest-death-test.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
#if GTEST_HAS_SEH
|
||||
#include <windows.h> // For RaiseException().
|
||||
#endif
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
|
||||
#if GTEST_HAS_EXCEPTIONS
|
||||
|
||||
#include <exception> // For std::exception.
|
||||
|
||||
// Tests that death tests report thrown exceptions as failures and that the
|
||||
// exceptions do not escape death test macros.
|
||||
TEST(CxxExceptionDeathTest, ExceptionIsFailure) {
|
||||
try {
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw 1, ""), "threw an exception");
|
||||
} catch (...) { // NOLINT
|
||||
FAIL() << "An exception escaped a death test macro invocation "
|
||||
<< "with catch_exceptions "
|
||||
<< (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled");
|
||||
}
|
||||
}
|
||||
|
||||
class TestException : public std::exception {
|
||||
public:
|
||||
virtual const char* what() const throw() { return "exceptional message"; }
|
||||
};
|
||||
|
||||
TEST(CxxExceptionDeathTest, PrintsMessageForStdExceptions) {
|
||||
// Verifies that the exception message is quoted in the failure text.
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""),
|
||||
"exceptional message");
|
||||
// Verifies that the location is mentioned in the failure text.
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""),
|
||||
"gtest-death-test_ex_test.cc");
|
||||
}
|
||||
#endif // GTEST_HAS_EXCEPTIONS
|
||||
|
||||
#if GTEST_HAS_SEH
|
||||
// Tests that enabling interception of SEH exceptions with the
|
||||
// catch_exceptions flag does not interfere with SEH exceptions being
|
||||
// treated as death by death tests.
|
||||
TEST(SehExceptionDeasTest, CatchExceptionsDoesNotInterfere) {
|
||||
EXPECT_DEATH(RaiseException(42, 0x0, 0, NULL), "")
|
||||
<< "with catch_exceptions "
|
||||
<< (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled");
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
testing::GTEST_FLAG(catch_exceptions) = GTEST_ENABLE_CATCH_EXCEPTIONS_ != 0;
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
@ -538,15 +538,18 @@ TEST_F(TestForDeathTest, SingleEvaluation) {
|
||||
}
|
||||
|
||||
// Tests that run-away death tests are reported as failures.
|
||||
TEST_F(TestForDeathTest, Runaway) {
|
||||
TEST_F(TestForDeathTest, RunawayIsFailure) {
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(static_cast<void>(0), "Foo"),
|
||||
"failed to die.");
|
||||
}
|
||||
|
||||
// Tests that death tests report executing 'return' in the statement as
|
||||
// failure.
|
||||
TEST_F(TestForDeathTest, ReturnIsFailure) {
|
||||
EXPECT_FATAL_FAILURE(ASSERT_DEATH(return, "Bar"),
|
||||
"illegal return in test statement.");
|
||||
}
|
||||
|
||||
|
||||
// Tests that EXPECT_DEBUG_DEATH works as expected,
|
||||
// that is, in debug mode, it:
|
||||
// 1. Asserts on death.
|
||||
|
Loading…
Reference in New Issue
Block a user