2016-12-13 19:54:17 +00:00
#!/usr/bin/env python
#
# Copyright 2006, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
""" Unit test for the gtest_xml_output module """
2020-03-11 14:54:18 +00:00
import datetime
2016-12-13 19:54:17 +00:00
import errno
import os
2020-03-11 14:54:18 +00:00
import re
2016-12-13 19:54:17 +00:00
import sys
from xml . dom import minidom , Node
import gtest_test_utils
import gtest_xml_test_utils
2020-03-11 14:54:18 +00:00
GTEST_FILTER_FLAG = ' --gtest_filter '
GTEST_LIST_TESTS_FLAG = ' --gtest_list_tests '
GTEST_OUTPUT_FLAG = ' --gtest_output '
GTEST_DEFAULT_OUTPUT_FILE = ' test_detail.xml '
GTEST_PROGRAM_NAME = ' gtest_xml_output_unittest_ '
# The flag indicating stacktraces are not supported
NO_STACKTRACE_SUPPORT_FLAG = ' --no_stacktrace_support '
2016-12-13 19:54:17 +00:00
2020-03-11 14:54:18 +00:00
# The environment variables for test sharding.
TOTAL_SHARDS_ENV_VAR = ' GTEST_TOTAL_SHARDS '
SHARD_INDEX_ENV_VAR = ' GTEST_SHARD_INDEX '
SHARD_STATUS_FILE_ENV_VAR = ' GTEST_SHARD_STATUS_FILE '
2016-12-13 19:54:17 +00:00
2020-03-11 14:54:18 +00:00
SUPPORTS_STACK_TRACES = NO_STACKTRACE_SUPPORT_FLAG not in sys . argv
2016-12-13 19:54:17 +00:00
if SUPPORTS_STACK_TRACES :
2020-03-11 14:54:18 +00:00
STACK_TRACE_TEMPLATE = ' \n Stack trace: \n * '
2016-12-13 19:54:17 +00:00
else :
2020-03-11 14:54:18 +00:00
STACK_TRACE_TEMPLATE = ' '
# unittest.main() can't handle unknown flags
sys . argv . remove ( NO_STACKTRACE_SUPPORT_FLAG )
2016-12-13 19:54:17 +00:00
EXPECTED_NON_EMPTY_XML = """ <?xml version= " 1.0 " encoding= " UTF-8 " ?>
2020-03-11 14:54:18 +00:00
< testsuites tests = " 23 " failures = " 4 " disabled = " 2 " errors = " 0 " time = " * " timestamp = " * " name = " AllTests " ad_hoc_property = " 42 " >
2016-12-13 19:54:17 +00:00
< testsuite name = " SuccessfulTest " tests = " 1 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " Succeeds " status = " run " time = " * " classname = " SuccessfulTest " / >
< / testsuite >
< testsuite name = " FailedTest " tests = " 1 " failures = " 1 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " Fails " status = " run " time = " * " classname = " FailedTest " >
2020-03-11 14:54:18 +00:00
< failure message = " gtest_xml_output_unittest_.cc:*
Expected equality of these values:
 1
 2 " type = " " > < ! [ CDATA [ gtest_xml_output_unittest_ . cc : *
Expected equality of these values :
1
2 % ( stack ) s ] ] > < / failure >
2016-12-13 19:54:17 +00:00
< / testcase >
< / testsuite >
< testsuite name = " MixedResultTest " tests = " 3 " failures = " 1 " disabled = " 1 " errors = " 0 " time = " * " >
< testcase name = " Succeeds " status = " run " time = " * " classname = " MixedResultTest " / >
< testcase name = " Fails " status = " run " time = " * " classname = " MixedResultTest " >
2020-03-11 14:54:18 +00:00
< failure message = " gtest_xml_output_unittest_.cc:*
Expected equality of these values:
 1
 2 " type = " " > < ! [ CDATA [ gtest_xml_output_unittest_ . cc : *
Expected equality of these values :
1
2 % ( stack ) s ] ] > < / failure >
< failure message = " gtest_xml_output_unittest_.cc:*
Expected equality of these values:
 2
 3 " type = " " > < ! [ CDATA [ gtest_xml_output_unittest_ . cc : *
Expected equality of these values :
2
3 % ( stack ) s ] ] > < / failure >
2016-12-13 19:54:17 +00:00
< / testcase >
< testcase name = " DISABLED_test " status = " notrun " time = " * " classname = " MixedResultTest " / >
< / testsuite >
< testsuite name = " XmlQuotingTest " tests = " 1 " failures = " 1 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " OutputsCData " status = " run " time = " * " classname = " XmlQuotingTest " >
2020-03-11 14:54:18 +00:00
< failure message = " gtest_xml_output_unittest_.cc:*
Failed
XML output: <?xml encoding="utf-8"><top><![CDATA[cdata text]]></top> " type = " " > < ! [ CDATA [ gtest_xml_output_unittest_ . cc : *
2016-12-13 19:54:17 +00:00
Failed
XML output : < ? xml encoding = " utf-8 " > < top > < ! [ CDATA [ cdata text ] ] > ] ] & gt ; < ! [ CDATA [ < / top > % ( stack ) s ] ] > < / failure >
< / testcase >
< / testsuite >
< testsuite name = " InvalidCharactersTest " tests = " 1 " failures = " 1 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " InvalidCharactersInMessage " status = " run " time = " * " classname = " InvalidCharactersTest " >
2020-03-11 14:54:18 +00:00
< failure message = " gtest_xml_output_unittest_.cc:*
Failed
Invalid characters in brackets [] " type = " " > < ! [ CDATA [ gtest_xml_output_unittest_ . cc : *
2016-12-13 19:54:17 +00:00
Failed
Invalid characters in brackets [ ] % ( stack ) s ] ] > < / failure >
< / testcase >
< / testsuite >
< testsuite name = " DisabledTest " tests = " 1 " failures = " 0 " disabled = " 1 " errors = " 0 " time = " * " >
< testcase name = " DISABLED_test_not_run " status = " notrun " time = " * " classname = " DisabledTest " / >
< / testsuite >
2020-03-11 14:54:18 +00:00
< testsuite name = " PropertyRecordingTest " tests = " 4 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " SetUpTestCase = " yes " TearDownTestCase = " aye " >
< testcase name = " OneProperty " status = " run " time = " * " classname = " PropertyRecordingTest " >
< properties >
< property name = " key_1 " value = " 1 " / >
< / properties >
< / testcase >
< testcase name = " IntValuedProperty " status = " run " time = " * " classname = " PropertyRecordingTest " >
< properties >
< property name = " key_int " value = " 1 " / >
< / properties >
< / testcase >
< testcase name = " ThreeProperties " status = " run " time = " * " classname = " PropertyRecordingTest " >
< properties >
< property name = " key_1 " value = " 1 " / >
< property name = " key_2 " value = " 2 " / >
< property name = " key_3 " value = " 3 " / >
< / properties >
< / testcase >
< testcase name = " TwoValuesForOneKeyUsesLastValue " status = " run " time = " * " classname = " PropertyRecordingTest " >
< properties >
< property name = " key_1 " value = " 2 " / >
< / properties >
< / testcase >
2016-12-13 19:54:17 +00:00
< / testsuite >
< testsuite name = " NoFixtureTest " tests = " 3 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " >
2020-03-11 14:54:18 +00:00
< testcase name = " RecordProperty " status = " run " time = " * " classname = " NoFixtureTest " >
< properties >
< property name = " key " value = " 1 " / >
< / properties >
< / testcase >
< testcase name = " ExternalUtilityThatCallsRecordIntValuedProperty " status = " run " time = " * " classname = " NoFixtureTest " >
< properties >
< property name = " key_for_utility_int " value = " 1 " / >
< / properties >
< / testcase >
< testcase name = " ExternalUtilityThatCallsRecordStringValuedProperty " status = " run " time = " * " classname = " NoFixtureTest " >
< properties >
< property name = " key_for_utility_string " value = " 1 " / >
< / properties >
< / testcase >
2016-12-13 19:54:17 +00:00
< / testsuite >
< testsuite name = " Single/ValueParamTest " tests = " 4 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " HasValueParamAttribute/0 " value_param = " 33 " status = " run " time = " * " classname = " Single/ValueParamTest " / >
< testcase name = " HasValueParamAttribute/1 " value_param = " 42 " status = " run " time = " * " classname = " Single/ValueParamTest " / >
< testcase name = " AnotherTestThatHasValueParamAttribute/0 " value_param = " 33 " status = " run " time = " * " classname = " Single/ValueParamTest " / >
< testcase name = " AnotherTestThatHasValueParamAttribute/1 " value_param = " 42 " status = " run " time = " * " classname = " Single/ValueParamTest " / >
< / testsuite >
< testsuite name = " TypedTest/0 " tests = " 1 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " HasTypeParamAttribute " type_param = " * " status = " run " time = " * " classname = " TypedTest/0 " / >
< / testsuite >
< testsuite name = " TypedTest/1 " tests = " 1 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " HasTypeParamAttribute " type_param = " * " status = " run " time = " * " classname = " TypedTest/1 " / >
< / testsuite >
< testsuite name = " Single/TypeParameterizedTestCase/0 " tests = " 1 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " HasTypeParamAttribute " type_param = " * " status = " run " time = " * " classname = " Single/TypeParameterizedTestCase/0 " / >
< / testsuite >
< testsuite name = " Single/TypeParameterizedTestCase/1 " tests = " 1 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " HasTypeParamAttribute " type_param = " * " status = " run " time = " * " classname = " Single/TypeParameterizedTestCase/1 " / >
< / testsuite >
< / testsuites > """ % { ' stack ' : STACK_TRACE_TEMPLATE}
2020-03-11 14:54:18 +00:00
EXPECTED_FILTERED_TEST_XML = """ <?xml version= " 1.0 " encoding= " UTF-8 " ?>
< testsuites tests = " 1 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * "
timestamp = " * " name = " AllTests " ad_hoc_property = " 42 " >
< testsuite name = " SuccessfulTest " tests = " 1 " failures = " 0 " disabled = " 0 "
errors = " 0 " time = " * " >
< testcase name = " Succeeds " status = " run " time = " * " classname = " SuccessfulTest " / >
< / testsuite >
< / testsuites > """
EXPECTED_SHARDED_TEST_XML = """ <?xml version= " 1.0 " encoding= " UTF-8 " ?>
< testsuites tests = " 3 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " timestamp = " * " name = " AllTests " ad_hoc_property = " 42 " >
< testsuite name = " SuccessfulTest " tests = " 1 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " Succeeds " status = " run " time = " * " classname = " SuccessfulTest " / >
< / testsuite >
< testsuite name = " NoFixtureTest " tests = " 1 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " RecordProperty " status = " run " time = " * " classname = " NoFixtureTest " >
< properties >
< property name = " key " value = " 1 " / >
< / properties >
< / testcase >
< / testsuite >
< testsuite name = " Single/ValueParamTest " tests = " 1 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * " >
< testcase name = " AnotherTestThatHasValueParamAttribute/1 " value_param = " 42 " status = " run " time = " * " classname = " Single/ValueParamTest " / >
< / testsuite >
< / testsuites > """
2016-12-13 19:54:17 +00:00
EXPECTED_EMPTY_XML = """ <?xml version= " 1.0 " encoding= " UTF-8 " ?>
2020-03-11 14:54:18 +00:00
< testsuites tests = " 0 " failures = " 0 " disabled = " 0 " errors = " 0 " time = " * "
timestamp = " * " name = " AllTests " >
2016-12-13 19:54:17 +00:00
< / testsuites > """
2020-03-11 14:54:18 +00:00
GTEST_PROGRAM_PATH = gtest_test_utils . GetTestExecutablePath ( GTEST_PROGRAM_NAME )
SUPPORTS_TYPED_TESTS = ' TypedTest ' in gtest_test_utils . Subprocess (
[ GTEST_PROGRAM_PATH , GTEST_LIST_TESTS_FLAG ] , capture_stderr = False ) . output
2016-12-13 19:54:17 +00:00
class GTestXMLOutputUnitTest ( gtest_xml_test_utils . GTestXMLTestCase ) :
"""
Unit test for Google Test ' s XML output functionality.
"""
2020-03-11 14:54:18 +00:00
# This test currently breaks on platforms that do not support typed and
# type-parameterized tests, so we don't run it under them.
if SUPPORTS_TYPED_TESTS :
def testNonEmptyXmlOutput ( self ) :
"""
Runs a test program that generates a non - empty XML output , and
tests that the XML output is expected .
"""
self . _TestXmlOutput ( GTEST_PROGRAM_NAME , EXPECTED_NON_EMPTY_XML , 1 )
2016-12-13 19:54:17 +00:00
def testEmptyXmlOutput ( self ) :
2020-03-11 14:54:18 +00:00
""" Verifies XML output for a Google Test binary without actual tests.
2016-12-13 19:54:17 +00:00
Runs a test program that generates an empty XML output , and
tests that the XML output is expected .
"""
2020-03-11 14:54:18 +00:00
self . _TestXmlOutput ( ' gtest_no_test_unittest ' , EXPECTED_EMPTY_XML , 0 )
def testTimestampValue ( self ) :
""" Checks whether the timestamp attribute in the XML output is valid.
Runs a test program that generates an empty XML output , and checks if
the timestamp attribute in the testsuites tag is valid .
"""
actual = self . _GetXmlOutput ( ' gtest_no_test_unittest ' , [ ] , { } , 0 )
date_time_str = actual . documentElement . getAttributeNode ( ' timestamp ' ) . value
# datetime.strptime() is only available in Python 2.5+ so we have to
# parse the expected datetime manually.
match = re . match ( r ' ( \ d+)-( \ d \ d)-( \ d \ d)T( \ d \ d):( \ d \ d):( \ d \ d) ' , date_time_str )
self . assertTrue (
re . match ,
' XML datettime string %s has incorrect format ' % date_time_str )
date_time_from_xml = datetime . datetime (
year = int ( match . group ( 1 ) ) , month = int ( match . group ( 2 ) ) ,
day = int ( match . group ( 3 ) ) , hour = int ( match . group ( 4 ) ) ,
minute = int ( match . group ( 5 ) ) , second = int ( match . group ( 6 ) ) )
time_delta = abs ( datetime . datetime . now ( ) - date_time_from_xml )
# timestamp value should be near the current local time
self . assertTrue ( time_delta < datetime . timedelta ( seconds = 600 ) ,
' time_delta is %s ' % time_delta )
actual . unlink ( )
2016-12-13 19:54:17 +00:00
def testDefaultOutputFile ( self ) :
"""
Confirms that Google Test produces an XML output file with the expected
default name if no name is explicitly specified .
"""
output_file = os . path . join ( gtest_test_utils . GetTempDir ( ) ,
GTEST_DEFAULT_OUTPUT_FILE )
gtest_prog_path = gtest_test_utils . GetTestExecutablePath (
2020-03-11 14:54:18 +00:00
' gtest_no_test_unittest ' )
2016-12-13 19:54:17 +00:00
try :
os . remove ( output_file )
except OSError , e :
if e . errno != errno . ENOENT :
raise
p = gtest_test_utils . Subprocess (
2020-03-11 14:54:18 +00:00
[ gtest_prog_path , ' %s =xml ' % GTEST_OUTPUT_FLAG ] ,
2016-12-13 19:54:17 +00:00
working_dir = gtest_test_utils . GetTempDir ( ) )
self . assert_ ( p . exited )
self . assertEquals ( 0 , p . exit_code )
self . assert_ ( os . path . isfile ( output_file ) )
def testSuppressedXmlOutput ( self ) :
"""
Tests that no XML file is generated if the default XML listener is
shut down before RUN_ALL_TESTS is invoked .
"""
xml_path = os . path . join ( gtest_test_utils . GetTempDir ( ) ,
2020-03-11 14:54:18 +00:00
GTEST_PROGRAM_NAME + ' out.xml ' )
2016-12-13 19:54:17 +00:00
if os . path . isfile ( xml_path ) :
os . remove ( xml_path )
2020-03-11 14:54:18 +00:00
command = [ GTEST_PROGRAM_PATH ,
' %s =xml: %s ' % ( GTEST_OUTPUT_FLAG , xml_path ) ,
' --shut_down_xml ' ]
2016-12-13 19:54:17 +00:00
p = gtest_test_utils . Subprocess ( command )
if p . terminated_by_signal :
2020-03-11 14:54:18 +00:00
# p.signal is available only if p.terminated_by_signal is True.
self . assertFalse (
p . terminated_by_signal ,
' %s was killed by signal %d ' % ( GTEST_PROGRAM_NAME , p . signal ) )
2016-12-13 19:54:17 +00:00
else :
self . assert_ ( p . exited )
self . assertEquals ( 1 , p . exit_code ,
" ' %s ' exited with code %s , which doesn ' t match "
2020-03-11 14:54:18 +00:00
' the expected exit code %s . '
2016-12-13 19:54:17 +00:00
% ( command , p . exit_code , 1 ) )
self . assert_ ( not os . path . isfile ( xml_path ) )
2020-03-11 14:54:18 +00:00
def testFilteredTestXmlOutput ( self ) :
""" Verifies XML output when a filter is applied.
2016-12-13 19:54:17 +00:00
2020-03-11 14:54:18 +00:00
Runs a test program that executes only some tests and verifies that
non - selected tests do not show up in the XML output .
2016-12-13 19:54:17 +00:00
"""
2020-03-11 14:54:18 +00:00
self . _TestXmlOutput ( GTEST_PROGRAM_NAME , EXPECTED_FILTERED_TEST_XML , 0 ,
extra_args = [ ' %s =SuccessfulTest.* ' % GTEST_FILTER_FLAG ] )
def testShardedTestXmlOutput ( self ) :
""" Verifies XML output when run using multiple shards.
Runs a test program that executes only one shard and verifies that tests
from other shards do not show up in the XML output .
"""
self . _TestXmlOutput (
GTEST_PROGRAM_NAME ,
EXPECTED_SHARDED_TEST_XML ,
0 ,
extra_env = { SHARD_INDEX_ENV_VAR : ' 0 ' ,
TOTAL_SHARDS_ENV_VAR : ' 10 ' } )
def _GetXmlOutput ( self , gtest_prog_name , extra_args , extra_env ,
expected_exit_code ) :
"""
Returns the xml output generated by running the program gtest_prog_name .
Furthermore , the program ' s exit code must be expected_exit_code.
2016-12-13 19:54:17 +00:00
"""
xml_path = os . path . join ( gtest_test_utils . GetTempDir ( ) ,
2020-03-11 14:54:18 +00:00
gtest_prog_name + ' out.xml ' )
2016-12-13 19:54:17 +00:00
gtest_prog_path = gtest_test_utils . GetTestExecutablePath ( gtest_prog_name )
2020-03-11 14:54:18 +00:00
command = ( [ gtest_prog_path , ' %s =xml: %s ' % ( GTEST_OUTPUT_FLAG , xml_path ) ] +
extra_args )
environ_copy = os . environ . copy ( )
if extra_env :
environ_copy . update ( extra_env )
p = gtest_test_utils . Subprocess ( command , env = environ_copy )
2016-12-13 19:54:17 +00:00
if p . terminated_by_signal :
self . assert_ ( False ,
2020-03-11 14:54:18 +00:00
' %s was killed by signal %d ' % ( gtest_prog_name , p . signal ) )
2016-12-13 19:54:17 +00:00
else :
self . assert_ ( p . exited )
self . assertEquals ( expected_exit_code , p . exit_code ,
" ' %s ' exited with code %s , which doesn ' t match "
2020-03-11 14:54:18 +00:00
' the expected exit code %s . '
2016-12-13 19:54:17 +00:00
% ( command , p . exit_code , expected_exit_code ) )
2020-03-11 14:54:18 +00:00
actual = minidom . parse ( xml_path )
return actual
def _TestXmlOutput ( self , gtest_prog_name , expected_xml ,
expected_exit_code , extra_args = None , extra_env = None ) :
"""
Asserts that the XML document generated by running the program
gtest_prog_name matches expected_xml , a string containing another
XML document . Furthermore , the program ' s exit code must be
expected_exit_code .
"""
2016-12-13 19:54:17 +00:00
2020-03-11 14:54:18 +00:00
actual = self . _GetXmlOutput ( gtest_prog_name , extra_args or [ ] ,
extra_env or { } , expected_exit_code )
2016-12-13 19:54:17 +00:00
expected = minidom . parseString ( expected_xml )
self . NormalizeXml ( actual . documentElement )
self . AssertEquivalentNodes ( expected . documentElement ,
actual . documentElement )
expected . unlink ( )
2020-03-11 14:54:18 +00:00
actual . unlink ( )
2016-12-13 19:54:17 +00:00
if __name__ == ' __main__ ' :
os . environ [ ' GTEST_STACK_TRACE_DEPTH ' ] = ' 1 '
gtest_test_utils . Main ( )