mirror of https://github.com/google/googletest.git
Don't repeat the failure summary in the XML report body
The XML printer puts the summary of a test part result into the "message" attribute of the <failure> or <skipped> element and the full message into the CDATA body of that same element. The two only differ when the message carries a stack trace, so in a build without stack trace support, and for every skipped result since those never get a trace, the report contains the exact same text twice. Write the CDATA body only when it holds more than the attribute already does. The "message" attribute keeps the summary, which is what JUnit consumers read, and nothing is dropped from the report. The JSON printer already reports the message just once. Fixes #4785
This commit is contained in:
parent
91c99b6ffe
commit
24ee021f44
|
|
@ -2173,8 +2173,8 @@ could generate this report:
|
|||
<testsuites tests="3" failures="1" errors="0" time="0.035" timestamp="2011-10-31T18:52:42" name="AllTests">
|
||||
<testsuite name="MathTest" tests="2" failures="1" errors="0" time="0.015">
|
||||
<testcase name="Addition" file="test.cpp" line="1" status="run" time="0.007" classname="">
|
||||
<failure message="Value of: add(1, 1)
 Actual: 3
Expected: 2" type="">...</failure>
|
||||
<failure message="Value of: add(1, -1)
 Actual: 1
Expected: 0" type="">...</failure>
|
||||
<failure message="Value of: add(1, 1)
 Actual: 3
Expected: 2" type=""/>
|
||||
<failure message="Value of: add(1, -1)
 Actual: 1
