Home | History | Annotate | Download | only in test
      1 #!/usr/bin/env python
      2 #
      3 # Copyright 2008, Google Inc.
      4 # All rights reserved.
      5 #
      6 # Redistribution and use in source and binary forms, with or without
      7 # modification, are permitted provided that the following conditions are
      8 # met:
      9 #
     10 #     * Redistributions of source code must retain the above copyright
     11 # notice, this list of conditions and the following disclaimer.
     12 #     * Redistributions in binary form must reproduce the above
     13 # copyright notice, this list of conditions and the following disclaimer
     14 # in the documentation and/or other materials provided with the
     15 # distribution.
     16 #     * Neither the name of Google Inc. nor the names of its
     17 # contributors may be used to endorse or promote products derived from
     18 # this software without specific prior written permission.
     19 #
     20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 
     32 """Tests the text output of Google C++ Testing Framework.
     33 
     34 SYNOPSIS
     35        gtest_output_test.py --gtest_build_dir=BUILD/DIR --gengolden
     36          # where BUILD/DIR contains the built gtest_output_test_ file.
     37        gtest_output_test.py --gengolden
     38        gtest_output_test.py
     39 """
     40 
     41 __author__ = 'wan (at] google.com (Zhanyong Wan)'
     42 
     43 import os
     44 import re
     45 import string
     46 import sys
     47 import unittest
     48 import gtest_test_utils
     49 
     50 
     51 # The flag for generating the golden file
     52 GENGOLDEN_FLAG = '--gengolden'
     53 
     54 IS_WINDOWS = os.name == 'nt'
     55 
     56 if IS_WINDOWS:
     57   PROGRAM = r'..\build.dbg8\gtest_output_test_.exe'
     58   GOLDEN_NAME = 'gtest_output_test_golden_win.txt'
     59 else:
     60   PROGRAM = 'gtest_output_test_'
     61   GOLDEN_NAME = 'gtest_output_test_golden_lin.txt'
     62 
     63 PROGRAM_PATH = os.path.join(gtest_test_utils.GetBuildDir(), PROGRAM)
     64 
     65 # At least one command we exercise must not have the
     66 # --gtest_internal_skip_environment_and_ad_hoc_tests flag.
     67 COMMAND_WITH_COLOR = ({}, PROGRAM_PATH + ' --gtest_color=yes')
     68 COMMAND_WITH_TIME = ({}, PROGRAM_PATH + ' --gtest_print_time '
     69                      '--gtest_internal_skip_environment_and_ad_hoc_tests '
     70                      '--gtest_filter="FatalFailureTest.*:LoggingTest.*"')
     71 COMMAND_WITH_DISABLED = ({}, PROGRAM_PATH + ' --gtest_also_run_disabled_tests '
     72                          '--gtest_internal_skip_environment_and_ad_hoc_tests '
     73                          '--gtest_filter="*DISABLED_*"')
     74 COMMAND_WITH_SHARDING = ({'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'},
     75                          PROGRAM_PATH +
     76                          ' --gtest_internal_skip_environment_and_ad_hoc_tests '
     77                          ' --gtest_filter="PassingTest.*"')
     78 
     79 GOLDEN_PATH = os.path.join(gtest_test_utils.GetSourceDir(),
     80                            GOLDEN_NAME)
     81 
     82 
     83 def ToUnixLineEnding(s):
     84   """Changes all Windows/Mac line endings in s to UNIX line endings."""
     85 
     86   return s.replace('\r\n', '\n').replace('\r', '\n')
     87 
     88 
     89 def RemoveLocations(output):
     90   """Removes all file location info from a Google Test program's output.
     91 
     92   Args:
     93        output:  the output of a Google Test program.
     94 
     95   Returns:
     96        output with all file location info (in the form of
     97        'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or
     98        'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by
     99        'FILE_NAME:#: '.
    100   """
    101 
    102   return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\: ', r'\1:#: ', output)
    103 
    104 
    105 def RemoveStackTraces(output):
    106   """Removes all stack traces from a Google Test program's output."""
    107 
    108   # *? means "find the shortest string that matches".
    109   return re.sub(r'Stack trace:(.|\n)*?\n\n',
    110                 'Stack trace: (omitted)\n\n', output)
    111 
    112 
    113 def RemoveTime(output):
    114   """Removes all time information from a Google Test program's output."""
    115 
    116   return re.sub(r'\(\d+ ms', '(? ms', output)
    117 
    118 
    119 def RemoveTestCounts(output):
    120   """Removes test counts from a Google Test program's output."""
    121 
    122   output = re.sub(r'\d+ tests from \d+ test cases',
    123                   '? tests from ? test cases', output)
    124   return re.sub(r'\d+ tests\.', '? tests.', output)
    125 
    126 
    127 def RemoveDeathTests(output):
    128   """Removes death test information from a Google Test program's output."""
    129 
    130   return re.sub(r'\n.*DeathTest.*', '', output)
    131 
    132 
    133 def NormalizeOutput(output):
    134   """Normalizes output (the output of gtest_output_test_.exe)."""
    135 
    136   output = ToUnixLineEnding(output)
    137   output = RemoveLocations(output)
    138   output = RemoveStackTraces(output)
    139   output = RemoveTime(output)
    140   return output
    141 
    142 
    143 def IterShellCommandOutput(env_cmd, stdin_string=None):
    144   """Runs a command in a sub-process, and iterates the lines in its STDOUT.
    145 
    146   Args:
    147 
    148     env_cmd:           The shell command. A 2-tuple where element 0 is a dict
    149                        of extra environment variables to set, and element 1
    150                        is a string with the command and any flags.
    151     stdin_string:      The string to be fed to the STDIN of the sub-process;
    152                        If None, the sub-process will inherit the STDIN
    153                        from the parent process.
    154   """
    155 
    156   # Spawns cmd in a sub-process, and gets its standard I/O file objects.
    157   # Set and save the environment properly.
    158   old_env_vars = dict(os.environ)
    159   os.environ.update(env_cmd[0])
    160   stdin_file, stdout_file = os.popen2(env_cmd[1], 'b')
    161   os.environ.clear()
    162   os.environ.update(old_env_vars)
    163 
    164   # If the caller didn't specify a string for STDIN, gets it from the
    165   # parent process.
    166   if stdin_string is None:
    167     stdin_string = sys.stdin.read()
    168 
    169   # Feeds the STDIN string to the sub-process.
    170   stdin_file.write(stdin_string)
    171   stdin_file.close()
    172 
    173   while True:
    174     line = stdout_file.readline()
    175     if not line:  # EOF
    176       stdout_file.close()
    177       break
    178 
    179     yield line
    180 
    181 
    182 def GetShellCommandOutput(env_cmd, stdin_string=None):
    183   """Runs a command in a sub-process, and returns its STDOUT in a string.
    184 
    185   Args:
    186 
    187     env_cmd:           The shell command. A 2-tuple where element 0 is a dict
    188                        of extra environment variables to set, and element 1
    189                        is a string with the command and any flags.
    190     stdin_string:      The string to be fed to the STDIN of the sub-process;
    191                        If None, the sub-process will inherit the STDIN
    192                        from the parent process.
    193   """
    194 
    195   lines = list(IterShellCommandOutput(env_cmd, stdin_string))
    196   return string.join(lines, '')
    197 
    198 
    199 def GetCommandOutput(env_cmd):
    200   """Runs a command and returns its output with all file location
    201   info stripped off.
    202 
    203   Args:
    204     env_cmd:  The shell command. A 2-tuple where element 0 is a dict of extra
    205               environment variables to set, and element 1 is a string with
    206               the command and any flags.
    207   """
    208 
    209   # Disables exception pop-ups on Windows.
    210   os.environ['GTEST_CATCH_EXCEPTIONS'] = '1'
    211   return NormalizeOutput(GetShellCommandOutput(env_cmd, ''))
    212 
    213 
    214 def GetOutputOfAllCommands():
    215   """Returns concatenated output from several representative commands."""
    216 
    217   return (GetCommandOutput(COMMAND_WITH_COLOR) +
    218           GetCommandOutput(COMMAND_WITH_TIME) +
    219           GetCommandOutput(COMMAND_WITH_DISABLED) +
    220           GetCommandOutput(COMMAND_WITH_SHARDING))
    221 
    222 
    223 class GTestOutputTest(unittest.TestCase):
    224   def testOutput(self):
    225     output = GetOutputOfAllCommands()
    226     golden_file = open(GOLDEN_PATH, 'rb')
    227     golden = golden_file.read()
    228     golden_file.close()
    229 
    230     # We want the test to pass regardless of death tests being
    231     # supported or not.
    232     self.assert_(output == golden or
    233                  RemoveTestCounts(output) ==
    234                  RemoveTestCounts(RemoveDeathTests(golden)))
    235 
    236 
    237 if __name__ == '__main__':
    238   if sys.argv[1:] == [GENGOLDEN_FLAG]:
    239     output = GetOutputOfAllCommands()
    240     golden_file = open(GOLDEN_PATH, 'wb')
    241     golden_file.write(output)
    242     golden_file.close()
    243   else:
    244     gtest_test_utils.Main()
    245