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
f5fa71f7
Commit
f5fa71f7
authored
Apr 05, 2013
by
vladlosev
Browse files
Implements support for calling Test::RecordProperty() outside of a test.
parent
5f18b68b
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
512 additions
and
187 deletions
+512
-187
include/gtest/gtest.h
include/gtest/gtest.h
+43
-22
src/gtest-internal-inl.h
src/gtest-internal-inl.h
+9
-3
src/gtest.cc
src/gtest.cc
+261
-109
test/gtest_unittest.cc
test/gtest_unittest.cc
+187
-47
test/gtest_xml_output_unittest.py
test/gtest_xml_output_unittest.py
+2
-2
test/gtest_xml_output_unittest_.cc
test/gtest_xml_output_unittest_.cc
+7
-3
test/gtest_xml_test_utils.py
test/gtest_xml_test_utils.py
+3
-1
No files found.
include/gtest/gtest.h
View file @
f5fa71f7
...
@@ -158,6 +158,7 @@ class StreamingListenerTest;
...
@@ -158,6 +158,7 @@ class StreamingListenerTest;
class
TestResultAccessor
;
class
TestResultAccessor
;
class
TestEventListenersAccessor
;
class
TestEventListenersAccessor
;
class
TestEventRepeater
;
class
TestEventRepeater
;
class
UnitTestRecordPropertyTestHelper
;
class
WindowsDeathTest
;
class
WindowsDeathTest
;
class
UnitTestImpl
*
GetUnitTestImpl
();
class
UnitTestImpl
*
GetUnitTestImpl
();
void
ReportFailureInUnknownLocation
(
TestPartResult
::
Type
result_type
,
void
ReportFailureInUnknownLocation
(
TestPartResult
::
Type
result_type
,
...
@@ -381,20 +382,21 @@ class GTEST_API_ Test {
...
@@ -381,20 +382,21 @@ class GTEST_API_ Test {
// non-fatal) failure.
// non-fatal) failure.
static
bool
HasFailure
()
{
return
HasFatalFailure
()
||
HasNonfatalFailure
();
}
static
bool
HasFailure
()
{
return
HasFatalFailure
()
||
HasNonfatalFailure
();
}
// Logs a property for the current test. Only the last value for a given
// Logs a property for the current test, test case, or for the entire
// key is remembered.
// invocation of the test program when used outside of the context of a
// These are public static so they can be called from utility functions
// test case. Only the last value for a given key is remembered. These
// that are not members of the test fixture.
// are public static so they can be called from utility functions that are
// The arguments are const char* instead strings, as Google Test is used
// not members of the test fixture. Calls to RecordProperty made during
// on platforms where string doesn't compile.
// lifespan of the test (from the moment its constructor starts to the
//
// moment its destructor finishes) will be output in XML as attributes of
// Note that a driving consideration for these RecordProperty methods
// the <testcase> element. Properties recorded from fixture's
// was to produce xml output suited to the Greenspan charting utility,
// SetUpTestCase or TearDownTestCase are logged as attributes of the
// which at present will only chart values that fit in a 32-bit int. It
// corresponding <testsuite> element. Calls to RecordProperty made in the
// is the user's responsibility to restrict their values to 32-bit ints
// global context (before or after invocation of RUN_ALL_TESTS and from
// if they intend them to be used with Greenspan.
// SetUp/TearDown method of Environment objects registered with Google
static
void
RecordProperty
(
const
char
*
key
,
const
char
*
value
);
// Test) will be output as attributes of the <testsuites> element.
static
void
RecordProperty
(
const
char
*
key
,
int
value
);
static
void
RecordProperty
(
const
std
::
string
&
key
,
const
std
::
string
&
value
);
static
void
RecordProperty
(
const
std
::
string
&
key
,
int
value
);
protected:
protected:
// Creates a Test object.
// Creates a Test object.
...
@@ -463,7 +465,7 @@ class TestProperty {
...
@@ -463,7 +465,7 @@ class TestProperty {
// C'tor. TestProperty does NOT have a default constructor.
// C'tor. TestProperty does NOT have a default constructor.
// Always use this constructor (with parameters) to create a
// Always use this constructor (with parameters) to create a
// TestProperty object.
// TestProperty object.
TestProperty
(
const
char
*
a_key
,
const
char
*
a_value
)
:
TestProperty
(
const
std
::
string
&
a_key
,
const
std
::
string
&
a_value
)
:
key_
(
a_key
),
value_
(
a_value
)
{
key_
(
a_key
),
value_
(
a_value
)
{
}
}
...
@@ -478,7 +480,7 @@ class TestProperty {
...
@@ -478,7 +480,7 @@ class TestProperty {
}
}
// Sets a new value, overriding the one supplied in the constructor.
// Sets a new value, overriding the one supplied in the constructor.
void
SetValue
(
const
char
*
new_value
)
{
void
SetValue
(
const
std
::
string
&
new_value
)
{
value_
=
new_value
;
value_
=
new_value
;
}
}
...
@@ -537,6 +539,7 @@ class GTEST_API_ TestResult {
...
@@ -537,6 +539,7 @@ class GTEST_API_ TestResult {
private:
private:
friend
class
TestInfo
;
friend
class
TestInfo
;
friend
class
TestCase
;
friend
class
UnitTest
;
friend
class
UnitTest
;
friend
class
internal
::
DefaultGlobalTestPartResultReporter
;
friend
class
internal
::
DefaultGlobalTestPartResultReporter
;
friend
class
internal
::
ExecDeathTest
;
friend
class
internal
::
ExecDeathTest
;
...
@@ -561,13 +564,16 @@ class GTEST_API_ TestResult {
...
@@ -561,13 +564,16 @@ class GTEST_API_ TestResult {
// a non-fatal failure if invalid (e.g., if it conflicts with reserved
// a non-fatal failure if invalid (e.g., if it conflicts with reserved
// key names). If a property is already recorded for the same key, the
// key names). If a property is already recorded for the same key, the
// value will be updated, rather than storing multiple values for the same
// value will be updated, rather than storing multiple values for the same
// key.
// key. xml_element specifies the element for which the property is being
void
RecordProperty
(
const
TestProperty
&
test_property
);
// recorded and is used for validation.
void
RecordProperty
(
const
std
::
string
&
xml_element
,
const
TestProperty
&
test_property
);
// Adds a failure if the key is a reserved attribute of Google Test
// Adds a failure if the key is a reserved attribute of Google Test
// testcase tags. Returns true if the property is valid.
// testcase tags. Returns true if the property is valid.
// TODO(russr): Validate attribute names are legal and human readable.
// TODO(russr): Validate attribute names are legal and human readable.
static
bool
ValidateTestProperty
(
const
TestProperty
&
test_property
);
static
bool
ValidateTestProperty
(
const
std
::
string
&
xml_element
,
const
TestProperty
&
test_property
);
// Adds a test part result to the list.
// Adds a test part result to the list.
void
AddTestPartResult
(
const
TestPartResult
&
test_part_result
);
void
AddTestPartResult
(
const
TestPartResult
&
test_part_result
);
...
@@ -792,6 +798,10 @@ class GTEST_API_ TestCase {
...
@@ -792,6 +798,10 @@ class GTEST_API_ TestCase {
// total_test_count() - 1. If i is not in that range, returns NULL.
// total_test_count() - 1. If i is not in that range, returns NULL.
const
TestInfo
*
GetTestInfo
(
int
i
)
const
;
const
TestInfo
*
GetTestInfo
(
int
i
)
const
;
// Returns the TestResult that holds test properties recorded during
// execution of SetUpTestCase and TearDownTestCase.
const
TestResult
&
ad_hoc_test_result
()
const
{
return
ad_hoc_test_result_
;
}
private:
private:
friend
class
Test
;
friend
class
Test
;
friend
class
internal
::
UnitTestImpl
;
friend
class
internal
::
UnitTestImpl
;
...
@@ -880,6 +890,9 @@ class GTEST_API_ TestCase {
...
@@ -880,6 +890,9 @@ class GTEST_API_ TestCase {
bool
should_run_
;
bool
should_run_
;
// Elapsed time, in milliseconds.
// Elapsed time, in milliseconds.
TimeInMillis
elapsed_time_
;
TimeInMillis
elapsed_time_
;
// Holds test properties recorded during execution of SetUpTestCase and
// TearDownTestCase.
TestResult
ad_hoc_test_result_
;
// We disallow copying TestCases.
// We disallow copying TestCases.
GTEST_DISALLOW_COPY_AND_ASSIGN_
(
TestCase
);
GTEST_DISALLOW_COPY_AND_ASSIGN_
(
TestCase
);
...
@@ -1165,6 +1178,10 @@ class GTEST_API_ UnitTest {
...
@@ -1165,6 +1178,10 @@ class GTEST_API_ UnitTest {
// total_test_case_count() - 1. If i is not in that range, returns NULL.
// total_test_case_count() - 1. If i is not in that range, returns NULL.
const
TestCase
*
GetTestCase
(
int
i
)
const
;
const
TestCase
*
GetTestCase
(
int
i
)
const
;
// Returns the TestResult containing information on test failures and
// properties logged outside of individual test cases.
const
TestResult
&
ad_hoc_test_result
()
const
;
// Returns the list of event listeners that can be used to track events
// Returns the list of event listeners that can be used to track events
// inside Google Test.
// inside Google Test.
TestEventListeners
&
listeners
();
TestEventListeners
&
listeners
();
...
@@ -1192,9 +1209,12 @@ class GTEST_API_ UnitTest {
...
@@ -1192,9 +1209,12 @@ class GTEST_API_ UnitTest {
const
std
::
string
&
os_stack_trace
)
const
std
::
string
&
os_stack_trace
)
GTEST_LOCK_EXCLUDED_
(
mutex_
);
GTEST_LOCK_EXCLUDED_
(
mutex_
);
// Adds a TestProperty to the current TestResult object. If the result already
// Adds a TestProperty to the current TestResult object when invoked from
// contains a property with the same key, the value will be updated.
// inside a test, to current TestCase's ad_hoc_test_result_ when invoked
void
RecordPropertyForCurrentTest
(
const
char
*
key
,
const
char
*
value
);
// from SetUpTestCase or TearDownTestCase, or to the global property set
// when invoked elsewhere. If the result already contains a property with
// the same key, the value will be updated.
void
RecordProperty
(
const
std
::
string
&
key
,
const
std
::
string
&
value
);
// Gets the i-th test case among all the test cases. i can range from 0 to
// Gets the i-th test case among all the test cases. i can range from 0 to
// total_test_case_count() - 1. If i is not in that range, returns NULL.
// total_test_case_count() - 1. If i is not in that range, returns NULL.
...
@@ -1210,6 +1230,7 @@ class GTEST_API_ UnitTest {
...
@@ -1210,6 +1230,7 @@ class GTEST_API_ UnitTest {
friend
class
internal
::
AssertHelper
;
friend
class
internal
::
AssertHelper
;
friend
class
internal
::
ScopedTrace
;
friend
class
internal
::
ScopedTrace
;
friend
class
internal
::
StreamingListenerTest
;
friend
class
internal
::
StreamingListenerTest
;
friend
class
internal
::
UnitTestRecordPropertyTestHelper
;
friend
Environment
*
AddGlobalTestEnvironment
(
Environment
*
env
);
friend
Environment
*
AddGlobalTestEnvironment
(
Environment
*
env
);
friend
internal
::
UnitTestImpl
*
internal
::
GetUnitTestImpl
();
friend
internal
::
UnitTestImpl
*
internal
::
GetUnitTestImpl
();
friend
void
internal
::
ReportFailureInUnknownLocation
(
friend
void
internal
::
ReportFailureInUnknownLocation
(
...
...
src/gtest-internal-inl.h
View file @
f5fa71f7
...
@@ -348,8 +348,7 @@ class TestPropertyKeyIs {
...
@@ -348,8 +348,7 @@ class TestPropertyKeyIs {
// Constructor.
// Constructor.
//
//
// TestPropertyKeyIs has NO default constructor.
// TestPropertyKeyIs has NO default constructor.
explicit
TestPropertyKeyIs
(
const
char
*
key
)
explicit
TestPropertyKeyIs
(
const
std
::
string
&
key
)
:
key_
(
key
)
{}
:
key_
(
key
)
{}
// Returns true iff the test name of test property matches on key_.
// Returns true iff the test name of test property matches on key_.
bool
operator
()(
const
TestProperty
&
test_property
)
const
{
bool
operator
()(
const
TestProperty
&
test_property
)
const
{
...
@@ -712,6 +711,12 @@ class GTEST_API_ UnitTestImpl {
...
@@ -712,6 +711,12 @@ class GTEST_API_ UnitTestImpl {
ad_hoc_test_result_
.
Clear
();
ad_hoc_test_result_
.
Clear
();
}
}
// Adds a TestProperty to the current TestResult object when invoked in a
// context of a test or a test case, or to the global property set. If the
// result already contains a property with the same key, the value will be
// updated.
void
RecordProperty
(
const
TestProperty
&
test_property
);
enum
ReactionToSharding
{
enum
ReactionToSharding
{
HONOR_SHARDING_PROTOCOL
,
HONOR_SHARDING_PROTOCOL
,
IGNORE_SHARDING_PROTOCOL
IGNORE_SHARDING_PROTOCOL
...
@@ -1038,8 +1043,9 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
...
@@ -1038,8 +1043,9 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
class
TestResultAccessor
{
class
TestResultAccessor
{
public:
public:
static
void
RecordProperty
(
TestResult
*
test_result
,
static
void
RecordProperty
(
TestResult
*
test_result
,
const
std
::
string
&
xml_element
,
const
TestProperty
&
property
)
{
const
TestProperty
&
property
)
{
test_result
->
RecordProperty
(
property
);
test_result
->
RecordProperty
(
xml_element
,
property
);
}
}
static
void
ClearTestPartResults
(
TestResult
*
test_result
)
{
static
void
ClearTestPartResults
(
TestResult
*
test_result
)
{
...
...
src/gtest.cc
View file @
f5fa71f7
...
@@ -1716,8 +1716,9 @@ void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
...
@@ -1716,8 +1716,9 @@ void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
// Adds a test property to the list. If a property with the same key as the
// Adds a test property to the list. If a property with the same key as the
// supplied property is already represented, the value of this test_property
// supplied property is already represented, the value of this test_property
// replaces the old value for that key.
// replaces the old value for that key.
void
TestResult
::
RecordProperty
(
const
TestProperty
&
test_property
)
{
void
TestResult
::
RecordProperty
(
const
std
::
string
&
xml_element
,
if
(
!
ValidateTestProperty
(
test_property
))
{
const
TestProperty
&
test_property
)
{
if
(
!
ValidateTestProperty
(
xml_element
,
test_property
))
{
return
;
return
;
}
}
internal
::
MutexLock
lock
(
&
test_properites_mutex_
);
internal
::
MutexLock
lock
(
&
test_properites_mutex_
);
...
@@ -1731,21 +1732,94 @@ void TestResult::RecordProperty(const TestProperty& test_property) {
...
@@ -1731,21 +1732,94 @@ void TestResult::RecordProperty(const TestProperty& test_property) {
property_with_matching_key
->
SetValue
(
test_property
.
value
());
property_with_matching_key
->
SetValue
(
test_property
.
value
());
}
}
// Adds a failure if the key is a reserved attribute of Google Test
// The list of reserved attributes used in the <testsuites> element of XML
// testcase tags. Returns true if the property is valid.
// output.
bool
TestResult
::
ValidateTestProperty
(
const
TestProperty
&
test_property
)
{
static
const
char
*
const
kReservedTestSuitesAttributes
[]
=
{
const
std
::
string
&
key
=
test_property
.
key
();
"disabled"
,
if
(
key
==
"name"
||
key
==
"status"
||
key
==
"time"
||
key
==
"classname"
)
{
"errors"
,
ADD_FAILURE
()
"failures"
,
<<
"Reserved key used in RecordProperty(): "
"name"
,
<<
key
"random_seed"
,
<<
" ('name', 'status', 'time', and 'classname' are reserved by "
"tests"
,
<<
GTEST_NAME_
<<
")"
;
"time"
,
"timestamp"
};
// The list of reserved attributes used in the <testsuite> element of XML
// output.
static
const
char
*
const
kReservedTestSuiteAttributes
[]
=
{
"disabled"
,
"errors"
,
"failures"
,
"name"
,
"tests"
,
"time"
};
// The list of reserved attributes used in the <testcase> element of XML output.
static
const
char
*
const
kReservedTestCaseAttributes
[]
=
{
"classname"
,
"name"
,
"status"
,
"time"
,
"type_param"
,
"value_param"
};
template
<
int
kSize
>
std
::
vector
<
std
::
string
>
ArrayAsVector
(
const
char
*
const
(
&
array
)[
kSize
])
{
return
std
::
vector
<
std
::
string
>
(
array
,
array
+
kSize
);
}
static
std
::
vector
<
std
::
string
>
GetReservedAttributesForElement
(
const
std
::
string
&
xml_element
)
{
if
(
xml_element
==
"testsuites"
)
{
return
ArrayAsVector
(
kReservedTestSuitesAttributes
);
}
else
if
(
xml_element
==
"testsuite"
)
{
return
ArrayAsVector
(
kReservedTestSuiteAttributes
);
}
else
if
(
xml_element
==
"testcase"
)
{
return
ArrayAsVector
(
kReservedTestCaseAttributes
);
}
else
{
GTEST_CHECK_
(
false
)
<<
"Unrecognized xml_element provided: "
<<
xml_element
;
}
// This code is unreachable but some compilers may not realizes that.
return
std
::
vector
<
std
::
string
>
();
}
static
std
::
string
FormatWordList
(
const
std
::
vector
<
std
::
string
>&
words
)
{
Message
word_list
;
for
(
size_t
i
=
0
;
i
<
words
.
size
();
++
i
)
{
if
(
i
>
0
&&
words
.
size
()
>
2
)
{
word_list
<<
", "
;
}
if
(
i
==
words
.
size
()
-
1
)
{
word_list
<<
"and "
;
}
word_list
<<
"'"
<<
words
[
i
]
<<
"'"
;
}
return
word_list
.
GetString
();
}
bool
ValidateTestPropertyName
(
const
std
::
string
&
property_name
,
const
std
::
vector
<
std
::
string
>&
reserved_names
)
{
if
(
std
::
find
(
reserved_names
.
begin
(),
reserved_names
.
end
(),
property_name
)
!=
reserved_names
.
end
())
{
ADD_FAILURE
()
<<
"Reserved key used in RecordProperty(): "
<<
property_name
<<
" ("
<<
FormatWordList
(
reserved_names
)
<<
" are reserved by "
<<
GTEST_NAME_
<<
")"
;
return
false
;
return
false
;
}
}
return
true
;
return
true
;
}
}
// Adds a failure if the key is a reserved attribute of the element named
// xml_element. Returns true if the property is valid.
bool
TestResult
::
ValidateTestProperty
(
const
std
::
string
&
xml_element
,
const
TestProperty
&
test_property
)
{
return
ValidateTestPropertyName
(
test_property
.
key
(),
GetReservedAttributesForElement
(
xml_element
));
}
// Clears the object.
// Clears the object.
void
TestResult
::
Clear
()
{
void
TestResult
::
Clear
()
{
test_part_results_
.
clear
();
test_part_results_
.
clear
();
...
@@ -1821,12 +1895,12 @@ void Test::TearDown() {
...
@@ -1821,12 +1895,12 @@ void Test::TearDown() {
}
}
// Allows user supplied key value pairs to be recorded for later output.
// Allows user supplied key value pairs to be recorded for later output.
void
Test
::
RecordProperty
(
const
char
*
key
,
const
char
*
value
)
{
void
Test
::
RecordProperty
(
const
std
::
string
&
key
,
const
std
::
string
&
value
)
{
UnitTest
::
GetInstance
()
->
RecordProperty
ForCurrentTest
(
key
,
value
);
UnitTest
::
GetInstance
()
->
RecordProperty
(
key
,
value
);
}
}
// Allows user supplied key value pairs to be recorded for later output.
// Allows user supplied key value pairs to be recorded for later output.
void
Test
::
RecordProperty
(
const
char
*
key
,
int
value
)
{
void
Test
::
RecordProperty
(
const
std
::
string
&
key
,
int
value
)
{
Message
value_message
;
Message
value_message
;
value_message
<<
value
;
value_message
<<
value
;
RecordProperty
(
key
,
value_message
.
GetString
().
c_str
());
RecordProperty
(
key
,
value_message
.
GetString
().
c_str
());
...
@@ -2355,6 +2429,7 @@ void TestCase::Run() {
...
@@ -2355,6 +2429,7 @@ void TestCase::Run() {
// Clears the results of all tests in this test case.
// Clears the results of all tests in this test case.
void
TestCase
::
ClearResult
()
{
void
TestCase
::
ClearResult
()
{
ad_hoc_test_result_
.
Clear
();
ForEach
(
test_info_list_
,
TestInfo
::
ClearTestResult
);
ForEach
(
test_info_list_
,
TestInfo
::
ClearTestResult
);
}
}
...
@@ -2925,13 +3000,13 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
...
@@ -2925,13 +3000,13 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
// is_attribute is true, the text is meant to appear as an attribute
// is_attribute is true, the text is meant to appear as an attribute
// value, and normalizable whitespace is preserved by replacing it
// value, and normalizable whitespace is preserved by replacing it
// with character references.
// with character references.
static
std
::
string
EscapeXml
(
const
char
*
str
,
bool
is_attribute
);
static
std
::
string
EscapeXml
(
const
std
::
string
&
str
,
bool
is_attribute
);
// Returns the given string with all characters invalid in XML removed.
// Returns the given string with all characters invalid in XML removed.
static
string
RemoveInvalidXmlCharacters
(
const
string
&
str
);
static
std
::
string
RemoveInvalidXmlCharacters
(
const
std
::
string
&
str
);
// Convenience wrapper around EscapeXml when str is an attribute value.
// Convenience wrapper around EscapeXml when str is an attribute value.
static
std
::
string
EscapeXmlAttribute
(
const
char
*
str
)
{
static
std
::
string
EscapeXmlAttribute
(
const
std
::
string
&
str
)
{
return
EscapeXml
(
str
,
true
);
return
EscapeXml
(
str
,
true
);
}
}
...
@@ -2940,6 +3015,13 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
...
@@ -2940,6 +3015,13 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
return
EscapeXml
(
str
,
false
);
return
EscapeXml
(
str
,
false
);
}
}
// Verifies that the given attribute belongs to the given element and
// streams the attribute as XML.
static
void
OutputXmlAttribute
(
std
::
ostream
*
stream
,
const
std
::
string
&
element_name
,
const
std
::
string
&
name
,
const
std
::
string
&
value
);
// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
static
void
OutputXmlCDataSection
(
::
std
::
ostream
*
stream
,
const
char
*
data
);
static
void
OutputXmlCDataSection
(
::
std
::
ostream
*
stream
,
const
char
*
data
);
...
@@ -2949,10 +3031,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
...
@@ -2949,10 +3031,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
const
TestInfo
&
test_info
);
const
TestInfo
&
test_info
);
// Prints an XML representation of a TestCase object
// Prints an XML representation of a TestCase object
static
void
PrintXmlTestCase
(
FILE
*
out
,
const
TestCase
&
test_case
);
static
void
PrintXmlTestCase
(
::
std
::
ostream
*
stream
,
const
TestCase
&
test_case
);
// Prints an XML summary of unit_test to output stream out.
// Prints an XML summary of unit_test to output stream out.
static
void
PrintXmlUnitTest
(
FILE
*
out
,
const
UnitTest
&
unit_test
);
static
void
PrintXmlUnitTest
(
::
std
::
ostream
*
stream
,
const
UnitTest
&
unit_test
);
// Produces a string representing the test properties in a result as space
// Produces a string representing the test properties in a result as space
// delimited XML attributes based on the property key="value" pairs.
// delimited XML attributes based on the property key="value" pairs.
...
@@ -3003,7 +3087,9 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
...
@@ -3003,7 +3087,9 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
fflush
(
stderr
);
fflush
(
stderr
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
PrintXmlUnitTest
(
xmlout
,
unit_test
);
std
::
stringstream
stream
;
PrintXmlUnitTest
(
&
stream
,
unit_test
);
fprintf
(
xmlout
,
"%s"
,
StringStreamToString
(
&
stream
).
c_str
());
fclose
(
xmlout
);
fclose
(
xmlout
);
}
}
...
@@ -3020,43 +3106,42 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
...
@@ -3020,43 +3106,42 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
// TODO(wan): It might be nice to have a minimally invasive, human-readable
// TODO(wan): It might be nice to have a minimally invasive, human-readable
// escaping scheme for invalid characters, rather than dropping them.
// escaping scheme for invalid characters, rather than dropping them.
std
::
string
XmlUnitTestResultPrinter
::
EscapeXml
(
std
::
string
XmlUnitTestResultPrinter
::
EscapeXml
(
const
char
*
str
,
bool
is_attribute
)
{
const
std
::
string
&
str
,
bool
is_attribute
)
{
Message
m
;
Message
m
;
if
(
str
!=
NULL
)
{
for
(
size_t
i
=
0
;
i
<
str
.
size
();
++
i
)
{
for
(
const
char
*
src
=
str
;
*
src
;
++
src
)
{
const
char
ch
=
str
[
i
];
switch
(
*
src
)
{
switch
(
ch
)
{
case
'<'
:
case
'<'
:
m
<<
"<"
;
m
<<
"<"
;
break
;
break
;
case
'>'
:
case
'>'
:
m
<<
">"
;
m
<<
">"
;
break
;
break
;
case
'&'
:
case
'&'
:
m
<<
"&"
;
m
<<
"&"
;
break
;
break
;
case
'\''
:
case
'\''
:
if
(
is_attribute
)
if
(
is_attribute
)
m
<<
"'"
;
m
<<
"'"
;
else
else
m
<<
'\''
;
m
<<
'\''
;
break
;
break
;
case
'"'
:
case
'"'
:
if
(
is_attribute
)
if
(
is_attribute
)
m
<<
"""
;
m
<<
"""
;
else
m
<<
'"'
;
break
;
default:
if
(
IsValidXmlCharacter
(
ch
))
{
if
(
is_attribute
&&
IsNormalizableWhitespace
(
ch
))
m
<<
"&#x"
<<
String
::
FormatByte
(
static_cast
<
unsigned
char
>
(
ch
))
<<
";"
;
else
else
m
<<
'"'
;
m
<<
ch
;
break
;
}
default:
break
;
if
(
IsValidXmlCharacter
(
*
src
))
{
if
(
is_attribute
&&
IsNormalizableWhitespace
(
*
src
))
m
<<
"&#x"
<<
String
::
FormatByte
(
static_cast
<
unsigned
char
>
(
*
src
))
<<
";"
;
else
m
<<
*
src
;
}
break
;
}
}
}
}
}
...
@@ -3066,10 +3151,11 @@ std::string XmlUnitTestResultPrinter::EscapeXml(
...
@@ -3066,10 +3151,11 @@ std::string XmlUnitTestResultPrinter::EscapeXml(
// Returns the given string with all characters invalid in XML removed.
// Returns the given string with all characters invalid in XML removed.
// Currently invalid characters are dropped from the string. An
// Currently invalid characters are dropped from the string. An
// alternative is to replace them with certain characters such as . or ?.
// alternative is to replace them with certain characters such as . or ?.
string
XmlUnitTestResultPrinter
::
RemoveInvalidXmlCharacters
(
const
string
&
str
)
{
std
::
string
XmlUnitTestResultPrinter
::
RemoveInvalidXmlCharacters
(
string
output
;
const
std
::
string
&
str
)
{
std
::
string
output
;
output
.
reserve
(
str
.
size
());
output
.
reserve
(
str
.
size
());
for
(
string
::
const_iterator
it
=
str
.
begin
();
it
!=
str
.
end
();
++
it
)
for
(
std
::
string
::
const_iterator
it
=
str
.
begin
();
it
!=
str
.
end
();
++
it
)
if
(
IsValidXmlCharacter
(
*
it
))
if
(
IsValidXmlCharacter
(
*
it
))
output
.
push_back
(
*
it
);
output
.
push_back
(
*
it
);
...
@@ -3145,30 +3231,47 @@ void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
...
@@ -3145,30 +3231,47 @@ void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
*
stream
<<
"]]>"
;
*
stream
<<
"]]>"
;
}
}
void
XmlUnitTestResultPrinter
::
OutputXmlAttribute
(
std
::
ostream
*
stream
,
const
std
::
string
&
element_name
,
const
std
::
string
&
name
,
const
std
::
string
&
value
)
{
const
std
::
vector
<
std
::
string
>&
allowed_names
=
GetReservedAttributesForElement
(
element_name
);
GTEST_CHECK_
(
std
::
find
(
allowed_names
.
begin
(),
allowed_names
.
end
(),
name
)
!=
allowed_names
.
end
())
<<
"Attribute "
<<
name
<<
" is not allowed for element <"
<<
element_name
<<
">."
;
*
stream
<<
" "
<<
name
<<
"=
\"
"
<<
EscapeXmlAttribute
(
value
)
<<
"
\"
"
;
}
// Prints an XML representation of a TestInfo object.
// Prints an XML representation of a TestInfo object.
// TODO(wan): There is also value in printing properties with the plain printer.
// TODO(wan): There is also value in printing properties with the plain printer.
void
XmlUnitTestResultPrinter
::
OutputXmlTestInfo
(
::
std
::
ostream
*
stream
,
void
XmlUnitTestResultPrinter
::
OutputXmlTestInfo
(
::
std
::
ostream
*
stream
,
const
char
*
test_case_name
,
const
char
*
test_case_name
,
const
TestInfo
&
test_info
)
{
const
TestInfo
&
test_info
)
{
const
TestResult
&
result
=
*
test_info
.
result
();
const
TestResult
&
result
=
*
test_info
.
result
();
*
stream
<<
" <testcase name=
\"
"
const
std
::
string
kTestcase
=
"testcase"
;
<<
EscapeXmlAttribute
(
test_info
.
name
()).
c_str
()
<<
"
\"
"
;
*
stream
<<
" <testcase"
;
OutputXmlAttribute
(
stream
,
kTestcase
,
"name"
,
test_info
.
name
());
if
(
test_info
.
value_param
()
!=
NULL
)
{
if
(
test_info
.
value_param
()
!=
NULL
)
{
*
stream
<<
" value_param=
\"
"
<<
EscapeXmlAttribute
(
test_info
.
value_param
())
OutputXmlAttribute
(
stream
,
kTestcase
,
"
value_param
"
,
<<
"
\"
"
;
test_info
.
value_param
())
;
}
}
if
(
test_info
.
type_param
()
!=
NULL
)
{
if
(
test_info
.
type_param
()
!=
NULL
)
{
*
stream
<<
" type_param=
\"
"
<<
EscapeXmlAttribute
(
test_info
.
type_param
())
OutputXmlAttribute
(
stream
,
kTestcase
,
"type_param"
,
test_info
.
type_param
());
<<
"
\"
"
;
}
}
*
stream
<<
"
status
=
\"
"
OutputXmlAttribute
(
stream
,
kTestcase
,
"status"
,
<<
(
test_info
.
should_run
()
?
"run"
:
"notrun"
)
test_info
.
should_run
()
?
"run"
:
"notrun"
)
;
<<
"
\"
time=
\"
"
OutputXmlAttribute
(
stream
,
kTestcase
,
"time"
,
<<
FormatTimeInMillisAsSeconds
(
result
.
elapsed_time
())
FormatTimeInMillisAsSeconds
(
result
.
elapsed_time
())
);
<<
"
\"
classname=
\"
"
<<
EscapeXmlAttribute
(
test_case_name
)
.
c_str
()
OutputXmlAttribute
(
stream
,
kTestcase
,
"classname"
,
test_case_name
)
;
<<
"
\"
"
<<
TestPropertiesAsXmlAttributes
(
result
)
.
c_str
()
;
*
stream
<<
TestPropertiesAsXmlAttributes
(
result
);
int
failures
=
0
;
int
failures
=
0
;
for
(
int
i
=
0
;
i
<
result
.
total_part_count
();
++
i
)
{
for
(
int
i
=
0
;
i
<
result
.
total_part_count
();
++
i
)
{
...
@@ -3196,45 +3299,64 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
...
@@ -3196,45 +3299,64 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
}
}
// Prints an XML representation of a TestCase object
// Prints an XML representation of a TestCase object
void
XmlUnitTestResultPrinter
::
PrintXmlTestCase
(
FILE
*
out
,
void
XmlUnitTestResultPrinter
::
PrintXmlTestCase
(
std
::
ostream
*
stream
,
const
TestCase
&
test_case
)
{
const
TestCase
&
test_case
)
{
fprintf
(
out
,
const
std
::
string
kTestsuite
=
"testsuite"
;
" <testsuite name=
\"
%s
\"
tests=
\"
%d
\"
failures=
\"
%d
\"
"
*
stream
<<
" <"
<<
kTestsuite
;
"disabled=
\"
%d
\"
"
,
OutputXmlAttribute
(
stream
,
kTestsuite
,
"name"
,
test_case
.
name
());
EscapeXmlAttribute
(
test_case
.
name
()).
c_str
(),
OutputXmlAttribute
(
stream
,
kTestsuite
,
"tests"
,
test_case
.
total_test_count
(),
StreamableToString
(
test_case
.
total_test_count
()));
test_case
.
failed_test_count
(),
OutputXmlAttribute
(
stream
,
kTestsuite
,
"failures"
,
test_case
.
disabled_test_count
());
StreamableToString
(
test_case
.
failed_test_count
()));
fprintf
(
out
,
OutputXmlAttribute
(
stream
,
kTestsuite
,
"disabled"
,
"errors=
\"
0
\"
time=
\"
%s
\"
>
\n
"
,
StreamableToString
(
test_case
.
disabled_test_count
()));
FormatTimeInMillisAsSeconds
(
test_case
.
elapsed_time
()).
c_str
());
OutputXmlAttribute
(
stream
,
kTestsuite
,
"errors"
,
"0"
);
for
(
int
i
=
0
;
i
<
test_case
.
total_test_count
();
++
i
)
{
OutputXmlAttribute
(
stream
,
kTestsuite
,
"time"
,
::
std
::
stringstream
stream
;
FormatTimeInMillisAsSeconds
(
test_case
.
elapsed_time
()));
OutputXmlTestInfo
(
&
stream
,
test_case
.
name
(),
*
test_case
.
GetTestInfo
(
i
));
*
stream
<<
TestPropertiesAsXmlAttributes
(
test_case
.
ad_hoc_test_result
())
fprintf
(
out
,
"%s"
,
StringStreamToString
(
&
stream
).
c_str
());
<<
">
\n
"
;
}
fprintf
(
out
,
" </testsuite>
\n
"
);
for
(
int
i
=
0
;
i
<
test_case
.
total_test_count
();
++
i
)
OutputXmlTestInfo
(
stream
,
test_case
.
name
(),
*
test_case
.
GetTestInfo
(
i
));
*
stream
<<
" </"
<<
kTestsuite
<<
">
\n
"
;
}
}
// Prints an XML summary of unit_test to output stream out.
// Prints an XML summary of unit_test to output stream out.
void
XmlUnitTestResultPrinter
::
PrintXmlUnitTest
(
FILE
*
out
,
void
XmlUnitTestResultPrinter
::
PrintXmlUnitTest
(
std
::
ostream
*
stream
,
const
UnitTest
&
unit_test
)
{
const
UnitTest
&
unit_test
)
{
fprintf
(
out
,
"<?xml version=
\"
1.0
\"
encoding=
\"
UTF-8
\"
?>
\n
"
);
const
std
::
string
kTestsuites
=
"testsuites"
;
fprintf
(
out
,
"<testsuites tests=
\"
%d
\"
failures=
\"
%d
\"
disabled=
\"
%d
\"
"
*
stream
<<
"<?xml version=
\"
1.0
\"
encoding=
\"
UTF-8
\"
?>
\n
"
;
"errors=
\"
0
\"
timestamp=
\"
%s
\"
time=
\"
%s
\"
"
,
*
stream
<<
"<"
<<
kTestsuites
;
unit_test
.
total_test_count
(),
unit_test
.
failed_test_count
(),
OutputXmlAttribute
(
stream
,
kTestsuites
,
"tests"
,
unit_test
.
disabled_test_count
(),
StreamableToString
(
unit_test
.
total_test_count
()));
FormatEpochTimeInMillisAsIso8601
(
unit_test
.
start_timestamp
()).
c_str
(),
OutputXmlAttribute
(
stream
,
kTestsuites
,
"failures"
,
FormatTimeInMillisAsSeconds
(
unit_test
.
elapsed_time
()).
c_str
());
StreamableToString
(
unit_test
.
failed_test_count
()));
OutputXmlAttribute
(
stream
,
kTestsuites
,
"disabled"
,
StreamableToString
(
unit_test
.
disabled_test_count
()));
OutputXmlAttribute
(
stream
,
kTestsuites
,
"errors"
,
"0"
);
OutputXmlAttribute
(
stream
,
kTestsuites
,
"timestamp"
,
FormatEpochTimeInMillisAsIso8601
(
unit_test
.
start_timestamp
()));
OutputXmlAttribute
(
stream
,
kTestsuites
,
"time"
,
FormatTimeInMillisAsSeconds
(
unit_test
.
elapsed_time
()));
if
(
GTEST_FLAG
(
shuffle
))
{
if
(
GTEST_FLAG
(
shuffle
))
{
fprintf
(
out
,
"random_seed=
\"
%d
\"
"
,
unit_test
.
random_seed
());
OutputXmlAttribute
(
stream
,
kTestsuites
,
"random_seed"
,
StreamableToString
(
unit_test
.
random_seed
()));
}
}
fprintf
(
out
,
"name=
\"
AllTests
\"
>
\n
"
);
for
(
int
i
=
0
;
i
<
unit_test
.
total_test_case_count
();
++
i
)
*
stream
<<
TestPropertiesAsXmlAttributes
(
unit_test
.
ad_hoc_test_result
());
PrintXmlTestCase
(
out
,
*
unit_test
.
GetTestCase
(
i
));
fprintf
(
out
,
"</testsuites>
\n
"
);
OutputXmlAttribute
(
stream
,
kTestsuites
,
"name"
,
"AllTests"
);
*
stream
<<
">
\n
"
;
for
(
int
i
=
0
;
i
<
unit_test
.
total_test_case_count
();
++
i
)
{
PrintXmlTestCase
(
stream
,
*
unit_test
.
GetTestCase
(
i
));
}
*
stream
<<
"</"
<<
kTestsuites
<<
">
\n
"
;
}
}
// Produces a string representing the test properties in a result as space
// Produces a string representing the test properties in a result as space
...
@@ -3452,7 +3574,7 @@ void TestEventListeners::SuppressEventForwarding() {
...
@@ -3452,7 +3574,7 @@ void TestEventListeners::SuppressEventForwarding() {
// We don't protect this under mutex_ as a user is not supposed to
// We don't protect this under mutex_ as a user is not supposed to
// call this before main() starts, from which point on the return
// call this before main() starts, from which point on the return
// value will never change.
// value will never change.
UnitTest
*
UnitTest
::
GetInstance
()
{
UnitTest
*
UnitTest
::
GetInstance
()
{
// When compiled with MSVC 7.1 in optimized mode, destroying the
// When compiled with MSVC 7.1 in optimized mode, destroying the
// UnitTest object upon exiting the program messes up the exit code,
// UnitTest object upon exiting the program messes up the exit code,
// causing successful tests to appear failed. We have to use a
// causing successful tests to appear failed. We have to use a
...
@@ -3537,6 +3659,12 @@ const TestCase* UnitTest::GetTestCase(int i) const {
...
@@ -3537,6 +3659,12 @@ const TestCase* UnitTest::GetTestCase(int i) const {
return
impl
()
->
GetTestCase
(
i
);
return
impl
()
->
GetTestCase
(
i
);
}
}
// Returns the TestResult containing information on test failures and
// properties logged outside of individual test cases.
const
TestResult
&
UnitTest
::
ad_hoc_test_result
()
const
{
return
*
impl
()
->
ad_hoc_test_result
();
}
// Gets the i-th test case among all the test cases. i can range from 0 to
// Gets the i-th test case among all the test cases. i can range from 0 to
// total_test_case_count() - 1. If i is not in that range, returns NULL.
// total_test_case_count() - 1. If i is not in that range, returns NULL.
TestCase
*
UnitTest
::
GetMutableTestCase
(
int
i
)
{
TestCase
*
UnitTest
::
GetMutableTestCase
(
int
i
)
{
...
@@ -3635,12 +3763,14 @@ void UnitTest::AddTestPartResult(
...
@@ -3635,12 +3763,14 @@ void UnitTest::AddTestPartResult(
}
}
}
}
// Creates and adds a property to the current TestResult. If a property matching
// Adds a TestProperty to the current TestResult object when invoked from
// the supplied value already exists, updates its value instead.
// inside a test, to current TestCase's ad_hoc_test_result_ when invoked
void
UnitTest
::
RecordPropertyForCurrentTest
(
const
char
*
key
,
// from SetUpTestCase or TearDownTestCase, or to the global property set
const
char
*
value
)
{
// when invoked elsewhere. If the result already contains a property with
const
TestProperty
test_property
(
key
,
value
);
// the same key, the value will be updated.
impl_
->
current_test_result
()
->
RecordProperty
(
test_property
);
void
UnitTest
::
RecordProperty
(
const
std
::
string
&
key
,
const
std
::
string
&
value
)
{
impl_
->
RecordProperty
(
TestProperty
(
key
,
value
));
}
}
// Runs all tests in this UnitTest object and prints the result.
// Runs all tests in this UnitTest object and prints the result.
...
@@ -3813,6 +3943,28 @@ UnitTestImpl::~UnitTestImpl() {
...
@@ -3813,6 +3943,28 @@ UnitTestImpl::~UnitTestImpl() {
delete
os_stack_trace_getter_
;
delete
os_stack_trace_getter_
;
}
}
// Adds a TestProperty to the current TestResult object when invoked in a
// context of a test, to current test case's ad_hoc_test_result when invoke
// from SetUpTestCase/TearDownTestCase, or to the global property set
// otherwise. If the result already contains a property with the same key,
// the value will be updated.
void
UnitTestImpl
::
RecordProperty
(
const
TestProperty
&
test_property
)
{
std
::
string
xml_element
;
TestResult
*
test_result
;
// TestResult appropriate for property recording.
if
(
current_test_info_
!=
NULL
)
{
xml_element
=
"testcase"
;
test_result
=
&
(
current_test_info_
->
result_
);
}
else
if
(
current_test_case_
!=
NULL
)
{
xml_element
=
"testsuite"
;
test_result
=
&
(
current_test_case_
->
ad_hoc_test_result_
);
}
else
{
xml_element
=
"testsuites"
;
test_result
=
&
ad_hoc_test_result_
;
}
test_result
->
RecordProperty
(
xml_element
,
test_property
);
}
#if GTEST_HAS_DEATH_TEST
#if GTEST_HAS_DEATH_TEST
// Disables event forwarding if the control is currently in a death test
// Disables event forwarding if the control is currently in a death test
// subprocess. Must not be called before InitGoogleTest.
// subprocess. Must not be called before InitGoogleTest.
...
...
test/gtest_unittest.cc
View file @
f5fa71f7
...
@@ -180,6 +180,18 @@ class TestEventListenersAccessor {
...
@@ -180,6 +180,18 @@ class TestEventListenersAccessor {
}
}
};
};
class
UnitTestRecordPropertyTestHelper
:
public
Test
{
protected:
UnitTestRecordPropertyTestHelper
()
{}
// Forwards to UnitTest::RecordProperty() to bypass access controls.
void
UnitTestRecordProperty
(
const
char
*
key
,
const
std
::
string
&
value
)
{
unit_test_
.
RecordProperty
(
key
,
value
);
}
UnitTest
unit_test_
;
};
}
// namespace internal
}
// namespace internal
}
// namespace testing
}
// namespace testing
...
@@ -188,6 +200,7 @@ using testing::AssertionResult;
...
@@ -188,6 +200,7 @@ using testing::AssertionResult;
using
testing
::
AssertionSuccess
;
using
testing
::
AssertionSuccess
;
using
testing
::
DoubleLE
;
using
testing
::
DoubleLE
;
using
testing
::
EmptyTestEventListener
;
using
testing
::
EmptyTestEventListener
;
using
testing
::
Environment
;
using
testing
::
FloatLE
;
using
testing
::
FloatLE
;
using
testing
::
GTEST_FLAG
(
also_run_disabled_tests
);
using
testing
::
GTEST_FLAG
(
also_run_disabled_tests
);
using
testing
::
GTEST_FLAG
(
break_on_failure
);
using
testing
::
GTEST_FLAG
(
break_on_failure
);
...
@@ -213,6 +226,7 @@ using testing::StaticAssertTypeEq;
...
@@ -213,6 +226,7 @@ using testing::StaticAssertTypeEq;
using
testing
::
Test
;
using
testing
::
Test
;
using
testing
::
TestCase
;
using
testing
::
TestCase
;
using
testing
::
TestEventListeners
;
using
testing
::
TestEventListeners
;
using
testing
::
TestInfo
;
using
testing
::
TestPartResult
;
using
testing
::
TestPartResult
;
using
testing
::
TestPartResultArray
;
using
testing
::
TestPartResultArray
;
using
testing
::
TestProperty
;
using
testing
::
TestProperty
;
...
@@ -1447,7 +1461,7 @@ TEST(TestResultPropertyTest, NoPropertiesFoundWhenNoneAreAdded) {
...
@@ -1447,7 +1461,7 @@ TEST(TestResultPropertyTest, NoPropertiesFoundWhenNoneAreAdded) {
TEST
(
TestResultPropertyTest
,
OnePropertyFoundWhenAdded
)
{
TEST
(
TestResultPropertyTest
,
OnePropertyFoundWhenAdded
)
{
TestResult
test_result
;
TestResult
test_result
;
TestProperty
property
(
"key_1"
,
"1"
);
TestProperty
property
(
"key_1"
,
"1"
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
property
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
"testcase"
,
property
);
ASSERT_EQ
(
1
,
test_result
.
test_property_count
());
ASSERT_EQ
(
1
,
test_result
.
test_property_count
());
const
TestProperty
&
actual_property
=
test_result
.
GetTestProperty
(
0
);
const
TestProperty
&
actual_property
=
test_result
.
GetTestProperty
(
0
);
EXPECT_STREQ
(
"key_1"
,
actual_property
.
key
());
EXPECT_STREQ
(
"key_1"
,
actual_property
.
key
());
...
@@ -1459,8 +1473,8 @@ TEST(TestResultPropertyTest, MultiplePropertiesFoundWhenAdded) {
...
@@ -1459,8 +1473,8 @@ TEST(TestResultPropertyTest, MultiplePropertiesFoundWhenAdded) {
TestResult
test_result
;
TestResult
test_result
;
TestProperty
property_1
(
"key_1"
,
"1"
);
TestProperty
property_1
(
"key_1"
,
"1"
);
TestProperty
property_2
(
"key_2"
,
"2"
);
TestProperty
property_2
(
"key_2"
,
"2"
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
property_1
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
"testcase"
,
property_1
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
property_2
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
"testcase"
,
property_2
);
ASSERT_EQ
(
2
,
test_result
.
test_property_count
());
ASSERT_EQ
(
2
,
test_result
.
test_property_count
());
const
TestProperty
&
actual_property_1
=
test_result
.
GetTestProperty
(
0
);
const
TestProperty
&
actual_property_1
=
test_result
.
GetTestProperty
(
0
);
EXPECT_STREQ
(
"key_1"
,
actual_property_1
.
key
());
EXPECT_STREQ
(
"key_1"
,
actual_property_1
.
key
());
...
@@ -1478,10 +1492,10 @@ TEST(TestResultPropertyTest, OverridesValuesForDuplicateKeys) {
...
@@ -1478,10 +1492,10 @@ TEST(TestResultPropertyTest, OverridesValuesForDuplicateKeys) {
TestProperty
property_2_1
(
"key_2"
,
"2"
);
TestProperty
property_2_1
(
"key_2"
,
"2"
);
TestProperty
property_1_2
(
"key_1"
,
"12"
);
TestProperty
property_1_2
(
"key_1"
,
"12"
);
TestProperty
property_2_2
(
"key_2"
,
"22"
);
TestProperty
property_2_2
(
"key_2"
,
"22"
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
property_1_1
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
"testcase"
,
property_1_1
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
property_2_1
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
"testcase"
,
property_2_1
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
property_1_2
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
"testcase"
,
property_1_2
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
property_2_2
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
"testcase"
,
property_2_2
);
ASSERT_EQ
(
2
,
test_result
.
test_property_count
());
ASSERT_EQ
(
2
,
test_result
.
test_property_count
());
const
TestProperty
&
actual_property_1
=
test_result
.
GetTestProperty
(
0
);
const
TestProperty
&
actual_property_1
=
test_result
.
GetTestProperty
(
0
);
...
@@ -1494,14 +1508,14 @@ TEST(TestResultPropertyTest, OverridesValuesForDuplicateKeys) {
...
@@ -1494,14 +1508,14 @@ TEST(TestResultPropertyTest, OverridesValuesForDuplicateKeys) {
}
}
// Tests TestResult::GetTestProperty().
// Tests TestResult::GetTestProperty().
TEST
(
TestResultProperty
Death
Test
,
GetTestProperty
)
{
TEST
(
TestResultPropertyTest
,
GetTestProperty
)
{
TestResult
test_result
;
TestResult
test_result
;
TestProperty
property_1
(
"key_1"
,
"1"
);
TestProperty
property_1
(
"key_1"
,
"1"
);
TestProperty
property_2
(
"key_2"
,
"2"
);
TestProperty
property_2
(
"key_2"
,
"2"
);
TestProperty
property_3
(
"key_3"
,
"3"
);
TestProperty
property_3
(
"key_3"
,
"3"
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
property_1
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
"testcase"
,
property_1
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
property_2
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
"testcase"
,
property_2
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
property_3
);
TestResultAccessor
::
RecordProperty
(
&
test_result
,
"testcase"
,
property_3
);
const
TestProperty
&
fetched_property_1
=
test_result
.
GetTestProperty
(
0
);
const
TestProperty
&
fetched_property_1
=
test_result
.
GetTestProperty
(
0
);
const
TestProperty
&
fetched_property_2
=
test_result
.
GetTestProperty
(
1
);
const
TestProperty
&
fetched_property_2
=
test_result
.
GetTestProperty
(
1
);
...
@@ -1520,42 +1534,6 @@ TEST(TestResultPropertyDeathTest, GetTestProperty) {
...
@@ -1520,42 +1534,6 @@ TEST(TestResultPropertyDeathTest, GetTestProperty) {
EXPECT_DEATH_IF_SUPPORTED
(
test_result
.
GetTestProperty
(
-
1
),
""
);
EXPECT_DEATH_IF_SUPPORTED
(
test_result
.
GetTestProperty
(
-
1
),
""
);
}
}
// When a property using a reserved key is supplied to this function, it tests
// that a non-fatal failure is added, a fatal failure is not added, and that the
// property is not recorded.
void
ExpectNonFatalFailureRecordingPropertyWithReservedKey
(
const
char
*
key
)
{
TestResult
test_result
;
TestProperty
property
(
key
,
"1"
);
EXPECT_NONFATAL_FAILURE
(
TestResultAccessor
::
RecordProperty
(
&
test_result
,
property
),
"Reserved key"
);
ASSERT_EQ
(
0
,
test_result
.
test_property_count
())
<<
"Not recorded"
;
}
// Attempting to recording a property with the Reserved literal "name"
// should add a non-fatal failure and the property should not be recorded.
TEST
(
TestResultPropertyTest
,
AddFailureWhenUsingReservedKeyCalledName
)
{
ExpectNonFatalFailureRecordingPropertyWithReservedKey
(
"name"
);
}
// Attempting to recording a property with the Reserved literal "status"
// should add a non-fatal failure and the property should not be recorded.
TEST
(
TestResultPropertyTest
,
AddFailureWhenUsingReservedKeyCalledStatus
)
{
ExpectNonFatalFailureRecordingPropertyWithReservedKey
(
"status"
);
}
// Attempting to recording a property with the Reserved literal "time"
// should add a non-fatal failure and the property should not be recorded.
TEST
(
TestResultPropertyTest
,
AddFailureWhenUsingReservedKeyCalledTime
)
{
ExpectNonFatalFailureRecordingPropertyWithReservedKey
(
"time"
);
}
// Attempting to recording a property with the Reserved literal "classname"
// should add a non-fatal failure and the property should not be recorded.
TEST
(
TestResultPropertyTest
,
AddFailureWhenUsingReservedKeyCalledClassname
)
{
ExpectNonFatalFailureRecordingPropertyWithReservedKey
(
"classname"
);
}
// Tests that GTestFlagSaver works on Windows and Mac.
// Tests that GTestFlagSaver works on Windows and Mac.
class
GTestFlagSaverTest
:
public
Test
{
class
GTestFlagSaverTest
:
public
Test
{
...
@@ -1961,6 +1939,168 @@ TEST(UnitTestTest, ReturnsPlausibleTimestamp) {
...
@@ -1961,6 +1939,168 @@ TEST(UnitTestTest, ReturnsPlausibleTimestamp) {
EXPECT_LE
(
UnitTest
::
GetInstance
()
->
start_timestamp
(),
GetTimeInMillis
());
EXPECT_LE
(
UnitTest
::
GetInstance
()
->
start_timestamp
(),
GetTimeInMillis
());
}
}
// When a property using a reserved key is supplied to this function, it
// tests that a non-fatal failure is added, a fatal failure is not added,
// and that the property is not recorded.
void
ExpectNonFatalFailureRecordingPropertyWithReservedKey
(
const
TestResult
&
test_result
,
const
char
*
key
)
{
EXPECT_NONFATAL_FAILURE
(
Test
::
RecordProperty
(
key
,
"1"
),
"Reserved key"
);
ASSERT_EQ
(
0
,
test_result
.
test_property_count
())
<<
"Property for key '"
<<
key
<<
"' recorded unexpectedly."
;
}
void
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest
(
const
char
*
key
)
{
const
TestInfo
*
test_info
=
UnitTest
::
GetInstance
()
->
current_test_info
();
ASSERT_TRUE
(
test_info
!=
NULL
);
ExpectNonFatalFailureRecordingPropertyWithReservedKey
(
*
test_info
->
result
(),
key
);
}
void
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase
(
const
char
*
key
)
{
const
TestCase
*
test_case
=
UnitTest
::
GetInstance
()
->
current_test_case
();
ASSERT_TRUE
(
test_case
!=
NULL
);
ExpectNonFatalFailureRecordingPropertyWithReservedKey
(
test_case
->
ad_hoc_test_result
(),
key
);
}
void
ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase
(
const
char
*
key
)
{
ExpectNonFatalFailureRecordingPropertyWithReservedKey
(
UnitTest
::
GetInstance
()
->
ad_hoc_test_result
(),
key
);
}
// Tests that property recording functions in UnitTest outside of tests
// functions correcly. Creating a separate instance of UnitTest ensures it
// is in a state similar to the UnitTest's singleton's between tests.
class
UnitTestRecordPropertyTest
:
public
testing
::
internal
::
UnitTestRecordPropertyTestHelper
{
public:
static
void
SetUpTestCase
()
{
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase
(
"disabled"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase
(
"errors"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase
(
"failures"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase
(
"name"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase
(
"tests"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase
(
"time"
);
Test
::
RecordProperty
(
"test_case_key_1"
,
"1"
);
const
TestCase
*
test_case
=
UnitTest
::
GetInstance
()
->
current_test_case
();
ASSERT_TRUE
(
test_case
!=
NULL
);
ASSERT_EQ
(
1
,
test_case
->
ad_hoc_test_result
().
test_property_count
());
EXPECT_STREQ
(
"test_case_key_1"
,
test_case
->
ad_hoc_test_result
().
GetTestProperty
(
0
).
key
());
EXPECT_STREQ
(
"1"
,
test_case
->
ad_hoc_test_result
().
GetTestProperty
(
0
).
value
());
}
};
// Tests TestResult has the expected property when added.
TEST_F
(
UnitTestRecordPropertyTest
,
OnePropertyFoundWhenAdded
)
{
UnitTestRecordProperty
(
"key_1"
,
"1"
);
ASSERT_EQ
(
1
,
unit_test_
.
ad_hoc_test_result
().
test_property_count
());
EXPECT_STREQ
(
"key_1"
,
unit_test_
.
ad_hoc_test_result
().
GetTestProperty
(
0
).
key
());
EXPECT_STREQ
(
"1"
,
unit_test_
.
ad_hoc_test_result
().
GetTestProperty
(
0
).
value
());
}
// Tests TestResult has multiple properties when added.
TEST_F
(
UnitTestRecordPropertyTest
,
MultiplePropertiesFoundWhenAdded
)
{
UnitTestRecordProperty
(
"key_1"
,
"1"
);
UnitTestRecordProperty
(
"key_2"
,
"2"
);
ASSERT_EQ
(
2
,
unit_test_
.
ad_hoc_test_result
().
test_property_count
());
EXPECT_STREQ
(
"key_1"
,
unit_test_
.
ad_hoc_test_result
().
GetTestProperty
(
0
).
key
());
EXPECT_STREQ
(
"1"
,
unit_test_
.
ad_hoc_test_result
().
GetTestProperty
(
0
).
value
());
EXPECT_STREQ
(
"key_2"
,
unit_test_
.
ad_hoc_test_result
().
GetTestProperty
(
1
).
key
());
EXPECT_STREQ
(
"2"
,
unit_test_
.
ad_hoc_test_result
().
GetTestProperty
(
1
).
value
());
}
// Tests TestResult::RecordProperty() overrides values for duplicate keys.
TEST_F
(
UnitTestRecordPropertyTest
,
OverridesValuesForDuplicateKeys
)
{
UnitTestRecordProperty
(
"key_1"
,
"1"
);
UnitTestRecordProperty
(
"key_2"
,
"2"
);
UnitTestRecordProperty
(
"key_1"
,
"12"
);
UnitTestRecordProperty
(
"key_2"
,
"22"
);
ASSERT_EQ
(
2
,
unit_test_
.
ad_hoc_test_result
().
test_property_count
());
EXPECT_STREQ
(
"key_1"
,
unit_test_
.
ad_hoc_test_result
().
GetTestProperty
(
0
).
key
());
EXPECT_STREQ
(
"12"
,
unit_test_
.
ad_hoc_test_result
().
GetTestProperty
(
0
).
value
());
EXPECT_STREQ
(
"key_2"
,
unit_test_
.
ad_hoc_test_result
().
GetTestProperty
(
1
).
key
());
EXPECT_STREQ
(
"22"
,
unit_test_
.
ad_hoc_test_result
().
GetTestProperty
(
1
).
value
());
}
TEST_F
(
UnitTestRecordPropertyTest
,
AddFailureInsideTestsWhenUsingTestCaseReservedKeys
)
{
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest
(
"name"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest
(
"value_param"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest
(
"type_param"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest
(
"status"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest
(
"time"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest
(
"classname"
);
}
TEST_F
(
UnitTestRecordPropertyTest
,
AddRecordWithReservedKeysGeneratesCorrectPropertyList
)
{
EXPECT_NONFATAL_FAILURE
(
Test
::
RecordProperty
(
"name"
,
"1"
),
"'classname', 'name', 'status', 'time', 'type_param', and 'value_param'"
" are reserved"
);
}
class
UnitTestRecordPropertyTestEnvironment
:
public
Environment
{
public:
virtual
void
TearDown
()
{
ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase
(
"tests"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase
(
"failures"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase
(
"disabled"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase
(
"errors"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase
(
"name"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase
(
"timestamp"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase
(
"time"
);
ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase
(
"random_seed"
);
}
};
// This will test property recording outside of any test or test case.
static
Environment
*
record_property_env
=
AddGlobalTestEnvironment
(
new
UnitTestRecordPropertyTestEnvironment
);
// This group of tests is for predicate assertions (ASSERT_PRED*, etc)
// This group of tests is for predicate assertions (ASSERT_PRED*, etc)
// of various arities. They do not attempt to be exhaustive. Rather,
// of various arities. They do not attempt to be exhaustive. Rather,
// view them as smoke tests that can be easily reviewed and verified.
// view them as smoke tests that can be easily reviewed and verified.
...
...
test/gtest_xml_output_unittest.py
View file @
f5fa71f7
...
@@ -57,7 +57,7 @@ else:
...
@@ -57,7 +57,7 @@ else:
STACK_TRACE_TEMPLATE
=
''
STACK_TRACE_TEMPLATE
=
''
EXPECTED_NON_EMPTY_XML
=
"""<?xml version="1.0" encoding="UTF-8"?>
EXPECTED_NON_EMPTY_XML
=
"""<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="23" failures="4" disabled="2" errors="0" time="*" timestamp="*" name="AllTests">
<testsuites tests="23" failures="4" disabled="2" errors="0" time="*" timestamp="*" name="AllTests"
ad_hoc_property="42"
>
<testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" errors="0" time="*">
<testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" errors="0" time="*">
<testcase name="Succeeds" status="run" time="*" classname="SuccessfulTest"/>
<testcase name="Succeeds" status="run" time="*" classname="SuccessfulTest"/>
</testsuite>
</testsuite>
...
@@ -97,7 +97,7 @@ Invalid characters in brackets []%(stack)s]]></failure>
...
@@ -97,7 +97,7 @@ Invalid characters in brackets []%(stack)s]]></failure>
<testsuite name="DisabledTest" tests="1" failures="0" disabled="1" errors="0" time="*">
<testsuite name="DisabledTest" tests="1" failures="0" disabled="1" errors="0" time="*">
<testcase name="DISABLED_test_not_run" status="notrun" time="*" classname="DisabledTest"/>
<testcase name="DISABLED_test_not_run" status="notrun" time="*" classname="DisabledTest"/>
</testsuite>
</testsuite>
<testsuite name="PropertyRecordingTest" tests="4" failures="0" disabled="0" errors="0" time="*">
<testsuite name="PropertyRecordingTest" tests="4" failures="0" disabled="0" errors="0" time="*"
SetUpTestCase="yes" TearDownTestCase="aye"
>
<testcase name="OneProperty" status="run" time="*" classname="PropertyRecordingTest" key_1="1"/>
<testcase name="OneProperty" status="run" time="*" classname="PropertyRecordingTest" key_1="1"/>
<testcase name="IntValuedProperty" status="run" time="*" classname="PropertyRecordingTest" key_int="1"/>
<testcase name="IntValuedProperty" status="run" time="*" classname="PropertyRecordingTest" key_int="1"/>
<testcase name="ThreeProperties" status="run" time="*" classname="PropertyRecordingTest" key_1="1" key_2="2" key_3="3"/>
<testcase name="ThreeProperties" status="run" time="*" classname="PropertyRecordingTest" key_1="1" key_2="2" key_3="3"/>
...
...
test/gtest_xml_output_unittest_.cc
View file @
f5fa71f7
...
@@ -95,6 +95,9 @@ TEST(InvalidCharactersTest, InvalidCharactersInMessage) {
...
@@ -95,6 +95,9 @@ TEST(InvalidCharactersTest, InvalidCharactersInMessage) {
}
}
class
PropertyRecordingTest
:
public
Test
{
class
PropertyRecordingTest
:
public
Test
{
public:
static
void
SetUpTestCase
()
{
RecordProperty
(
"SetUpTestCase"
,
"yes"
);
}
static
void
TearDownTestCase
()
{
RecordProperty
(
"TearDownTestCase"
,
"aye"
);
}
};
};
TEST_F
(
PropertyRecordingTest
,
OneProperty
)
{
TEST_F
(
PropertyRecordingTest
,
OneProperty
)
{
...
@@ -120,12 +123,12 @@ TEST(NoFixtureTest, RecordProperty) {
...
@@ -120,12 +123,12 @@ TEST(NoFixtureTest, RecordProperty) {
RecordProperty
(
"key"
,
"1"
);
RecordProperty
(
"key"
,
"1"
);
}
}
void
ExternalUtilityThatCallsRecordProperty
(
const
char
*
key
,
int
value
)
{
void
ExternalUtilityThatCallsRecordProperty
(
const
std
::
string
&
key
,
int
value
)
{
testing
::
Test
::
RecordProperty
(
key
,
value
);
testing
::
Test
::
RecordProperty
(
key
,
value
);
}
}
void
ExternalUtilityThatCallsRecordProperty
(
const
char
*
key
,
void
ExternalUtilityThatCallsRecordProperty
(
const
std
::
string
&
key
,
const
char
*
value
)
{
const
std
::
string
&
value
)
{
testing
::
Test
::
RecordProperty
(
key
,
value
);
testing
::
Test
::
RecordProperty
(
key
,
value
);
}
}
...
@@ -173,5 +176,6 @@ int main(int argc, char** argv) {
...
@@ -173,5 +176,6 @@ int main(int argc, char** argv) {
TestEventListeners
&
listeners
=
UnitTest
::
GetInstance
()
->
listeners
();
TestEventListeners
&
listeners
=
UnitTest
::
GetInstance
()
->
listeners
();
delete
listeners
.
Release
(
listeners
.
default_xml_generator
());
delete
listeners
.
Release
(
listeners
.
default_xml_generator
());
}
}
testing
::
Test
::
RecordProperty
(
"ad_hoc_property"
,
"42"
);
return
RUN_ALL_TESTS
();
return
RUN_ALL_TESTS
();
}
}
test/gtest_xml_test_utils.py
View file @
f5fa71f7
...
@@ -80,7 +80,9 @@ class GTestXMLTestCase(gtest_test_utils.TestCase):
...
@@ -80,7 +80,9 @@ class GTestXMLTestCase(gtest_test_utils.TestCase):
actual_attributes
=
actual_node
.
attributes
actual_attributes
=
actual_node
.
attributes
self
.
assertEquals
(
self
.
assertEquals
(
expected_attributes
.
length
,
actual_attributes
.
length
,
expected_attributes
.
length
,
actual_attributes
.
length
,
'attribute numbers differ in element '
+
actual_node
.
tagName
)
'attribute numbers differ in element %s:
\n
Expected: %r
\n
Actual: %r'
%
(
actual_node
.
tagName
,
expected_attributes
.
keys
(),
actual_attributes
.
keys
()))
for
i
in
range
(
expected_attributes
.
length
):
for
i
in
range
(
expected_attributes
.
length
):
expected_attr
=
expected_attributes
.
item
(
i
)
expected_attr
=
expected_attributes
.
item
(
i
)
actual_attr
=
actual_attributes
.
get
(
expected_attr
.
name
)
actual_attr
=
actual_attributes
.
get
(
expected_attr
.
name
)
...
...
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