Expected: 0" type=""/>
|
||||
</testcase>
|
||||
<testcase name="Subtraction" file="test.cpp" line="2" status="run" time="0.005" classname="">
|
||||
</testcase>
|
||||
|
|
|
|||
|
|
@ -4372,11 +4372,20 @@ void XmlUnitTestResultPrinter::OutputXmlTestResult(::std::ostream* stream,
|
|||
internal::FormatCompilerIndependentFileLocation(part.file_name(),
|
||||
part.line_number());
|
||||
const std::string summary = location + "\n" + part.summary();
|
||||
*stream << " <failure message=\"" << EscapeXmlAttribute(summary)
|
||||
<< "\" type=\"\">";
|
||||
const std::string detail = location + "\n" + part.message();
|
||||
OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
|
||||
*stream << "</failure>\n";
|
||||
*stream << " <failure message=\"" << EscapeXmlAttribute(summary)
|
||||
<< "\" type=\"\"";
|
||||
// The "message" attribute already carries the summary, so only write a
|
||||
// CDATA body when the full message adds something to it (a stack trace,
|
||||
// for instance). Otherwise the exact same text is reported twice.
|
||||
if (detail == summary) {
|
||||
*stream << " />\n";
|
||||
} else {
|
||||
*stream << ">";
|
||||
OutputXmlCDataSection(stream,
|
||||
RemoveInvalidXmlCharacters(detail).c_str());
|
||||
*stream << "</failure>\n";
|
||||
}
|
||||
} else if (part.skipped()) {
|
||||
if (++skips == 1 && failures == 0) {
|
||||
*stream << ">\n";
|
||||
|
|
@ -4385,11 +4394,17 @@ void XmlUnitTestResultPrinter::OutputXmlTestResult(::std::ostream* stream,
|
|||
internal::FormatCompilerIndependentFileLocation(part.file_name(),
|
||||
part.line_number());
|
||||
const std::string summary = location + "\n" + part.summary();
|
||||
*stream << " <skipped message=\"" << EscapeXmlAttribute(summary)
|
||||
<< "\">";
|
||||
const std::string detail = location + "\n" + part.message();
|
||||
OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
|
||||
*stream << "</skipped>\n";
|
||||
*stream << " <skipped message=\"" << EscapeXmlAttribute(summary)
|
||||
<< "\"";
|
||||
if (detail == summary) {
|
||||
*stream << " />\n";
|
||||
} else {
|
||||
*stream << ">";
|
||||
OutputXmlCDataSection(stream,
|
||||
RemoveInvalidXmlCharacters(detail).c_str());
|
||||
*stream << "</skipped>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,27 @@ else:
|
|||
# unittest.main() can't handle unknown flags
|
||||
sys.argv.remove(NO_STACKTRACE_SUPPORT_FLAG)
|
||||
|
||||
EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
def RemoveRepeatedDetails(xml):
|
||||
"""Drops the bodies of <failure> elements that only repeat their message.
|
||||
|
||||
GoogleTest writes the detail of a failure as a CDATA body only when it holds
|
||||
more than the "message" attribute already does. Without stack trace support
|
||||
the two are always identical, so the body is not written at all.
|
||||
|
||||
Args:
|
||||
xml: an expected XML document, as a string.
|
||||
|
||||
Returns:
|
||||
The document with such bodies replaced by empty elements.
|
||||
"""
|
||||
if SUPPORTS_STACK_TRACES:
|
||||
return xml
|
||||
return re.sub(r'><!\[CDATA\[.*?\]\]></failure>', ' />', xml, flags=re.DOTALL)
|
||||
|
||||
|
||||
EXPECTED_NON_EMPTY_XML = RemoveRepeatedDetails(
|
||||
"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites tests="28" failures="5" disabled="2" errors="0" time="*" timestamp="*" name="AllTests">
|
||||
<properties>
|
||||
<property name="ad_hoc_property" value="42"/>
|
||||
|
|
@ -115,23 +135,17 @@ Invalid characters in brackets []%(stack)s]]></failure>
|
|||
</testsuite>
|
||||
<testsuite name="SkippedTest" tests="3" failures="1" disabled="0" skipped="2" errors="0" time="*" timestamp="*">
|
||||
<testcase name="Skipped" status="run" file="gtest_xml_output_unittest_.cc" line="75" result="skipped" time="*" timestamp="*" classname="SkippedTest">
|
||||
<skipped message="gtest_xml_output_unittest_.cc:*

"><![CDATA[gtest_xml_output_unittest_.cc:*
|
||||
|
||||
]]></skipped>
|
||||
<skipped message="gtest_xml_output_unittest_.cc:*

" />
|
||||
</testcase>
|
||||
<testcase name="SkippedWithMessage" file="gtest_xml_output_unittest_.cc" line="79" status="run" result="skipped" time="*" timestamp="*" classname="SkippedTest">
|
||||
<skipped message="gtest_xml_output_unittest_.cc:*
It is good practice to tell why you skip a test.
"><![CDATA[gtest_xml_output_unittest_.cc:*
|
||||
It is good practice to tell why you skip a test.
|
||||
]]></skipped>
|
||||
<skipped message="gtest_xml_output_unittest_.cc:*
It is good practice to tell why you skip a test.
" />
|
||||
</testcase>
|
||||
<testcase name="SkippedAfterFailure" file="gtest_xml_output_unittest_.cc" line="83" status="run" result="completed" time="*" timestamp="*" classname="SkippedTest">
|
||||
<failure message="gtest_xml_output_unittest_.cc:*
Expected equality of these values:
 1
 2%(stack_entity)s" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
|
||||
Expected equality of these values:
|
||||
1
|
||||
2%(stack)s]]></failure>
|
||||
<skipped message="gtest_xml_output_unittest_.cc:*
It is good practice to tell why you skip a test.
"><![CDATA[gtest_xml_output_unittest_.cc:*
|
||||
It is good practice to tell why you skip a test.
|
||||
]]></skipped>
|
||||
<skipped message="gtest_xml_output_unittest_.cc:*
It is good practice to tell why you skip a test.
" />
|
||||
</testcase>
|
||||
|
||||
</testsuite>
|
||||
|
|
@ -184,8 +198,7 @@ It is good practice to tell why you skip a test.
|
|||
</testsuite>
|
||||
<testsuite name="SetupFailTest" tests="1" failures="0" disabled="0" skipped="1" errors="0" time="*" timestamp="*">
|
||||
<testcase name="NoopPassingTest" file="gtest_xml_output_unittest_.cc" line="172" status="run" result="skipped" time="*" timestamp="*" classname="SetupFailTest">
|
||||
<skipped message="gtest_xml_output_unittest_.cc:*
"><![CDATA[gtest_xml_output_unittest_.cc:*
|
||||
]]></skipped>
|
||||
<skipped message="gtest_xml_output_unittest_.cc:*
" />
|
||||
</testcase>
|
||||
<testcase name="" status="run" result="completed" classname="" time="*" timestamp="*">
|
||||
<failure message="gtest_xml_output_unittest_.cc:*
Expected equality of these values:
 1
 2%(stack_entity)s" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
