Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
yangql
googletest
Commits
fd6f2a8a
Commit
fd6f2a8a
authored
Jan 27, 2010
by
zhanyong.wan
Browse files
Implements stdout capturing (by Vlad Losev); fixes compiler error on NVCC (by Zhanyong Wan).
parent
27a65a9d
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
137 additions
and
61 deletions
+137
-61
include/gtest/internal/gtest-port.h
include/gtest/internal/gtest-port.h
+19
-4
src/gtest-port.cc
src/gtest-port.cc
+72
-54
src/gtest.cc
src/gtest.cc
+3
-0
test/gtest-port_test.cc
test/gtest-port_test.cc
+43
-3
No files found.
include/gtest/internal/gtest-port.h
View file @
fd6f2a8a
...
...
@@ -132,7 +132,10 @@
// LogToStderr() - directs all log messages to stderr.
// 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.
// GetCapturedStderr() - stops capturing stderr and returns the captured
// string.
...
...
@@ -353,12 +356,15 @@
#ifndef GTEST_USE_OWN_TR1_TUPLE
// The user didn't tell us, so we need to figure it out.
// We use our own
tr
1 tuple if we aren't sure the user has an
// We use our own
TR
1 tuple if we aren't sure the user has an
// 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
// 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
// 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
#else
#define GTEST_USE_OWN_TR1_TUPLE 1
...
...
@@ -690,13 +696,22 @@ class GTestLog {
inline
void
LogToStderr
()
{}
inline
void
FlushInfoLog
()
{
fflush
(
NULL
);
}
#if !GTEST_OS_WINDOWS_MOBILE
// Defines the stderr capturer:
// CaptureStdout - starts capturing stdout.
// GetCapturedStdout - stops capturing stdout and returns the captured string.
// CaptureStderr - starts capturing stderr.
// GetCapturedStderr - stops capturing stderr and returns the captured string.
//
void
CaptureStdout
();
String
GetCapturedStdout
();
void
CaptureStderr
();
String
GetCapturedStderr
();
#endif // !GTEST_OS_WINDOWS_MOBILE
#if GTEST_HAS_DEATH_TEST
// A copy of all command line arguments. Set by InitGoogleTest().
...
...
src/gtest-port.cc
View file @
fd6f2a8a
...
...
@@ -68,8 +68,10 @@ namespace internal {
#if defined(_MSC_VER) || defined(__BORLANDC__)
// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
const
int
kStdOutFileno
=
1
;
const
int
kStdErrFileno
=
2
;
#else
const
int
kStdOutFileno
=
STDOUT_FILENO
;
const
int
kStdErrFileno
=
STDERR_FILENO
;
#endif // _MSC_VER
...
...
@@ -439,18 +441,14 @@ GTestLog::~GTestLog() {
#pragma warning(disable: 4996)
#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:
// The ctor redirects stderr to a temporary file.
CapturedStderr
()
{
#if GTEST_OS_WINDOWS_MOBILE
// Not supported on Windows CE.
posix
::
Abort
();
#else
uncaptured_fd_
=
dup
(
kStdErrFileno
);
// The ctor redirects the stream to a temporary file.
CapturedStream
(
int
fd
)
:
fd_
(
fd
),
uncaptured_fd_
(
dup
(
fd
))
{
#if GTEST_OS_WINDOWS
char
temp_dir_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
// current directory, so we create the temporary file in the /tmp
// directory instead.
char
name_template
[]
=
"/tmp/captured_st
derr
.XXXXXX"
;
char
name_template
[]
=
"/tmp/captured_st
ream
.XXXXXX"
;
const
int
captured_fd
=
mkstemp
(
name_template
);
filename_
=
name_template
;
#endif // GTEST_OS_WINDOWS
fflush
(
NULL
);
dup2
(
captured_fd
,
kStdErrFileno
);
dup2
(
captured_fd
,
fd_
);
close
(
captured_fd
);
#endif // GTEST_OS_WINDOWS_MOBILE
}
~
CapturedStderr
()
{
#if !GTEST_OS_WINDOWS_MOBILE
~
CapturedStream
()
{
remove
(
filename_
.
c_str
());
#endif // !GTEST_OS_WINDOWS_MOBILE
}
// Stops redirecting stderr.
void
StopCapture
()
{
#if !GTEST_OS_WINDOWS_MOBILE
// Restores the original stream.
fflush
(
NULL
);
dup2
(
uncaptured_fd_
,
kStdErrFileno
);
close
(
uncaptured_fd_
);
uncaptured_fd_
=
-
1
;
#endif // !GTEST_OS_WINDOWS_MOBILE
}
String
GetCapturedString
()
{
if
(
uncaptured_fd_
!=
-
1
)
{
// Restores the original stream.
fflush
(
NULL
);
dup2
(
uncaptured_fd_
,
fd_
);
close
(
uncaptured_fd_
);
uncaptured_fd_
=
-
1
;
}
// Returns the name of the temporary file holding the stderr output.
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
// can use it here.
::
std
::
string
filename
()
const
{
return
filename_
;
}
FILE
*
const
file
=
posix
::
FOpen
(
filename_
.
c_str
(),
"r"
);
const
String
content
=
ReadEntireFile
(
file
);
posix
::
FClose
(
file
);
return
content
;
}
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_
;
// Name of the temporary file holding the stderr output.
::
std
::
string
filename_
;
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
static
CapturedStderr
*
g_captured_stderr
=
NULL
;
GTEST_DISALLOW_COPY_AND_ASSIGN_
(
CapturedStream
);
};
// Returns the size (in bytes) of a file.
s
tatic
size_t
GetFileSize
(
FILE
*
file
)
{
s
ize_t
CapturedStream
::
GetFileSize
(
FILE
*
file
)
{
fseek
(
file
,
0
,
SEEK_END
);
return
static_cast
<
size_t
>
(
ftell
(
file
));
}
// 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
);
char
*
const
buffer
=
new
char
[
file_size
];
...
...
@@ -535,30 +533,50 @@ static String ReadEntireFile(FILE * file) {
return
content
;
}
// Starts capturing stderr.
void
CaptureStderr
()
{
if
(
g_captured_stderr
!=
NULL
)
{
GTEST_LOG_
(
FATAL
)
<<
"Only one stderr capturer can exist at one time."
;
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
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
CapturedSt
derr
;
*
stream
=
new
CapturedSt
ream
(
fd
)
;
}
// Stops capturing stderr and returns the captured string.
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
// use it here.
String
GetCapturedStderr
()
{
g_captured_stderr
->
StopCapture
();
// Stops capturing the output stream and returns the captured string.
String
GetCapturedStream
(
CapturedStream
**
captured_stream
)
{
const
String
content
=
(
*
captured_stream
)
->
GetCapturedString
();
FILE
*
const
file
=
posix
::
FOpen
(
g_captured_stderr
->
filename
().
c_str
(),
"r"
);
const
String
content
=
ReadEntireFile
(
file
);
posix
::
FClose
(
file
);
delete
g_captured_stderr
;
g_captured_stderr
=
NULL
;
delete
*
captured_stream
;
*
captured_stream
=
NULL
;
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
// A copy of all command line arguments. Set by InitGoogleTest().
...
...
src/gtest.cc
View file @
fd6f2a8a
...
...
@@ -2634,6 +2634,9 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) {
SetConsoleTextAttribute
(
stdout_handle
,
GetColorAttribute
(
color
)
|
FOREGROUND_INTENSITY
);
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.
SetConsoleTextAttribute
(
stdout_handle
,
old_color_attrs
);
...
...
test/gtest-port_test.cc
View file @
fd6f2a8a
...
...
@@ -33,6 +33,8 @@
#include <gtest/internal/gtest-port.h>
#include <stdio.h>
#if GTEST_OS_MAC
#include <pthread.h>
#include <time.h>
...
...
@@ -699,11 +701,49 @@ TEST(RETest, PartialMatchWorks) {
#endif // GTEST_USES_POSIX_RE
TEST
(
CaptureStderrTest
,
CapturesStdErr
)
{
#if !GTEST_OS_WINDOWS_MOBILE
TEST
(
CaptureTest
,
CapturesStdout
)
{
CaptureStdout
();
fprintf
(
stdout
,
"abc"
);
EXPECT_STREQ
(
"abc"
,
GetCapturedStdout
().
c_str
());
CaptureStdout
();
fprintf
(
stdout
,
"def%cghi"
,
'\0'
);
EXPECT_EQ
(
::
std
::
string
(
"def
\0
ghi"
,
7
),
::
std
::
string
(
GetCapturedStdout
()));
}
TEST
(
CaptureTest
,
CapturesStderr
)
{
CaptureStderr
();
fprintf
(
stderr
,
"jkl"
);
EXPECT_STREQ
(
"jkl"
,
GetCapturedStderr
().
c_str
());
CaptureStderr
();
fprintf
(
stderr
,
"
abc"
);
ASSERT_STREQ
(
"abc"
,
GetCapturedStderr
()
.
c_str
(
));
fprintf
(
stderr
,
"
jkl%cmno"
,
'\0'
);
EXPECT_EQ
(
::
std
::
string
(
"jkl
\0
mno"
,
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 testing
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment