Modifies handling of C++ exceptions in death tests to treat exceptions escaping them as failures.
This commit is contained in:
		@@ -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.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user