media/webrtc/trunk/testing/gtest/test/gtest_output_test.py

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rwxr-xr-x

Back out 97036ab72558 which inappropriately compared turds to third parties.

michael@0 1 #!/usr/bin/env python
michael@0 2 #
michael@0 3 # Copyright 2008, Google Inc.
michael@0 4 # All rights reserved.
michael@0 5 #
michael@0 6 # Redistribution and use in source and binary forms, with or without
michael@0 7 # modification, are permitted provided that the following conditions are
michael@0 8 # met:
michael@0 9 #
michael@0 10 # * Redistributions of source code must retain the above copyright
michael@0 11 # notice, this list of conditions and the following disclaimer.
michael@0 12 # * Redistributions in binary form must reproduce the above
michael@0 13 # copyright notice, this list of conditions and the following disclaimer
michael@0 14 # in the documentation and/or other materials provided with the
michael@0 15 # distribution.
michael@0 16 # * Neither the name of Google Inc. nor the names of its
michael@0 17 # contributors may be used to endorse or promote products derived from
michael@0 18 # this software without specific prior written permission.
michael@0 19 #
michael@0 20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 23 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 24 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 25 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 26 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 27 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 28 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 29 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 30 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 31
michael@0 32 """Tests the text output of Google C++ Testing Framework.
michael@0 33
michael@0 34 SYNOPSIS
michael@0 35 gtest_output_test.py --build_dir=BUILD/DIR --gengolden
michael@0 36 # where BUILD/DIR contains the built gtest_output_test_ file.
michael@0 37 gtest_output_test.py --gengolden
michael@0 38 gtest_output_test.py
michael@0 39 """
michael@0 40
michael@0 41 __author__ = 'wan@google.com (Zhanyong Wan)'
michael@0 42
michael@0 43 import os
michael@0 44 import re
michael@0 45 import sys
michael@0 46 import gtest_test_utils
michael@0 47
michael@0 48
michael@0 49 # The flag for generating the golden file
michael@0 50 GENGOLDEN_FLAG = '--gengolden'
michael@0 51 CATCH_EXCEPTIONS_ENV_VAR_NAME = 'GTEST_CATCH_EXCEPTIONS'
michael@0 52
michael@0 53 IS_WINDOWS = os.name == 'nt'
michael@0 54
michael@0 55 # TODO(vladl@google.com): remove the _lin suffix.
michael@0 56 GOLDEN_NAME = 'gtest_output_test_golden_lin.txt'
michael@0 57
michael@0 58 PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_output_test_')
michael@0 59
michael@0 60 # At least one command we exercise must not have the
michael@0 61 # --gtest_internal_skip_environment_and_ad_hoc_tests flag.
michael@0 62 COMMAND_LIST_TESTS = ({}, [PROGRAM_PATH, '--gtest_list_tests'])
michael@0 63 COMMAND_WITH_COLOR = ({}, [PROGRAM_PATH, '--gtest_color=yes'])
michael@0 64 COMMAND_WITH_TIME = ({}, [PROGRAM_PATH,
michael@0 65 '--gtest_print_time',
michael@0 66 '--gtest_internal_skip_environment_and_ad_hoc_tests',
michael@0 67 '--gtest_filter=FatalFailureTest.*:LoggingTest.*'])
michael@0 68 COMMAND_WITH_DISABLED = (
michael@0 69 {}, [PROGRAM_PATH,
michael@0 70 '--gtest_also_run_disabled_tests',
michael@0 71 '--gtest_internal_skip_environment_and_ad_hoc_tests',
michael@0 72 '--gtest_filter=*DISABLED_*'])
michael@0 73 COMMAND_WITH_SHARDING = (
michael@0 74 {'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'},
michael@0 75 [PROGRAM_PATH,
michael@0 76 '--gtest_internal_skip_environment_and_ad_hoc_tests',
michael@0 77 '--gtest_filter=PassingTest.*'])
michael@0 78
michael@0 79 GOLDEN_PATH = os.path.join(gtest_test_utils.GetSourceDir(), GOLDEN_NAME)
michael@0 80
michael@0 81
michael@0 82 def ToUnixLineEnding(s):
michael@0 83 """Changes all Windows/Mac line endings in s to UNIX line endings."""
michael@0 84
michael@0 85 return s.replace('\r\n', '\n').replace('\r', '\n')
michael@0 86
michael@0 87
michael@0 88 def RemoveLocations(test_output):
michael@0 89 """Removes all file location info from a Google Test program's output.
michael@0 90
michael@0 91 Args:
michael@0 92 test_output: the output of a Google Test program.
michael@0 93
michael@0 94 Returns:
michael@0 95 output with all file location info (in the form of
michael@0 96 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or
michael@0 97 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by
michael@0 98 'FILE_NAME:#: '.
michael@0 99 """
michael@0 100
michael@0 101 return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\: ', r'\1:#: ', test_output)
michael@0 102
michael@0 103
michael@0 104 def RemoveStackTraceDetails(output):
michael@0 105 """Removes all stack traces from a Google Test program's output."""
michael@0 106
michael@0 107 # *? means "find the shortest string that matches".
michael@0 108 return re.sub(r'Stack trace:(.|\n)*?\n\n',
michael@0 109 'Stack trace: (omitted)\n\n', output)
michael@0 110
michael@0 111
michael@0 112 def RemoveStackTraces(output):
michael@0 113 """Removes all traces of stack traces from a Google Test program's output."""
michael@0 114
michael@0 115 # *? means "find the shortest string that matches".
michael@0 116 return re.sub(r'Stack trace:(.|\n)*?\n\n', '', output)
michael@0 117
michael@0 118
michael@0 119 def RemoveTime(output):
michael@0 120 """Removes all time information from a Google Test program's output."""
michael@0 121
michael@0 122 return re.sub(r'\(\d+ ms', '(? ms', output)
michael@0 123
michael@0 124
michael@0 125 def RemoveTypeInfoDetails(test_output):
michael@0 126 """Removes compiler-specific type info from Google Test program's output.
michael@0 127
michael@0 128 Args:
michael@0 129 test_output: the output of a Google Test program.
michael@0 130
michael@0 131 Returns:
michael@0 132 output with type information normalized to canonical form.
michael@0 133 """
michael@0 134
michael@0 135 # some compilers output the name of type 'unsigned int' as 'unsigned'
michael@0 136 return re.sub(r'unsigned int', 'unsigned', test_output)
michael@0 137
michael@0 138
michael@0 139 def NormalizeToCurrentPlatform(test_output):
michael@0 140 """Normalizes platform specific output details for easier comparison."""
michael@0 141
michael@0 142 if IS_WINDOWS:
michael@0 143 # Removes the color information that is not present on Windows.
michael@0 144 test_output = re.sub('\x1b\\[(0;3\d)?m', '', test_output)
michael@0 145 # Changes failure message headers into the Windows format.
michael@0 146 test_output = re.sub(r': Failure\n', r': error: ', test_output)
michael@0 147 # Changes file(line_number) to file:line_number.
michael@0 148 test_output = re.sub(r'((\w|\.)+)\((\d+)\):', r'\1:\3:', test_output)
michael@0 149
michael@0 150 return test_output
michael@0 151
michael@0 152
michael@0 153 def RemoveTestCounts(output):
michael@0 154 """Removes test counts from a Google Test program's output."""
michael@0 155
michael@0 156 output = re.sub(r'\d+ tests?, listed below',
michael@0 157 '? tests, listed below', output)
michael@0 158 output = re.sub(r'\d+ FAILED TESTS',
michael@0 159 '? FAILED TESTS', output)
michael@0 160 output = re.sub(r'\d+ tests? from \d+ test cases?',
michael@0 161 '? tests from ? test cases', output)
michael@0 162 output = re.sub(r'\d+ tests? from ([a-zA-Z_])',
michael@0 163 r'? tests from \1', output)
michael@0 164 return re.sub(r'\d+ tests?\.', '? tests.', output)
michael@0 165
michael@0 166
michael@0 167 def RemoveMatchingTests(test_output, pattern):
michael@0 168 """Removes output of specified tests from a Google Test program's output.
michael@0 169
michael@0 170 This function strips not only the beginning and the end of a test but also
michael@0 171 all output in between.
michael@0 172
michael@0 173 Args:
michael@0 174 test_output: A string containing the test output.
michael@0 175 pattern: A regex string that matches names of test cases or
michael@0 176 tests to remove.
michael@0 177
michael@0 178 Returns:
michael@0 179 Contents of test_output with tests whose names match pattern removed.
michael@0 180 """
michael@0 181
michael@0 182 test_output = re.sub(
michael@0 183 r'.*\[ RUN \] .*%s(.|\n)*?\[( FAILED | OK )\] .*%s.*\n' % (
michael@0 184 pattern, pattern),
michael@0 185 '',
michael@0 186 test_output)
michael@0 187 return re.sub(r'.*%s.*\n' % pattern, '', test_output)
michael@0 188
michael@0 189
michael@0 190 def NormalizeOutput(output):
michael@0 191 """Normalizes output (the output of gtest_output_test_.exe)."""
michael@0 192
michael@0 193 output = ToUnixLineEnding(output)
michael@0 194 output = RemoveLocations(output)
michael@0 195 output = RemoveStackTraceDetails(output)
michael@0 196 output = RemoveTime(output)
michael@0 197 return output
michael@0 198
michael@0 199
michael@0 200 def GetShellCommandOutput(env_cmd):
michael@0 201 """Runs a command in a sub-process, and returns its output in a string.
michael@0 202
michael@0 203 Args:
michael@0 204 env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra
michael@0 205 environment variables to set, and element 1 is a string with
michael@0 206 the command and any flags.
michael@0 207
michael@0 208 Returns:
michael@0 209 A string with the command's combined standard and diagnostic output.
michael@0 210 """
michael@0 211
michael@0 212 # Spawns cmd in a sub-process, and gets its standard I/O file objects.
michael@0 213 # Set and save the environment properly.
michael@0 214 environ = os.environ.copy()
michael@0 215 environ.update(env_cmd[0])
michael@0 216 p = gtest_test_utils.Subprocess(env_cmd[1], env=environ, capture_stderr=False)
michael@0 217
michael@0 218 return p.output
michael@0 219
michael@0 220
michael@0 221 def GetCommandOutput(env_cmd):
michael@0 222 """Runs a command and returns its output with all file location
michael@0 223 info stripped off.
michael@0 224
michael@0 225 Args:
michael@0 226 env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra
michael@0 227 environment variables to set, and element 1 is a string with
michael@0 228 the command and any flags.
michael@0 229 """
michael@0 230
michael@0 231 # Disables exception pop-ups on Windows.
michael@0 232 environ, cmdline = env_cmd
michael@0 233 environ = dict(environ) # Ensures we are modifying a copy.
michael@0 234 environ[CATCH_EXCEPTIONS_ENV_VAR_NAME] = '1'
michael@0 235 return NormalizeOutput(GetShellCommandOutput((environ, cmdline)))
michael@0 236
michael@0 237
michael@0 238 def GetOutputOfAllCommands():
michael@0 239 """Returns concatenated output from several representative commands."""
michael@0 240
michael@0 241 return (GetCommandOutput(COMMAND_WITH_COLOR) +
michael@0 242 GetCommandOutput(COMMAND_WITH_TIME) +
michael@0 243 GetCommandOutput(COMMAND_WITH_DISABLED) +
michael@0 244 GetCommandOutput(COMMAND_WITH_SHARDING))
michael@0 245
michael@0 246
michael@0 247 test_list = GetShellCommandOutput(COMMAND_LIST_TESTS)
michael@0 248 SUPPORTS_DEATH_TESTS = 'DeathTest' in test_list
michael@0 249 SUPPORTS_TYPED_TESTS = 'TypedTest' in test_list
michael@0 250 SUPPORTS_THREADS = 'ExpectFailureWithThreadsTest' in test_list
michael@0 251 SUPPORTS_STACK_TRACES = False
michael@0 252
michael@0 253 CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and
michael@0 254 SUPPORTS_TYPED_TESTS and
michael@0 255 SUPPORTS_THREADS)
michael@0 256
michael@0 257
michael@0 258 class GTestOutputTest(gtest_test_utils.TestCase):
michael@0 259 def RemoveUnsupportedTests(self, test_output):
michael@0 260 if not SUPPORTS_DEATH_TESTS:
michael@0 261 test_output = RemoveMatchingTests(test_output, 'DeathTest')
michael@0 262 if not SUPPORTS_TYPED_TESTS:
michael@0 263 test_output = RemoveMatchingTests(test_output, 'TypedTest')
michael@0 264 test_output = RemoveMatchingTests(test_output, 'TypedDeathTest')
michael@0 265 test_output = RemoveMatchingTests(test_output, 'TypeParamDeathTest')
michael@0 266 if not SUPPORTS_THREADS:
michael@0 267 test_output = RemoveMatchingTests(test_output,
michael@0 268 'ExpectFailureWithThreadsTest')
michael@0 269 test_output = RemoveMatchingTests(test_output,
michael@0 270 'ScopedFakeTestPartResultReporterTest')
michael@0 271 test_output = RemoveMatchingTests(test_output,
michael@0 272 'WorksConcurrently')
michael@0 273 if not SUPPORTS_STACK_TRACES:
michael@0 274 test_output = RemoveStackTraces(test_output)
michael@0 275
michael@0 276 return test_output
michael@0 277
michael@0 278 def testOutput(self):
michael@0 279 output = GetOutputOfAllCommands()
michael@0 280
michael@0 281 golden_file = open(GOLDEN_PATH, 'rb')
michael@0 282 # A mis-configured source control system can cause \r appear in EOL
michael@0 283 # sequences when we read the golden file irrespective of an operating
michael@0 284 # system used. Therefore, we need to strip those \r's from newlines
michael@0 285 # unconditionally.
michael@0 286 golden = ToUnixLineEnding(golden_file.read())
michael@0 287 golden_file.close()
michael@0 288
michael@0 289 # We want the test to pass regardless of certain features being
michael@0 290 # supported or not.
michael@0 291
michael@0 292 # We still have to remove type name specifics in all cases.
michael@0 293 normalized_actual = RemoveTypeInfoDetails(output)
michael@0 294 normalized_golden = RemoveTypeInfoDetails(golden)
michael@0 295
michael@0 296 if CAN_GENERATE_GOLDEN_FILE:
michael@0 297 self.assertEqual(normalized_golden, normalized_actual)
michael@0 298 else:
michael@0 299 normalized_actual = NormalizeToCurrentPlatform(
michael@0 300 RemoveTestCounts(normalized_actual))
michael@0 301 normalized_golden = NormalizeToCurrentPlatform(
michael@0 302 RemoveTestCounts(self.RemoveUnsupportedTests(normalized_golden)))
michael@0 303
michael@0 304 # This code is very handy when debugging golden file differences:
michael@0 305 if os.getenv('DEBUG_GTEST_OUTPUT_TEST'):
michael@0 306 open(os.path.join(
michael@0 307 gtest_test_utils.GetSourceDir(),
michael@0 308 '_gtest_output_test_normalized_actual.txt'), 'wb').write(
michael@0 309 normalized_actual)
michael@0 310 open(os.path.join(
michael@0 311 gtest_test_utils.GetSourceDir(),
michael@0 312 '_gtest_output_test_normalized_golden.txt'), 'wb').write(
michael@0 313 normalized_golden)
michael@0 314
michael@0 315 self.assertEqual(normalized_golden, normalized_actual)
michael@0 316
michael@0 317
michael@0 318 if __name__ == '__main__':
michael@0 319 if sys.argv[1:] == [GENGOLDEN_FLAG]:
michael@0 320 if CAN_GENERATE_GOLDEN_FILE:
michael@0 321 output = GetOutputOfAllCommands()
michael@0 322 golden_file = open(GOLDEN_PATH, 'wb')
michael@0 323 golden_file.write(output)
michael@0 324 golden_file.close()
michael@0 325 else:
michael@0 326 message = (
michael@0 327 """Unable to write a golden file when compiled in an environment
michael@0 328 that does not support all the required features (death tests, typed tests,
michael@0 329 and multiple threads). Please generate the golden file using a binary built
michael@0 330 with those features enabled.""")
michael@0 331
michael@0 332 sys.stderr.write(message)
michael@0 333 sys.exit(1)
michael@0 334 else:
michael@0 335 gtest_test_utils.Main()

mercurial