diff options
Diffstat (limited to 'utils/unittest/googletest/gtest.cc')
-rw-r--r-- | utils/unittest/googletest/gtest.cc | 1132 |
1 files changed, 661 insertions, 471 deletions
diff --git a/utils/unittest/googletest/gtest.cc b/utils/unittest/googletest/gtest.cc index 9aa5441149..7624497411 100644 --- a/utils/unittest/googletest/gtest.cc +++ b/utils/unittest/googletest/gtest.cc @@ -31,8 +31,8 @@ // // The Google C++ Testing Framework (Google Test) -#include <gtest/gtest.h> -#include <gtest/gtest-spi.h> +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" #include <ctype.h> #include <math.h> @@ -43,7 +43,7 @@ #include <wctype.h> #include <algorithm> -#include <ostream> +#include <ostream> // NOLINT #include <sstream> #include <vector> @@ -51,72 +51,76 @@ // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). -#define GTEST_HAS_GETTIMEOFDAY_ 1 +# define GTEST_HAS_GETTIMEOFDAY_ 1 -#include <fcntl.h> -#include <limits.h> -#include <sched.h> +# include <fcntl.h> // NOLINT +# include <limits.h> // NOLINT +# include <sched.h> // NOLINT // Declares vsnprintf(). This header is not available on Windows. -#include <strings.h> -#include <sys/mman.h> -#include <sys/time.h> -#include <unistd.h> -#include <string> -#include <vector> +# include <strings.h> // NOLINT +# include <sys/mman.h> // NOLINT +# include <sys/time.h> // NOLINT +# include <unistd.h> // NOLINT +# include <string> #elif GTEST_OS_SYMBIAN -#define GTEST_HAS_GETTIMEOFDAY_ 1 -#include <sys/time.h> // NOLINT +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include <sys/time.h> // NOLINT #elif GTEST_OS_ZOS -#define GTEST_HAS_GETTIMEOFDAY_ 1 -#include <sys/time.h> // NOLINT +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include <sys/time.h> // NOLINT // On z/OS we additionally need strings.h for strcasecmp. -#include <strings.h> // NOLINT +# include <strings.h> // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. -#include <windows.h> // NOLINT +# include <windows.h> // NOLINT #elif GTEST_OS_WINDOWS // We are on Windows proper. -#include <io.h> // NOLINT -#include <sys/timeb.h> // NOLINT -#include <sys/types.h> // NOLINT -#include <sys/stat.h> // NOLINT +# include <io.h> // NOLINT +# include <sys/timeb.h> // NOLINT +# include <sys/types.h> // NOLINT +# include <sys/stat.h> // NOLINT -#if GTEST_OS_WINDOWS_MINGW +# if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). // TODO(kenton@google.com): There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. -#define GTEST_HAS_GETTIMEOFDAY_ 1 -#include <sys/time.h> // NOLINT -#endif // GTEST_OS_WINDOWS_MINGW +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include <sys/time.h> // NOLINT +# endif // GTEST_OS_WINDOWS_MINGW // cpplint thinks that the header is already included, so we want to // silence it. -#include <windows.h> // NOLINT +# include <windows.h> // NOLINT #else // Assume other platforms have gettimeofday(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). -#define GTEST_HAS_GETTIMEOFDAY_ 1 +# define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to // silence it. -#include <sys/time.h> // NOLINT -#include <unistd.h> // NOLINT +# include <sys/time.h> // NOLINT +# include <unistd.h> // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS -#include <stdexcept> +# include <stdexcept> +#endif + +#if GTEST_CAN_STREAM_RESULTS_ +# include <arpa/inet.h> // NOLINT +# include <netdb.h> // NOLINT #endif // Indicates that this translation unit is part of Google Test's @@ -129,7 +133,7 @@ #undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS -#define vsnprintf _vsnprintf +# define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS namespace testing { @@ -187,7 +191,7 @@ GTEST_DEFINE_bool_( GTEST_DEFINE_bool_( catch_exceptions, - internal::BoolFromGTestEnv("catch_exceptions", false), + internal::BoolFromGTestEnv("catch_exceptions", true), "True iff " GTEST_NAME_ " should catch exceptions and treat them as test failures."); @@ -258,6 +262,13 @@ GTEST_DEFINE_int32_( "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); +GTEST_DEFINE_string_( + stream_result_to, + internal::StringFromGTestEnv("stream_result_to", ""), + "This flag specifies the host name and the port number on which to stream " + "test results. Example: \"localhost:555\". The flag is effective only on " + "Linux."); + GTEST_DEFINE_bool_( throw_on_failure, internal::BoolFromGTestEnv("throw_on_failure", false), @@ -490,20 +501,33 @@ bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, !MatchesFilter(full_name, negative.c_str())); } -#if GTEST_OS_WINDOWS +#if GTEST_HAS_SEH // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { - // Google Test should handle an exception if: + // Google Test should handle a SEH exception if: // 1. the user wants it to, AND - // 2. this is not a breakpoint exception. - return (GTEST_FLAG(catch_exceptions) && - exception_code != EXCEPTION_BREAKPOINT) ? - EXCEPTION_EXECUTE_HANDLER : - EXCEPTION_CONTINUE_SEARCH; + // 2. this is not a breakpoint exception, AND + // 3. this is not a C++ exception (VC++ implements them via SEH, + // apparently). + // + // SEH exception code for C++ exceptions. + // (see http://support.microsoft.com/kb/185294 for more information). + const DWORD kCxxExceptionCode = 0xe06d7363; + + bool should_handle = true; + + if (!GTEST_FLAG(catch_exceptions)) + should_handle = false; + else if (exception_code == EXCEPTION_BREAKPOINT) + should_handle = false; + else if (exception_code == kCxxExceptionCode) + should_handle = false; + + return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } -#endif // GTEST_OS_WINDOWS +#endif // GTEST_HAS_SEH } // namespace internal @@ -583,7 +607,7 @@ AssertionResult HasOneFailure(const char* /* results_expr */, const char* /* substr_expr */, const TestPartResultArray& results, TestPartResult::Type type, - const char* substr) { + const string& substr) { const String expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); @@ -594,23 +618,21 @@ AssertionResult HasOneFailure(const char* /* results_expr */, for (int i = 0; i < results.size(); i++) { msg << "\n" << results.GetTestPartResult(i); } - return AssertionFailure(msg); + return AssertionFailure() << msg; } const TestPartResult& r = results.GetTestPartResult(0); if (r.type() != type) { - msg << "Expected: " << expected << "\n" - << " Actual:\n" - << r; - return AssertionFailure(msg); + return AssertionFailure() << "Expected: " << expected << "\n" + << " Actual:\n" + << r; } - if (strstr(r.message(), substr) == NULL) { - msg << "Expected: " << expected << " containing \"" - << substr << "\"\n" - << " Actual:\n" - << r; - return AssertionFailure(msg); + if (strstr(r.message(), substr.c_str()) == NULL) { + return AssertionFailure() << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; } return AssertionSuccess(); @@ -622,7 +644,7 @@ AssertionResult HasOneFailure(const char* /* results_expr */, SingleFailureChecker:: SingleFailureChecker( const TestPartResultArray* results, TestPartResult::Type type, - const char* substr) + const string& substr) : results_(results), type_(type), substr_(substr) {} @@ -632,7 +654,7 @@ SingleFailureChecker:: SingleFailureChecker( // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. SingleFailureChecker::~SingleFailureChecker() { - EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str()); + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); } DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( @@ -764,25 +786,30 @@ TimeInMillis GetTimeInMillis() { return 0; #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; -#ifdef _MSC_VER + +# ifdef _MSC_VER + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. // TODO(kenton@google.com): Use GetTickCount()? Or use // SystemTimeToFileTime() -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. _ftime64(&now); -#pragma warning(pop) // Restores the warning state. -#else +# pragma warning(pop) // Restores the warning state. +# else + _ftime64(&now); -#endif // _MSC_VER + +# endif // _MSC_VER + return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, NULL); return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000; #else -#error "Don't know how to get the current time on your system." +# error "Don't know how to get the current time on your system." #endif } @@ -918,55 +945,13 @@ Message& Message::operator <<(const ::wstring& wstr) { } #endif // GTEST_HAS_GLOBAL_WSTRING -namespace internal { - -// Formats a value to be used in a failure message. - -// For a char value, we print it as a C++ char literal and as an -// unsigned integer (both in decimal and in hexadecimal). -String FormatForFailureMessage(char ch) { - const unsigned int ch_as_uint = ch; - // A String object cannot contain '\0', so we print "\\0" when ch is - // '\0'. - return String::Format("'%s' (%u, 0x%X)", - ch ? String::Format("%c", ch).c_str() : "\\0", - ch_as_uint, ch_as_uint); -} - -// For a wchar_t value, we print it as a C++ wchar_t literal and as an -// unsigned integer (both in decimal and in hexidecimal). -String FormatForFailureMessage(wchar_t wchar) { - // The C++ standard doesn't specify the exact size of the wchar_t - // type. It just says that it shall have the same size as another - // integral type, called its underlying type. - // - // Therefore, in order to print a wchar_t value in the numeric form, - // we first convert it to the largest integral type (UInt64) and - // then print the converted value. - // - // We use streaming to print the value as "%llu" doesn't work - // correctly with MSVC 7.1. - const UInt64 wchar_as_uint64 = wchar; - Message msg; - // A String object cannot contain '\0', so we print "\\0" when wchar is - // L'\0'. - char buffer[32]; // CodePointToUtf8 requires a buffer that big. - msg << "L'" - << (wchar ? CodePointToUtf8(static_cast<UInt32>(wchar), buffer) : "\\0") - << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16) - << wchar_as_uint64 << ")"; - return msg.GetString(); -} - -} // namespace internal - // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), message_(other.message_.get() != NULL ? - new internal::String(*other.message_) : - static_cast<internal::String*>(NULL)) { + new ::std::string(*other.message_) : + static_cast< ::std::string*>(NULL)) { } // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. @@ -1029,7 +1014,7 @@ AssertionResult EqFailure(const char* expected_expression, msg << "\nWhich is: " << expected_value; } - return AssertionFailure(msg); + return AssertionFailure() << msg; } // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. @@ -1059,13 +1044,12 @@ AssertionResult DoubleNearPredFormat(const char* expr1, // TODO(wan): do not print the value of an expression if it's // already a literal. - Message msg; - msg << "The difference between " << expr1 << " and " << expr2 + return AssertionFailure() + << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" << expr1 << " evaluates to " << val1 << ",\n" << expr2 << " evaluates to " << val2 << ", and\n" << abs_error_expr << " evaluates to " << abs_error << "."; - return AssertionFailure(msg); } @@ -1090,20 +1074,18 @@ AssertionResult FloatingPointLE(const char* expr1, // val2 is NaN, as the IEEE floating-point standard requires that // any predicate involving a NaN must return false. - StrStream val1_ss; + ::std::stringstream val1_ss; val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2) << val1; - StrStream val2_ss; + ::std::stringstream val2_ss; val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2) << val2; - Message msg; - msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" - << " Actual: " << StrStreamToString(&val1_ss) << " vs " - << StrStreamToString(&val2_ss); - - return AssertionFailure(msg); + return AssertionFailure() + << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StringStreamToString(&val1_ss) << " vs " + << StringStreamToString(&val2_ss); } } // namespace internal @@ -1150,11 +1132,10 @@ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ - Message msg;\ - msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ - return AssertionFailure(msg);\ }\ } @@ -1216,11 +1197,9 @@ AssertionResult CmpHelperSTRNE(const char* s1_expression, if (!String::CStringEquals(s1, s2)) { return AssertionSuccess(); } else { - Message msg; - msg << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; - return AssertionFailure(msg); + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; } } @@ -1232,11 +1211,10 @@ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, if (!String::CaseInsensitiveCStringEquals(s1, s2)) { return AssertionSuccess(); } else { - Message msg; - msg << "Expected: (" << s1_expression << ") != (" + return AssertionFailure() + << "Expected: (" << s1_expression << ") != (" << s2_expression << ") (ignoring case), actual: \"" << s1 << "\" vs \"" << s2 << "\""; - return AssertionFailure(msg); } } @@ -1285,13 +1263,12 @@ AssertionResult IsSubstringImpl( const bool is_wide_string = sizeof(needle[0]) > 1; const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; - return AssertionFailure( - Message() + return AssertionFailure() << "Value of: " << needle_expr << "\n" << " Actual: " << begin_string_quote << needle << "\"\n" << "Expected: " << (expected_to_be_substring ? "" : "not ") << "a substring of " << haystack_expr << "\n" - << "Which is: " << begin_string_quote << haystack << "\""); + << "Which is: " << begin_string_quote << haystack << "\""; } } // namespace @@ -1360,10 +1337,13 @@ namespace { AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT -#if GTEST_OS_WINDOWS_MOBILE +# if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't support FormatMessage. const char error_text[] = ""; -#else + +# else + // Looks up the human-readable system message for the HRESULT code // and since we're not passing any params to FormatMessage, we don't // want inserts expanded. @@ -1380,18 +1360,17 @@ AssertionResult HRESULTFailureHelper(const char* expr, kBufSize, // buf size NULL); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing cr-lf) - for (; message_length && isspace(error_text[message_length - 1]); + for (; message_length && IsSpace(error_text[message_length - 1]); --message_length) { error_text[message_length - 1] = '\0'; } -#endif // GTEST_OS_WINDOWS_MOBILE + +# endif // GTEST_OS_WINDOWS_MOBILE const String error_hex(String::Format("0x%08X ", hr)); - Message msg; - msg << "Expected: " << expr << " " << expected << ".\n" + return ::testing::AssertionFailure() + << "Expected: " << expr << " " << expected << ".\n" << " Actual: " << error_hex << error_text << "\n"; - - return ::testing::AssertionFailure(msg); } } // namespace @@ -1526,7 +1505,7 @@ String WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) num_chars = static_cast<int>(wcslen(str)); - StrStream stream; + ::std::stringstream stream; for (int i = 0; i < num_chars; ++i) { UInt32 unicode_code_point; @@ -1543,7 +1522,7 @@ String WideStringToUtf8(const wchar_t* str, int num_chars) { char buffer[32]; // CodePointToUtf8 requires a buffer this big. stream << CodePointToUtf8(unicode_code_point, buffer); } - return StrStreamToString(&stream); + return StringStreamToString(&stream); } // Converts a wide C string to a String using the UTF-8 encoding. @@ -1602,12 +1581,10 @@ AssertionResult CmpHelperSTRNE(const char* s1_expression, return AssertionSuccess(); } - Message msg; - msg << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: " - << String::ShowWideCStringQuoted(s1) - << " vs " << String::ShowWideCStringQuoted(s2); - return AssertionFailure(msg); + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << String::ShowWideCStringQuoted(s1) + << " vs " << String::ShowWideCStringQuoted(s2); } // Compares two C strings, ignoring case. Returns true iff they have @@ -1638,17 +1615,17 @@ bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { // current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { - if ( lhs == NULL ) return rhs == NULL; + if (lhs == NULL) return rhs == NULL; - if ( rhs == NULL ) return false; + if (rhs == NULL) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; -#elif GTEST_OS_LINUX +#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID return wcscasecmp(lhs, rhs) == 0; #else - // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes - // may not define it either. + // Android, Mac OS X and Cygwin don't define wcscasecmp. + // Other unknown OSes may not define it either. wint_t left, right; do { left = towlower(*lhs++); @@ -1730,10 +1707,12 @@ String String::Format(const char * format, ...) { // MSVC 8 deprecates vsnprintf(), so we want to suppress warning // 4996 (deprecated function) there. #ifdef _MSC_VER // We are using MSVC. -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + const int size = vsnprintf(buffer, kBufferSize, format, args); -#pragma warning(pop) // Restores the warning state. + +# pragma warning(pop) // Restores the warning state. #else // We are not using MSVC. const int size = vsnprintf(buffer, kBufferSize, format, args); #endif // _MSC_VER @@ -1751,16 +1730,16 @@ String String::Format(const char * format, ...) { } } -// Converts the buffer in a StrStream to a String, converting NUL +// Converts the buffer in a stringstream to a String, converting NUL // bytes to "\\0" along the way. -String StrStreamToString(StrStream* ss) { +String StringStreamToString(::std::stringstream* ss) { const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); - // We need to use a helper StrStream to do this transformation + // We need to use a helper stringstream to do this transformation // because String doesn't support push_back(). - StrStream helper; + ::std::stringstream helper; for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { helper << "\\0"; // Replaces NUL with "\\0"; @@ -1964,22 +1943,6 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type, } // namespace internal -#if GTEST_HAS_SEH -// We are on Windows with SEH. - -// Adds an "exception thrown" fatal failure to the current test. -static void AddExceptionThrownFailure(DWORD exception_code, - const char* location) { - Message message; - message << "Exception thrown with code 0x" << std::setbase(16) << - exception_code << std::setbase(10) << " in " << location << "."; - - internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, - message.GetString()); -} - -#endif // GTEST_HAS_SEH - // Google Test requires all tests in the same test case to use the same test // fixture class. This function checks if the current test has the // same fixture class as the first test in the current test case. If @@ -1990,15 +1953,13 @@ bool Test::HasSameFixtureClass() { const TestCase* const test_case = impl->current_test_case(); // Info about the first test in the current test case. - const internal::TestInfoImpl* const first_test_info = - test_case->test_info_list()[0]->impl(); - const internal::TypeId first_fixture_id = first_test_info->fixture_class_id(); + const TestInfo* const first_test_info = test_case->test_info_list()[0]; + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; const char* const first_test_name = first_test_info->name(); // Info about the current test. - const internal::TestInfoImpl* const this_test_info = - impl->current_test_info()->impl(); - const internal::TypeId this_fixture_id = this_test_info->fixture_class_id(); + const TestInfo* const this_test_info = impl->current_test_info(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; const char* const this_test_name = this_test_info->name(); if (this_fixture_id != first_fixture_id) { @@ -2048,62 +2009,167 @@ bool Test::HasSameFixtureClass() { return true; } -// Runs the test and updates the test result. -void Test::Run() { - if (!HasSameFixtureClass()) return; +#if GTEST_HAS_SEH - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); +// Adds an "exception thrown" fatal failure to the current test. This +// function returns its result via an output parameter pointer because VC++ +// prohibits creation of objects with destructors on stack in functions +// using __try (see error C2712). +static internal::String* FormatSehExceptionMessage(DWORD exception_code, + const char* location) { + Message message; + message << "SEH exception with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " thrown in " << location << "."; + + return new internal::String(message.GetString()); +} + +#endif // GTEST_HAS_SEH + +#if GTEST_HAS_EXCEPTIONS + +// Adds an "exception thrown" fatal failure to the current test. +static internal::String FormatCxxExceptionMessage(const char* description, + const char* location) { + Message message; + if (description != NULL) { + message << "C++ exception with description \"" << description << "\""; + } else { + message << "Unknown C++ exception"; + } + message << " thrown in " << location << "."; + + return message.GetString(); +} + +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result); + +// A failed Google Test assertion will throw an exception of this type when +// GTEST_FLAG(throw_on_failure) is true (if exceptions are enabled). We +// derive it from std::runtime_error, which is for errors presumably +// detectable only at run time. Since std::runtime_error inherits from +// std::exception, many testing frameworks know how to extract and print the +// message inside it. +class GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} +}; +#endif // GTEST_HAS_EXCEPTIONS + +namespace internal { +// We put these helper functions in the internal namespace as IBM's xlC +// compiler rejects the code if they were declared static. + +// Runs the given method and handles SEH exceptions it throws, when +// SEH is supported; returns the 0-value for type Result in case of an +// SEH exception. (Microsoft compilers cannot handle SEH and C++ +// exceptions in the same function. Therefore, we provide a separate +// wrapper function for handling SEH exceptions.) +template <class T, typename Result> +Result HandleSehExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { #if GTEST_HAS_SEH - // Catch SEH-style exceptions. - impl->os_stack_trace_getter()->UponLeavingGTest(); __try { - SetUp(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + return (object->*method)(); + } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT GetExceptionCode())) { - AddExceptionThrownFailure(GetExceptionCode(), "SetUp()"); + // We create the exception message on the heap because VC++ prohibits + // creation of objects with destructors on stack in functions using __try + // (see error C2712). + internal::String* exception_message = FormatSehExceptionMessage( + GetExceptionCode(), location); + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, + *exception_message); + delete exception_message; + return static_cast<Result>(0); } +#else + (void)location; + return (object->*method)(); +#endif // GTEST_HAS_SEH +} - // We will run the test only if SetUp() had no fatal failure. - if (!HasFatalFailure()) { - impl->os_stack_trace_getter()->UponLeavingGTest(); - __try { - TestBody(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( - GetExceptionCode())) { - AddExceptionThrownFailure(GetExceptionCode(), "the test body"); +// Runs the given method and catches and reports C++ and/or SEH-style +// exceptions, if they are supported; returns the 0-value for type +// Result in case of an SEH exception. +template <class T, typename Result> +Result HandleExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { + // NOTE: The user code can affect the way in which Google Test handles + // exceptions by setting GTEST_FLAG(catch_exceptions), but only before + // RUN_ALL_TESTS() starts. It is technically possible to check the flag + // after the exception is caught and either report or re-throw the + // exception based on the flag's value: + // + // try { + // // Perform the test method. + // } catch (...) { + // if (GTEST_FLAG(catch_exceptions)) + // // Report the exception as failure. + // else + // throw; // Re-throws the original exception. + // } + // + // However, the purpose of this flag is to allow the program to drop into + // the debugger when the exception is thrown. On most platforms, once the + // control enters the catch block, the exception origin information is + // lost and the debugger will stop the program at the point of the + // re-throw in this function -- instead of at the point of the original + // throw statement in the code under test. For this reason, we perform + // the check early, sacrificing the ability to affect Google Test's + // exception handling in the method where the exception is thrown. + if (internal::GetUnitTestImpl()->catch_exceptions()) { +#if GTEST_HAS_EXCEPTIONS + try { + return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const GoogleTestFailureException&) { // NOLINT + // This exception doesn't originate in code under test. It makes no + // sense to report it as a test failure. + throw; + } catch (const std::exception& e) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(e.what(), location)); + } catch (...) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(NULL, location)); } + return static_cast<Result>(0); +#else + return HandleSehExceptionsInMethodIfSupported(object, method, location); +#endif // GTEST_HAS_EXCEPTIONS + } else { + return (object->*method)(); } +} - // However, we want to clean up as much as possible. Hence we will - // always call TearDown(), even if SetUp() or the test body has - // failed. - impl->os_stack_trace_getter()->UponLeavingGTest(); - __try { - TearDown(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( - GetExceptionCode())) { - AddExceptionThrownFailure(GetExceptionCode(), "TearDown()"); - } +} // namespace internal -#else // We are on a compiler or platform that doesn't support SEH. - impl->os_stack_trace_getter()->UponLeavingGTest(); - SetUp(); +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); // We will run the test only if SetUp() was successful. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); - TestBody(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TestBody, "the test body"); } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); - TearDown(); -#endif // GTEST_HAS_SEH + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TearDown, "TearDown()"); } - // Returns true iff the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); @@ -2118,22 +2184,28 @@ bool Test::HasNonfatalFailure() { // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory -// object via impl_. +// object. +// TODO(vladl@google.com): Make a_test_case_name and a_name const string&'s +// to signify they cannot be NULLs. TestInfo::TestInfo(const char* a_test_case_name, const char* a_name, - const char* a_test_case_comment, - const char* a_comment, + const char* a_type_param, + const char* a_value_param, internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory) { - impl_ = new internal::TestInfoImpl(this, a_test_case_name, a_name, - a_test_case_comment, a_comment, - fixture_class_id, factory); -} + internal::TestFactoryBase* factory) + : test_case_name_(a_test_case_name), + name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + value_param_(a_value_param ? new std::string(a_value_param) : NULL), + fixture_class_id_(fixture_class_id), + should_run_(false), + is_disabled_(false), + matches_filter_(false), + factory_(factory), + result_() {} // Destructs a TestInfo object. -TestInfo::~TestInfo() { - delete impl_; -} +TestInfo::~TestInfo() { delete factory_; } namespace internal { @@ -2144,10 +2216,10 @@ namespace internal { // // test_case_name: name of the test case // name: name of the test -// test_case_comment: a comment on the test case that will be included in -// the test output -// comment: a comment on the test that will be included in the -// test output +// type_param: the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param: text representation of the test's value parameter, +// or NULL if this is not a value-parameterized test. // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case @@ -2156,13 +2228,14 @@ namespace internal { // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, - const char* test_case_comment, const char* comment, + const char* type_param, + const char* value_param, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = - new TestInfo(test_case_name, name, test_case_comment, comment, + new TestInfo(test_case_name, name, type_param, value_param, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; @@ -2189,41 +2262,6 @@ void ReportInvalidTestCaseType(const char* test_case_name, } // namespace internal -// Returns the test case name. -const char* TestInfo::test_case_name() const { - return impl_->test_case_name(); -} - -// Returns the test name. -const char* TestInfo::name() const { - return impl_->name(); -} - -// Returns the test case comment. -const char* TestInfo::test_case_comment() const { - return impl_->test_case_comment(); -} - -// Returns the test comment. -const char* TestInfo::comment() const { - return impl_->comment(); -} - -// Returns true if this test should run. |