1#!/usr/bin/env python
2# Copyright 2018, Google Inc.
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9#     * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11#     * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15#     * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31"""Unit test for the gtest_json_output module."""
32
33import datetime
34import errno
35import json
36import os
37import re
38import sys
39
40from googletest.test import gtest_json_test_utils
41from googletest.test import gtest_test_utils
42
43GTEST_FILTER_FLAG = '--gtest_filter'
44GTEST_LIST_TESTS_FLAG = '--gtest_list_tests'
45GTEST_OUTPUT_FLAG = '--gtest_output'
46GTEST_DEFAULT_OUTPUT_FILE = 'test_detail.json'
47GTEST_PROGRAM_NAME = 'gtest_xml_output_unittest_'
48
49# The flag indicating stacktraces are not supported
50NO_STACKTRACE_SUPPORT_FLAG = '--no_stacktrace_support'
51
52SUPPORTS_STACK_TRACES = NO_STACKTRACE_SUPPORT_FLAG not in sys.argv
53
54if SUPPORTS_STACK_TRACES:
55  STACK_TRACE_TEMPLATE = '\nStack trace:\n*'
56else:
57  STACK_TRACE_TEMPLATE = '\n'
58
59EXPECTED_NON_EMPTY = {
60    'tests': 26,
61    'failures': 5,
62    'disabled': 2,
63    'errors': 0,
64    'timestamp': '*',
65    'time': '*',
66    'ad_hoc_property': '42',
67    'name': 'AllTests',
68    'testsuites': [
69        {
70            'name': 'SuccessfulTest',
71            'tests': 1,
72            'failures': 0,
73            'disabled': 0,
74            'errors': 0,
75            'time': '*',
76            'timestamp': '*',
77            'testsuite': [{
78                'name': 'Succeeds',
79                'file': 'gtest_xml_output_unittest_.cc',
80                'line': 53,
81                'status': 'RUN',
82                'result': 'COMPLETED',
83                'time': '*',
84                'timestamp': '*',
85                'classname': 'SuccessfulTest',
86            }],
87        },
88        {
89            'name': 'FailedTest',
90            'tests': 1,
91            'failures': 1,
92            'disabled': 0,
93            'errors': 0,
94            'time': '*',
95            'timestamp': '*',
96            'testsuite': [{
97                'name': 'Fails',
98                'file': 'gtest_xml_output_unittest_.cc',
99                'line': 61,
100                'status': 'RUN',
101                'result': 'COMPLETED',
102                'time': '*',
103                'timestamp': '*',
104                'classname': 'FailedTest',
105                'failures': [{
106                    'failure': (
107                        'gtest_xml_output_unittest_.cc:*\n'
108                        'Expected equality of these values:\n'
109                        '  1\n  2'
110                        + STACK_TRACE_TEMPLATE
111                    ),
112                    'type': '',
113                }],
114            }],
115        },
116        {
117            'name': 'DisabledTest',
118            'tests': 1,
119            'failures': 0,
120            'disabled': 1,
121            'errors': 0,
122            'time': '*',
123            'timestamp': '*',
124            'testsuite': [{
125                'name': 'DISABLED_test_not_run',
126                'file': 'gtest_xml_output_unittest_.cc',
127                'line': 68,
128                'status': 'NOTRUN',
129                'result': 'SUPPRESSED',
130                'time': '*',
131                'timestamp': '*',
132                'classname': 'DisabledTest',
133            }],
134        },
135        {
136            'name': 'SkippedTest',
137            'tests': 3,
138            'failures': 1,
139            'disabled': 0,
140            'errors': 0,
141            'time': '*',
142            'timestamp': '*',
143            'testsuite': [
144                {
145                    'name': 'Skipped',
146                    'file': 'gtest_xml_output_unittest_.cc',
147                    'line': 75,
148                    'status': 'RUN',
149                    'result': 'SKIPPED',
150                    'time': '*',
151                    'timestamp': '*',
152                    'classname': 'SkippedTest',
153                },
154                {
155                    'name': 'SkippedWithMessage',
156                    'file': 'gtest_xml_output_unittest_.cc',
157                    'line': 79,
158                    'status': 'RUN',
159                    'result': 'SKIPPED',
160                    'time': '*',
161                    'timestamp': '*',
162                    'classname': 'SkippedTest',
163                },
164                {
165                    'name': 'SkippedAfterFailure',
166                    'file': 'gtest_xml_output_unittest_.cc',
167                    'line': 83,
168                    'status': 'RUN',
169                    'result': 'COMPLETED',
170                    'time': '*',
171                    'timestamp': '*',
172                    'classname': 'SkippedTest',
173                    'failures': [{
174                        'failure': (
175                            'gtest_xml_output_unittest_.cc:*\n'
176                            'Expected equality of these values:\n'
177                            '  1\n  2'
178                            + STACK_TRACE_TEMPLATE
179                        ),
180                        'type': '',
181                    }],
182                },
183            ],
184        },
185        {
186            'name': 'MixedResultTest',
187            'tests': 3,
188            'failures': 1,
189            'disabled': 1,
190            'errors': 0,
191            'time': '*',
192            'timestamp': '*',
193            'testsuite': [
194                {
195                    'name': 'Succeeds',
196                    'file': 'gtest_xml_output_unittest_.cc',
197                    'line': 88,
198                    'status': 'RUN',
199                    'result': 'COMPLETED',
200                    'time': '*',
201                    'timestamp': '*',
202                    'classname': 'MixedResultTest',
203                },
204                {
205                    'name': 'Fails',
206                    'file': 'gtest_xml_output_unittest_.cc',
207                    'line': 93,
208                    'status': 'RUN',
209                    'result': 'COMPLETED',
210                    'time': '*',
211                    'timestamp': '*',
212                    'classname': 'MixedResultTest',
213                    'failures': [
214                        {
215                            'failure': (
216                                'gtest_xml_output_unittest_.cc:*\n'
217                                'Expected equality of these values:\n'
218                                '  1\n  2'
219                                + STACK_TRACE_TEMPLATE
220                            ),
221                            'type': '',
222                        },
223                        {
224                            'failure': (
225                                'gtest_xml_output_unittest_.cc:*\n'
226                                'Expected equality of these values:\n'
227                                '  2\n  3'
228                                + STACK_TRACE_TEMPLATE
229                            ),
230                            'type': '',
231                        },
232                    ],
233                },
234                {
235                    'name': 'DISABLED_test',
236                    'file': 'gtest_xml_output_unittest_.cc',
237                    'line': 98,
238                    'status': 'NOTRUN',
239                    'result': 'SUPPRESSED',
240                    'time': '*',
241                    'timestamp': '*',
242                    'classname': 'MixedResultTest',
243                },
244            ],
245        },
246        {
247            'name': 'XmlQuotingTest',
248            'tests': 1,
249            'failures': 1,
250            'disabled': 0,
251            'errors': 0,
252            'time': '*',
253            'timestamp': '*',
254            'testsuite': [{
255                'name': 'OutputsCData',
256                'file': 'gtest_xml_output_unittest_.cc',
257                'line': 102,
258                'status': 'RUN',
259                'result': 'COMPLETED',
260                'time': '*',
261                'timestamp': '*',
262                'classname': 'XmlQuotingTest',
263                'failures': [{
264                    'failure': (
265                        'gtest_xml_output_unittest_.cc:*\n'
266                        'Failed\nXML output: <?xml encoding="utf-8">'
267                        '<top><![CDATA[cdata text]]></top>'
268                        + STACK_TRACE_TEMPLATE
269                    ),
270                    'type': '',
271                }],
272            }],
273        },
274        {
275            'name': 'InvalidCharactersTest',
276            'tests': 1,
277            'failures': 1,
278            'disabled': 0,
279            'errors': 0,
280            'time': '*',
281            'timestamp': '*',
282            'testsuite': [{
283                'name': 'InvalidCharactersInMessage',
284                'file': 'gtest_xml_output_unittest_.cc',
285                'line': 109,
286                'status': 'RUN',
287                'result': 'COMPLETED',
288                'time': '*',
289                'timestamp': '*',
290                'classname': 'InvalidCharactersTest',
291                'failures': [{
292                    'failure': (
293                        'gtest_xml_output_unittest_.cc:*\n'
294                        'Failed\nInvalid characters in brackets'
295                        ' [\x01\x02]'
296                        + STACK_TRACE_TEMPLATE
297                    ),
298                    'type': '',
299                }],
300            }],
301        },
302        {
303            'name': 'PropertyRecordingTest',
304            'tests': 4,
305            'failures': 0,
306            'disabled': 0,
307            'errors': 0,
308            'time': '*',
309            'timestamp': '*',
310            'SetUpTestSuite': 'yes',
311            'TearDownTestSuite': 'aye',
312            'testsuite': [
313                {
314                    'name': 'OneProperty',
315                    'file': 'gtest_xml_output_unittest_.cc',
316                    'line': 121,
317                    'status': 'RUN',
318                    'result': 'COMPLETED',
319                    'time': '*',
320                    'timestamp': '*',
321                    'classname': 'PropertyRecordingTest',
322                    'key_1': '1',
323                },
324                {
325                    'name': 'IntValuedProperty',
326                    'file': 'gtest_xml_output_unittest_.cc',
327                    'line': 125,
328                    'status': 'RUN',
329                    'result': 'COMPLETED',
330                    'time': '*',
331                    'timestamp': '*',
332                    'classname': 'PropertyRecordingTest',
333                    'key_int': '1',
334                },
335                {
336                    'name': 'ThreeProperties',
337                    'file': 'gtest_xml_output_unittest_.cc',
338                    'line': 129,
339                    'status': 'RUN',
340                    'result': 'COMPLETED',
341                    'time': '*',
342                    'timestamp': '*',
343                    'classname': 'PropertyRecordingTest',
344                    'key_1': '1',
345                    'key_2': '2',
346                    'key_3': '3',
347                },
348                {
349                    'name': 'TwoValuesForOneKeyUsesLastValue',
350                    'file': 'gtest_xml_output_unittest_.cc',
351                    'line': 135,
352                    'status': 'RUN',
353                    'result': 'COMPLETED',
354                    'time': '*',
355                    'timestamp': '*',
356                    'classname': 'PropertyRecordingTest',
357                    'key_1': '2',
358                },
359            ],
360        },
361        {
362            'name': 'NoFixtureTest',
363            'tests': 3,
364            'failures': 0,
365            'disabled': 0,
366            'errors': 0,
367            'time': '*',
368            'timestamp': '*',
369            'testsuite': [
370                {
371                    'name': 'RecordProperty',
372                    'file': 'gtest_xml_output_unittest_.cc',
373                    'line': 140,
374                    'status': 'RUN',
375                    'result': 'COMPLETED',
376                    'time': '*',
377                    'timestamp': '*',
378                    'classname': 'NoFixtureTest',
379                    'key': '1',
380                },
381                {
382                    'name': 'ExternalUtilityThatCallsRecordIntValuedProperty',
383                    'file': 'gtest_xml_output_unittest_.cc',
384                    'line': 153,
385                    'status': 'RUN',
386                    'result': 'COMPLETED',
387                    'time': '*',
388                    'timestamp': '*',
389                    'classname': 'NoFixtureTest',
390                    'key_for_utility_int': '1',
391                },
392                {
393                    'name': (
394                        'ExternalUtilityThatCallsRecordStringValuedProperty'
395                    ),
396                    'file': 'gtest_xml_output_unittest_.cc',
397                    'line': 157,
398                    'status': 'RUN',
399                    'result': 'COMPLETED',
400                    'time': '*',
401                    'timestamp': '*',
402                    'classname': 'NoFixtureTest',
403                    'key_for_utility_string': '1',
404                },
405            ],
406        },
407        {
408            'name': 'TypedTest/0',
409            'tests': 1,
410            'failures': 0,
411            'disabled': 0,
412            'errors': 0,
413            'time': '*',
414            'timestamp': '*',
415            'testsuite': [{
416                'name': 'HasTypeParamAttribute',
417                'type_param': 'int',
418                'file': 'gtest_xml_output_unittest_.cc',
419                'line': 173,
420                'status': 'RUN',
421                'result': 'COMPLETED',
422                'time': '*',
423                'timestamp': '*',
424                'classname': 'TypedTest/0',
425            }],
426        },
427        {
428            'name': 'TypedTest/1',
429            'tests': 1,
430            'failures': 0,
431            'disabled': 0,
432            'errors': 0,
433            'time': '*',
434            'timestamp': '*',
435            'testsuite': [{
436                'name': 'HasTypeParamAttribute',
437                'type_param': 'long',
438                'file': 'gtest_xml_output_unittest_.cc',
439                'line': 173,
440                'status': 'RUN',
441                'result': 'COMPLETED',
442                'time': '*',
443                'timestamp': '*',
444                'classname': 'TypedTest/1',
445            }],
446        },
447        {
448            'name': 'Single/TypeParameterizedTestSuite/0',
449            'tests': 1,
450            'failures': 0,
451            'disabled': 0,
452            'errors': 0,
453            'time': '*',
454            'timestamp': '*',
455            'testsuite': [{
456                'name': 'HasTypeParamAttribute',
457                'type_param': 'int',
458                'file': 'gtest_xml_output_unittest_.cc',
459                'line': 180,
460                'status': 'RUN',
461                'result': 'COMPLETED',
462                'time': '*',
463                'timestamp': '*',
464                'classname': 'Single/TypeParameterizedTestSuite/0',
465            }],
466        },
467        {
468            'name': 'Single/TypeParameterizedTestSuite/1',
469            'tests': 1,
470            'failures': 0,
471            'disabled': 0,
472            'errors': 0,
473            'time': '*',
474            'timestamp': '*',
475            'testsuite': [{
476                'name': 'HasTypeParamAttribute',
477                'type_param': 'long',
478                'file': 'gtest_xml_output_unittest_.cc',
479                'line': 180,
480                'status': 'RUN',
481                'result': 'COMPLETED',
482                'time': '*',
483                'timestamp': '*',
484                'classname': 'Single/TypeParameterizedTestSuite/1',
485            }],
486        },
487        {
488            'name': 'Single/ValueParamTest',
489            'tests': 4,
490            'failures': 0,
491            'disabled': 0,
492            'errors': 0,
493            'time': '*',
494            'timestamp': '*',
495            'testsuite': [
496                {
497                    'name': 'HasValueParamAttribute/0',
498                    'value_param': '33',
499                    'file': 'gtest_xml_output_unittest_.cc',
500                    'line': 164,
501                    'status': 'RUN',
502                    'result': 'COMPLETED',
503                    'time': '*',
504                    'timestamp': '*',
505                    'classname': 'Single/ValueParamTest',
506                },
507                {
508                    'name': 'HasValueParamAttribute/1',
509                    'value_param': '42',
510                    'file': 'gtest_xml_output_unittest_.cc',
511                    'line': 164,
512                    'status': 'RUN',
513                    'result': 'COMPLETED',
514                    'time': '*',
515                    'timestamp': '*',
516                    'classname': 'Single/ValueParamTest',
517                },
518                {
519                    'name': 'AnotherTestThatHasValueParamAttribute/0',
520                    'value_param': '33',
521                    'file': 'gtest_xml_output_unittest_.cc',
522                    'line': 165,
523                    'status': 'RUN',
524                    'result': 'COMPLETED',
525                    'time': '*',
526                    'timestamp': '*',
527                    'classname': 'Single/ValueParamTest',
528                },
529                {
530                    'name': 'AnotherTestThatHasValueParamAttribute/1',
531                    'value_param': '42',
532                    'file': 'gtest_xml_output_unittest_.cc',
533                    'line': 165,
534                    'status': 'RUN',
535                    'result': 'COMPLETED',
536                    'time': '*',
537                    'timestamp': '*',
538                    'classname': 'Single/ValueParamTest',
539                },
540            ],
541        },
542    ],
543}
544
545EXPECTED_FILTERED = {
546    'tests': 1,
547    'failures': 0,
548    'disabled': 0,
549    'errors': 0,
550    'time': '*',
551    'timestamp': '*',
552    'name': 'AllTests',
553    'ad_hoc_property': '42',
554    'testsuites': [{
555        'name': 'SuccessfulTest',
556        'tests': 1,
557        'failures': 0,
558        'disabled': 0,
559        'errors': 0,
560        'time': '*',
561        'timestamp': '*',
562        'testsuite': [{
563            'name': 'Succeeds',
564            'file': 'gtest_xml_output_unittest_.cc',
565            'line': 53,
566            'status': 'RUN',
567            'result': 'COMPLETED',
568            'time': '*',
569            'timestamp': '*',
570            'classname': 'SuccessfulTest',
571        }],
572    }],
573}
574
575EXPECTED_NO_TEST = {
576    'tests': 0,
577    'failures': 0,
578    'disabled': 0,
579    'errors': 0,
580    'time': '*',
581    'timestamp': '*',
582    'name': 'AllTests',
583    'testsuites': [{
584        'name': 'NonTestSuiteFailure',
585        'tests': 1,
586        'failures': 1,
587        'disabled': 0,
588        'skipped': 0,
589        'errors': 0,
590        'time': '*',
591        'timestamp': '*',
592        'testsuite': [{
593            'name': '',
594            'status': 'RUN',
595            'result': 'COMPLETED',
596            'time': '*',
597            'timestamp': '*',
598            'classname': '',
599            'failures': [{
600                'failure': (
601                    'gtest_no_test_unittest.cc:*\n'
602                    'Expected equality of these values:\n'
603                    '  1\n  2'
604                    + STACK_TRACE_TEMPLATE
605                ),
606                'type': '',
607            }],
608        }],
609    }],
610}
611
612GTEST_PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME)
613
614SUPPORTS_TYPED_TESTS = (
615    'TypedTest'
616    in gtest_test_utils.Subprocess(
617        [GTEST_PROGRAM_PATH, GTEST_LIST_TESTS_FLAG], capture_stderr=False
618    ).output
619)
620
621
622class GTestJsonOutputUnitTest(gtest_test_utils.TestCase):
623  """Unit test for Google Test's JSON output functionality."""
624
625  # This test currently breaks on platforms that do not support typed and
626  # type-parameterized tests, so we don't run it under them.
627  if SUPPORTS_TYPED_TESTS:
628
629    def testNonEmptyJsonOutput(self):
630      """Verifies JSON output for a Google Test binary with non-empty output.
631
632      Runs a test program that generates a non-empty JSON output, and
633      tests that the JSON output is expected.
634      """
635      self._TestJsonOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY, 1)
636
637  def testNoTestJsonOutput(self):
638    """Verifies JSON output for a Google Test binary without actual tests.
639
640    Runs a test program that generates an JSON output for a binary with no
641    tests, and tests that the JSON output is expected.
642    """
643
644    self._TestJsonOutput('gtest_no_test_unittest', EXPECTED_NO_TEST, 0)
645
646  def testTimestampValue(self):
647    """Checks whether the timestamp attribute in the JSON output is valid.
648
649    Runs a test program that generates an empty JSON output, and checks if
650    the timestamp attribute in the testsuites tag is valid.
651    """
652    actual = self._GetJsonOutput('gtest_no_test_unittest', [], 0)
653    date_time_str = actual['timestamp']
654    # datetime.strptime() is only available in Python 2.5+ so we have to
655    # parse the expected datetime manually.
656    match = re.match(r'(\d+)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)', date_time_str)
657    self.assertTrue(
658        re.match,
659        'JSON datettime string %s has incorrect format' % date_time_str,
660    )
661    date_time_from_json = datetime.datetime(
662        year=int(match.group(1)),
663        month=int(match.group(2)),
664        day=int(match.group(3)),
665        hour=int(match.group(4)),
666        minute=int(match.group(5)),
667        second=int(match.group(6)),
668    )
669
670    time_delta = abs(datetime.datetime.now() - date_time_from_json)
671    # timestamp value should be near the current local time
672    self.assertTrue(
673        time_delta < datetime.timedelta(seconds=600),
674        'time_delta is %s' % time_delta,
675    )
676
677  def testDefaultOutputFile(self):
678    """Verifies the default output file name.
679
680    Confirms that Google Test produces an JSON output file with the expected
681    default name if no name is explicitly specified.
682    """
683    output_file = os.path.join(
684        gtest_test_utils.GetTempDir(), GTEST_DEFAULT_OUTPUT_FILE
685    )
686    gtest_prog_path = gtest_test_utils.GetTestExecutablePath(
687        'gtest_no_test_unittest'
688    )
689    try:
690      os.remove(output_file)
691    except OSError:
692      e = sys.exc_info()[1]
693      if e.errno != errno.ENOENT:
694        raise
695
696    p = gtest_test_utils.Subprocess(
697        [gtest_prog_path, '%s=json' % GTEST_OUTPUT_FLAG],
698        working_dir=gtest_test_utils.GetTempDir(),
699    )
700    self.assertTrue(p.exited)
701    self.assertEqual(0, p.exit_code)
702    self.assertTrue(os.path.isfile(output_file))
703
704  def testSuppressedJsonOutput(self):
705    """Verifies that no JSON output is generated.
706
707    Tests that no JSON file is generated if the default JSON listener is
708    shut down before RUN_ALL_TESTS is invoked.
709    """
710
711    json_path = os.path.join(
712        gtest_test_utils.GetTempDir(), GTEST_PROGRAM_NAME + 'out.json'
713    )
714    if os.path.isfile(json_path):
715      os.remove(json_path)
716
717    command = [
718        GTEST_PROGRAM_PATH,
719        '%s=json:%s' % (GTEST_OUTPUT_FLAG, json_path),
720        '--shut_down_xml',
721    ]
722    p = gtest_test_utils.Subprocess(command)
723    if p.terminated_by_signal:
724      # p.signal is available only if p.terminated_by_signal is True.
725      self.assertFalse(
726          p.terminated_by_signal,
727          '%s was killed by signal %d' % (GTEST_PROGRAM_NAME, p.signal),
728      )
729    else:
730      self.assertTrue(p.exited)
731      self.assertEqual(
732          1,
733          p.exit_code,
734          "'%s' exited with code %s, which doesn't match "
735          'the expected exit code %s.' % (command, p.exit_code, 1),
736      )
737
738    self.assertTrue(not os.path.isfile(json_path))
739
740  def testFilteredTestJsonOutput(self):
741    """Verifies JSON output when a filter is applied.
742
743    Runs a test program that executes only some tests and verifies that
744    non-selected tests do not show up in the JSON output.
745    """
746
747    self._TestJsonOutput(
748        GTEST_PROGRAM_NAME,
749        EXPECTED_FILTERED,
750        0,
751        extra_args=['%s=SuccessfulTest.*' % GTEST_FILTER_FLAG],
752    )
753
754  def _GetJsonOutput(self, gtest_prog_name, extra_args, expected_exit_code):
755    """Returns the JSON output generated by running the program gtest_prog_name.
756
757    Furthermore, the program's exit code must be expected_exit_code.
758
759    Args:
760      gtest_prog_name: Google Test binary name.
761      extra_args: extra arguments to binary invocation.
762      expected_exit_code: program's exit code.
763    """
764    json_path = os.path.join(
765        gtest_test_utils.GetTempDir(), gtest_prog_name + 'out.json'
766    )
767    gtest_prog_path = gtest_test_utils.GetTestExecutablePath(gtest_prog_name)
768
769    command = [
770        gtest_prog_path,
771        '%s=json:%s' % (GTEST_OUTPUT_FLAG, json_path),
772    ] + extra_args
773    p = gtest_test_utils.Subprocess(command)
774    if p.terminated_by_signal:
775      self.assertTrue(
776          False, '%s was killed by signal %d' % (gtest_prog_name, p.signal)
777      )
778    else:
779      self.assertTrue(p.exited)
780      self.assertEqual(
781          expected_exit_code,
782          p.exit_code,
783          "'%s' exited with code %s, which doesn't match "
784          'the expected exit code %s.'
785          % (command, p.exit_code, expected_exit_code),
786      )
787    with open(json_path) as f:
788      actual = json.load(f)
789    return actual
790
791  def _TestJsonOutput(
792      self, gtest_prog_name, expected, expected_exit_code, extra_args=None
793  ):
794    """Checks the JSON output generated by the Google Test binary.
795
796    Asserts that the JSON document generated by running the program
797    gtest_prog_name matches expected_json, a string containing another
798    JSON document.  Furthermore, the program's exit code must be
799    expected_exit_code.
800
801    Args:
802      gtest_prog_name: Google Test binary name.
803      expected: expected output.
804      expected_exit_code: program's exit code.
805      extra_args: extra arguments to binary invocation.
806    """
807
808    actual = self._GetJsonOutput(
809        gtest_prog_name, extra_args or [], expected_exit_code
810    )
811    self.assertEqual(expected, gtest_json_test_utils.normalize(actual))
812
813
814if __name__ == '__main__':
815  if NO_STACKTRACE_SUPPORT_FLAG in sys.argv:
816    # unittest.main() can't handle unknown flags
817    sys.argv.remove(NO_STACKTRACE_SUPPORT_FLAG)
818
819  os.environ['GTEST_STACK_TRACE_DEPTH'] = '1'
820  gtest_test_utils.Main()
821