|
||||
|
|
@ -222,9 +235,10 @@ Expected equality of these values:
|
|||
<testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="200" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="Single/TypeParameterizedTestSuite/1" />
|
||||
</testsuite>
|
||||
</testsuites>""" % {
|
||||
'stack': STACK_TRACE_TEMPLATE,
|
||||
'stack_entity': STACK_TRACE_ENTITY_TEMPLATE,
|
||||
}
|
||||
'stack': STACK_TRACE_TEMPLATE,
|
||||
'stack_entity': STACK_TRACE_ENTITY_TEMPLATE,
|
||||
}
|
||||
)
|
||||
|
||||
EXPECTED_FILTERED_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" timestamp="*" name="AllTests">
|
||||
|
|
@ -263,7 +277,8 @@ EXPECTED_SHARDED_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?>
|
|||
</testsuite>
|
||||
</testsuites>"""
|
||||
|
||||
EXPECTED_NO_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
EXPECTED_NO_TEST_XML = RemoveRepeatedDetails(
|
||||
"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites tests="0" failures="0" disabled="0" errors="0" time="*"
|
||||
timestamp="*" name="AllTests">
|
||||
<testsuite name="NonTestSuiteFailure" tests="1" failures="1" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
|
||||
|
|
@ -275,9 +290,10 @@ Expected equality of these values:
|
|||
</testcase>
|
||||
</testsuite>
|
||||
</testsuites>""" % {
|
||||
'stack': STACK_TRACE_TEMPLATE,
|
||||
'stack_entity': STACK_TRACE_ENTITY_TEMPLATE,
|
||||
}
|
||||
'stack': STACK_TRACE_TEMPLATE,
|
||||
'stack_entity': STACK_TRACE_ENTITY_TEMPLATE,
|
||||
}
|
||||
)
|
||||
|
||||
GTEST_PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME)
|
||||
|
||||
|
|
@ -313,6 +329,32 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
|
|||
|
||||
self._TestXmlOutput('gtest_no_test_unittest', EXPECTED_NO_TEST_XML, 0)
|
||||
|
||||
def testFailureDetailIsNotACopyOfTheMessage(self):
|
||||
"""Verifies that a failure detail does not repeat the message attribute.
|
||||
|
||||
The "message" attribute of a <failure> or <skipped> element already holds
|
||||
the summary of the failure, so the body of the element is only written when
|
||||
it adds something to that summary.
|
||||
"""
|
||||
actual = self._GetXmlOutput(GTEST_PROGRAM_NAME, [], {}, 1)
|
||||
elements = actual.getElementsByTagName(
|
||||
'failure'
|
||||
) + actual.getElementsByTagName('skipped')
|
||||
self.assertTrue(elements, 'the test program reported no failure')
|
||||
for element in elements:
|
||||
detail = ''.join(
|
||||
child.nodeValue
|
||||
for child in element.childNodes
|
||||
if child.nodeType == child.CDATA_SECTION_NODE
|
||||
)
|
||||
self.assertNotEqual(
|
||||
element.getAttribute('message'),
|
||||
detail,
|
||||
'the detail of a <%s> element repeats its message attribute'
|
||||
% element.tagName,
|
||||
)
|
||||
actual.unlink()
|
||||
|
||||
def testTimestampValue(self):
|
||||
"""Checks whether the timestamp attribute in the XML output is valid.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue