Cleans up death test implementation (by Vlad Losev); changes the XML format to be closer to junitreport (by Zhanyong Wan).

This commit is contained in:
zhanyong.wan 2009-03-24 20:39:44 +00:00
parent 1f8a50e429
commit 2c0fc6d415
8 changed files with 291 additions and 390 deletions

View File

@ -41,6 +41,8 @@
#if GTEST_HAS_DEATH_TEST && GTEST_OS_WINDOWS
#include <io.h>
#elif GTEST_HAS_DEATH_TEST
#include <unistd.h>
#endif // GTEST_HAS_DEATH_TEST && GTEST_OS_WINDOWS
namespace testing {
@ -196,17 +198,17 @@ class InternalRunDeathTestFlag {
InternalRunDeathTestFlag(const String& file,
int line,
int index,
int status_fd)
: file_(file), line_(line), index_(index), status_fd_(status_fd) {}
int write_fd)
: file_(file), line_(line), index_(index), write_fd_(write_fd) {}
~InternalRunDeathTestFlag() {
if (status_fd_ >= 0)
if (write_fd_ >= 0)
// Suppress MSVC complaints about POSIX functions.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996)
#endif // _MSC_VER
close(status_fd_);
close(write_fd_);
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
@ -215,13 +217,13 @@ class InternalRunDeathTestFlag {
String file() const { return file_; }
int line() const { return line_; }
int index() const { return index_; }
int status_fd() const { return status_fd_; }
int write_fd() const { return write_fd_; }
private:
String file_;
int line_;
int index_;
int status_fd_;
int write_fd_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
};

View File

@ -48,6 +48,7 @@
#if GTEST_OS_WINDOWS
#include <windows.h>
#else
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
#endif // GTEST_OS_WINDOWS
@ -204,12 +205,12 @@ void DeathTestAbort(const String& message) {
const InternalRunDeathTestFlag* const flag =
GetUnitTestImpl()->internal_run_death_test_flag();
if (flag != NULL) {
// Suppress MSVC complaints about POSIX functions.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996)
#pragma warning(disable: 4996) // Suppresses deprecation warning
// about POSIX functions in MSVC.
#endif // _MSC_VER
FILE* parent = fdopen(flag->status_fd(), "w");
FILE* parent = fdopen(flag->write_fd(), "w");
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
@ -255,47 +256,53 @@ void DeathTestAbort(const String& message) {
} \
} while (0)
// Returns the message describing the last system error, regardless of the
// platform.
String GetLastSystemErrorMessage() {
#if GTEST_OS_WINDOWS
const DWORD error_num = ::GetLastError();
if (error_num == NULL)
return String("");
char* message_ptr;
::FormatMessageA(
// The caller does not provide a buffer. The function will allocate one.
FORMAT_MESSAGE_ALLOCATE_BUFFER |
// The function must look up an error message in its system error
// message table.
FORMAT_MESSAGE_FROM_SYSTEM |
// Do not expand insert sequences in the message definition.
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, // Message source. Ignored in this call.
error_num,
0x0, // Use system-default language.
reinterpret_cast<LPSTR>(&message_ptr),
0, // Buffer size. Ignored in this call.
NULL); // Message arguments. Ignored in this call.
const String message = message_ptr;
::LocalFree(message_ptr);
return message;
#else
return errno == 0 ? String("") : String(strerror(errno));
#endif // GTEST_OS_WINDOWS
// Returns the message describing the last system error in errno.
String GetLastErrnoDescription() {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996) // Suppresses deprecation warning
// about POSIX functions in MSVC.
#endif // _MSC_VER
return String(errno == 0 ? "" : strerror(errno));
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
}
// TODO(vladl@google.com): Move the definition of FailFromInternalError
// here.
#if GTEST_OS_WINDOWS
static void FailFromInternalError(HANDLE handle);
#else
static void FailFromInternalError(int fd);
#endif // GTEST_OS_WINDOWS
// This is called from a death test parent process to read a failure
// message from the death test child process and log it with the FATAL
// severity. On Windows, the message is read from a pipe handle. On other
// platforms, it is read from a file descriptor.
static void FailFromInternalError(int fd) {
Message error;
char buffer[256];
int num_read;
do {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996) // Suppresses deprecation warning
// about POSIX functions in MSVC.
#endif // _MSC_VER
while ((num_read = static_cast<int>(read(fd, buffer, 255))) > 0) {
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
buffer[num_read] = '\0';
error << buffer;
}
} while (num_read == -1 && errno == EINTR);
if (num_read == 0) {
GTEST_LOG_(FATAL, error);
} else {
const int last_error = errno;
const String message = GetLastErrnoDescription();
GTEST_LOG_(FATAL,
Message() << "Error while reading death test internal: "
<< message << " [" << last_error << "]");
}
}
// Death test constructor. Increments the running death test count
// for the current test.
@ -326,8 +333,6 @@ void DeathTest::set_last_death_test_message(const String& message) {
String DeathTest::last_death_test_message_;
// Provides cross platform implementation for some death functionality.
// TODO(vladl@google.com): Merge this class with DeathTest in
// gtest-death-test-internal.h.
class DeathTestImpl : public DeathTest {
protected:
DeathTestImpl(const char* statement, const RE* regex)
@ -335,8 +340,14 @@ class DeathTestImpl : public DeathTest {
regex_(regex),
spawned_(false),
status_(-1),
outcome_(IN_PROGRESS) {}
outcome_(IN_PROGRESS),
read_fd_(-1),
write_fd_(-1) {}
// read_fd_ is expected to be closed and cleared by a derived class.
~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
void Abort(AbortReason reason);
virtual bool Passed(bool status_ok);
const char* statement() const { return statement_; }
@ -347,6 +358,16 @@ class DeathTestImpl : public DeathTest {
void set_status(int status) { status_ = status; }
DeathTestOutcome outcome() const { return outcome_; }
void set_outcome(DeathTestOutcome outcome) { outcome_ = outcome; }
int read_fd() const { return read_fd_; }
void set_read_fd(int fd) { read_fd_ = fd; }
int write_fd() const { return write_fd_; }
void set_write_fd(int fd) { write_fd_ = fd; }
// Called in the parent process only. Reads the result code of the death
// test child process via a pipe, interprets it to set the outcome_
// member, and closes read_fd_. Outputs diagnostics and terminates in
// case of unexpected codes.
void ReadAndInterpretStatusByte();
private:
// The textual content of the code this object is testing. This class
@ -361,9 +382,161 @@ class DeathTestImpl : public DeathTest {
int status_;
// How the death test concluded.
DeathTestOutcome outcome_;
// Descriptor to the read end of the pipe to the child process. It is
// always -1 in the child process. The child keeps its write end of the
// pipe in write_fd_.
int read_fd_;
// Descriptor to the child's write end of the pipe to the parent process.
// It is always -1 in the parent process. The parent keeps its end of the
// pipe in read_fd_.
int write_fd_;
};
// TODO(vladl@google.com): Move definition of DeathTestImpl::Passed() here.
// Called in the parent process only. Reads the result code of the death
// test child process via a pipe, interprets it to set the outcome_
// member, and closes read_fd_. Outputs diagnostics and terminates in
// case of unexpected codes.
void DeathTestImpl::ReadAndInterpretStatusByte() {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996) // Suppresses deprecation warning
// about POSIX functions in MSVC.
#endif // _MSC_VER
char flag;
int bytes_read;
// The read() here blocks until data is available (signifying the
// failure of the death test) or until the pipe is closed (signifying
// its success), so it's okay to call this in the parent before
// the child process has exited.
do {
bytes_read = static_cast<int>(read(read_fd(), &flag, 1));
} while (bytes_read == -1 && errno == EINTR);
if (bytes_read == 0) {
set_outcome(DIED);
} else if (bytes_read == 1) {
switch (flag) {
case kDeathTestReturned:
set_outcome(RETURNED);
break;
case kDeathTestLived:
set_outcome(LIVED);
break;
case kDeathTestInternalError:
FailFromInternalError(read_fd()); // Does not return.
break;
default:
GTEST_LOG_(FATAL,
Message() << "Death test child process reported "
<< "unexpected status byte ("
<< static_cast<unsigned int>(flag) << ")");
}
} else {
GTEST_LOG_(FATAL,
Message() << "Read from death test child process failed: "
<< GetLastErrnoDescription());
}
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(read_fd()));
set_read_fd(-1);
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
}
// Signals that the death test code which should have exited, didn't.
// Should be called only in a death test child process.
// Writes a status byte to the child's status file descriptor, then
// calls _exit(1).
void DeathTestImpl::Abort(AbortReason reason) {
// The parent process considers the death test to be a failure if
// it finds any data in our pipe. So, here we write a single flag byte
// to the pipe, then exit.
const char status_ch =
reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996) // Suppresses deprecation warning
// about POSIX functions.
#endif // _MSC_VER
GTEST_DEATH_TEST_CHECK_SYSCALL_(write(write_fd(), &status_ch, 1));
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(write_fd()));
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
_exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
}
// Assesses the success or failure of a death test, using both private
// members which have previously been set, and one argument:
//
// Private data members:
// outcome: An enumeration describing how the death test
// concluded: DIED, LIVED, or RETURNED. The death test fails
// in the latter two cases.
// status: The exit status of the child process. On *nix, it is in the
// in the format specified by wait(2). On Windows, this is the
// value supplied to the ExitProcess() API or a numeric code
// of the exception that terminated the program.
// regex: A regular expression object to be applied to
// the test's captured standard error output; the death test
// fails if it does not match.
//
// Argument:
// status_ok: true if exit_status is acceptable in the context of
// this particular death test, which fails if it is false
//
// Returns true iff all of the above conditions are met. Otherwise, the
// first failing condition, in the order given above, is the one that is
// reported. Also sets the last death test message string.
bool DeathTestImpl::Passed(bool status_ok) {
if (!spawned())
return false;
#if GTEST_HAS_GLOBAL_STRING
const ::string error_message = GetCapturedStderr();
#else
const ::std::string error_message = GetCapturedStderr();
#endif // GTEST_HAS_GLOBAL_STRING
bool success = false;
Message buffer;
buffer << "Death test: " << statement() << "\n";
switch (outcome()) {
case LIVED:
buffer << " Result: failed to die.\n"
<< " Error msg: " << error_message;
break;
case RETURNED:
buffer << " Result: illegal return in test statement.\n"
<< " Error msg: " << error_message;
break;
case DIED:
if (status_ok) {
if (RE::PartialMatch(error_message, *regex())) {
success = true;
} else {
buffer << " Result: died but not with expected error.\n"
<< " Expected: " << regex()->pattern() << "\n"
<< "Actual msg: " << error_message;
}
} else {
buffer << " Result: died but not with expected exit code:\n"
<< " " << ExitSummary(status()) << "\n";
}
break;
case IN_PROGRESS:
default:
GTEST_LOG_(FATAL,
"DeathTest::Passed somehow called before conclusion of test");
}
DeathTest::set_last_death_test_message(buffer.GetString());
return success;
}
#if GTEST_OS_WINDOWS
// WindowsDeathTest implements death tests on Windows. Due to the
@ -404,7 +577,6 @@ class WindowsDeathTest : public DeathTestImpl {
// All of these virtual functions are inherited from DeathTest.
virtual int Wait();
virtual void Abort(AbortReason reason);
virtual TestRole AssumeRole();
private:
@ -412,10 +584,6 @@ class WindowsDeathTest : public DeathTestImpl {
const char* const file_;
// The line number on which the death test is located.
const int line_;
// Handle to the read end of the pipe to the child process.
// The child keeps its write end of the pipe in the status_handle_
// field of its InternalRunDeathTestFlag class.
AutoHandle read_handle_;
// Handle to the write end of the pipe to the child process.
AutoHandle write_handle_;
// Child process handle.
@ -430,9 +598,6 @@ class WindowsDeathTest : public DeathTestImpl {
// Waits for the child in a death test to exit, returning its exit
// status, or 0 if no child process exists. As a side effect, sets the
// outcome data member.
// TODO(vladl@google.com): Outcome classification logic is common with
// ForkingDeathTes::Wait(). Refactor it into a
// common function.
int WindowsDeathTest::Wait() {
if (!spawned())
return 0;
@ -456,44 +621,7 @@ int WindowsDeathTest::Wait() {
write_handle_.Reset();
event_handle_.Reset();
// ReadFile() blocks until data is available (signifying the
// failure of the death test) or until the pipe is closed (signifying
// its success), so it's okay to call this in the parent before or
// after the child process has exited.
char flag;
DWORD bytes_read;
GTEST_DEATH_TEST_CHECK_(::ReadFile(read_handle_.Get(),
&flag,
1,
&bytes_read,
NULL) ||
::GetLastError() == ERROR_BROKEN_PIPE);
if (bytes_read == 0) {
set_outcome(DIED);
} else if (bytes_read == 1) {
switch (flag) {
case kDeathTestReturned:
set_outcome(RETURNED);
break;
case kDeathTestLived:
set_outcome(LIVED);
break;
case kDeathTestInternalError:
FailFromInternalError(read_handle_.Get()); // Does not return.
break;
default:
GTEST_LOG_(FATAL,
Message() << "Death test child process reported "
<< " unexpected status byte ("
<< static_cast<unsigned int>(flag) << ")");
}
} else {
GTEST_LOG_(FATAL,
Message() << "Read from death test child process failed: "
<< GetLastSystemErrorMessage());
}
read_handle_.Reset(); // Done with reading.
ReadAndInterpretStatusByte();
// Waits for the child process to exit if it haven't already. This
// returns immediately if the child has already exited, regardless of
@ -510,34 +638,6 @@ int WindowsDeathTest::Wait() {
return this->status();
}
// TODO(vladl@google.com): define a cross-platform way to write to
// status_fd to be used both here and in ForkingDeathTest::Abort().
//
// Signals that the death test did not die as expected. This is called
// from the child process only.
void WindowsDeathTest::Abort(AbortReason reason) {
const InternalRunDeathTestFlag* const internal_flag =
GetUnitTestImpl()->internal_run_death_test_flag();
// The parent process considers the death test to be a failure if
// it finds any data in our pipe. So, here we write a single flag byte
// to the pipe, then exit.
const char status_ch =
reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996)
#endif // _MSC_VER
GTEST_DEATH_TEST_CHECK_SYSCALL_(write(internal_flag->status_fd(),
&status_ch, 1));
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
// The write handle will be closed when the child terminates in _exit().
_exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
}
// The AssumeRole process for a Windows death test. It creates a child
// process with the same executable as the current process to run the
// death test. The child process is given the --gtest_filter and
@ -553,6 +653,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
if (flag != NULL) {
// ParseInternalRunDeathTestFlag() has performed all the necessary
// processing.
set_write_fd(flag->write_fd());
return EXECUTE_TEST;
}
@ -564,7 +665,8 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
GTEST_DEATH_TEST_CHECK_(::CreatePipe(&read_handle, &write_handle,
&handles_are_inheritable,
0)); // Default buffer size.
read_handle_.Reset(read_handle);
set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
O_RDONLY));
write_handle_.Reset(write_handle);
event_handle_.Reset(::CreateEvent(
&handles_are_inheritable,
@ -642,92 +744,20 @@ class ForkingDeathTest : public DeathTestImpl {
// All of these virtual functions are inherited from DeathTest.
virtual int Wait();
virtual void Abort(AbortReason reason);
protected:
void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
void set_read_fd(int fd) { read_fd_ = fd; }
void set_write_fd(int fd) { write_fd_ = fd; }
private:
// PID of child process during death test; 0 in the child process itself.
pid_t child_pid_;
// File descriptors for communicating the death test's status byte.
int read_fd_; // Always -1 in the child process.
int write_fd_; // Always -1 in the parent process.
};
// Constructs a ForkingDeathTest.
ForkingDeathTest::ForkingDeathTest(const char* statement, const RE* regex)
: DeathTestImpl(statement, regex),
child_pid_(-1),
read_fd_(-1),
write_fd_(-1) {
}
#endif // GTEST_OS_WINDOWS
child_pid_(-1) {}
// This is called from a death test parent process to read a failure
// message from the death test child process and log it with the FATAL
// severity. On Windows, the message is read from a pipe handle. On other
// platforms, it is read from a file descriptor.
// TODO(vladl@google.com): Re-factor the code to merge common parts after
// the reading code is abstracted.
#if GTEST_OS_WINDOWS
static void FailFromInternalError(HANDLE handle) {
Message error;
char buffer[256];
bool read_succeeded = true;
DWORD bytes_read;
do {
// ERROR_BROKEN_PIPE arises when the other end of the pipe has been
// closed. This is a normal condition for us.
bytes_read = 0;
read_succeeded = ::ReadFile(handle,
buffer,
sizeof(buffer) - 1,
&bytes_read,
NULL) || ::GetLastError() == ERROR_BROKEN_PIPE;
buffer[bytes_read] = 0;
error << buffer;
} while (read_succeeded && bytes_read > 0);
if (read_succeeded) {
GTEST_LOG_(FATAL, error);
} else {
const DWORD last_error = ::GetLastError();
const String message = GetLastSystemErrorMessage();
GTEST_LOG_(FATAL,
Message() << "Error while reading death test internal: "
<< message << " [" << last_error << "]");
}
}
#else
static void FailFromInternalError(int fd) {
Message error;
char buffer[256];
ssize_t num_read;
do {
while ((num_read = read(fd, buffer, 255)) > 0) {
buffer[num_read] = '\0';
error << buffer;
}
} while (num_read == -1 && errno == EINTR);
if (num_read == 0) {
GTEST_LOG_(FATAL, error);
} else {
const int last_error = errno;
const String message = GetLastSystemErrorMessage();
GTEST_LOG_(FATAL,
Message() << "Error while reading death test internal: "
<< message << " [" << last_error << "]");
}
}
#endif // GTEST_OS_WINDOWS
#if !GTEST_OS_WINDOWS
// Waits for the child in a death test to exit, returning its exit
// status, or 0 if no child process exists. As a side effect, sets the
// outcome data member.
@ -735,135 +765,13 @@ int ForkingDeathTest::Wait() {
if (!spawned())
return 0;
// The read() here blocks until data is available (signifying the
// failure of the death test) or until the pipe is closed (signifying
// its success), so it's okay to call this in the parent before
// the child process has exited.
char flag;
ssize_t bytes_read;
ReadAndInterpretStatusByte();
do {
bytes_read = read(read_fd_, &flag, 1);
} while (bytes_read == -1 && errno == EINTR);
if (bytes_read == 0) {
set_outcome(DIED);
} else if (bytes_read == 1) {
switch (flag) {
case kDeathTestReturned:
set_outcome(RETURNED);
break;
case kDeathTestLived:
set_outcome(LIVED);
break;
case kDeathTestInternalError:
FailFromInternalError(read_fd_); // Does not return.
break;
default:
GTEST_LOG_(FATAL,
Message() << "Death test child process reported unexpected "
<< "status byte (" << static_cast<unsigned int>(flag)
<< ")");
}
} else {
const String error_message = GetLastSystemErrorMessage();
GTEST_LOG_(FATAL,
Message() << "Read from death test child process failed: "
<< error_message);
}
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(read_fd_));
int status;
GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status, 0));
set_status(status);
return status;
}
#endif // !GTEST_OS_WINDOWS
// Assesses the success or failure of a death test, using both private
// members which have previously been set, and one argument:
//
// Private data members:
// outcome: An enumeration describing how the death test
// concluded: DIED, LIVED, or RETURNED. The death test fails
// in the latter two cases.
// status: The exit status of the child process. On *nix, it is in the
// in the format specified by wait(2). On Windows, this is the
// value supplied to the ExitProcess() API or a numeric code
// of the exception that terminated the program.
// regex: A regular expression object to be applied to
// the test's captured standard error output; the death test
// fails if it does not match.
//
// Argument:
// status_ok: true if exit_status is acceptable in the context of
// this particular death test, which fails if it is false
//
// Returns true iff all of the above conditions are met. Otherwise, the
// first failing condition, in the order given above, is the one that is
// reported. Also sets the last death test message string.
bool DeathTestImpl::Passed(bool status_ok) {
if (!spawned())
return false;
#if GTEST_HAS_GLOBAL_STRING
const ::string error_message = GetCapturedStderr();
#else
const ::std::string error_message = GetCapturedStderr();
#endif // GTEST_HAS_GLOBAL_STRING
bool success = false;
Message buffer;
buffer << "Death test: " << statement() << "\n";
switch (outcome()) {
case LIVED:
buffer << " Result: failed to die.\n"
<< " Error msg: " << error_message;
break;
case RETURNED:
buffer << " Result: illegal return in test statement.\n"
<< " Error msg: " << error_message;
break;
case DIED:
if (status_ok) {
if (RE::PartialMatch(error_message, *regex())) {
success = true;
} else {
buffer << " Result: died but not with expected error.\n"
<< " Expected: " << regex()->pattern() << "\n"
<< "Actual msg: " << error_message;
}
} else {
buffer << " Result: died but not with expected exit code:\n"
<< " " << ExitSummary(status()) << "\n";
}
break;
case IN_PROGRESS:
default:
GTEST_LOG_(FATAL,
"DeathTest::Passed somehow called before conclusion of test");
}
DeathTest::set_last_death_test_message(buffer.GetString());
return success;
}
#if !GTEST_OS_WINDOWS
// Signals that the death test code which should have exited, didn't.
// Should be called only in a death test child process.
// Writes a status byte to the child's status file descriptor, then
// calls _exit(1).
void ForkingDeathTest::Abort(AbortReason reason) {
// The parent process considers the death test to be a failure if
// it finds any data in our pipe. So, here we write a single flag byte
// to the pipe, then exit.
const char flag =
reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
GTEST_DEATH_TEST_CHECK_SYSCALL_(write(write_fd_, &flag, 1));
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(write_fd_));
_exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
}
// A concrete death test class that forks, then immediately runs the test
// in the child process.
@ -978,12 +886,10 @@ inline char** GetEnviron() {
return *_NSGetEnviron();
}
#else
extern "C" char** environ; // Some POSIX platforms expect you
// to declare environ. extern "C" makes
// it reside in the global namespace.
inline char** GetEnviron() {
return environ;
}
// Some POSIX platforms expect you to declare environ. extern "C" makes
// it reside in the global namespace.
extern "C" char** environ;
inline char** GetEnviron() { return environ; }
#endif // GTEST_OS_MAC
// The main function for a threadsafe-style death test child process.
@ -1002,7 +908,7 @@ static int ExecDeathTestChildMain(void* child_arg) {
if (chdir(original_dir) != 0) {
DeathTestAbort(String::Format("chdir(\"%s\") failed: %s",
original_dir,
GetLastSystemErrorMessage().c_str()));
GetLastErrnoDescription().c_str()));
return EXIT_FAILURE;
}
@ -1015,7 +921,7 @@ static int ExecDeathTestChildMain(void* child_arg) {
DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s",
args->argv[0],
original_dir,
GetLastSystemErrorMessage().c_str()));
GetLastErrnoDescription().c_str()));
return EXIT_FAILURE;
}
@ -1083,7 +989,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
const int death_test_index = info->result()->death_test_count();
if (flag != NULL) {
set_write_fd(flag->status_fd());
set_write_fd(flag->write_fd());
return EXECUTE_TEST;
}
@ -1201,7 +1107,7 @@ static void SplitString(const ::std::string& str, char delimiter,
// signals the event, and returns a file descriptor wrapped around the pipe
// handle. This function is called in the child process only.
int GetStatusFileDescriptor(unsigned int parent_process_id,
size_t status_handle_as_size_t,
size_t write_handle_as_size_t,
size_t event_handle_as_size_t) {
AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
FALSE, // Non-inheritable.
@ -1215,22 +1121,22 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
// compile-time assertion when available.
GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
const HANDLE status_handle =
reinterpret_cast<HANDLE>(status_handle_as_size_t);
HANDLE dup_status_handle;
const HANDLE write_handle =
reinterpret_cast<HANDLE>(write_handle_as_size_t);
HANDLE dup_write_handle;
// The newly initialized handle is accessible only in in the parent
// process. To obtain one accessible within the child, we need to use
// DuplicateHandle.
if (!::DuplicateHandle(parent_process_handle.Get(), status_handle,
::GetCurrentProcess(), &dup_status_handle,
if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
::GetCurrentProcess(), &dup_write_handle,
0x0, // Requested privileges ignored since
// DUPLICATE_SAME_ACCESS is used.
FALSE, // Request non-inheritable handler.
DUPLICATE_SAME_ACCESS)) {
DeathTestAbort(String::Format(
"Unable to duplicate the pipe handle %Iu from the parent process %u",
status_handle_as_size_t, parent_process_id));
write_handle_as_size_t, parent_process_id));
}
const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
@ -1246,20 +1152,19 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
event_handle_as_size_t, parent_process_id));
}
const int status_fd =
::_open_osfhandle(reinterpret_cast<intptr_t>(dup_status_handle),
O_APPEND | O_TEXT);
if (status_fd == -1) {
const int write_fd =
::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
if (write_fd == -1) {
DeathTestAbort(String::Format(
"Unable to convert pipe handle %Iu to a file descriptor",
status_handle_as_size_t));
write_handle_as_size_t));
}
// Signals the parent that the write end of the pipe has been acquired
// so the parent can release its own write end.
::SetEvent(dup_event_handle);
return status_fd;
return write_fd;
}
#endif // GTEST_OS_WINDOWS
@ -1275,37 +1180,37 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
int index = -1;
::std::vector< ::std::string> fields;
SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);
int status_fd = -1;
int write_fd = -1;
#if GTEST_OS_WINDOWS
unsigned int parent_process_id = 0;
size_t status_handle_as_size_t = 0;
size_t write_handle_as_size_t = 0;
size_t event_handle_as_size_t = 0;
if (fields.size() != 6
|| !ParseNaturalNumber(fields[1], &line)
|| !ParseNaturalNumber(fields[2], &index)
|| !ParseNaturalNumber(fields[3], &parent_process_id)
|| !ParseNaturalNumber(fields[4], &status_handle_as_size_t)
|| !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
|| !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
DeathTestAbort(String::Format(
"Bad --gtest_internal_run_death_test flag: %s",
GTEST_FLAG(internal_run_death_test).c_str()));
}
status_fd = GetStatusFileDescriptor(parent_process_id,
status_handle_as_size_t,
event_handle_as_size_t);
write_fd = GetStatusFileDescriptor(parent_process_id,
write_handle_as_size_t,
event_handle_as_size_t);
#else
if (fields.size() != 4
|| !ParseNaturalNumber(fields[1], &line)
|| !ParseNaturalNumber(fields[2], &index)
|| !ParseNaturalNumber(fields[3], &status_fd)) {
|| !ParseNaturalNumber(fields[3], &write_fd)) {
DeathTestAbort(String::Format(
"Bad --gtest_internal_run_death_test flag: %s",
GTEST_FLAG(internal_run_death_test).c_str()));
}
#endif // GTEST_OS_WINDOWS
return new InternalRunDeathTestFlag(fields[0], line, index, status_fd);
return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
}
} // namespace internal

