From 35c39756495bea5959de5778aaaf33a94f8c1e2e Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 31 Aug 2010 18:21:13 +0000 Subject: Casts char to unsigned char before calling isspace() etc to avoid undefined behavior (by Zhanyong Wan); removes conditional #includes keyed on GTEST_HAS_PROTOBUF_ (by Zhanyong Wan); publishes GTEST_HAS_STREAM_REDIRECTION (by Vlad Losev); forward declares some classes properly (by Samuel Benzaquen); honors the --gtest_catch_exceptions flag (by Vlad Losev). --- include/gtest/gtest.h | 8 +++ include/gtest/internal/gtest-internal.h | 2 +- include/gtest/internal/gtest-port.h | 59 +++++++++++++++--- src/gtest-internal-inl.h | 26 ++++++-- src/gtest-port.cc | 30 +++++----- src/gtest-typed-test.cc | 2 +- src/gtest.cc | 93 +++++++++++++++++++---------- test/gtest-port_test.cc | 102 ++++++++++++++++---------------- test/gtest-printers_test.cc | 2 +- test/gtest_catch_exceptions_test.py | 22 ++++++- test/gtest_catch_exceptions_test_.cc | 17 ++++-- test/gtest_unittest.cc | 25 +++----- 12 files changed, 252 insertions(+), 136 deletions(-) diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h index 3efbece..73f0578 100644 --- a/include/gtest/gtest.h +++ b/include/gtest/gtest.h @@ -175,6 +175,14 @@ String StreamableToString(const T& streamable) { } // namespace internal +// The friend relationship of some of these classes is cyclic. +// If we don't forward declare them the compiler might confuse the classes +// in friendship clauses with same named classes on the scope. +class Test; +class TestCase; +class TestInfo; +class UnitTest; + // A class for indicating whether an assertion was successful. When // the assertion wasn't successful, the AssertionResult object // remembers a non-empty message that describes how it failed. diff --git a/include/gtest/internal/gtest-internal.h b/include/gtest/internal/gtest-internal.h index 1e453df..9cf9dd8 100644 --- a/include/gtest/internal/gtest-internal.h +++ b/include/gtest/internal/gtest-internal.h @@ -625,7 +625,7 @@ inline const char* SkipComma(const char* str) { if (comma == NULL) { return NULL; } - while (isspace(*(++comma))) {} + while (IsSpace(*(++comma))) {} return comma; } diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index 75c3f20..05ee192 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -64,6 +64,10 @@ // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". +// GTEST_HAS_STREAM_REDIRECTION +// - Define it to 1/0 to indicate whether the +// platform supports I/O stream redirection using +// dup() and dup2(). // GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google // Test's own tr1 tuple implementation should be // used. Unused when the user sets @@ -139,8 +143,9 @@ // // Regular expressions: // RE - a simple regular expression class using the POSIX -// Extended Regular Expression syntax. Not available on -// Windows. +// Extended Regular Expression syntax on UNIX-like +// platforms, or a reduced regular exception syntax on +// other platforms, including Windows. // // Logging: // GTEST_LOG_() - logs messages at the specified severity level. @@ -173,7 +178,8 @@ // Int32FromGTestEnv() - parses an Int32 environment variable. // StringFromGTestEnv() - parses a string environment variable. -#include // For ptrdiff_t +#include // for isspace, etc +#include // for ptrdiff_t #include #include #include @@ -495,9 +501,15 @@ // Determines whether to support stream redirection. This is used to test // output correctness and to implement death tests. -#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN -#define GTEST_HAS_STREAM_REDIRECTION_ 1 +#ifndef GTEST_HAS_STREAM_REDIRECTION +// By default, we assume that stream redirection is supported on all +// platforms except known mobile ones. +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN +#define GTEST_HAS_STREAM_REDIRECTION 0 +#else +#define GTEST_HAS_STREAM_REDIRECTION 1 #endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +#endif // GTEST_HAS_STREAM_REDIRECTION // Determines whether to support death tests. // Google Test does not support death tests for VC 7.1 and earlier as @@ -968,7 +980,7 @@ Derived* CheckedDowncastToActualType(Base* base) { #endif } -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION // Defines the stderr capturer: // CaptureStdout - starts capturing stdout. @@ -981,7 +993,7 @@ GTEST_API_ String GetCapturedStdout(); GTEST_API_ void CaptureStderr(); GTEST_API_ String GetCapturedStderr(); -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // GTEST_HAS_STREAM_REDIRECTION #if GTEST_HAS_DEATH_TEST @@ -1419,6 +1431,39 @@ typedef __int64 BiggestInt; typedef long long BiggestInt; // NOLINT #endif // GTEST_OS_WINDOWS +// Utilities for char. + +// isspace(int ch) and friends accept an unsigned char or EOF. char +// may be signed, depending on the compiler (or compiler flags). +// Therefore we need to cast a char to unsigned char before calling +// isspace(), etc. + +inline bool IsAlpha(char ch) { + return isalpha(static_cast(ch)) != 0; +} +inline bool IsAlNum(char ch) { + return isalnum(static_cast(ch)) != 0; +} +inline bool IsDigit(char ch) { + return isdigit(static_cast(ch)) != 0; +} +inline bool IsLower(char ch) { + return islower(static_cast(ch)) != 0; +} +inline bool IsSpace(char ch) { + return isspace(static_cast(ch)) != 0; +} +inline bool IsUpper(char ch) { + return isupper(static_cast(ch)) != 0; +} + +inline char ToLower(char ch) { + return static_cast(tolower(static_cast(ch))); +} +inline char ToUpper(char ch) { + return static_cast(toupper(static_cast(ch))); +} + // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between // Windows/MSVC and POSIX systems. Since some compilers define these diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 73920e4..fe53c21 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -771,9 +771,17 @@ class GTEST_API_ UnitTestImpl { // Restores the test cases and tests to their order before the first shuffle. void UnshuffleTests(); + // Returns the value of GTEST_FLAG(catch_exceptions) at the moment + // UnitTest::Run() starts. + bool catch_exceptions() const { return catch_exceptions_; } + private: friend class ::testing::UnitTest; + // Used by UnitTest::Run() to capture the state of + // GTEST_FLAG(catch_exceptions) at the moment it starts. + void set_catch_exceptions(bool value) { catch_exceptions_ = value; } + // The UnitTest object that owns this implementation object. UnitTest* const parent_; @@ -876,6 +884,10 @@ class GTEST_API_ UnitTestImpl { // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > gtest_trace_stack_; + // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() + // starts. + bool catch_exceptions_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl @@ -885,14 +897,16 @@ inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } +#if GTEST_USES_SIMPLE_RE + // Internal helper functions for implementing the simple regular // expression matcher. GTEST_API_ bool IsInSet(char ch, const char* str); -GTEST_API_ bool IsDigit(char ch); -GTEST_API_ bool IsPunct(char ch); +GTEST_API_ bool IsAsciiDigit(char ch); +GTEST_API_ bool IsAsciiPunct(char ch); GTEST_API_ bool IsRepeat(char ch); -GTEST_API_ bool IsWhiteSpace(char ch); -GTEST_API_ bool IsWordChar(char ch); +GTEST_API_ bool IsAsciiWhiteSpace(char ch); +GTEST_API_ bool IsAsciiWordChar(char ch); GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); GTEST_API_ bool ValidateRegex(const char* regex); @@ -901,6 +915,8 @@ GTEST_API_ bool MatchRepetitionAndRegexAtHead( bool escaped, char ch, char repeat, const char* regex, const char* str); GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); +#endif // GTEST_USES_SIMPLE_RE + // Parses the command line for Google Test flags, without initializing // other parts of Google Test. GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); @@ -947,7 +963,7 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // Fail fast if the given string does not begin with a digit; // this bypasses strtoXXX's "optional leading whitespace and plus // or minus sign" semantics, which are undesirable here. - if (str.empty() || !isdigit(str[0])) { + if (str.empty() || !IsDigit(str[0])) { return false; } errno = 0; diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 5eec8fa..8a7005f 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -181,20 +181,20 @@ bool IsInSet(char ch, const char* str) { // Returns true iff ch belongs to the given classification. Unlike // similar functions in , these aren't affected by the // current locale. -bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; } -bool IsPunct(char ch) { +bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsAsciiPunct(char ch) { return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); } bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } -bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } -bool IsWordChar(char ch) { +bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsAsciiWordChar(char ch) { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('0' <= ch && ch <= '9') || ch == '_'; } // Returns true iff "\\c" is a supported escape sequence. bool IsValidEscape(char c) { - return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW")); + return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); } // Returns true iff the given atom (specified by escaped and pattern) @@ -202,19 +202,19 @@ bool IsValidEscape(char c) { bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { if (escaped) { // "\\p" where p is pattern_char. switch (pattern_char) { - case 'd': return IsDigit(ch); - case 'D': return !IsDigit(ch); + case 'd': return IsAsciiDigit(ch); + case 'D': return !IsAsciiDigit(ch); case 'f': return ch == '\f'; case 'n': return ch == '\n'; case 'r': return ch == '\r'; - case 's': return IsWhiteSpace(ch); - case 'S': return !IsWhiteSpace(ch); + case 's': return IsAsciiWhiteSpace(ch); + case 'S': return !IsAsciiWhiteSpace(ch); case 't': return ch == '\t'; case 'v': return ch == '\v'; - case 'w': return IsWordChar(ch); - case 'W': return !IsWordChar(ch); + case 'w': return IsAsciiWordChar(ch); + case 'W': return !IsAsciiWordChar(ch); } - return IsPunct(pattern_char) && pattern_char == ch; + return IsAsciiPunct(pattern_char) && pattern_char == ch; } return (pattern_char == '.' && ch != '\n') || pattern_char == ch; @@ -449,7 +449,7 @@ GTestLog::~GTestLog() { #pragma warning(disable: 4996) #endif // _MSC_VER -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION // Object that captures an output stream (stdout/stderr). class CapturedStream { @@ -589,7 +589,7 @@ String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } // Stops capturing stderr and returns the captured string. String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // GTEST_HAS_STREAM_REDIRECTION #if GTEST_HAS_DEATH_TEST @@ -619,7 +619,7 @@ static String FlagToEnvVar(const char* flag) { Message env_var; for (size_t i = 0; i != full_flag.length(); i++) { - env_var << static_cast(toupper(full_flag.c_str()[i])); + env_var << ToUpper(full_flag.c_str()[i]); } return env_var.GetString(); diff --git a/src/gtest-typed-test.cc b/src/gtest-typed-test.cc index 3cc4b5d..f70043e 100644 --- a/src/gtest-typed-test.cc +++ b/src/gtest-typed-test.cc @@ -40,7 +40,7 @@ namespace internal { // Skips to the first non-space char in str. Returns an empty string if str // contains only whitespace characters. static const char* SkipSpaces(const char* str) { - while (isspace(*str)) + while (IsSpace(*str)) str++; return str; } diff --git a/src/gtest.cc b/src/gtest.cc index 93ab6a8..287ca88 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -501,7 +501,7 @@ 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. @@ -527,7 +527,7 @@ int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } -#endif // GTEST_OS_WINDOWS +#endif // GTEST_HAS_SEH } // namespace internal @@ -1362,7 +1362,7 @@ 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'; } @@ -1620,9 +1620,9 @@ 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; @@ -2096,26 +2096,53 @@ static Result HandleSehExceptionsInMethodIfSupported( template static 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(0); + 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(0); #else - return HandleSehExceptionsInMethodIfSupported(object, method, location); + return HandleSehExceptionsInMethodIfSupported(object, method, location); #endif // GTEST_HAS_EXCEPTIONS + } else { + return (object->*method)(); + } } // Runs the test and updates the test result. @@ -3773,17 +3800,19 @@ void UnitTest::RecordPropertyForCurrentTest(const char* key, // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { -#if GTEST_HAS_SEH - // Catch SEH-style exceptions. + // Captures the value of GTEST_FLAG(catch_exceptions). This value will be + // used for the duration of the program. + impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); +#if GTEST_HAS_SEH const bool in_death_test_child_process = internal::GTEST_FLAG(internal_run_death_test).length() > 0; // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs - // about crashes - they are expected.. - if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) { + // about crashes - they are expected. + if (impl()->catch_exceptions() || in_death_test_child_process) { #if !GTEST_OS_WINDOWS_MOBILE // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | @@ -3818,7 +3847,7 @@ int UnitTest::Run() { #endif // GTEST_HAS_SEH return HandleExceptionsInMethodIfSupported( - impl_, + impl(), &internal::UnitTestImpl::RunAllTests, "auxiliary test code (environments or event listeners)") ? 0 : 1; } @@ -3914,13 +3943,13 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. random_(0), // Will be reseeded before first use. -#if GTEST_HAS_DEATH_TEST elapsed_time_(0), +#if GTEST_HAS_DEATH_TEST internal_run_death_test_flag_(NULL), - death_test_factory_(new DefaultDeathTestFactory) { -#else - elapsed_time_(0) { -#endif // GTEST_HAS_DEATH_TEST + death_test_factory_(new DefaultDeathTestFactory), +#endif + // Will be overridden by the flag before first use. + catch_exceptions_(false) { listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } diff --git a/test/gtest-port_test.cc b/test/gtest-port_test.cc index 6cdbfab..e08afe8 100644 --- a/test/gtest-port_test.cc +++ b/test/gtest-port_test.cc @@ -377,33 +377,33 @@ TEST(IsInSetTest, WorksForNonNulChars) { EXPECT_TRUE(IsInSet('b', "ab")); } -TEST(IsDigitTest, IsFalseForNonDigit) { - EXPECT_FALSE(IsDigit('\0')); - EXPECT_FALSE(IsDigit(' ')); - EXPECT_FALSE(IsDigit('+')); - EXPECT_FALSE(IsDigit('-')); - EXPECT_FALSE(IsDigit('.')); - EXPECT_FALSE(IsDigit('a')); +TEST(IsAsciiDigitTest, IsFalseForNonDigit) { + EXPECT_FALSE(IsAsciiDigit('\0')); + EXPECT_FALSE(IsAsciiDigit(' ')); + EXPECT_FALSE(IsAsciiDigit('+')); + EXPECT_FALSE(IsAsciiDigit('-')); + EXPECT_FALSE(IsAsciiDigit('.')); + EXPECT_FALSE(IsAsciiDigit('a')); } -TEST(IsDigitTest, IsTrueForDigit) { - EXPECT_TRUE(IsDigit('0')); - EXPECT_TRUE(IsDigit('1')); - EXPECT_TRUE(IsDigit('5')); - EXPECT_TRUE(IsDigit('9')); +TEST(IsAsciiDigitTest, IsTrueForDigit) { + EXPECT_TRUE(IsAsciiDigit('0')); + EXPECT_TRUE(IsAsciiDigit('1')); + EXPECT_TRUE(IsAsciiDigit('5')); + EXPECT_TRUE(IsAsciiDigit('9')); } -TEST(IsPunctTest, IsFalseForNonPunct) { - EXPECT_FALSE(IsPunct('\0')); - EXPECT_FALSE(IsPunct(' ')); - EXPECT_FALSE(IsPunct('\n')); - EXPECT_FALSE(IsPunct('a')); - EXPECT_FALSE(IsPunct('0')); +TEST(IsAsciiPunctTest, IsFalseForNonPunct) { + EXPECT_FALSE(IsAsciiPunct('\0')); + EXPECT_FALSE(IsAsciiPunct(' ')); + EXPECT_FALSE(IsAsciiPunct('\n')); + EXPECT_FALSE(IsAsciiPunct('a')); + EXPECT_FALSE(IsAsciiPunct('0')); } -TEST(IsPunctTest, IsTrueForPunct) { +TEST(IsAsciiPunctTest, IsTrueForPunct) { for (const char* p = "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"; *p; p++) { - EXPECT_PRED1(IsPunct, *p); + EXPECT_PRED1(IsAsciiPunct, *p); } } @@ -421,47 +421,47 @@ TEST(IsRepeatTest, IsTrueForRepeatChar) { EXPECT_TRUE(IsRepeat('+')); } -TEST(IsWhiteSpaceTest, IsFalseForNonWhiteSpace) { - EXPECT_FALSE(IsWhiteSpace('\0')); - EXPECT_FALSE(IsWhiteSpace('a')); - EXPECT_FALSE(IsWhiteSpace('1')); - EXPECT_FALSE(IsWhiteSpace('+')); - EXPECT_FALSE(IsWhiteSpace('_')); +TEST(IsAsciiWhiteSpaceTest, IsFalseForNonWhiteSpace) { + EXPECT_FALSE(IsAsciiWhiteSpace('\0')); + EXPECT_FALSE(IsAsciiWhiteSpace('a')); + EXPECT_FALSE(IsAsciiWhiteSpace('1')); + EXPECT_FALSE(IsAsciiWhiteSpace('+')); + EXPECT_FALSE(IsAsciiWhiteSpace('_')); } -TEST(IsWhiteSpaceTest, IsTrueForWhiteSpace) { - EXPECT_TRUE(IsWhiteSpace(' ')); - EXPECT_TRUE(IsWhiteSpace('\n')); - EXPECT_TRUE(IsWhiteSpace('\r')); - EXPECT_TRUE(IsWhiteSpace('\t')); - EXPECT_TRUE(IsWhiteSpace('\v')); - EXPECT_TRUE(IsWhiteSpace('\f')); +TEST(IsAsciiWhiteSpaceTest, IsTrueForWhiteSpace) { + EXPECT_TRUE(IsAsciiWhiteSpace(' ')); + EXPECT_TRUE(IsAsciiWhiteSpace('\n')); + EXPECT_TRUE(IsAsciiWhiteSpace('\r')); + EXPECT_TRUE(IsAsciiWhiteSpace('\t')); + EXPECT_TRUE(IsAsciiWhiteSpace('\v')); + EXPECT_TRUE(IsAsciiWhiteSpace('\f')); } -TEST(IsWordCharTest, IsFalseForNonWordChar) { - EXPECT_FALSE(IsWordChar('\0')); - EXPECT_FALSE(IsWordChar('+')); - EXPECT_FALSE(IsWordChar('.')); - EXPECT_FALSE(IsWordChar(' ')); - EXPECT_FALSE(IsWordChar('\n')); +TEST(IsAsciiWordCharTest, IsFalseForNonWordChar) { + EXPECT_FALSE(IsAsciiWordChar('\0')); + EXPECT_FALSE(IsAsciiWordChar('+')); + EXPECT_FALSE(IsAsciiWordChar('.')); + EXPECT_FALSE(IsAsciiWordChar(' ')); + EXPECT_FALSE(IsAsciiWordChar('\n')); } -TEST(IsWordCharTest, IsTrueForLetter) { - EXPECT_TRUE(IsWordChar('a')); - EXPECT_TRUE(IsWordChar('b')); - EXPECT_TRUE(IsWordChar('A')); - EXPECT_TRUE(IsWordChar('Z')); +TEST(IsAsciiWordCharTest, IsTrueForLetter) { + EXPECT_TRUE(IsAsciiWordChar('a')); + EXPECT_TRUE(IsAsciiWordChar('b')); + EXPECT_TRUE(IsAsciiWordChar('A')); + EXPECT_TRUE(IsAsciiWordChar('Z')); } -TEST(IsWordCharTest, IsTrueForDigit) { - EXPECT_TRUE(IsWordChar('0')); - EXPECT_TRUE(IsWordChar('1')); - EXPECT_TRUE(IsWordChar('7')); - EXPECT_TRUE(IsWordChar('9')); +TEST(IsAsciiWordCharTest, IsTrueForDigit) { + EXPECT_TRUE(IsAsciiWordChar('0')); + EXPECT_TRUE(IsAsciiWordChar('1')); + EXPECT_TRUE(IsAsciiWordChar('7')); + EXPECT_TRUE(IsAsciiWordChar('9')); } -TEST(IsWordCharTest, IsTrueForUnderscore) { - EXPECT_TRUE(IsWordChar('_')); +TEST(IsAsciiWordCharTest, IsTrueForUnderscore) { + EXPECT_TRUE(IsAsciiWordChar('_')); } TEST(IsValidEscapeTest, IsFalseForNonPrintable) { diff --git a/test/gtest-printers_test.cc b/test/gtest-printers_test.cc index 5dec871..ce72421 100644 --- a/test/gtest-printers_test.cc +++ b/test/gtest-printers_test.cc @@ -817,7 +817,7 @@ TEST(PrintStlContainerTest, HashMultiSet) { std::vector numbers; for (size_t i = 0; i != result.length(); i++) { if (expected_pattern[i] == 'd') { - ASSERT_TRUE(isdigit(result[i]) != 0); + ASSERT_TRUE(isdigit(static_cast(result[i])) != 0); numbers.push_back(result[i] - '0'); } else { EXPECT_EQ(expected_pattern[i], result[i]) << " where result is " diff --git a/test/gtest_catch_exceptions_test.py b/test/gtest_catch_exceptions_test.py index c4d1756..061c5c3 100755 --- a/test/gtest_catch_exceptions_test.py +++ b/test/gtest_catch_exceptions_test.py @@ -43,6 +43,8 @@ import gtest_test_utils # Constants. LIST_TESTS_FLAG = '--gtest_list_tests' +CATCH_EXCEPTIONS_FLAG = '--gtest_catch_exceptions=1' +FILTER_FLAG='--gtest_filter' # Path to the gtest_catch_exceptions_ex_test_ binary, compiled with # exceptions enabled. @@ -59,10 +61,11 @@ TEST_LIST = gtest_test_utils.Subprocess([EXE_PATH, LIST_TESTS_FLAG]).output SUPPORTS_SEH_EXCEPTIONS = 'ThrowsSehException' in TEST_LIST if SUPPORTS_SEH_EXCEPTIONS: - BINARY_OUTPUT = gtest_test_utils.Subprocess([EXE_PATH]).output - -EX_BINARY_OUTPUT = gtest_test_utils.Subprocess([EX_EXE_PATH]).output + BINARY_OUTPUT = gtest_test_utils.Subprocess([EXE_PATH, + CATCH_EXCEPTIONS_FLAG]).output +EX_BINARY_OUTPUT = gtest_test_utils.Subprocess([EX_EXE_PATH, + CATCH_EXCEPTIONS_FLAG]).output # The tests. if SUPPORTS_SEH_EXCEPTIONS: @@ -199,5 +202,18 @@ class CatchCxxExceptionsTest(gtest_test_utils.TestCase): self.assert_('Unknown C++ exception thrown in the test body' in EX_BINARY_OUTPUT) + def testUnhandledCxxExceptionsAbortTheProgram(self): + # Filters out SEH exception tests on Windows. Unhandled SEH exceptions + # cause tests to show pop-up windows there. + FITLER_OUT_SEH_TESTS_FLAG = FILTER_FLAG + '=-*Seh*' + # By default, Google Test doesn't catch the exceptions. + uncaught_exceptions_ex_binary_output = gtest_test_utils.Subprocess( + [EX_EXE_PATH, FITLER_OUT_SEH_TESTS_FLAG]).output + + self.assert_('Unhandled C++ exception terminating the program' + in uncaught_exceptions_ex_binary_output) + self.assert_('unexpected' not in uncaught_exceptions_ex_binary_output) + + if __name__ == '__main__': gtest_test_utils.Main() diff --git a/test/gtest_catch_exceptions_test_.cc b/test/gtest_catch_exceptions_test_.cc index 8673681..2ba6eb4 100644 --- a/test/gtest_catch_exceptions_test_.cc +++ b/test/gtest_catch_exceptions_test_.cc @@ -35,17 +35,18 @@ #include #include // NOLINT +#include // For exit(). #if GTEST_HAS_SEH #include #endif #if GTEST_HAS_EXCEPTIONS +#include // For set_terminate(). #include #endif using testing::Test; -using testing::GTEST_FLAG(catch_exceptions); #if GTEST_HAS_SEH @@ -287,12 +288,20 @@ TEST(CxxExceptionTest, ThrowsNonStdCxxException) { throw "C-string"; } +// This terminate handler aborts the program using exit() rather than abort(). +// This avoids showing pop-ups on Windows systems and core dumps on Unix-like +// ones. +void TerminateHandler() { + fprintf(stderr, "%s\n", "Unhandled C++ exception terminating the program."); + fflush(NULL); + exit(3); +} + #endif // GTEST_HAS_EXCEPTIONS int main(int argc, char** argv) { -#if GTEST_HAS_SEH - // Tells Google Test to catch SEH-style exceptions on Windows. - GTEST_FLAG(catch_exceptions) = true; +#if GTEST_HAS_EXCEPTIONS + std::set_terminate(&TerminateHandler); #endif testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index d993c04..d709249 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -193,19 +193,15 @@ using testing::internal::kReference; using testing::internal::kTestTypeIdInGoogleTest; using testing::internal::scoped_ptr; -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION using testing::internal::CaptureStdout; using testing::internal::GetCapturedStdout; -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif #if GTEST_IS_THREADSAFE using testing::internal::ThreadWithParam; #endif -#if GTEST_HAS_PROTOBUF_ -using ::testing::internal::TestMessage; -#endif // GTEST_HAS_PROTOBUF_ - class TestingVector : public std::vector { }; @@ -5343,16 +5339,16 @@ class InitGoogleTestTest : public Test { const bool saved_help_flag = ::testing::internal::g_help_flag; ::testing::internal::g_help_flag = false; -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION CaptureStdout(); -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // Parses the command line. internal::ParseGoogleTestFlagsOnly(&argc1, const_cast(argv1)); -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION const String captured_stdout = GetCapturedStdout(); -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // Verifies the flag values. CheckFlags(expected); @@ -5365,7 +5361,7 @@ class InitGoogleTestTest : public Test { // help message for the flags it recognizes. EXPECT_EQ(should_print_help, ::testing::internal::g_help_flag); -#if GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_HAS_STREAM_REDIRECTION const char* const expected_help_fragment = "This program contains tests written using"; if (should_print_help) { @@ -5374,7 +5370,7 @@ class InitGoogleTestTest : public Test { EXPECT_PRED_FORMAT2(IsNotSubstring, expected_help_fragment, captured_stdout); } -#endif // GTEST_HAS_STREAM_REDIRECTION_ +#endif // GTEST_HAS_STREAM_REDIRECTION ::testing::internal::g_help_flag = saved_help_flag; } @@ -6887,13 +6883,10 @@ TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { } // Tests that IsAProtocolMessage::value is true when T is -// ProtocolMessage or a sub-class of it. +// proto2::Message or a sub-class of it. TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) { EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value); EXPECT_TRUE(IsAProtocolMessage::value); -#if GTEST_HAS_PROTOBUF_ - EXPECT_TRUE(IsAProtocolMessage::value); -#endif // GTEST_HAS_PROTOBUF_ } // Tests that IsAProtocolMessage::value is false when T is neither -- cgit v0.12