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

changeset 0
6474c204b198
     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()

mercurial