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).

This commit is contained in:
zhanyong.wan 2010-08-31 18:21:13 +00:00
parent a9f380f5c7
commit 35c3975649
12 changed files with 252 additions and 136 deletions

View File

@ -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.

View File

@ -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;
} }

View File

@ -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 @@
// //
// 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 @@
// 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 @@
// 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) {
#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();
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;
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

View File

@ -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 {
// 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() {
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(
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) {
// 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;

View File

@ -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) {
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() {
#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); }
// 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) {
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();

View File

@ -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;
} }

View File

@ -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) {
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,
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) {
// 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(
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,
// 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() {
#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)
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);
} }

View File

@ -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) {
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) {

View File

@ -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 "

View File

@ -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
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):
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()

View File

@ -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) {
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();

View File

@ -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 {
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 {
// 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 {
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) {
} }
// 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