View File

@ -1325,7 +1325,7 @@ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
// Returns the message describing the last system error, regardless of the
// platform.
String GetLastSystemErrorMessage();
String GetLastErrnoDescription();
#if GTEST_OS_WINDOWS
// Provides leak-safe Windows kernel handle ownership.

View File

@ -3044,7 +3044,7 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str,
//
// This is how Google Test concepts map to the DTD:
//
// <testsuite name="AllTests"> <-- corresponds to a UnitTest object
// <testsuites name="AllTests"> <-- corresponds to a UnitTest object
// <testsuite name="testcase-name"> <-- corresponds to a TestCase object
// <testcase name="test-name"> <-- corresponds to a TestInfo object
// <failure message="...">...</failure>
@ -3053,7 +3053,7 @@ internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str,
// <-- individual assertion failures
// </testcase>
// </testsuite>
// </testsuite>
// </testsuites>
namespace internal {
@ -3137,7 +3137,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
const internal::UnitTestImpl* const impl = unit_test->impl();
fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
fprintf(out,
"<testsuite tests=\"%d\" failures=\"%d\" disabled=\"%d\" "
"<testsuites tests=\"%d\" failures=\"%d\" disabled=\"%d\" "
"errors=\"0\" time=\"%s\" ",
impl->total_test_count(),
impl->failed_test_count(),
@ -3150,7 +3150,7 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
case_node = case_node->next()) {
PrintXmlTestCase(out, case_node->element());
}
fprintf(out, "</testsuite>\n");
fprintf(out, "</testsuites>\n");
}
// Produces a string representing the test properties in a result as space

