summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2010-08-31 18:21:13 +0000
committerzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2010-08-31 18:21:13 +0000
commit5d0c3dc09ece41c649deea59f975d0ff5548424a (patch)
treefe8cac8d619895feaa69a4e3678f1edd9d4945c4 /src
parentc95489ee7dd54fc6a2cd1d3e890c330718ead714 (diff)
downloadgtest-5d0c3dc09ece41c649deea59f975d0ff5548424a.tar.gz
gtest-5d0c3dc09ece41c649deea59f975d0ff5548424a.tar.bz2
gtest-5d0c3dc09ece41c649deea59f975d0ff5548424a.tar.xz
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).
git-svn-id: http://googletest.googlecode.com/svn/trunk@480 861a406c-534a-0410-8894-cb66d6ee9925
Diffstat (limited to 'src')
-rw-r--r--src/gtest-internal-inl.h26
-rw-r--r--src/gtest-port.cc30
-rw-r--r--src/gtest-typed-test.cc2
-rw-r--r--src/gtest.cc93
4 files changed, 98 insertions, 53 deletions
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<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);
}; // 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 <ctype.h>, 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<char>(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 <class T, typename Result>
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<Result>(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<Result>(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);
}