3
# Copyright 2008, Google Inc.
6
# Redistribution and use in source and binary forms, with or without
7
# modification, are permitted provided that the following conditions are
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
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.
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.
32
"""Tests the text output of Google C++ Testing Framework.
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
41
__author__ = 'wan@google.com (Zhanyong Wan)'
48
import gtest_test_utils
51
# The flag for generating the golden file
52
GENGOLDEN_FLAG = '--gengolden'
54
IS_WINDOWS = os.name == 'nt'
57
GOLDEN_NAME = 'gtest_output_test_golden_win.txt'
59
GOLDEN_NAME = 'gtest_output_test_golden_lin.txt'
61
PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_output_test_')
63
# At least one command we exercise must not have the
64
# --gtest_internal_skip_environment_and_ad_hoc_tests flag.
65
COMMAND_LIST_TESTS = ({}, PROGRAM_PATH + ' --gtest_list_tests')
66
COMMAND_WITH_COLOR = ({}, PROGRAM_PATH + ' --gtest_color=yes')
67
COMMAND_WITH_TIME = ({}, PROGRAM_PATH + ' --gtest_print_time '
68
'--gtest_internal_skip_environment_and_ad_hoc_tests '
69
'--gtest_filter="FatalFailureTest.*:LoggingTest.*"')
70
COMMAND_WITH_DISABLED = ({}, PROGRAM_PATH + ' --gtest_also_run_disabled_tests '
71
'--gtest_internal_skip_environment_and_ad_hoc_tests '
72
'--gtest_filter="*DISABLED_*"')
73
COMMAND_WITH_SHARDING = ({'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'},
75
' --gtest_internal_skip_environment_and_ad_hoc_tests '
76
' --gtest_filter="PassingTest.*"')
78
GOLDEN_PATH = os.path.join(gtest_test_utils.GetSourceDir(), GOLDEN_NAME)
81
def ToUnixLineEnding(s):
82
"""Changes all Windows/Mac line endings in s to UNIX line endings."""
84
return s.replace('\r\n', '\n').replace('\r', '\n')
87
def RemoveLocations(output):
88
"""Removes all file location info from a Google Test program's output.
91
output: the output of a Google Test program.
94
output with all file location info (in the form of
95
'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or
96
'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by
100
return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\: ', r'\1:#: ', output)
103
def RemoveStackTraces(output):
104
"""Removes all stack traces from a Google Test program's output."""
106
# *? means "find the shortest string that matches".
107
return re.sub(r'Stack trace:(.|\n)*?\n\n',
108
'Stack trace: (omitted)\n\n', output)
111
def RemoveTime(output):
112
"""Removes all time information from a Google Test program's output."""
114
return re.sub(r'\(\d+ ms', '(? ms', output)
117
def RemoveTestCounts(output):
118
"""Removes test counts from a Google Test program's output."""
120
output = re.sub(r'\d+ tests, listed below',
121
'? tests, listed below', output)
122
output = re.sub(r'\d+ FAILED TESTS',
123
'? FAILED TESTS', output)
124
output = re.sub(r'\d+ tests from \d+ test cases',
125
'? tests from ? test cases', output)
126
return re.sub(r'\d+ tests\.', '? tests.', output)
129
def RemoveMatchingTests(test_output, pattern):
130
"""Removes typed test information from a Google Test program's output.
132
This function strips not only the beginning and the end of a test but also all
136
test_output: A string containing the test output.
137
pattern: A string that matches names of test cases to remove.
140
Contents of test_output with removed test case whose names match pattern.
143
test_output = re.sub(
144
r'\[ RUN \] .*%s(.|\n)*?\[( FAILED | OK )\] .*%s.*\n' % (
148
return re.sub(r'.*%s.*\n' % pattern, '', test_output)
151
def NormalizeOutput(output):
152
"""Normalizes output (the output of gtest_output_test_.exe)."""
154
output = ToUnixLineEnding(output)
155
output = RemoveLocations(output)
156
output = RemoveStackTraces(output)
157
output = RemoveTime(output)
161
def IterShellCommandOutput(env_cmd, stdin_string=None):
162
"""Runs a command in a sub-process, and iterates the lines in its STDOUT.
166
env_cmd: The shell command. A 2-tuple where element 0 is a dict
167
of extra environment variables to set, and element 1
168
is a string with the command and any flags.
169
stdin_string: The string to be fed to the STDIN of the sub-process;
170
If None, the sub-process will inherit the STDIN
171
from the parent process.
174
# Spawns cmd in a sub-process, and gets its standard I/O file objects.
175
# Set and save the environment properly.
176
old_env_vars = dict(os.environ)
177
os.environ.update(env_cmd[0])
178
stdin_file, stdout_file = os.popen2(env_cmd[1], 'b')
180
os.environ.update(old_env_vars)
182
# If the caller didn't specify a string for STDIN, gets it from the
184
if stdin_string is None:
185
stdin_string = sys.stdin.read()
187
# Feeds the STDIN string to the sub-process.
188
stdin_file.write(stdin_string)
192
line = stdout_file.readline()
200
def GetShellCommandOutput(env_cmd, stdin_string=None):
201
"""Runs a command in a sub-process, and returns its STDOUT in a string.
205
env_cmd: The shell command. A 2-tuple where element 0 is a dict
206
of extra environment variables to set, and element 1
207
is a string with the command and any flags.
208
stdin_string: The string to be fed to the STDIN of the sub-process;
209
If None, the sub-process will inherit the STDIN
210
from the parent process.
213
lines = list(IterShellCommandOutput(env_cmd, stdin_string))
214
return string.join(lines, '')
217
def GetCommandOutput(env_cmd):
218
"""Runs a command and returns its output with all file location
222
env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra
223
environment variables to set, and element 1 is a string with
224
the command and any flags.
227
# Disables exception pop-ups on Windows.
228
os.environ['GTEST_CATCH_EXCEPTIONS'] = '1'
229
return NormalizeOutput(GetShellCommandOutput(env_cmd, ''))
232
def GetOutputOfAllCommands():
233
"""Returns concatenated output from several representative commands."""
235
return (GetCommandOutput(COMMAND_WITH_COLOR) +
236
GetCommandOutput(COMMAND_WITH_TIME) +
237
GetCommandOutput(COMMAND_WITH_DISABLED) +
238
GetCommandOutput(COMMAND_WITH_SHARDING))
241
test_list = GetShellCommandOutput(COMMAND_LIST_TESTS, '')
242
SUPPORTS_DEATH_TESTS = 'DeathTest' in test_list
243
SUPPORTS_TYPED_TESTS = 'TypedTest' in test_list
246
class GTestOutputTest(unittest.TestCase):
247
def RemoveUnsupportedTests(self, test_output):
248
if not SUPPORTS_DEATH_TESTS:
249
test_output = RemoveMatchingTests(test_output, 'DeathTest')
250
if not SUPPORTS_TYPED_TESTS:
251
test_output = RemoveMatchingTests(test_output, 'TypedTest')
254
def testOutput(self):
255
output = GetOutputOfAllCommands()
256
golden_file = open(GOLDEN_PATH, 'rb')
257
golden = golden_file.read()
260
# We want the test to pass regardless of death tests being
262
if SUPPORTS_DEATH_TESTS and SUPPORTS_TYPED_TESTS:
263
self.assert_(golden == output)
265
self.assert_(RemoveTestCounts(self.RemoveUnsupportedTests(golden)) ==
266
RemoveTestCounts(output))
269
if __name__ == '__main__':
270
if sys.argv[1:] == [GENGOLDEN_FLAG]:
271
if SUPPORTS_DEATH_TESTS and SUPPORTS_TYPED_TESTS:
272
output = GetOutputOfAllCommands()
273
golden_file = open(GOLDEN_PATH, 'wb')
274
golden_file.write(output)
277
print >> sys.stderr, ('Unable to write a golden file when compiled in an '
278
'environment that does not support death tests and '
279
'typed tests. Are you using VC 7.1?')
282
gtest_test_utils.Main()