diff options
author | Abseil Team <absl-team@google.com> | 2021-03-11 15:57:48 (GMT) |
---|---|---|
committer | Andy Soffer <asoffer@google.com> | 2021-03-16 13:51:18 (GMT) |
commit | ac1d60c2b5ae62a06eca1d2c0f9d6dc92cda8711 (patch) | |
tree | 5c26175b8bf501df76da71ef4b9cf33a49cca959 | |
parent | 3bd41ab23f4c77b26892a5829f35df4e4edc2093 (diff) | |
download | googletest-ac1d60c2b5ae62a06eca1d2c0f9d6dc92cda8711.zip googletest-ac1d60c2b5ae62a06eca1d2c0f9d6dc92cda8711.tar.gz googletest-ac1d60c2b5ae62a06eca1d2c0f9d6dc92cda8711.tar.bz2 |
Googletest export
gtest: Output a canned test suite for environment failures in XML/JSON
This surfaces useful information about the environment failure in a structured form.
As we can see from the updated test, previously unsurfaced information is now present.
PiperOrigin-RevId: 362292322
-rw-r--r-- | googletest/src/gtest.cc | 104 | ||||
-rw-r--r-- | googletest/test/googletest-json-output-unittest.py | 70 | ||||
-rwxr-xr-x | googletest/test/gtest_xml_output_unittest.py | 22 |
3 files changed, 177 insertions, 19 deletions
diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index 707e1a5..9089f50 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -3928,6 +3928,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + // Streams a test suite XML stanza containing the given test result. + // + // Requires: result.Failed() + static void OutputXmlTestSuiteForTestResult(::std::ostream* stream, + const TestResult& result); + // Streams an XML representation of a TestResult object. static void OutputXmlTestResult(::std::ostream* stream, const TestResult& result); @@ -4147,6 +4153,43 @@ void XmlUnitTestResultPrinter::OutputXmlAttribute( *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; } +// Streams a test suite XML stanza containing the given test result. +void XmlUnitTestResultPrinter::OutputXmlTestSuiteForTestResult( + ::std::ostream* stream, const TestResult& result) { + // Output the boilerplate for a minimal test suite with one test. + *stream << " <testsuite"; + OutputXmlAttribute(stream, "testsuite", "name", "NonTestSuiteFailure"); + OutputXmlAttribute(stream, "testsuite", "tests", "1"); + OutputXmlAttribute(stream, "testsuite", "failures", "1"); + OutputXmlAttribute(stream, "testsuite", "disabled", "0"); + OutputXmlAttribute(stream, "testsuite", "skipped", "0"); + OutputXmlAttribute(stream, "testsuite", "errors", "0"); + OutputXmlAttribute(stream, "testsuite", "time", + FormatTimeInMillisAsSeconds(result.elapsed_time())); + OutputXmlAttribute( + stream, "testsuite", "timestamp", + FormatEpochTimeInMillisAsIso8601(result.start_timestamp())); + *stream << ">"; + + // Output the boilerplate for a minimal test case with a single test. + *stream << " <testcase"; + OutputXmlAttribute(stream, "testcase", "name", ""); + OutputXmlAttribute(stream, "testcase", "status", "run"); + OutputXmlAttribute(stream, "testcase", "result", "completed"); + OutputXmlAttribute(stream, "testcase", "classname", ""); + OutputXmlAttribute(stream, "testcase", "time", + FormatTimeInMillisAsSeconds(result.elapsed_time())); + OutputXmlAttribute( + stream, "testcase", "timestamp", + FormatEpochTimeInMillisAsIso8601(result.start_timestamp())); + + // Output the actual test result. + OutputXmlTestResult(stream, result); + + // Complete the test suite. + *stream << " </testsuite>\n"; +} + // Prints an XML representation of a TestInfo object. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_suite_name, @@ -4309,6 +4352,13 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i)); } + + // If there was a test failure outside of one of the test suites (like in a + // test environment) include that in the output. + if (unit_test.ad_hoc_test_result().Failed()) { + OutputXmlTestSuiteForTestResult(stream, unit_test.ad_hoc_test_result()); + } + *stream << "</" << kTestsuites << ">\n"; } @@ -4399,6 +4449,12 @@ class JsonUnitTestResultPrinter : public EmptyTestEventListener { const std::string& indent, bool comma = true); + // Streams a test suite JSON stanza containing the given test result. + // + // Requires: result.Failed() + static void OutputJsonTestSuiteForTestResult(::std::ostream* stream, + const TestResult& result); + // Streams a JSON representation of a TestResult object. static void OutputJsonTestResult(::std::ostream* stream, const TestResult& result); @@ -4553,6 +4609,48 @@ void JsonUnitTestResultPrinter::OutputJsonKey( *stream << ",\n"; } +// Streams a test suite JSON stanza containing the given test result. +void JsonUnitTestResultPrinter::OutputJsonTestSuiteForTestResult( + ::std::ostream* stream, const TestResult& result) { + // Output the boilerplate for a new test suite. + *stream << Indent(4) << "{\n"; + OutputJsonKey(stream, "testsuite", "name", "NonTestSuiteFailure", Indent(6)); + OutputJsonKey(stream, "testsuite", "tests", 1, Indent(6)); + if (!GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, "testsuite", "failures", 1, Indent(6)); + OutputJsonKey(stream, "testsuite", "disabled", 0, Indent(6)); + OutputJsonKey(stream, "testsuite", "skipped", 0, Indent(6)); + OutputJsonKey(stream, "testsuite", "errors", 0, Indent(6)); + OutputJsonKey(stream, "testsuite", "time", + FormatTimeInMillisAsDuration(result.elapsed_time()), + Indent(6)); + OutputJsonKey(stream, "testsuite", "timestamp", + FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()), + Indent(6)); + } + *stream << Indent(6) << "\"testsuite\": [\n"; + + // Output the boilerplate for a new test case. + *stream << Indent(8) << "{\n"; + OutputJsonKey(stream, "testcase", "name", "", Indent(10)); + OutputJsonKey(stream, "testcase", "status", "RUN", Indent(10)); + OutputJsonKey(stream, "testcase", "result", "COMPLETED", Indent(10)); + OutputJsonKey(stream, "testcase", "timestamp", + FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()), + Indent(10)); + OutputJsonKey(stream, "testcase", "time", + FormatTimeInMillisAsDuration(result.elapsed_time()), + Indent(10)); + OutputJsonKey(stream, "testcase", "classname", "", Indent(10), false); + *stream << TestPropertiesAsJson(result, Indent(10)); + + // Output the actual test result. + OutputJsonTestResult(stream, result); + + // Finish the test suite. + *stream << "\n" << Indent(6) << "]\n" << Indent(4) << "}"; +} + // Prints a JSON representation of a TestInfo object. void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, const char* test_suite_name, @@ -4712,6 +4810,12 @@ void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, } } + // If there was a test failure outside of one of the test suites (like in a + // test environment) include that in the output. + if (unit_test.ad_hoc_test_result().Failed()) { + OutputJsonTestSuiteForTestResult(stream, unit_test.ad_hoc_test_result()); + } + *stream << "\n" << kIndent << "]\n" << "}\n"; } diff --git a/googletest/test/googletest-json-output-unittest.py b/googletest/test/googletest-json-output-unittest.py index e799d47..41c8565 100644 --- a/googletest/test/googletest-json-output-unittest.py +++ b/googletest/test/googletest-json-output-unittest.py @@ -612,15 +612,59 @@ EXPECTED_FILTERED = { }], } -EXPECTED_EMPTY = { - u'tests': 0, - u'failures': 0, - u'disabled': 0, - u'errors': 0, - u'time': u'*', - u'timestamp': u'*', - u'name': u'AllTests', - u'testsuites': [], +EXPECTED_NO_TEST = { + u'tests': + 0, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'name': + u'AllTests', + u'testsuites': [{ + u'name': + u'NonTestSuiteFailure', + u'tests': + 1, + u'failures': + 1, + u'disabled': + 0, + u'skipped': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': + u'', + u'status': + u'RUN', + u'result': + u'COMPLETED', + u'time': + u'*', + u'timestamp': + u'*', + u'classname': + u'', + u'failures': [{ + u'failure': u'gtest_no_test_unittest.cc:*\n' + u'Expected equality of these values:\n' + u' 1\n 2' + STACK_TRACE_TEMPLATE, + u'type': u'', + }] + }] + }], } GTEST_PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME) @@ -645,14 +689,14 @@ class GTestJsonOutputUnitTest(gtest_test_utils.TestCase): """ self._TestJsonOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY, 1) - def testEmptyJsonOutput(self): + def testNoTestJsonOutput(self): """Verifies JSON output for a Google Test binary without actual tests. - Runs a test program that generates an empty JSON output, and - tests that the JSON output is expected. + Runs a test program that generates an JSON output for a binary with no + tests, and tests that the JSON output is expected. """ - self._TestJsonOutput('gtest_no_test_unittest', EXPECTED_EMPTY, 0) + self._TestJsonOutput('gtest_no_test_unittest', EXPECTED_NO_TEST, 0) def testTimestampValue(self): """Checks whether the timestamp attribute in the JSON output is valid. diff --git a/googletest/test/gtest_xml_output_unittest.py b/googletest/test/gtest_xml_output_unittest.py index de8b8c7..eade7aa 100755 --- a/googletest/test/gtest_xml_output_unittest.py +++ b/googletest/test/gtest_xml_output_unittest.py @@ -216,10 +216,20 @@ EXPECTED_SHARDED_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?> </testsuite> </testsuites>""" -EXPECTED_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?> +EXPECTED_NO_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?> <testsuites tests="0" failures="0" disabled="0" errors="0" time="*" timestamp="*" name="AllTests"> -</testsuites>""" + <testsuite name="NonTestSuiteFailure" tests="1" failures="1" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> + <testcase name="" status="run" result="completed" time="*" timestamp="*" classname=""> + <failure message="gtest_no_test_unittest.cc:*
Expected equality of these values:
 1
 2" type=""><![CDATA[gtest_no_test_unittest.cc:* +Expected equality of these values: + 1 + 2%(stack)s]]></failure> + </testcase> + </testsuite> +</testsuites>""" % { + 'stack': STACK_TRACE_TEMPLATE +} GTEST_PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME) @@ -242,14 +252,14 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase): """ self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY_XML, 1) - def testEmptyXmlOutput(self): + def testNoTestXmlOutput(self): """Verifies XML output for a Google Test binary without actual tests. - Runs a test program that generates an empty XML output, and - tests that the XML output is expected. + Runs a test program that generates an XML output for a binary without tests, + and tests that the XML output is expected. """ - self._TestXmlOutput('gtest_no_test_unittest', EXPECTED_EMPTY_XML, 0) + self._TestXmlOutput('gtest_no_test_unittest', EXPECTED_NO_TEST_XML, 0) def testTimestampValue(self): """Checks whether the timestamp attribute in the XML output is valid. |