1b89a7cc2SEnji Cooper#!/usr/bin/env python 2b89a7cc2SEnji Cooper# 3b89a7cc2SEnji Cooper# Copyright 2008, Google Inc. 4b89a7cc2SEnji Cooper# All rights reserved. 5b89a7cc2SEnji Cooper# 6b89a7cc2SEnji Cooper# Redistribution and use in source and binary forms, with or without 7b89a7cc2SEnji Cooper# modification, are permitted provided that the following conditions are 8b89a7cc2SEnji Cooper# met: 9b89a7cc2SEnji Cooper# 10b89a7cc2SEnji Cooper# * Redistributions of source code must retain the above copyright 11b89a7cc2SEnji Cooper# notice, this list of conditions and the following disclaimer. 12b89a7cc2SEnji Cooper# * Redistributions in binary form must reproduce the above 13b89a7cc2SEnji Cooper# copyright notice, this list of conditions and the following disclaimer 14b89a7cc2SEnji Cooper# in the documentation and/or other materials provided with the 15b89a7cc2SEnji Cooper# distribution. 16b89a7cc2SEnji Cooper# * Neither the name of Google Inc. nor the names of its 17b89a7cc2SEnji Cooper# contributors may be used to endorse or promote products derived from 18b89a7cc2SEnji Cooper# this software without specific prior written permission. 19b89a7cc2SEnji Cooper# 20b89a7cc2SEnji Cooper# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21b89a7cc2SEnji Cooper# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22b89a7cc2SEnji Cooper# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23b89a7cc2SEnji Cooper# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24b89a7cc2SEnji Cooper# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25b89a7cc2SEnji Cooper# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26b89a7cc2SEnji Cooper# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27b89a7cc2SEnji Cooper# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28b89a7cc2SEnji Cooper# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29b89a7cc2SEnji Cooper# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30b89a7cc2SEnji Cooper# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31b89a7cc2SEnji Cooper 32b89a7cc2SEnji Cooperr"""Tests the text output of Google C++ Mocking Framework. 33b89a7cc2SEnji Cooper 34b89a7cc2SEnji CooperTo update the golden file: 35b89a7cc2SEnji Coopergmock_output_test.py --build_dir=BUILD/DIR --gengolden 36b89a7cc2SEnji Cooperwhere BUILD/DIR contains the built gmock_output_test_ file. 37b89a7cc2SEnji Coopergmock_output_test.py --gengolden 38b89a7cc2SEnji Coopergmock_output_test.py 39b89a7cc2SEnji Cooper 40b89a7cc2SEnji Cooper""" 41b89a7cc2SEnji Cooper 42*28f6c2f2SEnji Cooperfrom io import open # pylint: disable=redefined-builtin, g-importing-member 43b89a7cc2SEnji Cooperimport os 44b89a7cc2SEnji Cooperimport re 45b89a7cc2SEnji Cooperimport sys 46*28f6c2f2SEnji Cooperfrom googlemock.test import gmock_test_utils 47b89a7cc2SEnji Cooper 48b89a7cc2SEnji Cooper 49b89a7cc2SEnji Cooper# The flag for generating the golden file 50b89a7cc2SEnji CooperGENGOLDEN_FLAG = '--gengolden' 51b89a7cc2SEnji Cooper 52b89a7cc2SEnji CooperPROGRAM_PATH = gmock_test_utils.GetTestExecutablePath('gmock_output_test_') 53b89a7cc2SEnji CooperCOMMAND = [PROGRAM_PATH, '--gtest_stack_trace_depth=0', '--gtest_print_time=0'] 54b89a7cc2SEnji CooperGOLDEN_NAME = 'gmock_output_test_golden.txt' 55b89a7cc2SEnji CooperGOLDEN_PATH = os.path.join(gmock_test_utils.GetSourceDir(), GOLDEN_NAME) 56b89a7cc2SEnji Cooper 57b89a7cc2SEnji Cooper 58b89a7cc2SEnji Cooperdef ToUnixLineEnding(s): 59b89a7cc2SEnji Cooper """Changes all Windows/Mac line endings in s to UNIX line endings.""" 60b89a7cc2SEnji Cooper 61b89a7cc2SEnji Cooper return s.replace('\r\n', '\n').replace('\r', '\n') 62b89a7cc2SEnji Cooper 63b89a7cc2SEnji Cooper 64b89a7cc2SEnji Cooperdef RemoveReportHeaderAndFooter(output): 65b89a7cc2SEnji Cooper """Removes Google Test result report's header and footer from the output.""" 66b89a7cc2SEnji Cooper 67b89a7cc2SEnji Cooper output = re.sub(r'.*gtest_main.*\n', '', output) 68b89a7cc2SEnji Cooper output = re.sub(r'\[.*\d+ tests.*\n', '', output) 69b89a7cc2SEnji Cooper output = re.sub(r'\[.* test environment .*\n', '', output) 70b89a7cc2SEnji Cooper output = re.sub(r'\[=+\] \d+ tests .* ran.*', '', output) 71b89a7cc2SEnji Cooper output = re.sub(r'.* FAILED TESTS\n', '', output) 72b89a7cc2SEnji Cooper return output 73b89a7cc2SEnji Cooper 74b89a7cc2SEnji Cooper 75b89a7cc2SEnji Cooperdef RemoveLocations(output): 76b89a7cc2SEnji Cooper """Removes all file location info from a Google Test program's output. 77b89a7cc2SEnji Cooper 78b89a7cc2SEnji Cooper Args: 79b89a7cc2SEnji Cooper output: the output of a Google Test program. 80b89a7cc2SEnji Cooper 81b89a7cc2SEnji Cooper Returns: 82b89a7cc2SEnji Cooper output with all file location info (in the form of 83b89a7cc2SEnji Cooper 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or 84b89a7cc2SEnji Cooper 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by 85b89a7cc2SEnji Cooper 'FILE:#: '. 86b89a7cc2SEnji Cooper """ 87b89a7cc2SEnji Cooper 88b89a7cc2SEnji Cooper return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\:', 'FILE:#:', output) 89b89a7cc2SEnji Cooper 90b89a7cc2SEnji Cooper 91b89a7cc2SEnji Cooperdef NormalizeErrorMarker(output): 92b89a7cc2SEnji Cooper """Normalizes the error marker, which is different on Windows vs on Linux.""" 93b89a7cc2SEnji Cooper 94b89a7cc2SEnji Cooper return re.sub(r' error: ', ' Failure\n', output) 95b89a7cc2SEnji Cooper 96b89a7cc2SEnji Cooper 97b89a7cc2SEnji Cooperdef RemoveMemoryAddresses(output): 98b89a7cc2SEnji Cooper """Removes memory addresses from the test output.""" 99b89a7cc2SEnji Cooper 100b89a7cc2SEnji Cooper return re.sub(r'@\w+', '@0x#', output) 101b89a7cc2SEnji Cooper 102b89a7cc2SEnji Cooper 103b89a7cc2SEnji Cooperdef RemoveTestNamesOfLeakedMocks(output): 104b89a7cc2SEnji Cooper """Removes the test names of leaked mock objects from the test output.""" 105b89a7cc2SEnji Cooper 106b89a7cc2SEnji Cooper return re.sub(r'\(used in test .+\) ', '', output) 107b89a7cc2SEnji Cooper 108b89a7cc2SEnji Cooper 109b89a7cc2SEnji Cooperdef GetLeakyTests(output): 110b89a7cc2SEnji Cooper """Returns a list of test names that leak mock objects.""" 111b89a7cc2SEnji Cooper 112b89a7cc2SEnji Cooper # findall() returns a list of all matches of the regex in output. 113b89a7cc2SEnji Cooper # For example, if '(used in test FooTest.Bar)' is in output, the 114b89a7cc2SEnji Cooper # list will contain 'FooTest.Bar'. 115b89a7cc2SEnji Cooper return re.findall(r'\(used in test (.+)\)', output) 116b89a7cc2SEnji Cooper 117b89a7cc2SEnji Cooper 118b89a7cc2SEnji Cooperdef GetNormalizedOutputAndLeakyTests(output): 119b89a7cc2SEnji Cooper """Normalizes the output of gmock_output_test_. 120b89a7cc2SEnji Cooper 121b89a7cc2SEnji Cooper Args: 122b89a7cc2SEnji Cooper output: The test output. 123b89a7cc2SEnji Cooper 124b89a7cc2SEnji Cooper Returns: 125b89a7cc2SEnji Cooper A tuple (the normalized test output, the list of test names that have 126b89a7cc2SEnji Cooper leaked mocks). 127b89a7cc2SEnji Cooper """ 128b89a7cc2SEnji Cooper 129b89a7cc2SEnji Cooper output = ToUnixLineEnding(output) 130b89a7cc2SEnji Cooper output = RemoveReportHeaderAndFooter(output) 131b89a7cc2SEnji Cooper output = NormalizeErrorMarker(output) 132b89a7cc2SEnji Cooper output = RemoveLocations(output) 133b89a7cc2SEnji Cooper output = RemoveMemoryAddresses(output) 134b89a7cc2SEnji Cooper return (RemoveTestNamesOfLeakedMocks(output), GetLeakyTests(output)) 135b89a7cc2SEnji Cooper 136b89a7cc2SEnji Cooper 137b89a7cc2SEnji Cooperdef GetShellCommandOutput(cmd): 138b89a7cc2SEnji Cooper """Runs a command in a sub-process, and returns its STDOUT in a string.""" 139b89a7cc2SEnji Cooper 140b89a7cc2SEnji Cooper return gmock_test_utils.Subprocess(cmd, capture_stderr=False).output 141b89a7cc2SEnji Cooper 142b89a7cc2SEnji Cooper 143b89a7cc2SEnji Cooperdef GetNormalizedCommandOutputAndLeakyTests(cmd): 144b89a7cc2SEnji Cooper """Runs a command and returns its normalized output and a list of leaky tests. 145b89a7cc2SEnji Cooper 146b89a7cc2SEnji Cooper Args: 147b89a7cc2SEnji Cooper cmd: the shell command. 148b89a7cc2SEnji Cooper """ 149b89a7cc2SEnji Cooper 150b89a7cc2SEnji Cooper # Disables exception pop-ups on Windows. 151b89a7cc2SEnji Cooper os.environ['GTEST_CATCH_EXCEPTIONS'] = '1' 152b89a7cc2SEnji Cooper return GetNormalizedOutputAndLeakyTests(GetShellCommandOutput(cmd)) 153b89a7cc2SEnji Cooper 154b89a7cc2SEnji Cooper 155b89a7cc2SEnji Cooperclass GMockOutputTest(gmock_test_utils.TestCase): 156*28f6c2f2SEnji Cooper 157b89a7cc2SEnji Cooper def testOutput(self): 158b89a7cc2SEnji Cooper (output, leaky_tests) = GetNormalizedCommandOutputAndLeakyTests(COMMAND) 159b89a7cc2SEnji Cooper golden_file = open(GOLDEN_PATH, 'rb') 160*28f6c2f2SEnji Cooper golden = golden_file.read().decode('utf-8') 161b89a7cc2SEnji Cooper golden_file.close() 162*28f6c2f2SEnji Cooper # On Windows the repository might have been checked out with \r\n line 163*28f6c2f2SEnji Cooper # endings, so normalize it here. 164*28f6c2f2SEnji Cooper golden = ToUnixLineEnding(golden) 165b89a7cc2SEnji Cooper 166b89a7cc2SEnji Cooper # The normalized output should match the golden file. 167*28f6c2f2SEnji Cooper self.assertEqual(golden, output) 168b89a7cc2SEnji Cooper 169b89a7cc2SEnji Cooper # The raw output should contain 2 leaked mock object errors for 170b89a7cc2SEnji Cooper # test GMockOutputTest.CatchesLeakedMocks. 171*28f6c2f2SEnji Cooper self.assertEqual( 172*28f6c2f2SEnji Cooper [ 173*28f6c2f2SEnji Cooper 'GMockOutputTest.CatchesLeakedMocks', 174*28f6c2f2SEnji Cooper 'GMockOutputTest.CatchesLeakedMocks', 175*28f6c2f2SEnji Cooper ], 176*28f6c2f2SEnji Cooper leaky_tests, 177*28f6c2f2SEnji Cooper ) 178b89a7cc2SEnji Cooper 179b89a7cc2SEnji Cooper 180b89a7cc2SEnji Cooperif __name__ == '__main__': 181b89a7cc2SEnji Cooper if sys.argv[1:] == [GENGOLDEN_FLAG]: 182b89a7cc2SEnji Cooper (output, _) = GetNormalizedCommandOutputAndLeakyTests(COMMAND) 183b89a7cc2SEnji Cooper golden_file = open(GOLDEN_PATH, 'wb') 184b89a7cc2SEnji Cooper golden_file.write(output) 185b89a7cc2SEnji Cooper golden_file.close() 186b89a7cc2SEnji Cooper # Suppress the error "googletest was imported but a call to its main() 187b89a7cc2SEnji Cooper # was never detected." 188b89a7cc2SEnji Cooper os._exit(0) 189b89a7cc2SEnji Cooper else: 190b89a7cc2SEnji Cooper gmock_test_utils.Main() 191