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