Implements death tests on Windows (by Vlad Losev); enables POSIX regex on Mac and Cygwin; fixes build issue on some Linux versions due to PATH_MAX.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -48,6 +48,7 @@
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h> // NOLINT
|
||||
#include <unistd.h> // NOLINT
|
||||
#include <climits> // Some Linux distributions define PATH_MAX here.
|
||||
#endif // _WIN32_WCE or _WIN32
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
|
||||
@@ -45,17 +45,20 @@
|
||||
#error "It must not be included except by Google Test itself."
|
||||
#endif // GTEST_IMPLEMENTATION_
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <gtest/internal/gtest-port.h>
|
||||
#include <stdlib.h> // For strtoll/_strtoul64.
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
#include <windows.h> // NOLINT
|
||||
#include <windows.h> // For DWORD.
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
|
||||
#include <gtest/internal/gtest-port.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gtest/gtest-spi.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Declares the flags.
|
||||
@@ -1313,6 +1316,77 @@ bool MatchRegexAnywhere(const char* regex, const char* str);
|
||||
void ParseGoogleTestFlagsOnly(int* argc, char** argv);
|
||||
void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
// Returns the message describing the last system error, regardless of the
|
||||
// platform.
|
||||
String GetLastSystemErrorMessage();
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
// Provides leak-safe Windows kernel handle ownership.
|
||||
class AutoHandle {
|
||||
public:
|
||||
AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
|
||||
explicit AutoHandle(HANDLE handle) : handle_(handle) {}
|
||||
|
||||
~AutoHandle() { Reset(); }
|
||||
|
||||
HANDLE Get() const { return handle_; }
|
||||
void Reset() { Reset(INVALID_HANDLE_VALUE); }
|
||||
void Reset(HANDLE handle) {
|
||||
if (handle != handle_) {
|
||||
if (handle_ != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(handle_);
|
||||
handle_ = handle;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE handle_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
|
||||
};
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
|
||||
// Attempts to parse a string into a positive integer pointed to by the
|
||||
// number parameter. Returns true if that is possible.
|
||||
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
|
||||
// it here.
|
||||
template <typename Integer>
|
||||
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])) {
|
||||
return false;
|
||||
}
|
||||
errno = 0;
|
||||
|
||||
char* end;
|
||||
// BiggestConvertible is the largest integer type that system-provided
|
||||
// string-to-number conversion routines can return.
|
||||
#if GTEST_OS_WINDOWS
|
||||
typedef unsigned __int64 BiggestConvertible;
|
||||
const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);
|
||||
#else
|
||||
typedef unsigned long long BiggestConvertible; // NOLINT
|
||||
const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
const bool parse_success = *end == '\0' && errno == 0;
|
||||
|
||||
// TODO(vladl@google.com): Convert this to compile time assertion when it is
|
||||
// available.
|
||||
GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
|
||||
|
||||
const Integer result = static_cast<Integer>(parsed);
|
||||
if (parse_success && static_cast<BiggestConvertible>(result) == parsed) {
|
||||
*number = result;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
#include <regex.h>
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
#if !GTEST_OS_WINDOWS
|
||||
#include <unistd.h>
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
|
||||
#if GTEST_USES_SIMPLE_RE
|
||||
#include <string.h>
|
||||
@@ -63,6 +63,13 @@
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
// Microsoft does not provide a definition of STDERR_FILENO.
|
||||
const int kStdErrFileno = 2;
|
||||
#else
|
||||
const int kStdErrFileno = STDERR_FILENO;
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
|
||||
#if GTEST_USES_POSIX_RE
|
||||
|
||||
// Implements RE. Currently only needed for death tests.
|
||||
@@ -105,7 +112,13 @@ void RE::Init(const char* regex) {
|
||||
// previous expression returns false. Otherwise partial_regex_ may
|
||||
// not be properly initialized can may cause trouble when it's
|
||||
// freed.
|
||||
is_valid_ = (regcomp(&partial_regex_, regex, REG_EXTENDED) == 0) && is_valid_;
|
||||
//
|
||||
// Some implementation of POSIX regex (e.g. on at least some
|
||||
// versions of Cygwin) doesn't accept the empty string as a valid
|
||||
// regex. We change it to an equivalent form "()" to be safe.
|
||||
const char* const partial_regex = (*regex == '\0') ? "()" : regex;
|
||||
is_valid_ = (regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0)
|
||||
&& is_valid_;
|
||||
EXPECT_TRUE(is_valid_)
|
||||
<< "Regular expression \"" << regex
|
||||
<< "\" is not a valid POSIX Extended regular expression.";
|
||||
@@ -379,11 +392,19 @@ void GTestLog(GTestLogSeverity severity, const char* file,
|
||||
severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]";
|
||||
fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg);
|
||||
if (severity == GTEST_FATAL) {
|
||||
fflush(NULL); // abort() is not guaranteed to flush open file streams.
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
#if GTEST_HAS_STD_STRING
|
||||
|
||||
// Disable Microsoft deprecation warnings for POSIX functions called from
|
||||
// this class (creat, dup, dup2, and close)
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4996)
|
||||
#endif // _MSC_VER
|
||||
|
||||
// Defines the stderr capturer.
|
||||
|
||||
@@ -391,16 +412,26 @@ class CapturedStderr {
|
||||
public:
|
||||
// The ctor redirects stderr to a temporary file.
|
||||
CapturedStderr() {
|
||||
uncaptured_fd_ = dup(STDERR_FILENO);
|
||||
uncaptured_fd_ = dup(kStdErrFileno);
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
|
||||
char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
|
||||
|
||||
::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
|
||||
::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, temp_file_path);
|
||||
const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
|
||||
filename_ = temp_file_path;
|
||||
#else
|
||||
// There's no guarantee that a test has write access to the
|
||||
// current directory, so we create the temporary file in the /tmp
|
||||
// directory instead.
|
||||
char name_template[] = "/tmp/captured_stderr.XXXXXX";
|
||||
const int captured_fd = mkstemp(name_template);
|
||||
filename_ = name_template;
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
fflush(NULL);
|
||||
dup2(captured_fd, STDERR_FILENO);
|
||||
dup2(captured_fd, kStdErrFileno);
|
||||
close(captured_fd);
|
||||
}
|
||||
|
||||
@@ -412,7 +443,7 @@ class CapturedStderr {
|
||||
void StopCapture() {
|
||||
// Restores the original stream.
|
||||
fflush(NULL);
|
||||
dup2(uncaptured_fd_, STDERR_FILENO);
|
||||
dup2(uncaptured_fd_, kStdErrFileno);
|
||||
close(uncaptured_fd_);
|
||||
uncaptured_fd_ = -1;
|
||||
}
|
||||
@@ -427,6 +458,10 @@ class CapturedStderr {
|
||||
::std::string filename_;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
static CapturedStderr* g_captured_stderr = NULL;
|
||||
|
||||
// Returns the size (in bytes) of a file.
|
||||
@@ -436,8 +471,6 @@ static size_t GetFileSize(FILE * file) {
|
||||
}
|
||||
|
||||
// Reads the entire content of a file as a string.
|
||||
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
|
||||
// use it here.
|
||||
static ::std::string ReadEntireFile(FILE * file) {
|
||||
const size_t file_size = GetFileSize(file);
|
||||
char* const buffer = new char[file_size];
|
||||
@@ -473,9 +506,18 @@ void CaptureStderr() {
|
||||
// use it here.
|
||||
::std::string GetCapturedStderr() {
|
||||
g_captured_stderr->StopCapture();
|
||||
|
||||
// Disables Microsoft deprecation warning for fopen and fclose.
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4996)
|
||||
#endif // _MSC_VER
|
||||
FILE* const file = fopen(g_captured_stderr->filename().c_str(), "r");
|
||||
const ::std::string content = ReadEntireFile(file);
|
||||
fclose(file);
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
delete g_captured_stderr;
|
||||
g_captured_stderr = NULL;
|
||||
@@ -483,6 +525,10 @@ void CaptureStderr() {
|
||||
return content;
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_STD_STRING
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
// A copy of all command line arguments. Set by InitGoogleTest().
|
||||
::std::vector<String> g_argvs;
|
||||
|
||||
|
||||
38
src/gtest.cc
38
src/gtest.cc
@@ -3300,17 +3300,43 @@ void UnitTest::RecordPropertyForCurrentTest(const char* key,
|
||||
int UnitTest::Run() {
|
||||
#if GTEST_OS_WINDOWS
|
||||
|
||||
#if !defined(_WIN32_WCE)
|
||||
// SetErrorMode doesn't exist on CE.
|
||||
if (GTEST_FLAG(catch_exceptions)) {
|
||||
// The user wants Google Test to catch exceptions thrown by the tests.
|
||||
const bool in_death_test_child_process =
|
||||
internal::GTEST_FLAG(internal_run_death_test).GetLength() > 0;
|
||||
|
||||
// This lets fatal errors be handled by us, instead of causing pop-ups.
|
||||
// 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) {
|
||||
#if !defined(_WIN32_WCE)
|
||||
// SetErrorMode doesn't exist on CE.
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
|
||||
SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
|
||||
}
|
||||
#endif // _WIN32_WCE
|
||||
|
||||
// Death test children can be terminated with _abort(). On Windows,
|
||||
// _abort() can show a dialog with a warning message. This forces the
|
||||
// abort message to go to stderr instead.
|
||||
_set_error_mode(_OUT_TO_STDERR);
|
||||
|
||||
// In the debug version, Visual Studio pops up a separate dialog
|
||||
// offering a choice to debug the aborted program. We need to suppress
|
||||
// this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
|
||||
// executed. Google Test will notify the user of any unexpected
|
||||
// failure via stderr.
|
||||
#if _MSC_VER >= 1400
|
||||
// VC++ doesn't define _set_abort_behavior() prior to the version 8.0.
|
||||
// Users of prior VC versions shall suffer the agony and pain of
|
||||
// clicking through the countless debug dialogs.
|
||||
// TODO(vladl@google.com): find a way to suppress the abort dialog() in the
|
||||
// debug mode when compiled with VC 7.1 or lower.
|
||||
if (!GTEST_FLAG(break_on_failure))
|
||||
_set_abort_behavior(
|
||||
0x0, // Clear the following flags:
|
||||
_WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump.
|
||||
#endif // _MSC_VER >= 1400
|
||||
}
|
||||
|
||||
__try {
|
||||
return impl_->RunAllTests();
|
||||
} __except(internal::UnitTestOptions::GTestShouldProcessSEH(
|
||||
|
||||
Reference in New Issue
Block a user