gtest_xml_output_unittest.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2006, Google Inc.
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are
  8. # met:
  9. #
  10. # * Redistributions of source code must retain the above copyright
  11. # notice, this list of conditions and the following disclaimer.
  12. # * Redistributions in binary form must reproduce the above
  13. # copyright notice, this list of conditions and the following disclaimer
  14. # in the documentation and/or other materials provided with the
  15. # distribution.
  16. # * Neither the name of Google Inc. nor the names of its
  17. # contributors may be used to endorse or promote products derived from
  18. # this software without specific prior written permission.
  19. #
  20. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. """Unit test for the gtest_xml_output module"""
  32. __author__ = 'eefacm@gmail.com (Sean Mcafee)'
  33. import datetime
  34. import errno
  35. import os
  36. import re
  37. import sys
  38. from xml.dom import minidom, Node
  39. import gtest_test_utils
  40. import gtest_xml_test_utils
  41. GTEST_FILTER_FLAG = '--gtest_filter'
  42. GTEST_LIST_TESTS_FLAG = '--gtest_list_tests'
  43. GTEST_OUTPUT_FLAG = "--gtest_output"
  44. GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml"
  45. GTEST_PROGRAM_NAME = "gtest_xml_output_unittest_"
  46. SUPPORTS_STACK_TRACES = False
  47. if SUPPORTS_STACK_TRACES:
  48. STACK_TRACE_TEMPLATE = '\nStack trace:\n*'
  49. else:
  50. STACK_TRACE_TEMPLATE = ''
  51. EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
  52. <testsuites tests="23" failures="4" disabled="2" errors="0" time="*" timestamp="*" name="AllTests" ad_hoc_property="42">
  53. <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" errors="0" time="*">
  54. <testcase name="Succeeds" status="run" time="*" classname="SuccessfulTest"/>
  55. </testsuite>
  56. <testsuite name="FailedTest" tests="1" failures="1" disabled="0" errors="0" time="*">
  57. <testcase name="Fails" status="run" time="*" classname="FailedTest">
  58. <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Value of: 2&#x0A;Expected: 1" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
  59. Value of: 2
  60. Expected: 1%(stack)s]]></failure>
  61. </testcase>
  62. </testsuite>
  63. <testsuite name="MixedResultTest" tests="3" failures="1" disabled="1" errors="0" time="*">
  64. <testcase name="Succeeds" status="run" time="*" classname="MixedResultTest"/>
  65. <testcase name="Fails" status="run" time="*" classname="MixedResultTest">
  66. <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Value of: 2&#x0A;Expected: 1" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
  67. Value of: 2
  68. Expected: 1%(stack)s]]></failure>
  69. <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Value of: 3&#x0A;Expected: 2" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
  70. Value of: 3
  71. Expected: 2%(stack)s]]></failure>
  72. </testcase>
  73. <testcase name="DISABLED_test" status="notrun" time="*" classname="MixedResultTest"/>
  74. </testsuite>
  75. <testsuite name="XmlQuotingTest" tests="1" failures="1" disabled="0" errors="0" time="*">
  76. <testcase name="OutputsCData" status="run" time="*" classname="XmlQuotingTest">
  77. <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Failed&#x0A;XML output: &lt;?xml encoding=&quot;utf-8&quot;&gt;&lt;top&gt;&lt;![CDATA[cdata text]]&gt;&lt;/top&gt;" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
  78. Failed
  79. XML output: <?xml encoding="utf-8"><top><![CDATA[cdata text]]>]]&gt;<![CDATA[</top>%(stack)s]]></failure>
  80. </testcase>
  81. </testsuite>
  82. <testsuite name="InvalidCharactersTest" tests="1" failures="1" disabled="0" errors="0" time="*">
  83. <testcase name="InvalidCharactersInMessage" status="run" time="*" classname="InvalidCharactersTest">
  84. <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Failed&#x0A;Invalid characters in brackets []" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
  85. Failed
  86. Invalid characters in brackets []%(stack)s]]></failure>
  87. </testcase>
  88. </testsuite>
  89. <testsuite name="DisabledTest" tests="1" failures="0" disabled="1" errors="0" time="*">
  90. <testcase name="DISABLED_test_not_run" status="notrun" time="*" classname="DisabledTest"/>
  91. </testsuite>
  92. <testsuite name="PropertyRecordingTest" tests="4" failures="0" disabled="0" errors="0" time="*" SetUpTestCase="yes" TearDownTestCase="aye">
  93. <testcase name="OneProperty" status="run" time="*" classname="PropertyRecordingTest" key_1="1"/>
  94. <testcase name="IntValuedProperty" status="run" time="*" classname="PropertyRecordingTest" key_int="1"/>
  95. <testcase name="ThreeProperties" status="run" time="*" classname="PropertyRecordingTest" key_1="1" key_2="2" key_3="3"/>
  96. <testcase name="TwoValuesForOneKeyUsesLastValue" status="run" time="*" classname="PropertyRecordingTest" key_1="2"/>
  97. </testsuite>
  98. <testsuite name="NoFixtureTest" tests="3" failures="0" disabled="0" errors="0" time="*">
  99. <testcase name="RecordProperty" status="run" time="*" classname="NoFixtureTest" key="1"/>
  100. <testcase name="ExternalUtilityThatCallsRecordIntValuedProperty" status="run" time="*" classname="NoFixtureTest" key_for_utility_int="1"/>
  101. <testcase name="ExternalUtilityThatCallsRecordStringValuedProperty" status="run" time="*" classname="NoFixtureTest" key_for_utility_string="1"/>
  102. </testsuite>
  103. <testsuite name="Single/ValueParamTest" tests="4" failures="0" disabled="0" errors="0" time="*">
  104. <testcase name="HasValueParamAttribute/0" value_param="33" status="run" time="*" classname="Single/ValueParamTest" />
  105. <testcase name="HasValueParamAttribute/1" value_param="42" status="run" time="*" classname="Single/ValueParamTest" />
  106. <testcase name="AnotherTestThatHasValueParamAttribute/0" value_param="33" status="run" time="*" classname="Single/ValueParamTest" />
  107. <testcase name="AnotherTestThatHasValueParamAttribute/1" value_param="42" status="run" time="*" classname="Single/ValueParamTest" />
  108. </testsuite>
  109. <testsuite name="TypedTest/0" tests="1" failures="0" disabled="0" errors="0" time="*">
  110. <testcase name="HasTypeParamAttribute" type_param="*" status="run" time="*" classname="TypedTest/0" />
  111. </testsuite>
  112. <testsuite name="TypedTest/1" tests="1" failures="0" disabled="0" errors="0" time="*">
  113. <testcase name="HasTypeParamAttribute" type_param="*" status="run" time="*" classname="TypedTest/1" />
  114. </testsuite>
  115. <testsuite name="Single/TypeParameterizedTestCase/0" tests="1" failures="0" disabled="0" errors="0" time="*">
  116. <testcase name="HasTypeParamAttribute" type_param="*" status="run" time="*" classname="Single/TypeParameterizedTestCase/0" />
  117. </testsuite>
  118. <testsuite name="Single/TypeParameterizedTestCase/1" tests="1" failures="0" disabled="0" errors="0" time="*">
  119. <testcase name="HasTypeParamAttribute" type_param="*" status="run" time="*" classname="Single/TypeParameterizedTestCase/1" />
  120. </testsuite>
  121. </testsuites>""" % {'stack': STACK_TRACE_TEMPLATE}
  122. EXPECTED_FILTERED_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?>
  123. <testsuites tests="1" failures="0" disabled="0" errors="0" time="*"
  124. timestamp="*" name="AllTests" ad_hoc_property="42">
  125. <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0"
  126. errors="0" time="*">
  127. <testcase name="Succeeds" status="run" time="*" classname="SuccessfulTest"/>
  128. </testsuite>
  129. </testsuites>"""
  130. EXPECTED_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
  131. <testsuites tests="0" failures="0" disabled="0" errors="0" time="*"
  132. timestamp="*" name="AllTests">
  133. </testsuites>"""
  134. GTEST_PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME)
  135. SUPPORTS_TYPED_TESTS = 'TypedTest' in gtest_test_utils.Subprocess(
  136. [GTEST_PROGRAM_PATH, GTEST_LIST_TESTS_FLAG], capture_stderr=False).output
  137. class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
  138. """
  139. Unit test for Google Test's XML output functionality.
  140. """
  141. # This test currently breaks on platforms that do not support typed and
  142. # type-parameterized tests, so we don't run it under them.
  143. if SUPPORTS_TYPED_TESTS:
  144. def testNonEmptyXmlOutput(self):
  145. """
  146. Runs a test program that generates a non-empty XML output, and
  147. tests that the XML output is expected.
  148. """
  149. self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY_XML, 1)
  150. def testEmptyXmlOutput(self):
  151. """Verifies XML output for a Google Test binary without actual tests.
  152. Runs a test program that generates an empty XML output, and
  153. tests that the XML output is expected.
  154. """
  155. self._TestXmlOutput('gtest_no_test_unittest', EXPECTED_EMPTY_XML, 0)
  156. def testTimestampValue(self):
  157. """Checks whether the timestamp attribute in the XML output is valid.
  158. Runs a test program that generates an empty XML output, and checks if
  159. the timestamp attribute in the testsuites tag is valid.
  160. """
  161. actual = self._GetXmlOutput('gtest_no_test_unittest', [], 0)
  162. date_time_str = actual.documentElement.getAttributeNode('timestamp').value
  163. # datetime.strptime() is only available in Python 2.5+ so we have to
  164. # parse the expected datetime manually.
  165. match = re.match(r'(\d+)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)', date_time_str)
  166. self.assertTrue(
  167. re.match,
  168. 'XML datettime string %s has incorrect format' % date_time_str)
  169. date_time_from_xml = datetime.datetime(
  170. year=int(match.group(1)), month=int(match.group(2)),
  171. day=int(match.group(3)), hour=int(match.group(4)),
  172. minute=int(match.group(5)), second=int(match.group(6)))
  173. time_delta = abs(datetime.datetime.now() - date_time_from_xml)
  174. # timestamp value should be near the current local time
  175. self.assertTrue(time_delta < datetime.timedelta(seconds=600),
  176. 'time_delta is %s' % time_delta)
  177. actual.unlink()
  178. def testDefaultOutputFile(self):
  179. """
  180. Confirms that Google Test produces an XML output file with the expected
  181. default name if no name is explicitly specified.
  182. """
  183. output_file = os.path.join(gtest_test_utils.GetTempDir(),
  184. GTEST_DEFAULT_OUTPUT_FILE)
  185. gtest_prog_path = gtest_test_utils.GetTestExecutablePath(
  186. 'gtest_no_test_unittest')
  187. try:
  188. os.remove(output_file)
  189. except OSError, e:
  190. if e.errno != errno.ENOENT:
  191. raise
  192. p = gtest_test_utils.Subprocess(
  193. [gtest_prog_path, '%s=xml' % GTEST_OUTPUT_FLAG],
  194. working_dir=gtest_test_utils.GetTempDir())
  195. self.assert_(p.exited)
  196. self.assertEquals(0, p.exit_code)
  197. self.assert_(os.path.isfile(output_file))
  198. def testSuppressedXmlOutput(self):
  199. """
  200. Tests that no XML file is generated if the default XML listener is
  201. shut down before RUN_ALL_TESTS is invoked.
  202. """
  203. xml_path = os.path.join(gtest_test_utils.GetTempDir(),
  204. GTEST_PROGRAM_NAME + 'out.xml')
  205. if os.path.isfile(xml_path):
  206. os.remove(xml_path)
  207. command = [GTEST_PROGRAM_PATH,
  208. '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path),
  209. '--shut_down_xml']
  210. p = gtest_test_utils.Subprocess(command)
  211. if p.terminated_by_signal:
  212. # p.signal is avalable only if p.terminated_by_signal is True.
  213. self.assertFalse(
  214. p.terminated_by_signal,
  215. '%s was killed by signal %d' % (GTEST_PROGRAM_NAME, p.signal))
  216. else:
  217. self.assert_(p.exited)
  218. self.assertEquals(1, p.exit_code,
  219. "'%s' exited with code %s, which doesn't match "
  220. 'the expected exit code %s.'
  221. % (command, p.exit_code, 1))
  222. self.assert_(not os.path.isfile(xml_path))
  223. def testFilteredTestXmlOutput(self):
  224. """Verifies XML output when a filter is applied.
  225. Runs a test program that executes only some tests and verifies that
  226. non-selected tests do not show up in the XML output.
  227. """
  228. self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_FILTERED_TEST_XML, 0,
  229. extra_args=['%s=SuccessfulTest.*' % GTEST_FILTER_FLAG])
  230. def _GetXmlOutput(self, gtest_prog_name, extra_args, expected_exit_code):
  231. """
  232. Returns the xml output generated by running the program gtest_prog_name.
  233. Furthermore, the program's exit code must be expected_exit_code.
  234. """
  235. xml_path = os.path.join(gtest_test_utils.GetTempDir(),
  236. gtest_prog_name + 'out.xml')
  237. gtest_prog_path = gtest_test_utils.GetTestExecutablePath(gtest_prog_name)
  238. command = ([gtest_prog_path, '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path)] +
  239. extra_args)
  240. p = gtest_test_utils.Subprocess(command)
  241. if p.terminated_by_signal:
  242. self.assert_(False,
  243. '%s was killed by signal %d' % (gtest_prog_name, p.signal))
  244. else:
  245. self.assert_(p.exited)
  246. self.assertEquals(expected_exit_code, p.exit_code,
  247. "'%s' exited with code %s, which doesn't match "
  248. 'the expected exit code %s.'
  249. % (command, p.exit_code, expected_exit_code))
  250. actual = minidom.parse(xml_path)
  251. return actual
  252. def _TestXmlOutput(self, gtest_prog_name, expected_xml,
  253. expected_exit_code, extra_args=None):
  254. """
  255. Asserts that the XML document generated by running the program
  256. gtest_prog_name matches expected_xml, a string containing another
  257. XML document. Furthermore, the program's exit code must be
  258. expected_exit_code.
  259. """
  260. actual = self._GetXmlOutput(gtest_prog_name, extra_args or [],
  261. expected_exit_code)
  262. expected = minidom.parseString(expected_xml)
  263. self.NormalizeXml(actual.documentElement)
  264. self.AssertEquivalentNodes(expected.documentElement,
  265. actual.documentElement)
  266. expected.unlink()
  267. actual.unlink()
  268. if __name__ == '__main__':
  269. os.environ['GTEST_STACK_TRACE_DEPTH'] = '1'
  270. gtest_test_utils.Main()