Implements stdout capturing (by Vlad Losev); fixes compiler error on NVCC (by Zhanyong Wan).
This commit is contained in:
parent
27a65a9d67
commit
fd6f2a8a4b
|
@ -132,7 +132,10 @@
|
||||||
// LogToStderr() - directs all log messages to stderr.
|
// LogToStderr() - directs all log messages to stderr.
|
||||||
// FlushInfoLog() - flushes informational log messages.
|
// FlushInfoLog() - flushes informational log messages.
|
||||||
//
|
//
|
||||||
// Stderr capturing:
|
// Stdout and stderr capturing:
|
||||||
|
// CaptureStdout() - starts capturing stdout.
|
||||||
|
// GetCapturedStdout() - stops capturing stdout and returns the captured
|
||||||
|
// string.
|
||||||
// CaptureStderr() - starts capturing stderr.
|
// CaptureStderr() - starts capturing stderr.
|
||||||
// GetCapturedStderr() - stops capturing stderr and returns the captured
|
// GetCapturedStderr() - stops capturing stderr and returns the captured
|
||||||
// string.
|
// string.
|
||||||
|
@ -353,12 +356,15 @@
|
||||||
#ifndef GTEST_USE_OWN_TR1_TUPLE
|
#ifndef GTEST_USE_OWN_TR1_TUPLE
|
||||||
// The user didn't tell us, so we need to figure it out.
|
// The user didn't tell us, so we need to figure it out.
|
||||||
|
|
||||||
// We use our own tr1 tuple if we aren't sure the user has an
|
// We use our own TR1 tuple if we aren't sure the user has an
|
||||||
// implementation of it already. At this time, GCC 4.0.0+ and MSVC
|
// implementation of it already. At this time, GCC 4.0.0+ and MSVC
|
||||||
// 2010 are the only mainstream compilers that come with a TR1 tuple
|
// 2010 are the only mainstream compilers that come with a TR1 tuple
|
||||||
|
// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by
|
||||||
|
// defining __GNUC__ and friends, but cannot compile GCC's tuple
|
||||||
// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB
|
// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB
|
||||||
// Feature Pack download, which we cannot assume the user has.
|
// Feature Pack download, which we cannot assume the user has.
|
||||||
#if (defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)) || _MSC_VER >= 1600
|
#if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \
|
||||||
|
|| _MSC_VER >= 1600
|
||||||
#define GTEST_USE_OWN_TR1_TUPLE 0
|
#define GTEST_USE_OWN_TR1_TUPLE 0
|
||||||
#else
|
#else
|
||||||
#define GTEST_USE_OWN_TR1_TUPLE 1
|
#define GTEST_USE_OWN_TR1_TUPLE 1
|
||||||
|
@ -690,13 +696,22 @@ class GTestLog {
|
||||||
inline void LogToStderr() {}
|
inline void LogToStderr() {}
|
||||||
inline void FlushInfoLog() { fflush(NULL); }
|
inline void FlushInfoLog() { fflush(NULL); }
|
||||||
|
|
||||||
|
#if !GTEST_OS_WINDOWS_MOBILE
|
||||||
|
|
||||||
// Defines the stderr capturer:
|
// Defines the stderr capturer:
|
||||||
|
// CaptureStdout - starts capturing stdout.
|
||||||
|
// GetCapturedStdout - stops capturing stdout and returns the captured string.
|
||||||
// CaptureStderr - starts capturing stderr.
|
// CaptureStderr - starts capturing stderr.
|
||||||
// GetCapturedStderr - stops capturing stderr and returns the captured string.
|
// GetCapturedStderr - stops capturing stderr and returns the captured string.
|
||||||
|
//
|
||||||
|
void CaptureStdout();
|
||||||
|
String GetCapturedStdout();
|
||||||
void CaptureStderr();
|
void CaptureStderr();
|
||||||
String GetCapturedStderr();
|
String GetCapturedStderr();
|
||||||
|
|
||||||
|
#endif // !GTEST_OS_WINDOWS_MOBILE
|
||||||
|
|
||||||
|
|
||||||
#if GTEST_HAS_DEATH_TEST
|
#if GTEST_HAS_DEATH_TEST
|
||||||
|
|
||||||
// A copy of all command line arguments. Set by InitGoogleTest().
|
// A copy of all command line arguments. Set by InitGoogleTest().
|
||||||
|
|
|
@ -68,8 +68,10 @@ namespace internal {
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||||
// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
|
// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
|
||||||
|
const int kStdOutFileno = 1;
|
||||||
const int kStdErrFileno = 2;
|
const int kStdErrFileno = 2;
|
||||||
#else
|
#else
|
||||||
|
const int kStdOutFileno = STDOUT_FILENO;
|
||||||
const int kStdErrFileno = STDERR_FILENO;
|
const int kStdErrFileno = STDERR_FILENO;
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
@ -439,18 +441,14 @@ GTestLog::~GTestLog() {
|
||||||
#pragma warning(disable: 4996)
|
#pragma warning(disable: 4996)
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
// Defines the stderr capturer.
|
// Stream capturing is not supported on Windows Mobile.
|
||||||
|
#if !GTEST_OS_WINDOWS_MOBILE
|
||||||
|
|
||||||
class CapturedStderr {
|
// Object that captures an output stream (stdout/stderr).
|
||||||
|
class CapturedStream {
|
||||||
public:
|
public:
|
||||||
// The ctor redirects stderr to a temporary file.
|
// The ctor redirects the stream to a temporary file.
|
||||||
CapturedStderr() {
|
CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
|
||||||
#if GTEST_OS_WINDOWS_MOBILE
|
|
||||||
// Not supported on Windows CE.
|
|
||||||
posix::Abort();
|
|
||||||
#else
|
|
||||||
uncaptured_fd_ = dup(kStdErrFileno);
|
|
||||||
|
|
||||||
#if GTEST_OS_WINDOWS
|
#if GTEST_OS_WINDOWS
|
||||||
char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
|
char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
|
||||||
char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
|
char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
|
||||||
|
@ -463,57 +461,57 @@ class CapturedStderr {
|
||||||
// There's no guarantee that a test has write access to the
|
// There's no guarantee that a test has write access to the
|
||||||
// current directory, so we create the temporary file in the /tmp
|
// current directory, so we create the temporary file in the /tmp
|
||||||
// directory instead.
|
// directory instead.
|
||||||
char name_template[] = "/tmp/captured_stderr.XXXXXX";
|
char name_template[] = "/tmp/captured_stream.XXXXXX";
|
||||||
const int captured_fd = mkstemp(name_template);
|
const int captured_fd = mkstemp(name_template);
|
||||||
filename_ = name_template;
|
filename_ = name_template;
|
||||||
#endif // GTEST_OS_WINDOWS
|
#endif // GTEST_OS_WINDOWS
|
||||||
fflush(NULL);
|
fflush(NULL);
|
||||||
dup2(captured_fd, kStdErrFileno);
|
dup2(captured_fd, fd_);
|
||||||
close(captured_fd);
|
close(captured_fd);
|
||||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~CapturedStderr() {
|
~CapturedStream() {
|
||||||
#if !GTEST_OS_WINDOWS_MOBILE
|
|
||||||
remove(filename_.c_str());
|
remove(filename_.c_str());
|
||||||
#endif // !GTEST_OS_WINDOWS_MOBILE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stops redirecting stderr.
|
String GetCapturedString() {
|
||||||
void StopCapture() {
|
if (uncaptured_fd_ != -1) {
|
||||||
#if !GTEST_OS_WINDOWS_MOBILE
|
// Restores the original stream.
|
||||||
// Restores the original stream.
|
fflush(NULL);
|
||||||
fflush(NULL);
|
dup2(uncaptured_fd_, fd_);
|
||||||
dup2(uncaptured_fd_, kStdErrFileno);
|
close(uncaptured_fd_);
|
||||||
close(uncaptured_fd_);
|
uncaptured_fd_ = -1;
|
||||||
uncaptured_fd_ = -1;
|
}
|
||||||
#endif // !GTEST_OS_WINDOWS_MOBILE
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the name of the temporary file holding the stderr output.
|
FILE* const file = posix::FOpen(filename_.c_str(), "r");
|
||||||
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
|
const String content = ReadEntireFile(file);
|
||||||
// can use it here.
|
posix::FClose(file);
|
||||||
::std::string filename() const { return filename_; }
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Reads the entire content of a file as a String.
|
||||||
|
static String ReadEntireFile(FILE* file);
|
||||||
|
|
||||||
|
// Returns the size (in bytes) of a file.
|
||||||
|
static size_t GetFileSize(FILE* file);
|
||||||
|
|
||||||
|
const int fd_; // A stream to capture.
|
||||||
int uncaptured_fd_;
|
int uncaptured_fd_;
|
||||||
|
// Name of the temporary file holding the stderr output.
|
||||||
::std::string filename_;
|
::std::string filename_;
|
||||||
|
|
||||||
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
static CapturedStderr* g_captured_stderr = NULL;
|
|
||||||
|
|
||||||
// Returns the size (in bytes) of a file.
|
// Returns the size (in bytes) of a file.
|
||||||
static size_t GetFileSize(FILE * file) {
|
size_t CapturedStream::GetFileSize(FILE* file) {
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
return static_cast<size_t>(ftell(file));
|
return static_cast<size_t>(ftell(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads the entire content of a file as a string.
|
// Reads the entire content of a file as a string.
|
||||||
static String ReadEntireFile(FILE * file) {
|
String CapturedStream::ReadEntireFile(FILE* file) {
|
||||||
const size_t file_size = GetFileSize(file);
|
const size_t file_size = GetFileSize(file);
|
||||||
char* const buffer = new char[file_size];
|
char* const buffer = new char[file_size];
|
||||||
|
|
||||||
|
@ -535,30 +533,50 @@ static String ReadEntireFile(FILE * file) {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts capturing stderr.
|
#ifdef _MSC_VER
|
||||||
void CaptureStderr() {
|
#pragma warning(pop)
|
||||||
if (g_captured_stderr != NULL) {
|
#endif // _MSC_VER
|
||||||
GTEST_LOG_(FATAL) << "Only one stderr capturer can exist at one time.";
|
|
||||||
|
static CapturedStream* g_captured_stderr = NULL;
|
||||||
|
static CapturedStream* g_captured_stdout = NULL;
|
||||||
|
|
||||||
|
// Starts capturing an output stream (stdout/stderr).
|
||||||
|
void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
|
||||||
|
if (*stream != NULL) {
|
||||||
|
GTEST_LOG_(FATAL) << "Only one " << stream_name
|
||||||
|
<< " capturer can exist at a time.";
|
||||||
}
|
}
|
||||||
g_captured_stderr = new CapturedStderr;
|
*stream = new CapturedStream(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stops capturing stderr and returns the captured string.
|
// Stops capturing the output stream and returns the captured string.
|
||||||
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
|
String GetCapturedStream(CapturedStream** captured_stream) {
|
||||||
// use it here.
|
const String content = (*captured_stream)->GetCapturedString();
|
||||||
String GetCapturedStderr() {
|
|
||||||
g_captured_stderr->StopCapture();
|
|
||||||
|
|
||||||
FILE* const file = posix::FOpen(g_captured_stderr->filename().c_str(), "r");
|
delete *captured_stream;
|
||||||
const String content = ReadEntireFile(file);
|
*captured_stream = NULL;
|
||||||
posix::FClose(file);
|
|
||||||
|
|
||||||
delete g_captured_stderr;
|
|
||||||
g_captured_stderr = NULL;
|
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Starts capturing stdout.
|
||||||
|
void CaptureStdout() {
|
||||||
|
CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts capturing stderr.
|
||||||
|
void CaptureStderr() {
|
||||||
|
CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stops capturing stdout and returns the captured string.
|
||||||
|
String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); }
|
||||||
|
|
||||||
|
// Stops capturing stderr and returns the captured string.
|
||||||
|
String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); }
|
||||||
|
|
||||||
|
#endif // !GTEST_OS_WINDOWS_MOBILE
|
||||||
|
|
||||||
#if GTEST_HAS_DEATH_TEST
|
#if GTEST_HAS_DEATH_TEST
|
||||||
|
|
||||||
// A copy of all command line arguments. Set by InitGoogleTest().
|
// A copy of all command line arguments. Set by InitGoogleTest().
|
||||||
|
|
|
@ -2634,6 +2634,9 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) {
|
||||||
SetConsoleTextAttribute(stdout_handle,
|
SetConsoleTextAttribute(stdout_handle,
|
||||||
GetColorAttribute(color) | FOREGROUND_INTENSITY);
|
GetColorAttribute(color) | FOREGROUND_INTENSITY);
|
||||||
vprintf(fmt, args);
|
vprintf(fmt, args);
|
||||||
|
// Unless we flush stream buffers now the next SetConsoleTextAttribute
|
||||||
|
// call can reset the color before the output reaches the console.
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
// Restores the text color.
|
// Restores the text color.
|
||||||
SetConsoleTextAttribute(stdout_handle, old_color_attrs);
|
SetConsoleTextAttribute(stdout_handle, old_color_attrs);
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
|
|
||||||
#include <gtest/internal/gtest-port.h>
|
#include <gtest/internal/gtest-port.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#if GTEST_OS_MAC
|
#if GTEST_OS_MAC
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -699,11 +701,49 @@ TEST(RETest, PartialMatchWorks) {
|
||||||
|
|
||||||
#endif // GTEST_USES_POSIX_RE
|
#endif // GTEST_USES_POSIX_RE
|
||||||
|
|
||||||
TEST(CaptureStderrTest, CapturesStdErr) {
|
#if !GTEST_OS_WINDOWS_MOBILE
|
||||||
CaptureStderr();
|
|
||||||
fprintf(stderr, "abc");
|
TEST(CaptureTest, CapturesStdout) {
|
||||||
ASSERT_STREQ("abc", GetCapturedStderr().c_str());
|
CaptureStdout();
|
||||||
|
fprintf(stdout, "abc");
|
||||||
|
EXPECT_STREQ("abc", GetCapturedStdout().c_str());
|
||||||
|
|
||||||
|
CaptureStdout();
|
||||||
|
fprintf(stdout, "def%cghi", '\0');
|
||||||
|
EXPECT_EQ(::std::string("def\0ghi", 7), ::std::string(GetCapturedStdout()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(CaptureTest, CapturesStderr) {
|
||||||
|
CaptureStderr();
|
||||||
|
fprintf(stderr, "jkl");
|
||||||
|
EXPECT_STREQ("jkl", GetCapturedStderr().c_str());
|
||||||
|
|
||||||
|
CaptureStderr();
|
||||||
|
fprintf(stderr, "jkl%cmno", '\0');
|
||||||
|
EXPECT_EQ(::std::string("jkl\0mno", 7), ::std::string(GetCapturedStderr()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that stdout and stderr capture don't interfere with each other.
|
||||||
|
TEST(CaptureTest, CapturesStdoutAndStderr) {
|
||||||
|
CaptureStdout();
|
||||||
|
CaptureStderr();
|
||||||
|
fprintf(stdout, "pqr");
|
||||||
|
fprintf(stderr, "stu");
|
||||||
|
EXPECT_STREQ("pqr", GetCapturedStdout().c_str());
|
||||||
|
EXPECT_STREQ("stu", GetCapturedStderr().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CaptureDeathTest, CannotReenterStdoutCapture) {
|
||||||
|
CaptureStdout();
|
||||||
|
EXPECT_DEATH_IF_SUPPORTED(CaptureStdout();,
|
||||||
|
"Only one stdout capturer can exist at a time");
|
||||||
|
GetCapturedStdout();
|
||||||
|
|
||||||
|
// We cannot test stderr capturing using death tests as they use it
|
||||||
|
// themselves.
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !GTEST_OS_WINDOWS_MOBILE
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
Loading…
Reference in New Issue
Block a user