OLD | NEW |
(Empty) | |
| 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++ Mocking Framework. |
| 33 |
| 34 SYNOPSIS |
| 35 gmock_output_test.py --gmock_build_dir=BUILD/DIR --gengolden |
| 36 # where BUILD/DIR contains the built gmock_output_test_ file. |
| 37 gmock_output_test.py --gengolden |
| 38 gmock_output_test.py |
| 39 """ |
| 40 |
| 41 __author__ = 'wan@google.com (Zhanyong Wan)' |
| 42 |
| 43 import gmock_test_utils |
| 44 import os |
| 45 import re |
| 46 import string |
| 47 import sys |
| 48 import unittest |
| 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.dbg\gmock_output_test_.exe' |
| 58 else: |
| 59 PROGRAM = 'gmock_output_test_' |
| 60 |
| 61 PROGRAM_PATH = os.path.join(gmock_test_utils.GetBuildDir(), PROGRAM) |
| 62 COMMAND = PROGRAM_PATH + ' --gtest_stack_trace_depth=0 --gtest_print_time=0' |
| 63 GOLDEN_NAME = 'gmock_output_test_golden.txt' |
| 64 GOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(), |
| 65 GOLDEN_NAME) |
| 66 |
| 67 |
| 68 def ToUnixLineEnding(s): |
| 69 """Changes all Windows/Mac line endings in s to UNIX line endings.""" |
| 70 |
| 71 return s.replace('\r\n', '\n').replace('\r', '\n') |
| 72 |
| 73 |
| 74 def RemoveReportHeaderAndFooter(output): |
| 75 """Removes Google Test result report's header and footer from the output.""" |
| 76 |
| 77 output = re.sub(r'.*gtest_main.*\n', '', output) |
| 78 output = re.sub(r'\[.*\d+ tests.*\n', '', output) |
| 79 output = re.sub(r'\[.* test environment .*\n', '', output) |
| 80 output = re.sub(r'\[=+\] \d+ tests .* ran.*', '', output) |
| 81 output = re.sub(r'.* FAILED TESTS\n', '', output) |
| 82 return output |
| 83 |
| 84 |
| 85 def RemoveLocations(output): |
| 86 """Removes all file location info from a Google Test program's output. |
| 87 |
| 88 Args: |
| 89 output: the output of a Google Test program. |
| 90 |
| 91 Returns: |
| 92 output with all file location info (in the form of |
| 93 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or |
| 94 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by |
| 95 'FILE:#: '. |
| 96 """ |
| 97 |
| 98 return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\:', 'FILE:#:', output) |
| 99 |
| 100 |
| 101 def NormalizeErrorMarker(output): |
| 102 """Normalizes the error marker, which is different on Windows vs on Linux.""" |
| 103 |
| 104 return re.sub(r' error: ', ' Failure\n', output) |
| 105 |
| 106 |
| 107 def RemoveMemoryAddresses(output): |
| 108 """Removes memory addresses from the test output.""" |
| 109 |
| 110 return re.sub(r'@\w+', '@0x#', output) |
| 111 |
| 112 |
| 113 def RemoveTestNamesOfLeakedMocks(output): |
| 114 """Removes the test names of leaked mock objects from the test output.""" |
| 115 |
| 116 return re.sub(r'\(used in test .+\) ', '', output) |
| 117 |
| 118 |
| 119 def GetLeakyTests(output): |
| 120 """Returns a list of test names that leak mock objects.""" |
| 121 |
| 122 # findall() returns a list of all matches of the regex in output. |
| 123 # For example, if '(used in test FooTest.Bar)' is in output, the |
| 124 # list will contain 'FooTest.Bar'. |
| 125 return re.findall(r'\(used in test (.+)\)', output) |
| 126 |
| 127 |
| 128 def GetNormalizedOutputAndLeakyTests(output): |
| 129 """Normalizes the output of gmock_output_test_. |
| 130 |
| 131 Args: |
| 132 output: The test output. |
| 133 |
| 134 Returns: |
| 135 A tuple (the normalized test output, the list of test names that have |
| 136 leaked mocks). |
| 137 """ |
| 138 |
| 139 output = ToUnixLineEnding(output) |
| 140 output = RemoveReportHeaderAndFooter(output) |
| 141 output = NormalizeErrorMarker(output) |
| 142 output = RemoveLocations(output) |
| 143 output = RemoveMemoryAddresses(output) |
| 144 return (RemoveTestNamesOfLeakedMocks(output), GetLeakyTests(output)) |
| 145 |
| 146 |
| 147 def IterShellCommandOutput(cmd, stdin_string=None): |
| 148 """Runs a command in a sub-process, and iterates the lines in its STDOUT. |
| 149 |
| 150 Args: |
| 151 |
| 152 cmd: The shell command. |
| 153 stdin_string: The string to be fed to the STDIN of the sub-process; |
| 154 If None, the sub-process will inherit the STDIN |
| 155 from the parent process. |
| 156 """ |
| 157 |
| 158 # Spawns cmd in a sub-process, and gets its standard I/O file objects. |
| 159 stdin_file, stdout_file = os.popen2(cmd, 'b') |
| 160 |
| 161 # If the caller didn't specify a string for STDIN, gets it from the |
| 162 # parent process. |
| 163 if stdin_string is None: |
| 164 stdin_string = sys.stdin.read() |
| 165 |
| 166 # Feeds the STDIN string to the sub-process. |
| 167 stdin_file.write(stdin_string) |
| 168 stdin_file.close() |
| 169 |
| 170 while True: |
| 171 line = stdout_file.readline() |
| 172 if not line: # EOF |
| 173 stdout_file.close() |
| 174 break |
| 175 |
| 176 yield line |
| 177 |
| 178 |
| 179 def GetShellCommandOutput(cmd, stdin_string=None): |
| 180 """Runs a command in a sub-process, and returns its STDOUT in a string. |
| 181 |
| 182 Args: |
| 183 |
| 184 cmd: The shell command. |
| 185 stdin_string: The string to be fed to the STDIN of the sub-process; |
| 186 If None, the sub-process will inherit the STDIN |
| 187 from the parent process. |
| 188 """ |
| 189 |
| 190 lines = list(IterShellCommandOutput(cmd, stdin_string)) |
| 191 return string.join(lines, '') |
| 192 |
| 193 |
| 194 def GetNormalizedCommandOutputAndLeakyTests(cmd): |
| 195 """Runs a command and returns its normalized output and a list of leaky tests. |
| 196 |
| 197 Args: |
| 198 cmd: the shell command. |
| 199 """ |
| 200 |
| 201 # Disables exception pop-ups on Windows. |
| 202 os.environ['GTEST_CATCH_EXCEPTIONS'] = '1' |
| 203 return GetNormalizedOutputAndLeakyTests(GetShellCommandOutput(cmd, '')) |
| 204 |
| 205 |
| 206 class GMockOutputTest(unittest.TestCase): |
| 207 def testOutput(self): |
| 208 (output, leaky_tests) = GetNormalizedCommandOutputAndLeakyTests(COMMAND) |
| 209 golden_file = open(GOLDEN_PATH, 'rb') |
| 210 golden = golden_file.read() |
| 211 golden_file.close() |
| 212 |
| 213 # The normalized output should match the golden file. |
| 214 self.assertEquals(golden, output) |
| 215 |
| 216 # The raw output should contain 2 leaked mock object errors for |
| 217 # test GMockOutputTest.CatchesLeakedMocks. |
| 218 self.assertEquals(['GMockOutputTest.CatchesLeakedMocks', |
| 219 'GMockOutputTest.CatchesLeakedMocks'], |
| 220 leaky_tests) |
| 221 |
| 222 |
| 223 if __name__ == '__main__': |
| 224 if sys.argv[1:] == [GENGOLDEN_FLAG]: |
| 225 (output, _) = GetNormalizedCommandOutputAndLeakyTests(COMMAND) |
| 226 golden_file = open(GOLDEN_PATH, 'wb') |
| 227 golden_file.write(output) |
| 228 golden_file.close() |
| 229 else: |
| 230 gmock_test_utils.Main() |
OLD | NEW |