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
ba072ccc
Commit
ba072ccc
authored
Feb 22, 2013
by
kosak
Browse files
Fixes gUnit streaming output format.
parent
cc1fdb58
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
232 additions
and
111 deletions
+232
-111
include/gtest/gtest.h
include/gtest/gtest.h
+3
-0
src/gtest-internal-inl.h
src/gtest-internal-inl.h
+153
-0
src/gtest.cc
src/gtest.cc
+1
-111
test/gtest_unittest.cc
test/gtest_unittest.cc
+75
-0
No files found.
include/gtest/gtest.h
View file @
ba072ccc
...
...
@@ -154,6 +154,7 @@ class ExecDeathTest;
class
NoExecDeathTest
;
class
FinalSuccessChecker
;
class
GTestFlagSaver
;
class
StreamingListenerTest
;
class
TestResultAccessor
;
class
TestEventListenersAccessor
;
class
TestEventRepeater
;
...
...
@@ -679,6 +680,7 @@ class GTEST_API_ TestInfo {
friend
class
Test
;
friend
class
TestCase
;
friend
class
internal
::
UnitTestImpl
;
friend
class
internal
::
StreamingListenerTest
;
friend
TestInfo
*
internal
::
MakeAndRegisterTestInfo
(
const
char
*
test_case_name
,
const
char
*
name
,
...
...
@@ -1219,6 +1221,7 @@ class GTEST_API_ UnitTest {
friend
class
Test
;
friend
class
internal
::
AssertHelper
;
friend
class
internal
::
ScopedTrace
;
friend
class
internal
::
StreamingListenerTest
;
friend
Environment
*
AddGlobalTestEnvironment
(
Environment
*
env
);
friend
internal
::
UnitTestImpl
*
internal
::
GetUnitTestImpl
();
friend
void
internal
::
ReportFailureInUnknownLocation
(
...
...
src/gtest-internal-inl.h
View file @
ba072ccc
...
...
@@ -58,6 +58,11 @@
#include "gtest/internal/gtest-port.h"
#if GTEST_CAN_STREAM_RESULTS_
# include <arpa/inet.h> // NOLINT
# include <netdb.h> // NOLINT
#endif
#if GTEST_OS_WINDOWS
# include <windows.h> // NOLINT
#endif // GTEST_OS_WINDOWS
...
...
@@ -1048,6 +1053,154 @@ class TestResultAccessor {
}
};
#if GTEST_CAN_STREAM_RESULTS_
// Streams test results to the given port on the given host machine.
class
StreamingListener
:
public
EmptyTestEventListener
{
public:
// Abstract base class for writing strings to a socket.
class
AbstractSocketWriter
{
public:
virtual
~
AbstractSocketWriter
()
{}
// Sends a string to the socket.
virtual
void
Send
(
const
string
&
message
)
=
0
;
// Closes the socket.
virtual
void
CloseConnection
()
{}
// Sends a string and a newline to the socket.
void
SendLn
(
const
string
&
message
)
{
Send
(
message
+
"
\n
"
);
}
};
// Concrete class for actually writing strings to a socket.
class
SocketWriter
:
public
AbstractSocketWriter
{
public:
SocketWriter
(
const
string
&
host
,
const
string
&
port
)
:
sockfd_
(
-
1
),
host_name_
(
host
),
port_num_
(
port
)
{
MakeConnection
();
}
virtual
~
SocketWriter
()
{
if
(
sockfd_
!=
-
1
)
CloseConnection
();
}
// Sends a string to the socket.
virtual
void
Send
(
const
string
&
message
)
{
GTEST_CHECK_
(
sockfd_
!=
-
1
)
<<
"Send() can be called only when there is a connection."
;
const
int
len
=
static_cast
<
int
>
(
message
.
length
());
if
(
write
(
sockfd_
,
message
.
c_str
(),
len
)
!=
len
)
{
GTEST_LOG_
(
WARNING
)
<<
"stream_result_to: failed to stream to "
<<
host_name_
<<
":"
<<
port_num_
;
}
}
private:
// Creates a client socket and connects to the server.
void
MakeConnection
();
// Closes the socket.
void
CloseConnection
()
{
GTEST_CHECK_
(
sockfd_
!=
-
1
)
<<
"CloseConnection() can be called only when there is a connection."
;
close
(
sockfd_
);
sockfd_
=
-
1
;
}
int
sockfd_
;
// socket file descriptor
const
string
host_name_
;
const
string
port_num_
;
GTEST_DISALLOW_COPY_AND_ASSIGN_
(
SocketWriter
);
};
// class SocketWriter
// Escapes '=', '&', '%', and '\n' characters in str as "%xx".
static
string
UrlEncode
(
const
char
*
str
);
StreamingListener
(
const
string
&
host
,
const
string
&
port
)
:
socket_writer_
(
new
SocketWriter
(
host
,
port
))
{
Start
();
}
explicit
StreamingListener
(
AbstractSocketWriter
*
socket_writer
)
:
socket_writer_
(
socket_writer
)
{
Start
();
}
void
OnTestProgramStart
(
const
UnitTest
&
/* unit_test */
)
{
SendLn
(
"event=TestProgramStart"
);
}
void
OnTestProgramEnd
(
const
UnitTest
&
unit_test
)
{
// Note that Google Test current only report elapsed time for each
// test iteration, not for the entire test program.
SendLn
(
"event=TestProgramEnd&passed="
+
FormatBool
(
unit_test
.
Passed
()));
// Notify the streaming server to stop.
socket_writer_
->
CloseConnection
();
}
void
OnTestIterationStart
(
const
UnitTest
&
/* unit_test */
,
int
iteration
)
{
SendLn
(
"event=TestIterationStart&iteration="
+
StreamableToString
(
iteration
));
}
void
OnTestIterationEnd
(
const
UnitTest
&
unit_test
,
int
/* iteration */
)
{
SendLn
(
"event=TestIterationEnd&passed="
+
FormatBool
(
unit_test
.
Passed
())
+
"&elapsed_time="
+
StreamableToString
(
unit_test
.
elapsed_time
())
+
"ms"
);
}
void
OnTestCaseStart
(
const
TestCase
&
test_case
)
{
SendLn
(
std
::
string
(
"event=TestCaseStart&name="
)
+
test_case
.
name
());
}
void
OnTestCaseEnd
(
const
TestCase
&
test_case
)
{
SendLn
(
"event=TestCaseEnd&passed="
+
FormatBool
(
test_case
.
Passed
())
+
"&elapsed_time="
+
StreamableToString
(
test_case
.
elapsed_time
())
+
"ms"
);
}
void
OnTestStart
(
const
TestInfo
&
test_info
)
{
SendLn
(
std
::
string
(
"event=TestStart&name="
)
+
test_info
.
name
());
}
void
OnTestEnd
(
const
TestInfo
&
test_info
)
{
SendLn
(
"event=TestEnd&passed="
+
FormatBool
((
test_info
.
result
())
->
Passed
())
+
"&elapsed_time="
+
StreamableToString
((
test_info
.
result
())
->
elapsed_time
())
+
"ms"
);
}
void
OnTestPartResult
(
const
TestPartResult
&
test_part_result
)
{
const
char
*
file_name
=
test_part_result
.
file_name
();
if
(
file_name
==
NULL
)
file_name
=
""
;
SendLn
(
"event=TestPartResult&file="
+
UrlEncode
(
file_name
)
+
"&line="
+
StreamableToString
(
test_part_result
.
line_number
())
+
"&message="
+
UrlEncode
(
test_part_result
.
message
()));
}
private:
// Sends the given message and a newline to the socket.
void
SendLn
(
const
string
&
message
)
{
socket_writer_
->
SendLn
(
message
);
}
// Called at the start of streaming to notify the receiver what
// protocol we are using.
void
Start
()
{
SendLn
(
"gtest_streaming_protocol_version=1.0"
);
}
string
FormatBool
(
bool
value
)
{
return
value
?
"1"
:
"0"
;
}
const
scoped_ptr
<
AbstractSocketWriter
>
socket_writer_
;
GTEST_DISALLOW_COPY_AND_ASSIGN_
(
StreamingListener
);
};
// class StreamingListener
#endif // GTEST_CAN_STREAM_RESULTS_
}
// namespace internal
}
// namespace testing
...
...
src/gtest.cc
View file @
ba072ccc
...
...
@@ -3230,116 +3230,6 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
#if GTEST_CAN_STREAM_RESULTS_
// Streams test results to the given port on the given host machine.
class
StreamingListener
:
public
EmptyTestEventListener
{
public:
// Escapes '=', '&', '%', and '\n' characters in str as "%xx".
static
string
UrlEncode
(
const
char
*
str
);
StreamingListener
(
const
string
&
host
,
const
string
&
port
)
:
sockfd_
(
-
1
),
host_name_
(
host
),
port_num_
(
port
)
{
MakeConnection
();
SendLn
(
"gtest_streaming_protocol_version=1.0"
);
}
virtual
~
StreamingListener
()
{
if
(
sockfd_
!=
-
1
)
CloseConnection
();
}
void
OnTestProgramStart
(
const
UnitTest
&
/* unit_test */
)
{
SendLn
(
"event=TestProgramStart"
);
}
void
OnTestProgramEnd
(
const
UnitTest
&
unit_test
)
{
// Note that Google Test current only report elapsed time for each
// test iteration, not for the entire test program.
SendLn
(
"event=TestProgramEnd&passed="
+
StreamableToString
(
unit_test
.
Passed
()));
// Notify the streaming server to stop.
CloseConnection
();
}
void
OnTestIterationStart
(
const
UnitTest
&
/* unit_test */
,
int
iteration
)
{
SendLn
(
"event=TestIterationStart&iteration="
+
StreamableToString
(
iteration
));
}
void
OnTestIterationEnd
(
const
UnitTest
&
unit_test
,
int
/* iteration */
)
{
SendLn
(
"event=TestIterationEnd&passed="
+
StreamableToString
(
unit_test
.
Passed
())
+
"&elapsed_time="
+
StreamableToString
(
unit_test
.
elapsed_time
())
+
"ms"
);
}
void
OnTestCaseStart
(
const
TestCase
&
test_case
)
{
SendLn
(
std
::
string
(
"event=TestCaseStart&name="
)
+
test_case
.
name
());
}
void
OnTestCaseEnd
(
const
TestCase
&
test_case
)
{
SendLn
(
"event=TestCaseEnd&passed="
+
StreamableToString
(
test_case
.
Passed
())
+
"&elapsed_time="
+
StreamableToString
(
test_case
.
elapsed_time
())
+
"ms"
);
}
void
OnTestStart
(
const
TestInfo
&
test_info
)
{
SendLn
(
std
::
string
(
"event=TestStart&name="
)
+
test_info
.
name
());
}
void
OnTestEnd
(
const
TestInfo
&
test_info
)
{
SendLn
(
"event=TestEnd&passed="
+
StreamableToString
((
test_info
.
result
())
->
Passed
())
+
"&elapsed_time="
+
StreamableToString
((
test_info
.
result
())
->
elapsed_time
())
+
"ms"
);
}
void
OnTestPartResult
(
const
TestPartResult
&
test_part_result
)
{
const
char
*
file_name
=
test_part_result
.
file_name
();
if
(
file_name
==
NULL
)
file_name
=
""
;
SendLn
(
"event=TestPartResult&file="
+
UrlEncode
(
file_name
)
+
"&line="
+
StreamableToString
(
test_part_result
.
line_number
())
+
"&message="
+
UrlEncode
(
test_part_result
.
message
()));
}
private:
// Creates a client socket and connects to the server.
void
MakeConnection
();
// Closes the socket.
void
CloseConnection
()
{
GTEST_CHECK_
(
sockfd_
!=
-
1
)
<<
"CloseConnection() can be called only when there is a connection."
;
close
(
sockfd_
);
sockfd_
=
-
1
;
}
// Sends a string to the socket.
void
Send
(
const
string
&
message
)
{
GTEST_CHECK_
(
sockfd_
!=
-
1
)
<<
"Send() can be called only when there is a connection."
;
const
int
len
=
static_cast
<
int
>
(
message
.
length
());
if
(
write
(
sockfd_
,
message
.
c_str
(),
len
)
!=
len
)
{
GTEST_LOG_
(
WARNING
)
<<
"stream_result_to: failed to stream to "
<<
host_name_
<<
":"
<<
port_num_
;
}
}
// Sends a string and a newline to the socket.
void
SendLn
(
const
string
&
message
)
{
Send
(
message
+
"
\n
"
);
}
int
sockfd_
;
// socket file descriptor
const
string
host_name_
;
const
string
port_num_
;
GTEST_DISALLOW_COPY_AND_ASSIGN_
(
StreamingListener
);
};
// class StreamingListener
// Checks if str contains '=', '&', '%' or '\n' characters. If yes,
// replaces them by "%xx" where xx is their hexadecimal value. For
// example, replaces "=" with "%3D". This algorithm is O(strlen(str))
...
...
@@ -3364,7 +3254,7 @@ string StreamingListener::UrlEncode(const char* str) {
return
result
;
}
void
StreamingListener
::
MakeConnection
()
{
void
StreamingListener
::
SocketWriter
::
MakeConnection
()
{
GTEST_CHECK_
(
sockfd_
==
-
1
)
<<
"MakeConnection() can't be called when there is already a connection."
;
...
...
test/gtest_unittest.cc
View file @
ba072ccc
...
...
@@ -79,6 +79,81 @@ TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) {
namespace
testing
{
namespace
internal
{
#if GTEST_CAN_STREAM_RESULTS_
class
StreamingListenerTest
:
public
Test
{
public:
class
FakeSocketWriter
:
public
StreamingListener
::
AbstractSocketWriter
{
public:
// Sends a string to the socket.
virtual
void
Send
(
const
string
&
message
)
{
output_
+=
message
;
}
string
output_
;
};
StreamingListenerTest
()
:
fake_sock_writer_
(
new
FakeSocketWriter
),
streamer_
(
fake_sock_writer_
),
test_info_obj_
(
"FooTest"
,
"Bar"
,
NULL
,
NULL
,
0
,
NULL
)
{}
protected:
string
*
output
()
{
return
&
(
fake_sock_writer_
->
output_
);
}
FakeSocketWriter
*
const
fake_sock_writer_
;
StreamingListener
streamer_
;
UnitTest
unit_test_
;
TestInfo
test_info_obj_
;
// The name test_info_ was taken by testing::Test.
};
TEST_F
(
StreamingListenerTest
,
OnTestProgramEnd
)
{
*
output
()
=
""
;
streamer_
.
OnTestProgramEnd
(
unit_test_
);
EXPECT_EQ
(
"event=TestProgramEnd&passed=1
\n
"
,
*
output
());
}
TEST_F
(
StreamingListenerTest
,
OnTestIterationEnd
)
{
*
output
()
=
""
;
streamer_
.
OnTestIterationEnd
(
unit_test_
,
42
);
EXPECT_EQ
(
"event=TestIterationEnd&passed=1&elapsed_time=0ms
\n
"
,
*
output
());
}
TEST_F
(
StreamingListenerTest
,
OnTestCaseStart
)
{
*
output
()
=
""
;
streamer_
.
OnTestCaseStart
(
TestCase
(
"FooTest"
,
"Bar"
,
NULL
,
NULL
));
EXPECT_EQ
(
"event=TestCaseStart&name=FooTest
\n
"
,
*
output
());
}
TEST_F
(
StreamingListenerTest
,
OnTestCaseEnd
)
{
*
output
()
=
""
;
streamer_
.
OnTestCaseEnd
(
TestCase
(
"FooTest"
,
"Bar"
,
NULL
,
NULL
));
EXPECT_EQ
(
"event=TestCaseEnd&passed=1&elapsed_time=0ms
\n
"
,
*
output
());
}
TEST_F
(
StreamingListenerTest
,
OnTestStart
)
{
*
output
()
=
""
;
streamer_
.
OnTestStart
(
test_info_obj_
);
EXPECT_EQ
(
"event=TestStart&name=Bar
\n
"
,
*
output
());
}
TEST_F
(
StreamingListenerTest
,
OnTestEnd
)
{
*
output
()
=
""
;
streamer_
.
OnTestEnd
(
test_info_obj_
);
EXPECT_EQ
(
"event=TestEnd&passed=1&elapsed_time=0ms
\n
"
,
*
output
());
}
TEST_F
(
StreamingListenerTest
,
OnTestPartResult
)
{
*
output
()
=
""
;
streamer_
.
OnTestPartResult
(
TestPartResult
(
TestPartResult
::
kFatalFailure
,
"foo.cc"
,
42
,
"failed=
\n
&%"
));
// Meta characters in the failure message should be properly escaped.
EXPECT_EQ
(
"event=TestPartResult&file=foo.cc&line=42&message=failed%3D%0A%26%25
\n
"
,
*
output
());
}
#endif // GTEST_CAN_STREAM_RESULTS_
// Provides access to otherwise private parts of the TestEventListeners class
// that are needed to test it.
class
TestEventListenersAccessor
{
...
...
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