View File

@ -65,7 +65,7 @@ using testing::Message;
using testing::internal::DeathTest;
using testing::internal::DeathTestFactory;
using testing::internal::FilePath;
using testing::internal::GetLastSystemErrorMessage;
using testing::internal::GetLastErrnoDescription;
using testing::internal::ParseNaturalNumber;
using testing::internal::String;
@ -990,20 +990,13 @@ TEST(StreamingAssertionsDeathTest, DeathTest) {
}, "expected failure");
}
// Tests that GetLastSystemErrorMessage returns an empty string when the
// Tests that GetLastErrnoDescription returns an empty string when the
// last error is 0 and non-empty string when it is non-zero.
TEST(GetLastSystemErrorMessageTest, GetLastSystemErrorMessageWorks) {
#if GTEST_OS_WINDOWS
::SetLastError(ERROR_FILE_NOT_FOUND);
EXPECT_STRNE("", GetLastSystemErrorMessage().c_str());
::SetLastError(0);
EXPECT_STREQ("", GetLastSystemErrorMessage().c_str());
#else
TEST(GetLastErrnoDescription, GetLastErrnoDescriptionWorks) {
errno = ENOENT;
EXPECT_STRNE("", GetLastSystemErrorMessage().c_str());
EXPECT_STRNE("", GetLastErrnoDescription().c_str());
errno = 0;
EXPECT_STREQ("", GetLastSystemErrorMessage().c_str());
#endif
EXPECT_STREQ("", GetLastErrnoDescription().c_str());
}
#if GTEST_OS_WINDOWS

View File

@ -48,19 +48,19 @@ GTEST_OUTPUT_1_TEST = "gtest_xml_outfile1_test_"
GTEST_OUTPUT_2_TEST = "gtest_xml_outfile2_test_"
EXPECTED_XML_1 = """<?xml version="1.0" encoding="UTF-8"?>
<testsuite tests="1" failures="0" disabled="0" errors="0" time="*" name="AllTests">
<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" name="AllTests">
<testsuite name="PropertyOne" tests="1" failures="0" disabled="0" errors="0" time="*">
<testcase name="TestSomeProperties" status="run" time="*" classname="PropertyOne" SetUpProp="1" TestSomeProperty="1" TearDownProp="1" />
</testsuite>
</testsuite>
</testsuites>
"""
EXPECTED_XML_2 = """<?xml version="1.0" encoding="UTF-8"?>
<testsuite tests="1" failures="0" disabled="0" errors="0" time="*" name="AllTests">
<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" name="AllTests">
<testsuite name="PropertyTwo" tests="1" failures="0" disabled="0" errors="0" time="*">
<testcase name="TestSomeProperties" status="run" time="*" classname="PropertyTwo" SetUpProp="2" TestSomeProperty="2" TearDownProp="2" />
</testsuite>
</testsuite>
</testsuites>
"""

View File

@ -48,7 +48,7 @@ GTEST_OUTPUT_FLAG = "--gtest_output"
GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml"
EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
<testsuite tests="13" failures="2" disabled="2" errors="0" time="*" name="AllTests">
<testsuites tests="13" failures="2" disabled="2" errors="0" time="*" name="AllTests">
<testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" errors="0" time="*">
<testcase name="Succeeds" status="run" time="*" classname="SuccessfulTest"/>
</testsuite>
@ -85,12 +85,12 @@ Expected: 2]]></failure>
<testcase name="ExternalUtilityThatCallsRecordIntValuedProperty" status="run" time="*" classname="NoFixtureTest" key_for_utility_int="1"/>
<testcase name="ExternalUtilityThatCallsRecordStringValuedProperty" status="run" time="*" classname="NoFixtureTest" key_for_utility_string="1"/>
</testsuite>
</testsuite>"""
</testsuites>"""
EXPECTED_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
<testsuite tests="0" failures="0" disabled="0" errors="0" time="*" name="AllTests">
</testsuite>"""
<testsuites tests="0" failures="0" disabled="0" errors="0" time="*" name="AllTests">
</testsuites>"""
class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):

