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