1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/trunk/testing/gtest/test/gtest_output_test.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,335 @@ 1.4 +#!/usr/bin/env python 1.5 +# 1.6 +# Copyright 2008, Google Inc. 1.7 +# All rights reserved. 1.8 +# 1.9 +# Redistribution and use in source and binary forms, with or without 1.10 +# modification, are permitted provided that the following conditions are 1.11 +# met: 1.12 +# 1.13 +# * Redistributions of source code must retain the above copyright 1.14 +# notice, this list of conditions and the following disclaimer. 1.15 +# * Redistributions in binary form must reproduce the above 1.16 +# copyright notice, this list of conditions and the following disclaimer 1.17 +# in the documentation and/or other materials provided with the 1.18 +# distribution. 1.19 +# * Neither the name of Google Inc. nor the names of its 1.20 +# contributors may be used to endorse or promote products derived from 1.21 +# this software without specific prior written permission. 1.22 +# 1.23 +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.24 +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.25 +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.26 +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.27 +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.28 +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.29 +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.30 +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.31 +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.32 +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.33 +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.34 + 1.35 +"""Tests the text output of Google C++ Testing Framework. 1.36 + 1.37 +SYNOPSIS 1.38 + gtest_output_test.py --build_dir=BUILD/DIR --gengolden 1.39 + # where BUILD/DIR contains the built gtest_output_test_ file. 1.40 + gtest_output_test.py --gengolden 1.41 + gtest_output_test.py 1.42 +""" 1.43 + 1.44 +__author__ = 'wan@google.com (Zhanyong Wan)' 1.45 + 1.46 +import os 1.47 +import re 1.48 +import sys 1.49 +import gtest_test_utils 1.50 + 1.51 + 1.52 +# The flag for generating the golden file 1.53 +GENGOLDEN_FLAG = '--gengolden' 1.54 +CATCH_EXCEPTIONS_ENV_VAR_NAME = 'GTEST_CATCH_EXCEPTIONS' 1.55 + 1.56 +IS_WINDOWS = os.name == 'nt' 1.57 + 1.58 +# TODO(vladl@google.com): remove the _lin suffix. 1.59 +GOLDEN_NAME = 'gtest_output_test_golden_lin.txt' 1.60 + 1.61 +PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_output_test_') 1.62 + 1.63 +# At least one command we exercise must not have the 1.64 +# --gtest_internal_skip_environment_and_ad_hoc_tests flag. 1.65 +COMMAND_LIST_TESTS = ({}, [PROGRAM_PATH, '--gtest_list_tests']) 1.66 +COMMAND_WITH_COLOR = ({}, [PROGRAM_PATH, '--gtest_color=yes']) 1.67 +COMMAND_WITH_TIME = ({}, [PROGRAM_PATH, 1.68 + '--gtest_print_time', 1.69 + '--gtest_internal_skip_environment_and_ad_hoc_tests', 1.70 + '--gtest_filter=FatalFailureTest.*:LoggingTest.*']) 1.71 +COMMAND_WITH_DISABLED = ( 1.72 + {}, [PROGRAM_PATH, 1.73 + '--gtest_also_run_disabled_tests', 1.74 + '--gtest_internal_skip_environment_and_ad_hoc_tests', 1.75 + '--gtest_filter=*DISABLED_*']) 1.76 +COMMAND_WITH_SHARDING = ( 1.77 + {'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'}, 1.78 + [PROGRAM_PATH, 1.79 + '--gtest_internal_skip_environment_and_ad_hoc_tests', 1.80 + '--gtest_filter=PassingTest.*']) 1.81 + 1.82 +GOLDEN_PATH = os.path.join(gtest_test_utils.GetSourceDir(), GOLDEN_NAME) 1.83 + 1.84 + 1.85 +def ToUnixLineEnding(s): 1.86 + """Changes all Windows/Mac line endings in s to UNIX line endings.""" 1.87 + 1.88 + return s.replace('\r\n', '\n').replace('\r', '\n') 1.89 + 1.90 + 1.91 +def RemoveLocations(test_output): 1.92 + """Removes all file location info from a Google Test program's output. 1.93 + 1.94 + Args: 1.95 + test_output: the output of a Google Test program. 1.96 + 1.97 + Returns: 1.98 + output with all file location info (in the form of 1.99 + 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or 1.100 + 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by 1.101 + 'FILE_NAME:#: '. 1.102 + """ 1.103 + 1.104 + return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\: ', r'\1:#: ', test_output) 1.105 + 1.106 + 1.107 +def RemoveStackTraceDetails(output): 1.108 + """Removes all stack traces from a Google Test program's output.""" 1.109 + 1.110 + # *? means "find the shortest string that matches". 1.111 + return re.sub(r'Stack trace:(.|\n)*?\n\n', 1.112 + 'Stack trace: (omitted)\n\n', output) 1.113 + 1.114 + 1.115 +def RemoveStackTraces(output): 1.116 + """Removes all traces of stack traces from a Google Test program's output.""" 1.117 + 1.118 + # *? means "find the shortest string that matches". 1.119 + return re.sub(r'Stack trace:(.|\n)*?\n\n', '', output) 1.120 + 1.121 + 1.122 +def RemoveTime(output): 1.123 + """Removes all time information from a Google Test program's output.""" 1.124 + 1.125 + return re.sub(r'\(\d+ ms', '(? ms', output) 1.126 + 1.127 + 1.128 +def RemoveTypeInfoDetails(test_output): 1.129 + """Removes compiler-specific type info from Google Test program's output. 1.130 + 1.131 + Args: 1.132 + test_output: the output of a Google Test program. 1.133 + 1.134 + Returns: 1.135 + output with type information normalized to canonical form. 1.136 + """ 1.137 + 1.138 + # some compilers output the name of type 'unsigned int' as 'unsigned' 1.139 + return re.sub(r'unsigned int', 'unsigned', test_output) 1.140 + 1.141 + 1.142 +def NormalizeToCurrentPlatform(test_output): 1.143 + """Normalizes platform specific output details for easier comparison.""" 1.144 + 1.145 + if IS_WINDOWS: 1.146 + # Removes the color information that is not present on Windows. 1.147 + test_output = re.sub('\x1b\\[(0;3\d)?m', '', test_output) 1.148 + # Changes failure message headers into the Windows format. 1.149 + test_output = re.sub(r': Failure\n', r': error: ', test_output) 1.150 + # Changes file(line_number) to file:line_number. 1.151 + test_output = re.sub(r'((\w|\.)+)\((\d+)\):', r'\1:\3:', test_output) 1.152 + 1.153 + return test_output 1.154 + 1.155 + 1.156 +def RemoveTestCounts(output): 1.157 + """Removes test counts from a Google Test program's output.""" 1.158 + 1.159 + output = re.sub(r'\d+ tests?, listed below', 1.160 + '? tests, listed below', output) 1.161 + output = re.sub(r'\d+ FAILED TESTS', 1.162 + '? FAILED TESTS', output) 1.163 + output = re.sub(r'\d+ tests? from \d+ test cases?', 1.164 + '? tests from ? test cases', output) 1.165 + output = re.sub(r'\d+ tests? from ([a-zA-Z_])', 1.166 + r'? tests from \1', output) 1.167 + return re.sub(r'\d+ tests?\.', '? tests.', output) 1.168 + 1.169 + 1.170 +def RemoveMatchingTests(test_output, pattern): 1.171 + """Removes output of specified tests from a Google Test program's output. 1.172 + 1.173 + This function strips not only the beginning and the end of a test but also 1.174 + all output in between. 1.175 + 1.176 + Args: 1.177 + test_output: A string containing the test output. 1.178 + pattern: A regex string that matches names of test cases or 1.179 + tests to remove. 1.180 + 1.181 + Returns: 1.182 + Contents of test_output with tests whose names match pattern removed. 1.183 + """ 1.184 + 1.185 + test_output = re.sub( 1.186 + r'.*\[ RUN \] .*%s(.|\n)*?\[( FAILED | OK )\] .*%s.*\n' % ( 1.187 + pattern, pattern), 1.188 + '', 1.189 + test_output) 1.190 + return re.sub(r'.*%s.*\n' % pattern, '', test_output) 1.191 + 1.192 + 1.193 +def NormalizeOutput(output): 1.194 + """Normalizes output (the output of gtest_output_test_.exe).""" 1.195 + 1.196 + output = ToUnixLineEnding(output) 1.197 + output = RemoveLocations(output) 1.198 + output = RemoveStackTraceDetails(output) 1.199 + output = RemoveTime(output) 1.200 + return output 1.201 + 1.202 + 1.203 +def GetShellCommandOutput(env_cmd): 1.204 + """Runs a command in a sub-process, and returns its output in a string. 1.205 + 1.206 + Args: 1.207 + env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra 1.208 + environment variables to set, and element 1 is a string with 1.209 + the command and any flags. 1.210 + 1.211 + Returns: 1.212 + A string with the command's combined standard and diagnostic output. 1.213 + """ 1.214 + 1.215 + # Spawns cmd in a sub-process, and gets its standard I/O file objects. 1.216 + # Set and save the environment properly. 1.217 + environ = os.environ.copy() 1.218 + environ.update(env_cmd[0]) 1.219 + p = gtest_test_utils.Subprocess(env_cmd[1], env=environ, capture_stderr=False) 1.220 + 1.221 + return p.output 1.222 + 1.223 + 1.224 +def GetCommandOutput(env_cmd): 1.225 + """Runs a command and returns its output with all file location 1.226 + info stripped off. 1.227 + 1.228 + Args: 1.229 + env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra 1.230 + environment variables to set, and element 1 is a string with 1.231 + the command and any flags. 1.232 + """ 1.233 + 1.234 + # Disables exception pop-ups on Windows. 1.235 + environ, cmdline = env_cmd 1.236 + environ = dict(environ) # Ensures we are modifying a copy. 1.237 + environ[CATCH_EXCEPTIONS_ENV_VAR_NAME] = '1' 1.238 + return NormalizeOutput(GetShellCommandOutput((environ, cmdline))) 1.239 + 1.240 + 1.241 +def GetOutputOfAllCommands(): 1.242 + """Returns concatenated output from several representative commands.""" 1.243 + 1.244 + return (GetCommandOutput(COMMAND_WITH_COLOR) + 1.245 + GetCommandOutput(COMMAND_WITH_TIME) + 1.246 + GetCommandOutput(COMMAND_WITH_DISABLED) + 1.247 + GetCommandOutput(COMMAND_WITH_SHARDING)) 1.248 + 1.249 + 1.250 +test_list = GetShellCommandOutput(COMMAND_LIST_TESTS) 1.251 +SUPPORTS_DEATH_TESTS = 'DeathTest' in test_list 1.252 +SUPPORTS_TYPED_TESTS = 'TypedTest' in test_list 1.253 +SUPPORTS_THREADS = 'ExpectFailureWithThreadsTest' in test_list 1.254 +SUPPORTS_STACK_TRACES = False 1.255 + 1.256 +CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and 1.257 + SUPPORTS_TYPED_TESTS and 1.258 + SUPPORTS_THREADS) 1.259 + 1.260 + 1.261 +class GTestOutputTest(gtest_test_utils.TestCase): 1.262 + def RemoveUnsupportedTests(self, test_output): 1.263 + if not SUPPORTS_DEATH_TESTS: 1.264 + test_output = RemoveMatchingTests(test_output, 'DeathTest') 1.265 + if not SUPPORTS_TYPED_TESTS: 1.266 + test_output = RemoveMatchingTests(test_output, 'TypedTest') 1.267 + test_output = RemoveMatchingTests(test_output, 'TypedDeathTest') 1.268 + test_output = RemoveMatchingTests(test_output, 'TypeParamDeathTest') 1.269 + if not SUPPORTS_THREADS: 1.270 + test_output = RemoveMatchingTests(test_output, 1.271 + 'ExpectFailureWithThreadsTest') 1.272 + test_output = RemoveMatchingTests(test_output, 1.273 + 'ScopedFakeTestPartResultReporterTest') 1.274 + test_output = RemoveMatchingTests(test_output, 1.275 + 'WorksConcurrently') 1.276 + if not SUPPORTS_STACK_TRACES: 1.277 + test_output = RemoveStackTraces(test_output) 1.278 + 1.279 + return test_output 1.280 + 1.281 + def testOutput(self): 1.282 + output = GetOutputOfAllCommands() 1.283 + 1.284 + golden_file = open(GOLDEN_PATH, 'rb') 1.285 + # A mis-configured source control system can cause \r appear in EOL 1.286 + # sequences when we read the golden file irrespective of an operating 1.287 + # system used. Therefore, we need to strip those \r's from newlines 1.288 + # unconditionally. 1.289 + golden = ToUnixLineEnding(golden_file.read()) 1.290 + golden_file.close() 1.291 + 1.292 + # We want the test to pass regardless of certain features being 1.293 + # supported or not. 1.294 + 1.295 + # We still have to remove type name specifics in all cases. 1.296 + normalized_actual = RemoveTypeInfoDetails(output) 1.297 + normalized_golden = RemoveTypeInfoDetails(golden) 1.298 + 1.299 + if CAN_GENERATE_GOLDEN_FILE: 1.300 + self.assertEqual(normalized_golden, normalized_actual) 1.301 + else: 1.302 + normalized_actual = NormalizeToCurrentPlatform( 1.303 + RemoveTestCounts(normalized_actual)) 1.304 + normalized_golden = NormalizeToCurrentPlatform( 1.305 + RemoveTestCounts(self.RemoveUnsupportedTests(normalized_golden))) 1.306 + 1.307 + # This code is very handy when debugging golden file differences: 1.308 + if os.getenv('DEBUG_GTEST_OUTPUT_TEST'): 1.309 + open(os.path.join( 1.310 + gtest_test_utils.GetSourceDir(), 1.311 + '_gtest_output_test_normalized_actual.txt'), 'wb').write( 1.312 + normalized_actual) 1.313 + open(os.path.join( 1.314 + gtest_test_utils.GetSourceDir(), 1.315 + '_gtest_output_test_normalized_golden.txt'), 'wb').write( 1.316 + normalized_golden) 1.317 + 1.318 + self.assertEqual(normalized_golden, normalized_actual) 1.319 + 1.320 + 1.321 +if __name__ == '__main__': 1.322 + if sys.argv[1:] == [GENGOLDEN_FLAG]: 1.323 + if CAN_GENERATE_GOLDEN_FILE: 1.324 + output = GetOutputOfAllCommands() 1.325 + golden_file = open(GOLDEN_PATH, 'wb') 1.326 + golden_file.write(output) 1.327 + golden_file.close() 1.328 + else: 1.329 + message = ( 1.330 + """Unable to write a golden file when compiled in an environment 1.331 +that does not support all the required features (death tests, typed tests, 1.332 +and multiple threads). Please generate the golden file using a binary built 1.333 +with those features enabled.""") 1.334 + 1.335 + sys.stderr.write(message) 1.336 + sys.exit(1) 1.337 + else: 1.338 + gtest_test_utils.Main()