View File

@ -92,6 +92,7 @@ class GTestXMLTestCase(unittest.TestCase):
self.AssertEquivalentNodes(child, actual_children[child_id])
identifying_attribute = {
"testsuites": "name",
"testsuite": "name",
"testcase": "name",
"failure": "message",
@ -101,14 +102,14 @@ class GTestXMLTestCase(unittest.TestCase):
"""
Fetches all of the child nodes of element, a DOM Element object.
Returns them as the values of a dictionary keyed by the IDs of the
children. For <testsuite> and <testcase> elements, the ID is the
value of their "name" attribute; for <failure> elements, it is the
value of the "message" attribute; for CDATA section node, it is
"detail". An exception is raised if any element other than the
above four is encountered, if two child elements with the same
identifying attributes are encountered, or if any other type of
node is encountered, other than Text nodes containing only
whitespace.
children. For <testsuites>, <testsuite> and <testcase> elements,
the ID is the value of their "name" attribute; for <failure>
elements, it is the value of the "message" attribute; for CDATA
section node, it is "detail". An exception is raised if any
element other than the above four is encountered, if two child
elements with the same identifying attributes are encountered, or
if any other type of node is encountered, other than Text nodes
containing only whitespace.
"""
children = {}
@ -133,16 +134,16 @@ class GTestXMLTestCase(unittest.TestCase):
Normalizes Google Test's XML output to eliminate references to transient
information that may change from run to run.
* The "time" attribute of <testsuite> and <testcase> elements is
replaced with a single asterisk, if it contains only digit
characters.
* The "time" attribute of <testsuites>, <testsuite> and <testcase>
elements is replaced with a single asterisk, if it contains
only digit characters.
* The line number reported in the first line of the "message"
attribute of <failure> elements is replaced with a single asterisk.
* The directory names in file paths are removed.
* The stack traces are removed.
"""
if element.tagName in ("testsuite", "testcase"):
if element.tagName in ("testsuites", "testsuite", "testcase"):
time = element.getAttributeNode("time")
time.value = re.sub(r"^\d+(\.\d+)?$", "*", time.value)
elif element.tagName == "failure":