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 32r"""Tests the text output of Google C++ Mocking Framework. 33 34To update the golden file: 35gmock_output_test.py --build_dir=BUILD/DIR --gengolden 36where BUILD/DIR contains the built gmock_output_test_ file. 37gmock_output_test.py --gengolden 38gmock_output_test.py 39 40""" 41 42import os 43import re 44import sys 45import gmock_test_utils 46 47 48# The flag for generating the golden file 49GENGOLDEN_FLAG = '--gengolden' 50 51PROGRAM_PATH = gmock_test_utils.GetTestExecutablePath('gmock_output_test_') 52COMMAND = [PROGRAM_PATH, '--gtest_stack_trace_depth=0', '--gtest_print_time=0'] 53GOLDEN_NAME = 'gmock_output_test_golden.txt' 54GOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(), GOLDEN_NAME) 55 56 57def ToUnixLineEnding(s): 58 """Changes all Windows/Mac line endings in s to UNIX line endings.""" 59 60 return s.replace('\r\n', '\n').replace('\r', '\n') 61 62 63def RemoveReportHeaderAndFooter(output): 64 """Removes Google Test result report's header and footer from the output.""" 65 66 output = re.sub(r'.*gtest_main.*\n', '', output) 67 output = re.sub(r'\[.*\d+ tests.*\n', '', output) 68 output = re.sub(r'\[.* test environment .*\n', '', output) 69 output = re.sub(r'\[=+\] \d+ tests .* ran.*', '', output) 70 output = re.sub(r'.* FAILED TESTS\n', '', output) 71 return output 72 73 74def RemoveLocations(output): 75 """Removes all file location info from a Google Test program's output. 76 77 Args: 78 output: the output of a Google Test program. 79 80 Returns: 81 output with all file location info (in the form of 82 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or 83 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by 84 'FILE:#: '. 85 """ 86 87 return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\:', 'FILE:#:', output) 88 89 90def NormalizeErrorMarker(output): 91 """Normalizes the error marker, which is different on Windows vs on Linux.""" 92 93 return re.sub(r' error: ', ' Failure\n', output) 94 95 96def RemoveMemoryAddresses(output): 97 """Removes memory addresses from the test output.""" 98 99 return re.sub(r'@\w+', '@0x#', output) 100 101 102def RemoveTestNamesOfLeakedMocks(output): 103 """Removes the test names of leaked mock objects from the test output.""" 104 105 return re.sub(r'\(used in test .+\) ', '', output) 106 107 108def GetLeakyTests(output): 109 """Returns a list of test names that leak mock objects.""" 110 111 # findall() returns a list of all matches of the regex in output. 112 # For example, if '(used in test FooTest.Bar)' is in output, the 113 # list will contain 'FooTest.Bar'. 114 return re.findall(r'\(used in test (.+)\)', output) 115 116 117def GetNormalizedOutputAndLeakyTests(output): 118 """Normalizes the output of gmock_output_test_. 119 120 Args: 121 output: The test output. 122 123 Returns: 124 A tuple (the normalized test output, the list of test names that have 125 leaked mocks). 126 """ 127 128 output = ToUnixLineEnding(output) 129 output = RemoveReportHeaderAndFooter(output) 130 output = NormalizeErrorMarker(output) 131 output = RemoveLocations(output) 132 output = RemoveMemoryAddresses(output) 133 return (RemoveTestNamesOfLeakedMocks(output), GetLeakyTests(output)) 134 135 136def GetShellCommandOutput(cmd): 137 """Runs a command in a sub-process, and returns its STDOUT in a string.""" 138 139 return gmock_test_utils.Subprocess(cmd, capture_stderr=False).output 140 141 142def GetNormalizedCommandOutputAndLeakyTests(cmd): 143 """Runs a command and returns its normalized output and a list of leaky tests. 144 145 Args: 146 cmd: the shell command. 147 """ 148 149 # Disables exception pop-ups on Windows. 150 os.environ['GTEST_CATCH_EXCEPTIONS'] = '1' 151 return GetNormalizedOutputAndLeakyTests(GetShellCommandOutput(cmd)) 152 153 154class GMockOutputTest(gmock_test_utils.TestCase): 155 def testOutput(self): 156 (output, leaky_tests) = GetNormalizedCommandOutputAndLeakyTests(COMMAND) 157 golden_file = open(GOLDEN_PATH, 'rb') 158 golden = golden_file.read() 159 golden_file.close() 160 161 # The normalized output should match the golden file. 162 self.assertEquals(golden, output) 163 164 # The raw output should contain 2 leaked mock object errors for 165 # test GMockOutputTest.CatchesLeakedMocks. 166 self.assertEquals(['GMockOutputTest.CatchesLeakedMocks', 167 'GMockOutputTest.CatchesLeakedMocks'], 168 leaky_tests) 169 170 171if __name__ == '__main__': 172 if sys.argv[1:] == [GENGOLDEN_FLAG]: 173 (output, _) = GetNormalizedCommandOutputAndLeakyTests(COMMAND) 174 golden_file = open(GOLDEN_PATH, 'wb') 175 golden_file.write(output) 176 golden_file.close() 177 # Suppress the error "googletest was imported but a call to its main() 178 # was never detected." 179 os._exit(0) 180 else: 181 gmock_test_utils.Main() 182