xref: /freebsd-src/contrib/googletest/googletest/test/gtest_xml_output_unittest.py (revision 5ca8c28cd8c725b81781201cfdb5f9969396f934)
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
32"""Unit test for the gtest_xml_output module"""
33
34import datetime
35import errno
36import os
37import re
38import sys
39from xml.dom import minidom, Node
40
41from googletest.test import gtest_test_utils
42from googletest.test import gtest_xml_test_utils
43
44GTEST_FILTER_FLAG = '--gtest_filter'
45GTEST_LIST_TESTS_FLAG = '--gtest_list_tests'
46GTEST_OUTPUT_FLAG = '--gtest_output'
47GTEST_DEFAULT_OUTPUT_FILE = 'test_detail.xml'
48GTEST_PROGRAM_NAME = 'gtest_xml_output_unittest_'
49
50# The flag indicating stacktraces are not supported
51NO_STACKTRACE_SUPPORT_FLAG = '--no_stacktrace_support'
52
53# The environment variables for test sharding.
54TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS'
55SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX'
56SHARD_STATUS_FILE_ENV_VAR = 'GTEST_SHARD_STATUS_FILE'
57
58SUPPORTS_STACK_TRACES = NO_STACKTRACE_SUPPORT_FLAG not in sys.argv
59
60if SUPPORTS_STACK_TRACES:
61  STACK_TRACE_TEMPLATE = '\nStack trace:\n*'
62  STACK_TRACE_ENTITY_TEMPLATE = ''
63else:
64  STACK_TRACE_TEMPLATE = '\n'
65  STACK_TRACE_ENTITY_TEMPLATE = '
'
66  # unittest.main() can't handle unknown flags
67  sys.argv.remove(NO_STACKTRACE_SUPPORT_FLAG)
68
69EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
70<testsuites tests="26" failures="5" disabled="2" errors="0" time="*" timestamp="*" name="AllTests" ad_hoc_property="42">
71  <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
72    <testcase name="Succeeds" file="gtest_xml_output_unittest_.cc" line="53" status="run" result="completed" time="*" timestamp="*" classname="SuccessfulTest"/>
73  </testsuite>
74  <testsuite name="FailedTest" tests="1" failures="1" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
75    <testcase name="Fails" file="gtest_xml_output_unittest_.cc" line="61" status="run" result="completed" time="*" timestamp="*" classname="FailedTest">
76      <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Expected equality of these values:&#x0A;  1&#x0A;  2%(stack_entity)s" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
77Expected equality of these values:
78  1
79  2%(stack)s]]></failure>
80    </testcase>
81  </testsuite>
82  <testsuite name="MixedResultTest" tests="3" failures="1" disabled="1" skipped="0" errors="0" time="*" timestamp="*">
83    <testcase name="Succeeds" file="gtest_xml_output_unittest_.cc" line="88" status="run" result="completed" time="*" timestamp="*" classname="MixedResultTest"/>
84    <testcase name="Fails" file="gtest_xml_output_unittest_.cc" line="93" status="run" result="completed" time="*" timestamp="*" classname="MixedResultTest">
85      <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Expected equality of these values:&#x0A;  1&#x0A;  2%(stack_entity)s" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
86Expected equality of these values:
87  1
88  2%(stack)s]]></failure>
89      <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Expected equality of these values:&#x0A;  2&#x0A;  3%(stack_entity)s" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
90Expected equality of these values:
91  2
92  3%(stack)s]]></failure>
93    </testcase>
94    <testcase name="DISABLED_test" file="gtest_xml_output_unittest_.cc" line="98" status="notrun" result="suppressed" time="*" timestamp="*" classname="MixedResultTest"/>
95  </testsuite>
96  <testsuite name="XmlQuotingTest" tests="1" failures="1" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
97    <testcase name="OutputsCData" file="gtest_xml_output_unittest_.cc" line="102" status="run" result="completed" time="*" timestamp="*" classname="XmlQuotingTest">
98      <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;%(stack_entity)s" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
99Failed
100XML output: <?xml encoding="utf-8"><top><![CDATA[cdata text]]>]]&gt;<![CDATA[</top>%(stack)s]]></failure>
101    </testcase>
102  </testsuite>
103  <testsuite name="InvalidCharactersTest" tests="1" failures="1" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
104    <testcase name="InvalidCharactersInMessage" file="gtest_xml_output_unittest_.cc" line="109" status="run" result="completed" time="*" timestamp="*" classname="InvalidCharactersTest">
105      <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Failed&#x0A;Invalid characters in brackets []%(stack_entity)s" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
106Failed
107Invalid characters in brackets []%(stack)s]]></failure>
108    </testcase>
109  </testsuite>
110  <testsuite name="DisabledTest" tests="1" failures="0" disabled="1" skipped="0" errors="0" time="*" timestamp="*">
111    <testcase name="DISABLED_test_not_run" file="gtest_xml_output_unittest_.cc" line="68" status="notrun" result="suppressed" time="*" timestamp="*" classname="DisabledTest"/>
112  </testsuite>
113  <testsuite name="SkippedTest" tests="3" failures="1" disabled="0" skipped="2" errors="0" time="*" timestamp="*">
114    <testcase name="Skipped" status="run" file="gtest_xml_output_unittest_.cc" line="75" result="skipped" time="*" timestamp="*" classname="SkippedTest">
115      <skipped message="gtest_xml_output_unittest_.cc:*&#x0A;&#x0A;"><![CDATA[gtest_xml_output_unittest_.cc:*
116
117]]></skipped>
118    </testcase>
119    <testcase name="SkippedWithMessage" file="gtest_xml_output_unittest_.cc" line="79" status="run" result="skipped" time="*" timestamp="*" classname="SkippedTest">
120      <skipped message="gtest_xml_output_unittest_.cc:*&#x0A;It is good practice to tell why you skip a test.&#x0A;"><![CDATA[gtest_xml_output_unittest_.cc:*
121It is good practice to tell why you skip a test.
122]]></skipped>
123    </testcase>
124    <testcase name="SkippedAfterFailure" file="gtest_xml_output_unittest_.cc" line="83" status="run" result="completed" time="*" timestamp="*" classname="SkippedTest">
125      <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Expected equality of these values:&#x0A;  1&#x0A;  2%(stack_entity)s" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
126Expected equality of these values:
127  1
128  2%(stack)s]]></failure>
129      <skipped message="gtest_xml_output_unittest_.cc:*&#x0A;It is good practice to tell why you skip a test.&#x0A;"><![CDATA[gtest_xml_output_unittest_.cc:*
130It is good practice to tell why you skip a test.
131]]></skipped>
132    </testcase>
133
134  </testsuite>
135  <testsuite name="PropertyRecordingTest" tests="4" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*" SetUpTestSuite="yes" TearDownTestSuite="aye">
136    <testcase name="OneProperty" file="gtest_xml_output_unittest_.cc" line="121" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest">
137      <properties>
138        <property name="key_1" value="1"/>
139      </properties>
140    </testcase>
141    <testcase name="IntValuedProperty" file="gtest_xml_output_unittest_.cc" line="125" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest">
142      <properties>
143        <property name="key_int" value="1"/>
144      </properties>
145    </testcase>
146    <testcase name="ThreeProperties" file="gtest_xml_output_unittest_.cc" line="129" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest">
147      <properties>
148        <property name="key_1" value="1"/>
149        <property name="key_2" value="2"/>
150        <property name="key_3" value="3"/>
151      </properties>
152    </testcase>
153    <testcase name="TwoValuesForOneKeyUsesLastValue" file="gtest_xml_output_unittest_.cc" line="135" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest">
154      <properties>
155        <property name="key_1" value="2"/>
156      </properties>
157    </testcase>
158  </testsuite>
159  <testsuite name="NoFixtureTest" tests="3" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
160     <testcase name="RecordProperty" file="gtest_xml_output_unittest_.cc" line="140" status="run" result="completed" time="*" timestamp="*" classname="NoFixtureTest">
161       <properties>
162         <property name="key" value="1"/>
163       </properties>
164     </testcase>
165     <testcase name="ExternalUtilityThatCallsRecordIntValuedProperty" file="gtest_xml_output_unittest_.cc" line="153" status="run" result="completed" time="*" timestamp="*" classname="NoFixtureTest">
166       <properties>
167         <property name="key_for_utility_int" value="1"/>
168       </properties>
169     </testcase>
170     <testcase name="ExternalUtilityThatCallsRecordStringValuedProperty" file="gtest_xml_output_unittest_.cc" line="157" status="run" result="completed" time="*" timestamp="*" classname="NoFixtureTest">
171       <properties>
172         <property name="key_for_utility_string" value="1"/>
173       </properties>
174     </testcase>
175  </testsuite>
176  <testsuite name="Single/ValueParamTest" tests="4" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
177    <testcase name="HasValueParamAttribute/0" file="gtest_xml_output_unittest_.cc" line="164" value_param="33" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" />
178    <testcase name="HasValueParamAttribute/1" file="gtest_xml_output_unittest_.cc" line="164" value_param="42" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" />
179    <testcase name="AnotherTestThatHasValueParamAttribute/0" file="gtest_xml_output_unittest_.cc" line="165" value_param="33" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" />
180    <testcase name="AnotherTestThatHasValueParamAttribute/1" file="gtest_xml_output_unittest_.cc" line="165" value_param="42" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" />
181  </testsuite>
182  <testsuite name="TypedTest/0" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
183    <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="173" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="TypedTest/0" />
184  </testsuite>
185  <testsuite name="TypedTest/1" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
186    <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="173" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="TypedTest/1" />
187  </testsuite>
188  <testsuite name="Single/TypeParameterizedTestSuite/0" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
189    <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="180" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="Single/TypeParameterizedTestSuite/0" />
190  </testsuite>
191  <testsuite name="Single/TypeParameterizedTestSuite/1" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
192    <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="180" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="Single/TypeParameterizedTestSuite/1" />
193  </testsuite>
194</testsuites>""" % {
195    'stack': STACK_TRACE_TEMPLATE,
196    'stack_entity': STACK_TRACE_ENTITY_TEMPLATE,
197}
198
199EXPECTED_FILTERED_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?>
200<testsuites tests="1" failures="0" disabled="0" errors="0" time="*"
201            timestamp="*" name="AllTests" ad_hoc_property="42">
202  <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" skipped="0"
203             errors="0" time="*" timestamp="*">
204    <testcase name="Succeeds" file="gtest_xml_output_unittest_.cc" line="53" status="run" result="completed" time="*" timestamp="*" classname="SuccessfulTest"/>
205  </testsuite>
206</testsuites>"""
207
208EXPECTED_SHARDED_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?>
209<testsuites tests="3" failures="0" disabled="0" errors="0" time="*" timestamp="*" name="AllTests" ad_hoc_property="42">
210  <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
211    <testcase name="Succeeds" file="gtest_xml_output_unittest_.cc" line="53" status="run" result="completed" time="*" timestamp="*" classname="SuccessfulTest"/>
212  </testsuite>
213  <testsuite name="PropertyRecordingTest" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*" SetUpTestSuite="yes" TearDownTestSuite="aye">
214    <testcase name="IntValuedProperty" file="gtest_xml_output_unittest_.cc" line="125" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest">
215      <properties>
216        <property name="key_int" value="1"/>
217      </properties>
218    </testcase>
219  </testsuite>
220  <testsuite name="Single/ValueParamTest" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
221    <testcase name="HasValueParamAttribute/0" file="gtest_xml_output_unittest_.cc" line="164" value_param="33" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" />
222  </testsuite>
223</testsuites>"""
224
225EXPECTED_NO_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?>
226<testsuites tests="0" failures="0" disabled="0" errors="0" time="*"
227            timestamp="*" name="AllTests">
228  <testsuite name="NonTestSuiteFailure" tests="1" failures="1" disabled="0" skipped="0" errors="0" time="*" timestamp="*">
229    <testcase name="" status="run" result="completed" time="*" timestamp="*" classname="">
230      <failure message="gtest_no_test_unittest.cc:*&#x0A;Expected equality of these values:&#x0A;  1&#x0A;  2%(stack_entity)s" type=""><![CDATA[gtest_no_test_unittest.cc:*
231Expected equality of these values:
232  1
233  2%(stack)s]]></failure>
234    </testcase>
235  </testsuite>
236</testsuites>""" % {
237    'stack': STACK_TRACE_TEMPLATE,
238    'stack_entity': STACK_TRACE_ENTITY_TEMPLATE,
239}
240
241GTEST_PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME)
242
243SUPPORTS_TYPED_TESTS = (
244    'TypedTest'
245    in gtest_test_utils.Subprocess(
246        [GTEST_PROGRAM_PATH, GTEST_LIST_TESTS_FLAG], capture_stderr=False
247    ).output
248)
249
250
251class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
252  """Unit test for Google Test's XML output functionality."""
253
254  # This test currently breaks on platforms that do not support typed and
255  # type-parameterized tests, so we don't run it under them.
256  if SUPPORTS_TYPED_TESTS:
257
258    def testNonEmptyXmlOutput(self):
259      """Generates non-empty XML and verifies it matches the expected output.
260
261      Runs a test program that generates a non-empty XML output, and
262      tests that the XML output is expected.
263      """
264      self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY_XML, 1)
265
266  def testNoTestXmlOutput(self):
267    """Verifies XML output for a Google Test binary without actual tests.
268
269    Runs a test program that generates an XML output for a binary without tests,
270    and tests that the XML output is expected.
271    """
272
273    self._TestXmlOutput('gtest_no_test_unittest', EXPECTED_NO_TEST_XML, 0)
274
275  def testTimestampValue(self):
276    """Checks whether the timestamp attribute in the XML output is valid.
277
278    Runs a test program that generates an empty XML output, and checks if
279    the timestamp attribute in the testsuites tag is valid.
280    """
281    actual = self._GetXmlOutput('gtest_no_test_unittest', [], {}, 0)
282    date_time_str = actual.documentElement.getAttributeNode('timestamp').value
283    # datetime.strptime() is only available in Python 2.5+ so we have to
284    # parse the expected datetime manually.
285    match = re.match(r'(\d+)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)', date_time_str)
286    self.assertTrue(
287        re.match, 'XML datettime string %s has incorrect format' % date_time_str
288    )
289    date_time_from_xml = datetime.datetime(
290        year=int(match.group(1)),
291        month=int(match.group(2)),
292        day=int(match.group(3)),
293        hour=int(match.group(4)),
294        minute=int(match.group(5)),
295        second=int(match.group(6)),
296    )
297
298    time_delta = abs(datetime.datetime.now() - date_time_from_xml)
299    # timestamp value should be near the current local time
300    self.assertLess(time_delta, datetime.timedelta(seconds=600))
301    actual.unlink()
302
303  def testDefaultOutputFile(self):
304    """Tests XML file with default name is created when name is not specified.
305
306    Confirms that Google Test produces an XML output file with the expected
307    default name if no name is explicitly specified.
308    """
309    output_file = os.path.join(
310        gtest_test_utils.GetTempDir(), GTEST_DEFAULT_OUTPUT_FILE
311    )
312    gtest_prog_path = gtest_test_utils.GetTestExecutablePath(
313        'gtest_no_test_unittest'
314    )
315    try:
316      os.remove(output_file)
317    except OSError:
318      e = sys.exc_info()[1]
319      if e.errno != errno.ENOENT:
320        raise
321
322    p = gtest_test_utils.Subprocess(
323        [gtest_prog_path, '%s=xml' % GTEST_OUTPUT_FLAG],
324        working_dir=gtest_test_utils.GetTempDir(),
325    )
326    self.assertTrue(p.exited)
327    self.assertEqual(0, p.exit_code)
328    self.assertTrue(os.path.isfile(output_file))
329
330  def testSuppressedXmlOutput(self):
331    """Verifies XML output is suppressed if default listener is shut down.
332
333    Tests that no XML file is generated if the default XML listener is
334    shut down before RUN_ALL_TESTS is invoked.
335    """
336
337    xml_path = os.path.join(
338        gtest_test_utils.GetTempDir(), GTEST_PROGRAM_NAME + 'out.xml'
339    )
340    if os.path.isfile(xml_path):
341      os.remove(xml_path)
342
343    command = [
344        GTEST_PROGRAM_PATH,
345        '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path),
346        '--shut_down_xml',
347    ]
348    p = gtest_test_utils.Subprocess(command)
349    if p.terminated_by_signal:
350      # p.signal is available only if p.terminated_by_signal is True.
351      self.assertFalse(
352          p.terminated_by_signal,
353          '%s was killed by signal %d' % (GTEST_PROGRAM_NAME, p.signal),
354      )
355    else:
356      self.assertTrue(p.exited)
357      self.assertEqual(
358          1,
359          p.exit_code,
360          "'%s' exited with code %s, which doesn't match "
361          'the expected exit code %s.' % (command, p.exit_code, 1),
362      )
363
364    self.assertFalse(os.path.isfile(xml_path))
365
366  def testFilteredTestXmlOutput(self):
367    """Verifies XML output when a filter is applied.
368
369    Runs a test program that executes only some tests and verifies that
370    non-selected tests do not show up in the XML output.
371    """
372
373    self._TestXmlOutput(
374        GTEST_PROGRAM_NAME,
375        EXPECTED_FILTERED_TEST_XML,
376        0,
377        extra_args=['%s=SuccessfulTest.*' % GTEST_FILTER_FLAG],
378    )
379
380  def testShardedTestXmlOutput(self):
381    """Verifies XML output when run using multiple shards.
382
383    Runs a test program that executes only one shard and verifies that tests
384    from other shards do not show up in the XML output.
385    """
386
387    self._TestXmlOutput(
388        GTEST_PROGRAM_NAME,
389        EXPECTED_SHARDED_TEST_XML,
390        0,
391        extra_env={SHARD_INDEX_ENV_VAR: '0', TOTAL_SHARDS_ENV_VAR: '10'},
392    )
393
394  def _GetXmlOutput(
395      self, gtest_prog_name, extra_args, extra_env, expected_exit_code
396  ):
397    """Returns the XML output generated by running the program gtest_prog_name.
398
399    Furthermore, the program's exit code must be expected_exit_code.
400
401    Args:
402      gtest_prog_name: Program to run.
403      extra_args: Optional arguments to pass to program.
404      extra_env: Optional environment variables to set.
405      expected_exit_code: Expected exit code from running gtest_prog_name.
406    """
407    xml_path = os.path.join(
408        gtest_test_utils.GetTempDir(), gtest_prog_name + 'out.xml'
409    )
410    gtest_prog_path = gtest_test_utils.GetTestExecutablePath(gtest_prog_name)
411
412    command = [
413        gtest_prog_path,
414        '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path),
415    ] + extra_args
416    environ_copy = os.environ.copy()
417    if extra_env:
418      environ_copy.update(extra_env)
419    p = gtest_test_utils.Subprocess(command, env=environ_copy)
420
421    if p.terminated_by_signal:
422      self.assertTrue(
423          False, '%s was killed by signal %d' % (gtest_prog_name, p.signal)
424      )
425    else:
426      self.assertTrue(p.exited)
427      self.assertEqual(
428          expected_exit_code,
429          p.exit_code,
430          "'%s' exited with code %s, which doesn't match "
431          'the expected exit code %s.'
432          % (command, p.exit_code, expected_exit_code),
433      )
434    actual = minidom.parse(xml_path)
435    return actual
436
437  def _TestXmlOutput(
438      self,
439      gtest_prog_name,
440      expected_xml,
441      expected_exit_code,
442      extra_args=None,
443      extra_env=None,
444  ):
445    """Asserts that the XML document matches.
446
447    Asserts that the XML document generated by running the program
448    gtest_prog_name matches expected_xml, a string containing another
449    XML document.  Furthermore, the program's exit code must be
450    expected_exit_code.
451
452    Args:
453      gtest_prog_name: Program to run.
454      expected_xml: Path to XML document to match.
455      expected_exit_code: Expected exit code from running gtest_prog_name.
456      extra_args: Optional arguments to pass to program.
457      extra_env: Optional environment variables to set.
458    """
459
460    actual = self._GetXmlOutput(
461        gtest_prog_name, extra_args or [], extra_env or {}, expected_exit_code
462    )
463    expected = minidom.parseString(expected_xml)
464    self.NormalizeXml(actual.documentElement)
465    self.AssertEquivalentNodes(expected.documentElement, actual.documentElement)
466    expected.unlink()
467    actual.unlink()
468
469
470if __name__ == '__main__':
471  os.environ['GTEST_STACK_TRACE_DEPTH'] = '1'
472  gtest_test_utils.Main()
473