Commit 35c39756 by zhanyong.wan

Casts char to unsigned char before calling isspace() etc to avoid undefined…

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).
parent a9f380f5
...@@ -175,6 +175,14 @@ String StreamableToString(const T& streamable) { ...@@ -175,6 +175,14 @@ String StreamableToString(const T& streamable) {
} // namespace internal } // 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 // A class for indicating whether an assertion was successful. When
// the assertion wasn't successful, the AssertionResult object // the assertion wasn't successful, the AssertionResult object
// remembers a non-empty message that describes how it failed. // remembers a non-empty message that describes how it failed.
......
...@@ -625,7 +625,7 @@ inline const char* SkipComma(const char* str) { ...@@ -625,7 +625,7 @@ inline const char* SkipComma(const char* str) {
if (comma == NULL) { if (comma == NULL) {
return NULL; return NULL;
} }
while (isspace(*(++comma))) {} while (IsSpace(*(++comma))) {}
return comma; return comma;
} }
......
...@@ -64,6 +64,10 @@ ...@@ -64,6 +64,10 @@
// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the
// compiler supports Microsoft's "Structured // compiler supports Microsoft's "Structured
// Exception Handling". // 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 // GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google
// Test's own tr1 tuple implementation should be // Test's own tr1 tuple implementation should be
// used. Unused when the user sets // used. Unused when the user sets
...@@ -139,8 +143,9 @@ ...@@ -139,8 +143,9 @@
// //
// Regular expressions: // Regular expressions:
// RE - a simple regular expression class using the POSIX // RE - a simple regular expression class using the POSIX
// Extended Regular Expression syntax. Not available on // Extended Regular Expression syntax on UNIX-like
// Windows. // platforms, or a reduced regular exception syntax on
// other platforms, including Windows.
// //
// Logging: // Logging:
// GTEST_LOG_() - logs messages at the specified severity level. // GTEST_LOG_() - logs messages at the specified severity level.
...@@ -173,7 +178,8 @@ ...@@ -173,7 +178,8 @@
// Int32FromGTestEnv() - parses an Int32 environment variable. // Int32FromGTestEnv() - parses an Int32 environment variable.
// StringFromGTestEnv() - parses a string environment variable. // StringFromGTestEnv() - parses a string environment variable.
#include <stddef.h> // For ptrdiff_t #include <ctype.h> // for isspace, etc
#include <stddef.h> // for ptrdiff_t
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
...@@ -495,9 +501,15 @@ ...@@ -495,9 +501,15 @@
// Determines whether to support stream redirection. This is used to test // Determines whether to support stream redirection. This is used to test
// output correctness and to implement death tests. // output correctness and to implement death tests.
#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN #ifndef GTEST_HAS_STREAM_REDIRECTION
#define GTEST_HAS_STREAM_REDIRECTION_ 1 // 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_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN
#endif // GTEST_HAS_STREAM_REDIRECTION
// Determines whether to support death tests. // Determines whether to support death tests.
// Google Test does not support death tests for VC 7.1 and earlier as // Google Test does not support death tests for VC 7.1 and earlier as
...@@ -968,7 +980,7 @@ Derived* CheckedDowncastToActualType(Base* base) { ...@@ -968,7 +980,7 @@ Derived* CheckedDowncastToActualType(Base* base) {
#endif #endif
} }
#if GTEST_HAS_STREAM_REDIRECTION_ #if GTEST_HAS_STREAM_REDIRECTION
// Defines the stderr capturer: // Defines the stderr capturer:
// CaptureStdout - starts capturing stdout. // CaptureStdout - starts capturing stdout.
...@@ -981,7 +993,7 @@ GTEST_API_ String GetCapturedStdout(); ...@@ -981,7 +993,7 @@ GTEST_API_ String GetCapturedStdout();
GTEST_API_ void CaptureStderr(); GTEST_API_ void CaptureStderr();
GTEST_API_ String GetCapturedStderr(); GTEST_API_ String GetCapturedStderr();
#endif // GTEST_HAS_STREAM_REDIRECTION_ #endif // GTEST_HAS_STREAM_REDIRECTION
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
...@@ -1419,6 +1431,39 @@ typedef __int64 BiggestInt; ...@@ -1419,6 +1431,39 @@ typedef __int64 BiggestInt;
typedef long long BiggestInt; // NOLINT typedef long long BiggestInt; // NOLINT
#endif // GTEST_OS_WINDOWS #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<unsigned char>(ch)) != 0;
}
inline bool IsAlNum(char ch) {
return isalnum(static_cast<unsigned char>(ch)) != 0;
}
inline bool IsDigit(char ch) {
return isdigit(static_cast<unsigned char>(ch)) != 0;
}
inline bool IsLower(char ch) {
return islower(static_cast<unsigned char>(ch)) != 0;
}
inline bool IsSpace(char ch) {
return isspace(static_cast<unsigned char>(ch)) != 0;
}
inline bool IsUpper(char ch) {
return isupper(static_cast<unsigned char>(ch)) != 0;
}
inline char ToLower(char ch) {
return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
}
inline char ToUpper(char ch) {
return static_cast<char>(toupper(static_cast<unsigned char>(ch)));
}
// The testing::internal::posix namespace holds wrappers for common // The testing::internal::posix namespace holds wrappers for common
// POSIX functions. These wrappers hide the differences between // POSIX functions. These wrappers hide the differences between
// Windows/MSVC and POSIX systems. Since some compilers define these // Windows/MSVC and POSIX systems. Since some compilers define these
......
...@@ -771,9 +771,17 @@ class GTEST_API_ UnitTestImpl { ...@@ -771,9 +771,17 @@ class GTEST_API_ UnitTestImpl {
// Restores the test cases and tests to their order before the first shuffle. // Restores the test cases and tests to their order before the first shuffle.
void UnshuffleTests(); void UnshuffleTests();
// Returns the value of GTEST_FLAG(catch_exceptions) at the moment
// UnitTest::Run() starts.
bool catch_exceptions() const { return catch_exceptions_; }
private: private:
friend class ::testing::UnitTest; 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. // The UnitTest object that owns this implementation object.
UnitTest* const parent_; UnitTest* const parent_;
...@@ -876,6 +884,10 @@ class GTEST_API_ UnitTestImpl { ...@@ -876,6 +884,10 @@ class GTEST_API_ UnitTestImpl {
// A per-thread stack of traces created by the SCOPED_TRACE() macro. // A per-thread stack of traces created by the SCOPED_TRACE() macro.
internal::ThreadLocal<std::vector<TraceInfo> > gtest_trace_stack_; internal::ThreadLocal<std::vector<TraceInfo> > gtest_trace_stack_;
// The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests()
// starts.
bool catch_exceptions_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);
}; // class UnitTestImpl }; // class UnitTestImpl
...@@ -885,14 +897,16 @@ inline UnitTestImpl* GetUnitTestImpl() { ...@@ -885,14 +897,16 @@ inline UnitTestImpl* GetUnitTestImpl() {
return UnitTest::GetInstance()->impl(); return UnitTest::GetInstance()->impl();
} }
#if GTEST_USES_SIMPLE_RE
// Internal helper functions for implementing the simple regular // Internal helper functions for implementing the simple regular
// expression matcher. // expression matcher.
GTEST_API_ bool IsInSet(char ch, const char* str); GTEST_API_ bool IsInSet(char ch, const char* str);
GTEST_API_ bool IsDigit(char ch); GTEST_API_ bool IsAsciiDigit(char ch);
GTEST_API_ bool IsPunct(char ch); GTEST_API_ bool IsAsciiPunct(char ch);
GTEST_API_ bool IsRepeat(char ch); GTEST_API_ bool IsRepeat(char ch);
GTEST_API_ bool IsWhiteSpace(char ch); GTEST_API_ bool IsAsciiWhiteSpace(char ch);
GTEST_API_ bool IsWordChar(char ch); GTEST_API_ bool IsAsciiWordChar(char ch);
GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool IsValidEscape(char ch);
GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch);
GTEST_API_ bool ValidateRegex(const char* regex); GTEST_API_ bool ValidateRegex(const char* regex);
...@@ -901,6 +915,8 @@ GTEST_API_ bool MatchRepetitionAndRegexAtHead( ...@@ -901,6 +915,8 @@ GTEST_API_ bool MatchRepetitionAndRegexAtHead(
bool escaped, char ch, char repeat, const char* regex, const char* str); bool escaped, char ch, char repeat, const char* regex, const char* str);
GTEST_API_ bool MatchRegexAnywhere(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 // Parses the command line for Google Test flags, without initializing
// other parts of Google Test. // other parts of Google Test.
GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv);
...@@ -947,7 +963,7 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { ...@@ -947,7 +963,7 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
// Fail fast if the given string does not begin with a digit; // Fail fast if the given string does not begin with a digit;
// this bypasses strtoXXX's "optional leading whitespace and plus // this bypasses strtoXXX's "optional leading whitespace and plus
// or minus sign" semantics, which are undesirable here. // or minus sign" semantics, which are undesirable here.
if (str.empty() || !isdigit(str[0])) { if (str.empty() || !IsDigit(str[0])) {
return false; return false;
} }
errno = 0; errno = 0;
......
...@@ -181,20 +181,20 @@ bool IsInSet(char ch, const char* str) { ...@@ -181,20 +181,20 @@ bool IsInSet(char ch, const char* str) {
// Returns true iff ch belongs to the given classification. Unlike // Returns true iff ch belongs to the given classification. Unlike
// similar functions in <ctype.h>, these aren't affected by the // similar functions in <ctype.h>, these aren't affected by the
// current locale. // current locale.
bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; } bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
bool IsPunct(char ch) { bool IsAsciiPunct(char ch) {
return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
} }
bool IsRepeat(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 IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }
bool IsWordChar(char ch) { bool IsAsciiWordChar(char ch) {
return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
('0' <= ch && ch <= '9') || ch == '_'; ('0' <= ch && ch <= '9') || ch == '_';
} }
// Returns true iff "\\c" is a supported escape sequence. // Returns true iff "\\c" is a supported escape sequence.
bool IsValidEscape(char c) { 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) // Returns true iff the given atom (specified by escaped and pattern)
...@@ -202,19 +202,19 @@ bool IsValidEscape(char c) { ...@@ -202,19 +202,19 @@ bool IsValidEscape(char c) {
bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
if (escaped) { // "\\p" where p is pattern_char. if (escaped) { // "\\p" where p is pattern_char.
switch (pattern_char) { switch (pattern_char) {
case 'd': return IsDigit(ch); case 'd': return IsAsciiDigit(ch);
case 'D': return !IsDigit(ch); case 'D': return !IsAsciiDigit(ch);
case 'f': return ch == '\f'; case 'f': return ch == '\f';
case 'n': return ch == '\n'; case 'n': return ch == '\n';
case 'r': return ch == '\r'; case 'r': return ch == '\r';
case 's': return IsWhiteSpace(ch); case 's': return IsAsciiWhiteSpace(ch);
case 'S': return !IsWhiteSpace(ch); case 'S': return !IsAsciiWhiteSpace(ch);
case 't': return ch == '\t'; case 't': return ch == '\t';
case 'v': return ch == '\v'; case 'v': return ch == '\v';
case 'w': return IsWordChar(ch); case 'w': return IsAsciiWordChar(ch);
case 'W': return !IsWordChar(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; return (pattern_char == '.' && ch != '\n') || pattern_char == ch;
...@@ -449,7 +449,7 @@ GTestLog::~GTestLog() { ...@@ -449,7 +449,7 @@ GTestLog::~GTestLog() {
#pragma warning(disable: 4996) #pragma warning(disable: 4996)
#endif // _MSC_VER #endif // _MSC_VER
#if GTEST_HAS_STREAM_REDIRECTION_ #if GTEST_HAS_STREAM_REDIRECTION
// Object that captures an output stream (stdout/stderr). // Object that captures an output stream (stdout/stderr).
class CapturedStream { class CapturedStream {
...@@ -589,7 +589,7 @@ String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } ...@@ -589,7 +589,7 @@ String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); }
// Stops capturing stderr and returns the captured string. // Stops capturing stderr and returns the captured string.
String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); }
#endif // GTEST_HAS_STREAM_REDIRECTION_ #endif // GTEST_HAS_STREAM_REDIRECTION
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
...@@ -619,7 +619,7 @@ static String FlagToEnvVar(const char* flag) { ...@@ -619,7 +619,7 @@ static String FlagToEnvVar(const char* flag) {
Message env_var; Message env_var;
for (size_t i = 0; i != full_flag.length(); i++) { for (size_t i = 0; i != full_flag.length(); i++) {
env_var << static_cast<char>(toupper(full_flag.c_str()[i])); env_var << ToUpper(full_flag.c_str()[i]);
} }
return env_var.GetString(); return env_var.GetString();
......
...@@ -40,7 +40,7 @@ namespace internal { ...@@ -40,7 +40,7 @@ namespace internal {
// Skips to the first non-space char in str. Returns an empty string if str // Skips to the first non-space char in str. Returns an empty string if str
// contains only whitespace characters. // contains only whitespace characters.
static const char* SkipSpaces(const char* str) { static const char* SkipSpaces(const char* str) {
while (isspace(*str)) while (IsSpace(*str))
str++; str++;
return str; return str;
} }
......
...@@ -501,7 +501,7 @@ bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, ...@@ -501,7 +501,7 @@ bool UnitTestOptions::FilterMatchesTest(const String &test_case_name,
!MatchesFilter(full_name, negative.c_str())); !MatchesFilter(full_name, negative.c_str()));
} }
#if GTEST_OS_WINDOWS #if GTEST_HAS_SEH
// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
// This function is useful as an __except condition. // This function is useful as an __except condition.
...@@ -527,7 +527,7 @@ int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { ...@@ -527,7 +527,7 @@ int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
} }
#endif // GTEST_OS_WINDOWS #endif // GTEST_HAS_SEH
} // namespace internal } // namespace internal
...@@ -1362,7 +1362,7 @@ AssertionResult HRESULTFailureHelper(const char* expr, ...@@ -1362,7 +1362,7 @@ AssertionResult HRESULTFailureHelper(const char* expr,
kBufSize, // buf size kBufSize, // buf size
NULL); // no arguments for inserts NULL); // no arguments for inserts
// Trims tailing white space (FormatMessage leaves a trailing cr-lf) // 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) { --message_length) {
error_text[message_length - 1] = '\0'; error_text[message_length - 1] = '\0';
} }
...@@ -1620,9 +1620,9 @@ bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { ...@@ -1620,9 +1620,9 @@ bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
// current locale. // current locale.
bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
const wchar_t* rhs) { 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 #if GTEST_OS_WINDOWS
return _wcsicmp(lhs, rhs) == 0; return _wcsicmp(lhs, rhs) == 0;
...@@ -2096,26 +2096,53 @@ static Result HandleSehExceptionsInMethodIfSupported( ...@@ -2096,26 +2096,53 @@ static Result HandleSehExceptionsInMethodIfSupported(
template <class T, typename Result> template <class T, typename Result>
static Result HandleExceptionsInMethodIfSupported( static Result HandleExceptionsInMethodIfSupported(
T* object, Result (T::*method)(), const char* location) { 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 #if GTEST_HAS_EXCEPTIONS
try { try {
return HandleSehExceptionsInMethodIfSupported(object, method, location); return HandleSehExceptionsInMethodIfSupported(object, method, location);
} catch (const GoogleTestFailureException&) { // NOLINT } catch (const GoogleTestFailureException&) { // NOLINT
// This exception doesn't originate in code under test. It makes no // This exception doesn't originate in code under test. It makes no
// sense to report it as a test failure. // sense to report it as a test failure.
throw; throw;
} catch (const std::exception& e) { // NOLINT } catch (const std::exception& e) { // NOLINT
internal::ReportFailureInUnknownLocation( internal::ReportFailureInUnknownLocation(
TestPartResult::kFatalFailure, TestPartResult::kFatalFailure,
FormatCxxExceptionMessage(e.what(), location)); FormatCxxExceptionMessage(e.what(), location));
} catch (...) { // NOLINT } catch (...) { // NOLINT
internal::ReportFailureInUnknownLocation( internal::ReportFailureInUnknownLocation(
TestPartResult::kFatalFailure, TestPartResult::kFatalFailure,
FormatCxxExceptionMessage(NULL, location)); FormatCxxExceptionMessage(NULL, location));
} }
return static_cast<Result>(0); return static_cast<Result>(0);
#else #else
return HandleSehExceptionsInMethodIfSupported(object, method, location); return HandleSehExceptionsInMethodIfSupported(object, method, location);
#endif // GTEST_HAS_EXCEPTIONS #endif // GTEST_HAS_EXCEPTIONS
} else {
return (object->*method)();
}
} }
// Runs the test and updates the test result. // Runs the test and updates the test result.
...@@ -3773,17 +3800,19 @@ void UnitTest::RecordPropertyForCurrentTest(const char* key, ...@@ -3773,17 +3800,19 @@ void UnitTest::RecordPropertyForCurrentTest(const char* key,
// We don't protect this under mutex_, as we only support calling it // We don't protect this under mutex_, as we only support calling it
// from the main thread. // from the main thread.
int UnitTest::Run() { int UnitTest::Run() {
#if GTEST_HAS_SEH // Captures the value of GTEST_FLAG(catch_exceptions). This value will be
// Catch SEH-style exceptions. // 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 = const bool in_death_test_child_process =
internal::GTEST_FLAG(internal_run_death_test).length() > 0; internal::GTEST_FLAG(internal_run_death_test).length() > 0;
// Either the user wants Google Test to catch exceptions thrown by the // Either the user wants Google Test to catch exceptions thrown by the
// tests or this is executing in the context of death test child // 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 // process. In either case the user does not want to see pop-up dialogs
// about crashes - they are expected.. // about crashes - they are expected.
if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) { if (impl()->catch_exceptions() || in_death_test_child_process) {
#if !GTEST_OS_WINDOWS_MOBILE #if !GTEST_OS_WINDOWS_MOBILE
// SetErrorMode doesn't exist on CE. // SetErrorMode doesn't exist on CE.
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
...@@ -3818,7 +3847,7 @@ int UnitTest::Run() { ...@@ -3818,7 +3847,7 @@ int UnitTest::Run() {
#endif // GTEST_HAS_SEH #endif // GTEST_HAS_SEH
return HandleExceptionsInMethodIfSupported( return HandleExceptionsInMethodIfSupported(
impl_, impl(),
&internal::UnitTestImpl::RunAllTests, &internal::UnitTestImpl::RunAllTests,
"auxiliary test code (environments or event listeners)") ? 0 : 1; "auxiliary test code (environments or event listeners)") ? 0 : 1;
} }
...@@ -3914,13 +3943,13 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) ...@@ -3914,13 +3943,13 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent)
post_flag_parse_init_performed_(false), post_flag_parse_init_performed_(false),
random_seed_(0), // Will be overridden by the flag before first use. random_seed_(0), // Will be overridden by the flag before first use.
random_(0), // Will be reseeded before first use. random_(0), // Will be reseeded before first use.
#if GTEST_HAS_DEATH_TEST
elapsed_time_(0), elapsed_time_(0),
#if GTEST_HAS_DEATH_TEST
internal_run_death_test_flag_(NULL), internal_run_death_test_flag_(NULL),
death_test_factory_(new DefaultDeathTestFactory) { death_test_factory_(new DefaultDeathTestFactory),
#else #endif
elapsed_time_(0) { // Will be overridden by the flag before first use.
#endif // GTEST_HAS_DEATH_TEST catch_exceptions_(false) {
listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter);
} }
......
...@@ -377,33 +377,33 @@ TEST(IsInSetTest, WorksForNonNulChars) { ...@@ -377,33 +377,33 @@ TEST(IsInSetTest, WorksForNonNulChars) {
EXPECT_TRUE(IsInSet('b', "ab")); EXPECT_TRUE(IsInSet('b', "ab"));
} }
TEST(IsDigitTest, IsFalseForNonDigit) { TEST(IsAsciiDigitTest, IsFalseForNonDigit) {
EXPECT_FALSE(IsDigit('\0')); EXPECT_FALSE(IsAsciiDigit('\0'));
EXPECT_FALSE(IsDigit(' ')); EXPECT_FALSE(IsAsciiDigit(' '));
EXPECT_FALSE(IsDigit('+')); EXPECT_FALSE(IsAsciiDigit('+'));
EXPECT_FALSE(IsDigit('-')); EXPECT_FALSE(IsAsciiDigit('-'));
EXPECT_FALSE(IsDigit('.')); EXPECT_FALSE(IsAsciiDigit('.'));
EXPECT_FALSE(IsDigit('a')); EXPECT_FALSE(IsAsciiDigit('a'));
} }
TEST(IsDigitTest, IsTrueForDigit) { TEST(IsAsciiDigitTest, IsTrueForDigit) {
EXPECT_TRUE(IsDigit('0')); EXPECT_TRUE(IsAsciiDigit('0'));
EXPECT_TRUE(IsDigit('1')); EXPECT_TRUE(IsAsciiDigit('1'));
EXPECT_TRUE(IsDigit('5')); EXPECT_TRUE(IsAsciiDigit('5'));
EXPECT_TRUE(IsDigit('9')); EXPECT_TRUE(IsAsciiDigit('9'));
} }
TEST(IsPunctTest, IsFalseForNonPunct) { TEST(IsAsciiPunctTest, IsFalseForNonPunct) {
EXPECT_FALSE(IsPunct('\0')); EXPECT_FALSE(IsAsciiPunct('\0'));
EXPECT_FALSE(IsPunct(' ')); EXPECT_FALSE(IsAsciiPunct(' '));
EXPECT_FALSE(IsPunct('\n')); EXPECT_FALSE(IsAsciiPunct('\n'));
EXPECT_FALSE(IsPunct('a')); EXPECT_FALSE(IsAsciiPunct('a'));
EXPECT_FALSE(IsPunct('0')); EXPECT_FALSE(IsAsciiPunct('0'));
} }
TEST(IsPunctTest, IsTrueForPunct) { TEST(IsAsciiPunctTest, IsTrueForPunct) {
for (const char* p = "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"; *p; p++) { for (const char* p = "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"; *p; p++) {
EXPECT_PRED1(IsPunct, *p); EXPECT_PRED1(IsAsciiPunct, *p);
} }
} }
...@@ -421,47 +421,47 @@ TEST(IsRepeatTest, IsTrueForRepeatChar) { ...@@ -421,47 +421,47 @@ TEST(IsRepeatTest, IsTrueForRepeatChar) {
EXPECT_TRUE(IsRepeat('+')); EXPECT_TRUE(IsRepeat('+'));
} }
TEST(IsWhiteSpaceTest, IsFalseForNonWhiteSpace) { TEST(IsAsciiWhiteSpaceTest, IsFalseForNonWhiteSpace) {
EXPECT_FALSE(IsWhiteSpace('\0')); EXPECT_FALSE(IsAsciiWhiteSpace('\0'));
EXPECT_FALSE(IsWhiteSpace('a')); EXPECT_FALSE(IsAsciiWhiteSpace('a'));
EXPECT_FALSE(IsWhiteSpace('1')); EXPECT_FALSE(IsAsciiWhiteSpace('1'));
EXPECT_FALSE(IsWhiteSpace('+')); EXPECT_FALSE(IsAsciiWhiteSpace('+'));
EXPECT_FALSE(IsWhiteSpace('_')); EXPECT_FALSE(IsAsciiWhiteSpace('_'));
} }
TEST(IsWhiteSpaceTest, IsTrueForWhiteSpace) { TEST(IsAsciiWhiteSpaceTest, IsTrueForWhiteSpace) {
EXPECT_TRUE(IsWhiteSpace(' ')); EXPECT_TRUE(IsAsciiWhiteSpace(' '));
EXPECT_TRUE(IsWhiteSpace('\n')); EXPECT_TRUE(IsAsciiWhiteSpace('\n'));
EXPECT_TRUE(IsWhiteSpace('\r')); EXPECT_TRUE(IsAsciiWhiteSpace('\r'));
EXPECT_TRUE(IsWhiteSpace('\t')); EXPECT_TRUE(IsAsciiWhiteSpace('\t'));
EXPECT_TRUE(IsWhiteSpace('\v')); EXPECT_TRUE(IsAsciiWhiteSpace('\v'));
EXPECT_TRUE(IsWhiteSpace('\f')); EXPECT_TRUE(IsAsciiWhiteSpace('\f'));
} }
TEST(IsWordCharTest, IsFalseForNonWordChar) { TEST(IsAsciiWordCharTest, IsFalseForNonWordChar) {
EXPECT_FALSE(IsWordChar('\0')); EXPECT_FALSE(IsAsciiWordChar('\0'));
EXPECT_FALSE(IsWordChar('+')); EXPECT_FALSE(IsAsciiWordChar('+'));
EXPECT_FALSE(IsWordChar('.')); EXPECT_FALSE(IsAsciiWordChar('.'));
EXPECT_FALSE(IsWordChar(' ')); EXPECT_FALSE(IsAsciiWordChar(' '));
EXPECT_FALSE(IsWordChar('\n')); EXPECT_FALSE(IsAsciiWordChar('\n'));
} }
TEST(IsWordCharTest, IsTrueForLetter) { TEST(IsAsciiWordCharTest, IsTrueForLetter) {
EXPECT_TRUE(IsWordChar('a')); EXPECT_TRUE(IsAsciiWordChar('a'));
EXPECT_TRUE(IsWordChar('b')); EXPECT_TRUE(IsAsciiWordChar('b'));
EXPECT_TRUE(IsWordChar('A')); EXPECT_TRUE(IsAsciiWordChar('A'));
EXPECT_TRUE(IsWordChar('Z')); EXPECT_TRUE(IsAsciiWordChar('Z'));
} }
TEST(IsWordCharTest, IsTrueForDigit) { TEST(IsAsciiWordCharTest, IsTrueForDigit) {
EXPECT_TRUE(IsWordChar('0')); EXPECT_TRUE(IsAsciiWordChar('0'));
EXPECT_TRUE(IsWordChar('1')); EXPECT_TRUE(IsAsciiWordChar('1'));
EXPECT_TRUE(IsWordChar('7')); EXPECT_TRUE(IsAsciiWordChar('7'));
EXPECT_TRUE(IsWordChar('9')); EXPECT_TRUE(IsAsciiWordChar('9'));
} }
TEST(IsWordCharTest, IsTrueForUnderscore) { TEST(IsAsciiWordCharTest, IsTrueForUnderscore) {
EXPECT_TRUE(IsWordChar('_')); EXPECT_TRUE(IsAsciiWordChar('_'));
} }
TEST(IsValidEscapeTest, IsFalseForNonPrintable) { TEST(IsValidEscapeTest, IsFalseForNonPrintable) {
......
...@@ -817,7 +817,7 @@ TEST(PrintStlContainerTest, HashMultiSet) { ...@@ -817,7 +817,7 @@ TEST(PrintStlContainerTest, HashMultiSet) {
std::vector<int> numbers; std::vector<int> numbers;
for (size_t i = 0; i != result.length(); i++) { for (size_t i = 0; i != result.length(); i++) {
if (expected_pattern[i] == 'd') { if (expected_pattern[i] == 'd') {
ASSERT_TRUE(isdigit(result[i]) != 0); ASSERT_TRUE(isdigit(static_cast<unsigned char>(result[i])) != 0);
numbers.push_back(result[i] - '0'); numbers.push_back(result[i] - '0');
} else { } else {
EXPECT_EQ(expected_pattern[i], result[i]) << " where result is " EXPECT_EQ(expected_pattern[i], result[i]) << " where result is "
......
...@@ -43,6 +43,8 @@ import gtest_test_utils ...@@ -43,6 +43,8 @@ import gtest_test_utils
# Constants. # Constants.
LIST_TESTS_FLAG = '--gtest_list_tests' 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 # Path to the gtest_catch_exceptions_ex_test_ binary, compiled with
# exceptions enabled. # exceptions enabled.
...@@ -59,10 +61,11 @@ TEST_LIST = gtest_test_utils.Subprocess([EXE_PATH, LIST_TESTS_FLAG]).output ...@@ -59,10 +61,11 @@ TEST_LIST = gtest_test_utils.Subprocess([EXE_PATH, LIST_TESTS_FLAG]).output
SUPPORTS_SEH_EXCEPTIONS = 'ThrowsSehException' in TEST_LIST SUPPORTS_SEH_EXCEPTIONS = 'ThrowsSehException' in TEST_LIST
if SUPPORTS_SEH_EXCEPTIONS: if SUPPORTS_SEH_EXCEPTIONS:
BINARY_OUTPUT = gtest_test_utils.Subprocess([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]).output
EX_BINARY_OUTPUT = gtest_test_utils.Subprocess([EX_EXE_PATH,
CATCH_EXCEPTIONS_FLAG]).output
# The tests. # The tests.
if SUPPORTS_SEH_EXCEPTIONS: if SUPPORTS_SEH_EXCEPTIONS:
...@@ -199,5 +202,18 @@ class CatchCxxExceptionsTest(gtest_test_utils.TestCase): ...@@ -199,5 +202,18 @@ class CatchCxxExceptionsTest(gtest_test_utils.TestCase):
self.assert_('Unknown C++ exception thrown in the test body' self.assert_('Unknown C++ exception thrown in the test body'
in EX_BINARY_OUTPUT) 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__': if __name__ == '__main__':
gtest_test_utils.Main() gtest_test_utils.Main()
...@@ -35,17 +35,18 @@ ...@@ -35,17 +35,18 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <stdio.h> // NOLINT #include <stdio.h> // NOLINT
#include <stdlib.h> // For exit().
#if GTEST_HAS_SEH #if GTEST_HAS_SEH
#include <windows.h> #include <windows.h>
#endif #endif
#if GTEST_HAS_EXCEPTIONS #if GTEST_HAS_EXCEPTIONS
#include <exception> // For set_terminate().
#include <stdexcept> #include <stdexcept>
#endif #endif
using testing::Test; using testing::Test;
using testing::GTEST_FLAG(catch_exceptions);
#if GTEST_HAS_SEH #if GTEST_HAS_SEH
...@@ -287,12 +288,20 @@ TEST(CxxExceptionTest, ThrowsNonStdCxxException) { ...@@ -287,12 +288,20 @@ TEST(CxxExceptionTest, ThrowsNonStdCxxException) {
throw "C-string"; 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 #endif // GTEST_HAS_EXCEPTIONS
int main(int argc, char** argv) { int main(int argc, char** argv) {
#if GTEST_HAS_SEH #if GTEST_HAS_EXCEPTIONS
// Tells Google Test to catch SEH-style exceptions on Windows. std::set_terminate(&TerminateHandler);
GTEST_FLAG(catch_exceptions) = true;
#endif #endif
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
......
...@@ -193,19 +193,15 @@ using testing::internal::kReference; ...@@ -193,19 +193,15 @@ using testing::internal::kReference;
using testing::internal::kTestTypeIdInGoogleTest; using testing::internal::kTestTypeIdInGoogleTest;
using testing::internal::scoped_ptr; using testing::internal::scoped_ptr;
#if GTEST_HAS_STREAM_REDIRECTION_ #if GTEST_HAS_STREAM_REDIRECTION
using testing::internal::CaptureStdout; using testing::internal::CaptureStdout;
using testing::internal::GetCapturedStdout; using testing::internal::GetCapturedStdout;
#endif // GTEST_HAS_STREAM_REDIRECTION_ #endif
#if GTEST_IS_THREADSAFE #if GTEST_IS_THREADSAFE
using testing::internal::ThreadWithParam; using testing::internal::ThreadWithParam;
#endif #endif
#if GTEST_HAS_PROTOBUF_
using ::testing::internal::TestMessage;
#endif // GTEST_HAS_PROTOBUF_
class TestingVector : public std::vector<int> { class TestingVector : public std::vector<int> {
}; };
...@@ -5343,16 +5339,16 @@ class InitGoogleTestTest : public Test { ...@@ -5343,16 +5339,16 @@ class InitGoogleTestTest : public Test {
const bool saved_help_flag = ::testing::internal::g_help_flag; const bool saved_help_flag = ::testing::internal::g_help_flag;
::testing::internal::g_help_flag = false; ::testing::internal::g_help_flag = false;
#if GTEST_HAS_STREAM_REDIRECTION_ #if GTEST_HAS_STREAM_REDIRECTION
CaptureStdout(); CaptureStdout();
#endif // GTEST_HAS_STREAM_REDIRECTION_ #endif
// Parses the command line. // Parses the command line.
internal::ParseGoogleTestFlagsOnly(&argc1, const_cast<CharType**>(argv1)); internal::ParseGoogleTestFlagsOnly(&argc1, const_cast<CharType**>(argv1));
#if GTEST_HAS_STREAM_REDIRECTION_ #if GTEST_HAS_STREAM_REDIRECTION
const String captured_stdout = GetCapturedStdout(); const String captured_stdout = GetCapturedStdout();
#endif // GTEST_HAS_STREAM_REDIRECTION_ #endif
// Verifies the flag values. // Verifies the flag values.
CheckFlags(expected); CheckFlags(expected);
...@@ -5365,7 +5361,7 @@ class InitGoogleTestTest : public Test { ...@@ -5365,7 +5361,7 @@ class InitGoogleTestTest : public Test {
// help message for the flags it recognizes. // help message for the flags it recognizes.
EXPECT_EQ(should_print_help, ::testing::internal::g_help_flag); 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 = const char* const expected_help_fragment =
"This program contains tests written using"; "This program contains tests written using";
if (should_print_help) { if (should_print_help) {
...@@ -5374,7 +5370,7 @@ class InitGoogleTestTest : public Test { ...@@ -5374,7 +5370,7 @@ class InitGoogleTestTest : public Test {
EXPECT_PRED_FORMAT2(IsNotSubstring, EXPECT_PRED_FORMAT2(IsNotSubstring,
expected_help_fragment, captured_stdout); expected_help_fragment, captured_stdout);
} }
#endif // GTEST_HAS_STREAM_REDIRECTION_ #endif // GTEST_HAS_STREAM_REDIRECTION
::testing::internal::g_help_flag = saved_help_flag; ::testing::internal::g_help_flag = saved_help_flag;
} }
...@@ -6887,13 +6883,10 @@ TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { ...@@ -6887,13 +6883,10 @@ TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) {
} }
// Tests that IsAProtocolMessage<T>::value is true when T is // Tests that IsAProtocolMessage<T>::value is true when T is
// ProtocolMessage or a sub-class of it. // proto2::Message or a sub-class of it.
TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) { TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) {
EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value); EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value);
EXPECT_TRUE(IsAProtocolMessage<ProtocolMessage>::value); EXPECT_TRUE(IsAProtocolMessage<ProtocolMessage>::value);
#if GTEST_HAS_PROTOBUF_
EXPECT_TRUE(IsAProtocolMessage<const TestMessage>::value);
#endif // GTEST_HAS_PROTOBUF_
} }
// Tests that IsAProtocolMessage<T>::value is false when T is neither // Tests that IsAProtocolMessage<T>::value is false when T is neither
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment