xref: /aosp_15_r20/external/google-fruit/tests/fruit_test_common.py (revision a65addddcf69f38db5b288d787b6b7571a57bb8f)
1*a65addddSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*a65addddSAndroid Build Coastguard Worker#  Copyright 2016 Google Inc. All Rights Reserved.
3*a65addddSAndroid Build Coastguard Worker#
4*a65addddSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*a65addddSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*a65addddSAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*a65addddSAndroid Build Coastguard Worker#
8*a65addddSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*a65addddSAndroid Build Coastguard Worker#
10*a65addddSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*a65addddSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS-IS" BASIS,
12*a65addddSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*a65addddSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*a65addddSAndroid Build Coastguard Worker# limitations under the License.
15*a65addddSAndroid Build Coastguard Worker
16*a65addddSAndroid Build Coastguard Workerimport os
17*a65addddSAndroid Build Coastguard Workerimport tempfile
18*a65addddSAndroid Build Coastguard Workerimport unittest
19*a65addddSAndroid Build Coastguard Workerimport textwrap
20*a65addddSAndroid Build Coastguard Workerimport re
21*a65addddSAndroid Build Coastguard Workerimport sys
22*a65addddSAndroid Build Coastguard Workerimport shlex
23*a65addddSAndroid Build Coastguard Worker
24*a65addddSAndroid Build Coastguard Workerimport itertools
25*a65addddSAndroid Build Coastguard Worker
26*a65addddSAndroid Build Coastguard Workerimport subprocess
27*a65addddSAndroid Build Coastguard Worker
28*a65addddSAndroid Build Coastguard Workerfrom absl.testing import parameterized
29*a65addddSAndroid Build Coastguard Worker
30*a65addddSAndroid Build Coastguard Workerfrom fruit_test_config import *
31*a65addddSAndroid Build Coastguard Worker
32*a65addddSAndroid Build Coastguard Workerfrom absl.testing import absltest
33*a65addddSAndroid Build Coastguard Worker
34*a65addddSAndroid Build Coastguard Workerrun_under_valgrind = RUN_TESTS_UNDER_VALGRIND.lower() not in ('false', 'off', 'no', '0', '')
35*a65addddSAndroid Build Coastguard Worker
36*a65addddSAndroid Build Coastguard Workerdef pretty_print_command(command, env):
37*a65addddSAndroid Build Coastguard Worker    return 'cd %s; env -i %s %s' % (
38*a65addddSAndroid Build Coastguard Worker        shlex.quote(os.getcwd()),
39*a65addddSAndroid Build Coastguard Worker        ' '.join('%s=%s' % (var_name, shlex.quote(value)) for var_name, value in env.items() if var_name != 'PWD'),
40*a65addddSAndroid Build Coastguard Worker        ' '.join(shlex.quote(x) for x in command))
41*a65addddSAndroid Build Coastguard Worker
42*a65addddSAndroid Build Coastguard Workerdef multiple_parameters(*param_lists):
43*a65addddSAndroid Build Coastguard Worker    param_lists = [[params if isinstance(params, tuple) else (params,)
44*a65addddSAndroid Build Coastguard Worker                    for params in param_list]
45*a65addddSAndroid Build Coastguard Worker                   for param_list in param_lists]
46*a65addddSAndroid Build Coastguard Worker    result = param_lists[0]
47*a65addddSAndroid Build Coastguard Worker    for param_list in param_lists[1:]:
48*a65addddSAndroid Build Coastguard Worker        result = [(*args1, *args2)
49*a65addddSAndroid Build Coastguard Worker                  for args1 in result
50*a65addddSAndroid Build Coastguard Worker                  for args2 in param_list]
51*a65addddSAndroid Build Coastguard Worker    return parameterized.parameters(*result)
52*a65addddSAndroid Build Coastguard Worker
53*a65addddSAndroid Build Coastguard Workerdef multiple_named_parameters(*param_lists):
54*a65addddSAndroid Build Coastguard Worker    result = param_lists[0]
55*a65addddSAndroid Build Coastguard Worker    for param_list in param_lists[1:]:
56*a65addddSAndroid Build Coastguard Worker        result = [(name1 + ', ' + name2, *args1, *args2)
57*a65addddSAndroid Build Coastguard Worker                  for name1, *args1 in result
58*a65addddSAndroid Build Coastguard Worker                  for name2, *args2 in param_list]
59*a65addddSAndroid Build Coastguard Worker    return parameterized.named_parameters(*result)
60*a65addddSAndroid Build Coastguard Worker
61*a65addddSAndroid Build Coastguard Workerclass CommandFailedException(Exception):
62*a65addddSAndroid Build Coastguard Worker    def __init__(self, command, env, stdout, stderr, error_code):
63*a65addddSAndroid Build Coastguard Worker        self.command = command
64*a65addddSAndroid Build Coastguard Worker        self.env = env
65*a65addddSAndroid Build Coastguard Worker        self.stdout = stdout
66*a65addddSAndroid Build Coastguard Worker        self.stderr = stderr
67*a65addddSAndroid Build Coastguard Worker        self.error_code = error_code
68*a65addddSAndroid Build Coastguard Worker
69*a65addddSAndroid Build Coastguard Worker    def __str__(self):
70*a65addddSAndroid Build Coastguard Worker        return textwrap.dedent('''\
71*a65addddSAndroid Build Coastguard Worker        Ran command: {command}
72*a65addddSAndroid Build Coastguard Worker        Exit code {error_code}
73*a65addddSAndroid Build Coastguard Worker        Stdout:
74*a65addddSAndroid Build Coastguard Worker        {stdout}
75*a65addddSAndroid Build Coastguard Worker
76*a65addddSAndroid Build Coastguard Worker        Stderr:
77*a65addddSAndroid Build Coastguard Worker        {stderr}
78*a65addddSAndroid Build Coastguard Worker        ''').format(command=pretty_print_command(self.command, self.env), error_code=self.error_code, stdout=self.stdout, stderr=self.stderr)
79*a65addddSAndroid Build Coastguard Worker
80*a65addddSAndroid Build Coastguard Workerdef run_command(executable, args=[], modify_env=lambda env: env):
81*a65addddSAndroid Build Coastguard Worker    command = [executable] + args
82*a65addddSAndroid Build Coastguard Worker    modified_env = modify_env(os.environ)
83*a65addddSAndroid Build Coastguard Worker    print('Executing command:', pretty_print_command(command, modified_env))
84*a65addddSAndroid Build Coastguard Worker    try:
85*a65addddSAndroid Build Coastguard Worker        p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, env=modified_env)
86*a65addddSAndroid Build Coastguard Worker        (stdout, stderr) = p.communicate()
87*a65addddSAndroid Build Coastguard Worker    except Exception as e:
88*a65addddSAndroid Build Coastguard Worker        raise Exception("While executing: %s" % command)
89*a65addddSAndroid Build Coastguard Worker    if p.returncode != 0:
90*a65addddSAndroid Build Coastguard Worker        raise CommandFailedException(command, modified_env, stdout, stderr, p.returncode)
91*a65addddSAndroid Build Coastguard Worker    print('Execution successful.')
92*a65addddSAndroid Build Coastguard Worker    print('stdout:')
93*a65addddSAndroid Build Coastguard Worker    print(stdout)
94*a65addddSAndroid Build Coastguard Worker    print('')
95*a65addddSAndroid Build Coastguard Worker    print('stderr:')
96*a65addddSAndroid Build Coastguard Worker    print(stderr)
97*a65addddSAndroid Build Coastguard Worker    print('')
98*a65addddSAndroid Build Coastguard Worker    return (stdout, stderr)
99*a65addddSAndroid Build Coastguard Worker
100*a65addddSAndroid Build Coastguard Workerdef run_compiled_executable(executable):
101*a65addddSAndroid Build Coastguard Worker    if run_under_valgrind:
102*a65addddSAndroid Build Coastguard Worker        args = VALGRIND_FLAGS.split() + [executable]
103*a65addddSAndroid Build Coastguard Worker        run_command('valgrind', args = args, modify_env = modify_env_for_compiled_executables)
104*a65addddSAndroid Build Coastguard Worker    else:
105*a65addddSAndroid Build Coastguard Worker        run_command(executable, modify_env = modify_env_for_compiled_executables)
106*a65addddSAndroid Build Coastguard Worker
107*a65addddSAndroid Build Coastguard Workerclass CompilationFailedException(Exception):
108*a65addddSAndroid Build Coastguard Worker    def __init__(self, command, env, error_message):
109*a65addddSAndroid Build Coastguard Worker        self.command = command
110*a65addddSAndroid Build Coastguard Worker        self.env = env
111*a65addddSAndroid Build Coastguard Worker        self.error_message = error_message
112*a65addddSAndroid Build Coastguard Worker
113*a65addddSAndroid Build Coastguard Worker    def __str__(self):
114*a65addddSAndroid Build Coastguard Worker        return textwrap.dedent('''\
115*a65addddSAndroid Build Coastguard Worker        Ran command: {command}
116*a65addddSAndroid Build Coastguard Worker        Error message:
117*a65addddSAndroid Build Coastguard Worker        {error_message}
118*a65addddSAndroid Build Coastguard Worker        ''').format(command=pretty_print_command(self.command, self.env), error_message=self.error_message)
119*a65addddSAndroid Build Coastguard Worker
120*a65addddSAndroid Build Coastguard Workerclass PosixCompiler:
121*a65addddSAndroid Build Coastguard Worker    def __init__(self):
122*a65addddSAndroid Build Coastguard Worker        self.executable = CXX
123*a65addddSAndroid Build Coastguard Worker        self.name = CXX_COMPILER_NAME
124*a65addddSAndroid Build Coastguard Worker
125*a65addddSAndroid Build Coastguard Worker    def compile_discarding_output(self, source, include_dirs, args=[]):
126*a65addddSAndroid Build Coastguard Worker        try:
127*a65addddSAndroid Build Coastguard Worker            args = args + ['-c', source, '-o', os.path.devnull]
128*a65addddSAndroid Build Coastguard Worker            self._compile(include_dirs, args=args)
129*a65addddSAndroid Build Coastguard Worker        except CommandFailedException as e:
130*a65addddSAndroid Build Coastguard Worker            raise CompilationFailedException(e.command, e.env, e.stderr)
131*a65addddSAndroid Build Coastguard Worker
132*a65addddSAndroid Build Coastguard Worker    def compile_and_link(self, source, include_dirs, output_file_name, args=[]):
133*a65addddSAndroid Build Coastguard Worker        self._compile(
134*a65addddSAndroid Build Coastguard Worker            include_dirs,
135*a65addddSAndroid Build Coastguard Worker            args = (
136*a65addddSAndroid Build Coastguard Worker                [source]
137*a65addddSAndroid Build Coastguard Worker                + ADDITIONAL_LINKER_FLAGS.split()
138*a65addddSAndroid Build Coastguard Worker                + args
139*a65addddSAndroid Build Coastguard Worker                + ['-o', output_file_name]
140*a65addddSAndroid Build Coastguard Worker            ))
141*a65addddSAndroid Build Coastguard Worker
142*a65addddSAndroid Build Coastguard Worker    def _compile(self, include_dirs, args):
143*a65addddSAndroid Build Coastguard Worker        include_flags = ['-I%s' % include_dir for include_dir in include_dirs]
144*a65addddSAndroid Build Coastguard Worker        args = (
145*a65addddSAndroid Build Coastguard Worker            FRUIT_TEST_COMPILE_FLAGS.split()
146*a65addddSAndroid Build Coastguard Worker            + include_flags
147*a65addddSAndroid Build Coastguard Worker            + ['-g0', '-Werror']
148*a65addddSAndroid Build Coastguard Worker            + args
149*a65addddSAndroid Build Coastguard Worker        )
150*a65addddSAndroid Build Coastguard Worker        run_command(self.executable, args)
151*a65addddSAndroid Build Coastguard Worker
152*a65addddSAndroid Build Coastguard Worker    def get_disable_deprecation_warning_flags(self):
153*a65addddSAndroid Build Coastguard Worker        return ['-Wno-deprecated-declarations']
154*a65addddSAndroid Build Coastguard Worker
155*a65addddSAndroid Build Coastguard Worker    def get_disable_all_warnings_flags(self):
156*a65addddSAndroid Build Coastguard Worker        return ['-Wno-error']
157*a65addddSAndroid Build Coastguard Worker
158*a65addddSAndroid Build Coastguard Workerclass MsvcCompiler:
159*a65addddSAndroid Build Coastguard Worker    def __init__(self):
160*a65addddSAndroid Build Coastguard Worker        self.executable = CXX
161*a65addddSAndroid Build Coastguard Worker        self.name = CXX_COMPILER_NAME
162*a65addddSAndroid Build Coastguard Worker
163*a65addddSAndroid Build Coastguard Worker    def compile_discarding_output(self, source, include_dirs, args=[]):
164*a65addddSAndroid Build Coastguard Worker        try:
165*a65addddSAndroid Build Coastguard Worker            args = args + ['/c', source]
166*a65addddSAndroid Build Coastguard Worker            self._compile(include_dirs, args = args)
167*a65addddSAndroid Build Coastguard Worker        except CommandFailedException as e:
168*a65addddSAndroid Build Coastguard Worker            # Note that we use stdout here, unlike above. MSVC reports compilation warnings and errors on stdout.
169*a65addddSAndroid Build Coastguard Worker            raise CompilationFailedException(e.command, e.env, e.stdout)
170*a65addddSAndroid Build Coastguard Worker
171*a65addddSAndroid Build Coastguard Worker    def compile_and_link(self, source, include_dirs, output_file_name, args=[]):
172*a65addddSAndroid Build Coastguard Worker        self._compile(
173*a65addddSAndroid Build Coastguard Worker            include_dirs,
174*a65addddSAndroid Build Coastguard Worker            args = (
175*a65addddSAndroid Build Coastguard Worker                [source]
176*a65addddSAndroid Build Coastguard Worker                + ADDITIONAL_LINKER_FLAGS.split()
177*a65addddSAndroid Build Coastguard Worker                + args
178*a65addddSAndroid Build Coastguard Worker                + ['/Fe' + output_file_name]
179*a65addddSAndroid Build Coastguard Worker            ))
180*a65addddSAndroid Build Coastguard Worker
181*a65addddSAndroid Build Coastguard Worker    def _compile(self, include_dirs, args):
182*a65addddSAndroid Build Coastguard Worker        include_flags = ['-I%s' % include_dir for include_dir in include_dirs]
183*a65addddSAndroid Build Coastguard Worker        args = (
184*a65addddSAndroid Build Coastguard Worker            FRUIT_TEST_COMPILE_FLAGS.split()
185*a65addddSAndroid Build Coastguard Worker            + include_flags
186*a65addddSAndroid Build Coastguard Worker            + ['/WX']
187*a65addddSAndroid Build Coastguard Worker            + args
188*a65addddSAndroid Build Coastguard Worker        )
189*a65addddSAndroid Build Coastguard Worker        run_command(self.executable, args)
190*a65addddSAndroid Build Coastguard Worker
191*a65addddSAndroid Build Coastguard Worker    def get_disable_deprecation_warning_flags(self):
192*a65addddSAndroid Build Coastguard Worker        return ['/wd4996']
193*a65addddSAndroid Build Coastguard Worker
194*a65addddSAndroid Build Coastguard Worker    def get_disable_all_warnings_flags(self):
195*a65addddSAndroid Build Coastguard Worker        return ['/WX:NO']
196*a65addddSAndroid Build Coastguard Worker
197*a65addddSAndroid Build Coastguard Workerif CXX_COMPILER_NAME == 'MSVC':
198*a65addddSAndroid Build Coastguard Worker    compiler = MsvcCompiler()
199*a65addddSAndroid Build Coastguard Worker    if PATH_TO_COMPILED_FRUIT_LIB.endswith('.dll'):
200*a65addddSAndroid Build Coastguard Worker        path_to_fruit_lib = PATH_TO_COMPILED_FRUIT_LIB[:-4] + '.lib'
201*a65addddSAndroid Build Coastguard Worker    else:
202*a65addddSAndroid Build Coastguard Worker        path_to_fruit_lib = PATH_TO_COMPILED_FRUIT_LIB
203*a65addddSAndroid Build Coastguard Worker    if PATH_TO_COMPILED_TEST_HEADERS_LIB.endswith('.dll'):
204*a65addddSAndroid Build Coastguard Worker        path_to_test_headers_lib = PATH_TO_COMPILED_TEST_HEADERS_LIB[:-4] + '.lib'
205*a65addddSAndroid Build Coastguard Worker    else:
206*a65addddSAndroid Build Coastguard Worker        path_to_test_headers_lib = PATH_TO_COMPILED_TEST_HEADERS_LIB
207*a65addddSAndroid Build Coastguard Worker    fruit_tests_linker_flags = [path_to_fruit_lib, path_to_test_headers_lib]
208*a65addddSAndroid Build Coastguard Worker    fruit_error_message_extraction_regex = 'error C2338: (.*)'
209*a65addddSAndroid Build Coastguard Workerelse:
210*a65addddSAndroid Build Coastguard Worker    compiler = PosixCompiler()
211*a65addddSAndroid Build Coastguard Worker    fruit_tests_linker_flags = [
212*a65addddSAndroid Build Coastguard Worker        '-lfruit',
213*a65addddSAndroid Build Coastguard Worker        '-ltest_headers_copy',
214*a65addddSAndroid Build Coastguard Worker        '-L' + PATH_TO_COMPILED_FRUIT,
215*a65addddSAndroid Build Coastguard Worker        '-Wl,-rpath,' + PATH_TO_COMPILED_FRUIT,
216*a65addddSAndroid Build Coastguard Worker        '-L' + PATH_TO_COMPILED_TEST_HEADERS,
217*a65addddSAndroid Build Coastguard Worker        '-Wl,-rpath,' + PATH_TO_COMPILED_TEST_HEADERS,
218*a65addddSAndroid Build Coastguard Worker    ]
219*a65addddSAndroid Build Coastguard Worker    fruit_error_message_extraction_regex = 'static.assert(.*)'
220*a65addddSAndroid Build Coastguard Worker
221*a65addddSAndroid Build Coastguard Workerfruit_tests_include_dirs = ADDITIONAL_INCLUDE_DIRS.splitlines() + [
222*a65addddSAndroid Build Coastguard Worker    PATH_TO_FRUIT_TEST_HEADERS,
223*a65addddSAndroid Build Coastguard Worker    PATH_TO_FRUIT_STATIC_HEADERS,
224*a65addddSAndroid Build Coastguard Worker    PATH_TO_FRUIT_GENERATED_HEADERS,
225*a65addddSAndroid Build Coastguard Worker]
226*a65addddSAndroid Build Coastguard Worker
227*a65addddSAndroid Build Coastguard Worker_assert_helper = unittest.TestCase()
228*a65addddSAndroid Build Coastguard Worker
229*a65addddSAndroid Build Coastguard Workerdef modify_env_for_compiled_executables(env):
230*a65addddSAndroid Build Coastguard Worker    env = env.copy()
231*a65addddSAndroid Build Coastguard Worker    path_to_fruit_lib_dir = os.path.dirname(PATH_TO_COMPILED_FRUIT_LIB)
232*a65addddSAndroid Build Coastguard Worker    path_to_fruit_test_headers_dir = os.path.dirname(PATH_TO_COMPILED_TEST_HEADERS_LIB)
233*a65addddSAndroid Build Coastguard Worker    print('PATH_TO_COMPILED_FRUIT_LIB:', PATH_TO_COMPILED_FRUIT_LIB)
234*a65addddSAndroid Build Coastguard Worker    print('PATH_TO_COMPILED_TEST_HEADERS_LIB:', PATH_TO_COMPILED_TEST_HEADERS_LIB)
235*a65addddSAndroid Build Coastguard Worker    print('Adding directory to PATH:', path_to_fruit_lib_dir)
236*a65addddSAndroid Build Coastguard Worker    print('Adding directory to PATH:', path_to_fruit_test_headers_dir)
237*a65addddSAndroid Build Coastguard Worker    env["PATH"] += os.pathsep + path_to_fruit_lib_dir + os.pathsep + path_to_fruit_test_headers_dir
238*a65addddSAndroid Build Coastguard Worker    return env
239*a65addddSAndroid Build Coastguard Worker
240*a65addddSAndroid Build Coastguard Workerdef _create_temporary_file(file_content, file_name_suffix=''):
241*a65addddSAndroid Build Coastguard Worker    file_descriptor, file_name = tempfile.mkstemp(text=True, suffix=file_name_suffix)
242*a65addddSAndroid Build Coastguard Worker    file = os.fdopen(file_descriptor, mode='w')
243*a65addddSAndroid Build Coastguard Worker    file.write(file_content)
244*a65addddSAndroid Build Coastguard Worker    file.close()
245*a65addddSAndroid Build Coastguard Worker    return file_name
246*a65addddSAndroid Build Coastguard Worker
247*a65addddSAndroid Build Coastguard Workerdef _cap_to_lines(s, n):
248*a65addddSAndroid Build Coastguard Worker    lines = s.splitlines()
249*a65addddSAndroid Build Coastguard Worker    if len(lines) <= n:
250*a65addddSAndroid Build Coastguard Worker        return s
251*a65addddSAndroid Build Coastguard Worker    else:
252*a65addddSAndroid Build Coastguard Worker        return '\n'.join(lines[0:n] + ['...'])
253*a65addddSAndroid Build Coastguard Worker
254*a65addddSAndroid Build Coastguard Workerdef _replace_using_test_params(s, test_params):
255*a65addddSAndroid Build Coastguard Worker    for var_name, value in test_params.items():
256*a65addddSAndroid Build Coastguard Worker        if isinstance(value, str):
257*a65addddSAndroid Build Coastguard Worker            s = re.sub(r'\b%s\b' % var_name, value, s)
258*a65addddSAndroid Build Coastguard Worker    return s
259*a65addddSAndroid Build Coastguard Worker
260*a65addddSAndroid Build Coastguard Workerdef _construct_final_source_code(setup_source_code, source_code, test_params):
261*a65addddSAndroid Build Coastguard Worker    setup_source_code = textwrap.dedent(setup_source_code)
262*a65addddSAndroid Build Coastguard Worker    source_code = textwrap.dedent(source_code)
263*a65addddSAndroid Build Coastguard Worker    source_code = _replace_using_test_params(source_code, test_params)
264*a65addddSAndroid Build Coastguard Worker    return setup_source_code + source_code
265*a65addddSAndroid Build Coastguard Worker
266*a65addddSAndroid Build Coastguard Workerdef try_remove_temporary_file(filename):
267*a65addddSAndroid Build Coastguard Worker    try:
268*a65addddSAndroid Build Coastguard Worker        os.remove(filename)
269*a65addddSAndroid Build Coastguard Worker    except:
270*a65addddSAndroid Build Coastguard Worker        # When running Fruit tests on Windows using Appveyor, the remove command fails for temporary files sometimes.
271*a65addddSAndroid Build Coastguard Worker        # This shouldn't cause the tests to fail, so we ignore the exception and go ahead.
272*a65addddSAndroid Build Coastguard Worker        pass
273*a65addddSAndroid Build Coastguard Worker
274*a65addddSAndroid Build Coastguard Workerdef normalize_error_message_lines(lines):
275*a65addddSAndroid Build Coastguard Worker    # Different compilers output a different number of spaces when pretty-printing types.
276*a65addddSAndroid Build Coastguard Worker    # When using libc++, sometimes std::foo identifiers are reported as std::__1::foo.
277*a65addddSAndroid Build Coastguard Worker    return [line.replace(' ', '').replace('std::__1::', 'std::') for line in lines]
278*a65addddSAndroid Build Coastguard Worker
279*a65addddSAndroid Build Coastguard Workerdef expect_compile_error_helper(
280*a65addddSAndroid Build Coastguard Worker        check_error_fun,
281*a65addddSAndroid Build Coastguard Worker        setup_source_code,
282*a65addddSAndroid Build Coastguard Worker        source_code,
283*a65addddSAndroid Build Coastguard Worker        test_params={},
284*a65addddSAndroid Build Coastguard Worker        ignore_deprecation_warnings=False,
285*a65addddSAndroid Build Coastguard Worker        ignore_warnings=False):
286*a65addddSAndroid Build Coastguard Worker    source_code = _construct_final_source_code(setup_source_code, source_code, test_params)
287*a65addddSAndroid Build Coastguard Worker
288*a65addddSAndroid Build Coastguard Worker    source_file_name = _create_temporary_file(source_code, file_name_suffix='.cpp')
289*a65addddSAndroid Build Coastguard Worker
290*a65addddSAndroid Build Coastguard Worker    try:
291*a65addddSAndroid Build Coastguard Worker        args = []
292*a65addddSAndroid Build Coastguard Worker        if ignore_deprecation_warnings:
293*a65addddSAndroid Build Coastguard Worker            args += compiler.get_disable_deprecation_warning_flags()
294*a65addddSAndroid Build Coastguard Worker        if ignore_warnings:
295*a65addddSAndroid Build Coastguard Worker            args += compiler.get_disable_all_warnings_flags()
296*a65addddSAndroid Build Coastguard Worker        if ENABLE_COVERAGE:
297*a65addddSAndroid Build Coastguard Worker            # When collecting coverage these arguments are enabled by default; however we must disable them in tests
298*a65addddSAndroid Build Coastguard Worker            # expected to fail at compile-time because GCC would otherwise fail with an error like:
299*a65addddSAndroid Build Coastguard Worker            # /tmp/tmp4m22cey7.cpp:1:0: error: cannot open /dev/null.gcno
300*a65addddSAndroid Build Coastguard Worker            args += ['-fno-profile-arcs', '-fno-test-coverage']
301*a65addddSAndroid Build Coastguard Worker        compiler.compile_discarding_output(
302*a65addddSAndroid Build Coastguard Worker            source=source_file_name,
303*a65addddSAndroid Build Coastguard Worker            include_dirs=fruit_tests_include_dirs,
304*a65addddSAndroid Build Coastguard Worker            args=args)
305*a65addddSAndroid Build Coastguard Worker        raise Exception('The test should have failed to compile, but it compiled successfully')
306*a65addddSAndroid Build Coastguard Worker    except CompilationFailedException as e1:
307*a65addddSAndroid Build Coastguard Worker        e = e1
308*a65addddSAndroid Build Coastguard Worker
309*a65addddSAndroid Build Coastguard Worker    error_message = e.error_message
310*a65addddSAndroid Build Coastguard Worker    error_message_lines = error_message.splitlines()
311*a65addddSAndroid Build Coastguard Worker    error_message_head = _cap_to_lines(error_message, 40)
312*a65addddSAndroid Build Coastguard Worker
313*a65addddSAndroid Build Coastguard Worker    check_error_fun(e, error_message_lines, error_message_head)
314*a65addddSAndroid Build Coastguard Worker
315*a65addddSAndroid Build Coastguard Worker    try_remove_temporary_file(source_file_name)
316*a65addddSAndroid Build Coastguard Worker
317*a65addddSAndroid Build Coastguard Workerdef apply_any_error_context_replacements(error_string, following_lines):
318*a65addddSAndroid Build Coastguard Worker    if CXX_COMPILER_NAME == 'MSVC':
319*a65addddSAndroid Build Coastguard Worker        # MSVC errors are of the form:
320*a65addddSAndroid Build Coastguard Worker        #
321*a65addddSAndroid Build Coastguard Worker        # C:\Path\To\header\foo.h(59): note: see reference to class template instantiation 'fruit::impl::NoBindingFoundError<fruit::Annotated<Annotation,U>>' being compiled
322*a65addddSAndroid Build Coastguard Worker        #         with
323*a65addddSAndroid Build Coastguard Worker        #         [
324*a65addddSAndroid Build Coastguard Worker        #              Annotation=Annotation1,
325*a65addddSAndroid Build Coastguard Worker        #              U=std::function<std::unique_ptr<ScalerImpl,std::default_delete<ScalerImpl>> (double)>
326*a65addddSAndroid Build Coastguard Worker        #         ]
327*a65addddSAndroid Build Coastguard Worker        #
328*a65addddSAndroid Build Coastguard Worker        # So we need to parse the following few lines and use them to replace the placeholder types in the Fruit error type.
329*a65addddSAndroid Build Coastguard Worker        replacement_lines = []
330*a65addddSAndroid Build Coastguard Worker        if len(following_lines) >= 4 and following_lines[0].strip() == 'with':
331*a65addddSAndroid Build Coastguard Worker            assert following_lines[1].strip() == '[', 'Line was: ' + following_lines[1]
332*a65addddSAndroid Build Coastguard Worker            for line in itertools.islice(following_lines, 2, None):
333*a65addddSAndroid Build Coastguard Worker                line = line.strip()
334*a65addddSAndroid Build Coastguard Worker                if line == ']':
335*a65addddSAndroid Build Coastguard Worker                    break
336*a65addddSAndroid Build Coastguard Worker                if line.endswith(','):
337*a65addddSAndroid Build Coastguard Worker                    line = line[:-1]
338*a65addddSAndroid Build Coastguard Worker                replacement_lines.append(line)
339*a65addddSAndroid Build Coastguard Worker
340*a65addddSAndroid Build Coastguard Worker        for replacement_line in replacement_lines:
341*a65addddSAndroid Build Coastguard Worker            match = re.search('([A-Za-z0-9_-]*)=(.*)', replacement_line)
342*a65addddSAndroid Build Coastguard Worker            if not match:
343*a65addddSAndroid Build Coastguard Worker                raise Exception('Failed to parse replacement line: %s' % replacement_line)
344*a65addddSAndroid Build Coastguard Worker            (type_variable, type_expression) = match.groups()
345*a65addddSAndroid Build Coastguard Worker            error_string = re.sub(r'\b' + type_variable + r'\b', type_expression, error_string)
346*a65addddSAndroid Build Coastguard Worker    return error_string
347*a65addddSAndroid Build Coastguard Worker
348*a65addddSAndroid Build Coastguard Workerdef expect_generic_compile_error(expected_error_regex, setup_source_code, source_code, test_params={}):
349*a65addddSAndroid Build Coastguard Worker    """
350*a65addddSAndroid Build Coastguard Worker    Tests that the given source produces the expected error during compilation.
351*a65addddSAndroid Build Coastguard Worker
352*a65addddSAndroid Build Coastguard Worker    :param expected_fruit_error_regex: A regex used to match the Fruit error type,
353*a65addddSAndroid Build Coastguard Worker           e.g. 'NoBindingFoundForAbstractClassError<ScalerImpl>'.
354*a65addddSAndroid Build Coastguard Worker           Any identifiers contained in the regex will be replaced using test_params (where a replacement is defined).
355*a65addddSAndroid Build Coastguard Worker    :param expected_fruit_error_desc_regex: A regex used to match the Fruit error description,
356*a65addddSAndroid Build Coastguard Worker           e.g. 'No explicit binding was found for C, and C is an abstract class'.
357*a65addddSAndroid Build Coastguard Worker    :param setup_source_code: The first part of the source code. This is dedented separately from source_code and it's
358*a65addddSAndroid Build Coastguard Worker           *not* subject to test_params, unlike source_code.
359*a65addddSAndroid Build Coastguard Worker    :param source_code: The second part of the source code. Any identifiers will be replaced using test_params
360*a65addddSAndroid Build Coastguard Worker           (where a replacement is defined). This will be dedented.
361*a65addddSAndroid Build Coastguard Worker    :param test_params: A dict containing the definition of some identifiers. Each identifier in
362*a65addddSAndroid Build Coastguard Worker           expected_fruit_error_regex and source_code will be replaced (textually) with its definition (if a definition
363*a65addddSAndroid Build Coastguard Worker           was provided).
364*a65addddSAndroid Build Coastguard Worker    """
365*a65addddSAndroid Build Coastguard Worker
366*a65addddSAndroid Build Coastguard Worker    expected_error_regex = _replace_using_test_params(expected_error_regex, test_params)
367*a65addddSAndroid Build Coastguard Worker    expected_error_regex = expected_error_regex.replace(' ', '')
368*a65addddSAndroid Build Coastguard Worker
369*a65addddSAndroid Build Coastguard Worker    def check_error(e, error_message_lines, error_message_head):
370*a65addddSAndroid Build Coastguard Worker        error_message_lines_with_replacements = [
371*a65addddSAndroid Build Coastguard Worker            apply_any_error_context_replacements(line, error_message_lines[line_number + 1:])
372*a65addddSAndroid Build Coastguard Worker            for line_number, line in enumerate(error_message_lines)]
373*a65addddSAndroid Build Coastguard Worker
374*a65addddSAndroid Build Coastguard Worker        normalized_error_message_lines = normalize_error_message_lines(error_message_lines_with_replacements)
375*a65addddSAndroid Build Coastguard Worker
376*a65addddSAndroid Build Coastguard Worker        for line in normalized_error_message_lines:
377*a65addddSAndroid Build Coastguard Worker            if re.search(expected_error_regex, line):
378*a65addddSAndroid Build Coastguard Worker                return
379*a65addddSAndroid Build Coastguard Worker        raise Exception(textwrap.dedent('''\
380*a65addddSAndroid Build Coastguard Worker            Expected error {expected_error} but the compiler output did not contain that.
381*a65addddSAndroid Build Coastguard Worker            Compiler command line: {compiler_command}
382*a65addddSAndroid Build Coastguard Worker            Error message was:
383*a65addddSAndroid Build Coastguard Worker            {error_message}
384*a65addddSAndroid Build Coastguard Worker            ''').format(expected_error = expected_error_regex, compiler_command=e.command, error_message = error_message_head))
385*a65addddSAndroid Build Coastguard Worker
386*a65addddSAndroid Build Coastguard Worker    expect_compile_error_helper(check_error, setup_source_code, source_code, test_params)
387*a65addddSAndroid Build Coastguard Worker
388*a65addddSAndroid Build Coastguard Workerdef expect_compile_error(
389*a65addddSAndroid Build Coastguard Worker        expected_fruit_error_regex,
390*a65addddSAndroid Build Coastguard Worker        expected_fruit_error_desc_regex,
391*a65addddSAndroid Build Coastguard Worker        setup_source_code,
392*a65addddSAndroid Build Coastguard Worker        source_code,
393*a65addddSAndroid Build Coastguard Worker        test_params={},
394*a65addddSAndroid Build Coastguard Worker        ignore_deprecation_warnings=False,
395*a65addddSAndroid Build Coastguard Worker        ignore_warnings=False,
396*a65addddSAndroid Build Coastguard Worker        disable_error_line_number_check=False):
397*a65addddSAndroid Build Coastguard Worker    """
398*a65addddSAndroid Build Coastguard Worker    Tests that the given source produces the expected error during compilation.
399*a65addddSAndroid Build Coastguard Worker
400*a65addddSAndroid Build Coastguard Worker    :param expected_fruit_error_regex: A regex used to match the Fruit error type,
401*a65addddSAndroid Build Coastguard Worker           e.g. 'NoBindingFoundForAbstractClassError<ScalerImpl>'.
402*a65addddSAndroid Build Coastguard Worker           Any identifiers contained in the regex will be replaced using test_params (where a replacement is defined).
403*a65addddSAndroid Build Coastguard Worker    :param expected_fruit_error_desc_regex: A regex used to match the Fruit error description,
404*a65addddSAndroid Build Coastguard Worker           e.g. 'No explicit binding was found for C, and C is an abstract class'.
405*a65addddSAndroid Build Coastguard Worker    :param setup_source_code: The first part of the source code. This is dedented separately from source_code and it's
406*a65addddSAndroid Build Coastguard Worker           *not* subject to test_params, unlike source_code.
407*a65addddSAndroid Build Coastguard Worker    :param source_code: The second part of the source code. Any identifiers will be replaced using test_params
408*a65addddSAndroid Build Coastguard Worker           (where a replacement is defined). This will be dedented.
409*a65addddSAndroid Build Coastguard Worker    :param test_params: A dict containing the definition of some identifiers. Each identifier in
410*a65addddSAndroid Build Coastguard Worker           expected_fruit_error_regex and source_code will be replaced (textually) with its definition (if a definition
411*a65addddSAndroid Build Coastguard Worker           was provided).
412*a65addddSAndroid Build Coastguard Worker    :param ignore_deprecation_warnings: A boolean. If True, deprecation warnings will be ignored.
413*a65addddSAndroid Build Coastguard Worker    :param ignore_warnings: A boolean. If True, all warnings will be ignored.
414*a65addddSAndroid Build Coastguard Worker    :param disable_error_line_number_check: A boolean. If True, the test will not fail if there are other diagnostic
415*a65addddSAndroid Build Coastguard Worker           lines before the expected error.
416*a65addddSAndroid Build Coastguard Worker    """
417*a65addddSAndroid Build Coastguard Worker    if '\n' in expected_fruit_error_regex:
418*a65addddSAndroid Build Coastguard Worker        raise Exception('expected_fruit_error_regex should not contain newlines')
419*a65addddSAndroid Build Coastguard Worker    if '\n' in expected_fruit_error_desc_regex:
420*a65addddSAndroid Build Coastguard Worker        raise Exception('expected_fruit_error_desc_regex should not contain newlines')
421*a65addddSAndroid Build Coastguard Worker
422*a65addddSAndroid Build Coastguard Worker    expected_fruit_error_regex = _replace_using_test_params(expected_fruit_error_regex, test_params)
423*a65addddSAndroid Build Coastguard Worker    expected_fruit_error_regex = expected_fruit_error_regex.replace(' ', '')
424*a65addddSAndroid Build Coastguard Worker
425*a65addddSAndroid Build Coastguard Worker    def check_error(e, error_message_lines, error_message_head):
426*a65addddSAndroid Build Coastguard Worker        normalized_error_message_lines = normalize_error_message_lines(error_message_lines)
427*a65addddSAndroid Build Coastguard Worker
428*a65addddSAndroid Build Coastguard Worker        for line_number, line in enumerate(normalized_error_message_lines):
429*a65addddSAndroid Build Coastguard Worker            match = re.search('fruit::impl::(.*Error<.*>)', line)
430*a65addddSAndroid Build Coastguard Worker            if match:
431*a65addddSAndroid Build Coastguard Worker                actual_fruit_error_line_number = line_number
432*a65addddSAndroid Build Coastguard Worker                actual_fruit_error = match.groups()[0]
433*a65addddSAndroid Build Coastguard Worker                actual_fruit_error = apply_any_error_context_replacements(actual_fruit_error, normalized_error_message_lines[line_number + 1:])
434*a65addddSAndroid Build Coastguard Worker                break
435*a65addddSAndroid Build Coastguard Worker        else:
436*a65addddSAndroid Build Coastguard Worker            raise Exception(textwrap.dedent('''\
437*a65addddSAndroid Build Coastguard Worker                Expected error {expected_error} but the compiler output did not contain user-facing Fruit errors.
438*a65addddSAndroid Build Coastguard Worker                Compiler command line: {compiler_command}
439*a65addddSAndroid Build Coastguard Worker                Error message was:
440*a65addddSAndroid Build Coastguard Worker                {error_message}
441*a65addddSAndroid Build Coastguard Worker                ''').format(expected_error = expected_fruit_error_regex, compiler_command = e.command, error_message = error_message_head))
442*a65addddSAndroid Build Coastguard Worker
443*a65addddSAndroid Build Coastguard Worker        for line_number, line in enumerate(error_message_lines):
444*a65addddSAndroid Build Coastguard Worker            match = re.search(fruit_error_message_extraction_regex, line)
445*a65addddSAndroid Build Coastguard Worker            if match:
446*a65addddSAndroid Build Coastguard Worker                actual_static_assert_error_line_number = line_number
447*a65addddSAndroid Build Coastguard Worker                actual_static_assert_error = match.groups()[0]
448*a65addddSAndroid Build Coastguard Worker                break
449*a65addddSAndroid Build Coastguard Worker        else:
450*a65addddSAndroid Build Coastguard Worker            raise Exception(textwrap.dedent('''\
451*a65addddSAndroid Build Coastguard Worker                Expected error {expected_error} but the compiler output did not contain static_assert errors.
452*a65addddSAndroid Build Coastguard Worker                Compiler command line: {compiler_command}
453*a65addddSAndroid Build Coastguard Worker                Error message was:
454*a65addddSAndroid Build Coastguard Worker                {error_message}
455*a65addddSAndroid Build Coastguard Worker                ''').format(expected_error = expected_fruit_error_regex, compiler_command=e.command, error_message = error_message_head))
456*a65addddSAndroid Build Coastguard Worker
457*a65addddSAndroid Build Coastguard Worker        try:
458*a65addddSAndroid Build Coastguard Worker            regex_search_result = re.search(expected_fruit_error_regex, actual_fruit_error)
459*a65addddSAndroid Build Coastguard Worker        except Exception as e:
460*a65addddSAndroid Build Coastguard Worker            raise Exception('re.search() failed for regex \'%s\'' % expected_fruit_error_regex) from e
461*a65addddSAndroid Build Coastguard Worker        if not regex_search_result:
462*a65addddSAndroid Build Coastguard Worker            raise Exception(textwrap.dedent('''\
463*a65addddSAndroid Build Coastguard Worker                The compilation failed as expected, but with a different error type.
464*a65addddSAndroid Build Coastguard Worker                Expected Fruit error type:    {expected_fruit_error_regex}
465*a65addddSAndroid Build Coastguard Worker                Error type was:               {actual_fruit_error}
466*a65addddSAndroid Build Coastguard Worker                Expected static assert error: {expected_fruit_error_desc_regex}
467*a65addddSAndroid Build Coastguard Worker                Static assert was:            {actual_static_assert_error}
468*a65addddSAndroid Build Coastguard Worker                Error message was:
469*a65addddSAndroid Build Coastguard Worker                {error_message}
470*a65addddSAndroid Build Coastguard Worker                '''.format(
471*a65addddSAndroid Build Coastguard Worker                expected_fruit_error_regex = expected_fruit_error_regex,
472*a65addddSAndroid Build Coastguard Worker                actual_fruit_error = actual_fruit_error,
473*a65addddSAndroid Build Coastguard Worker                expected_fruit_error_desc_regex = expected_fruit_error_desc_regex,
474*a65addddSAndroid Build Coastguard Worker                actual_static_assert_error = actual_static_assert_error,
475*a65addddSAndroid Build Coastguard Worker                error_message = error_message_head)))
476*a65addddSAndroid Build Coastguard Worker        try:
477*a65addddSAndroid Build Coastguard Worker            regex_search_result = re.search(expected_fruit_error_desc_regex, actual_static_assert_error)
478*a65addddSAndroid Build Coastguard Worker        except Exception as e:
479*a65addddSAndroid Build Coastguard Worker            raise Exception('re.search() failed for regex \'%s\'' % expected_fruit_error_desc_regex) from e
480*a65addddSAndroid Build Coastguard Worker        if not regex_search_result:
481*a65addddSAndroid Build Coastguard Worker            raise Exception(textwrap.dedent('''\
482*a65addddSAndroid Build Coastguard Worker                The compilation failed as expected, but with a different error message.
483*a65addddSAndroid Build Coastguard Worker                Expected Fruit error type:    {expected_fruit_error_regex}
484*a65addddSAndroid Build Coastguard Worker                Error type was:               {actual_fruit_error}
485*a65addddSAndroid Build Coastguard Worker                Expected static assert error: {expected_fruit_error_desc_regex}
486*a65addddSAndroid Build Coastguard Worker                Static assert was:            {actual_static_assert_error}
487*a65addddSAndroid Build Coastguard Worker                Error message:
488*a65addddSAndroid Build Coastguard Worker                {error_message}
489*a65addddSAndroid Build Coastguard Worker                '''.format(
490*a65addddSAndroid Build Coastguard Worker                expected_fruit_error_regex = expected_fruit_error_regex,
491*a65addddSAndroid Build Coastguard Worker                actual_fruit_error = actual_fruit_error,
492*a65addddSAndroid Build Coastguard Worker                expected_fruit_error_desc_regex = expected_fruit_error_desc_regex,
493*a65addddSAndroid Build Coastguard Worker                actual_static_assert_error = actual_static_assert_error,
494*a65addddSAndroid Build Coastguard Worker                error_message = error_message_head)))
495*a65addddSAndroid Build Coastguard Worker
496*a65addddSAndroid Build Coastguard Worker        # 6 is just a constant that works for both g++ (<=6.0.0 at least) and clang++ (<=4.0.0 at least).
497*a65addddSAndroid Build Coastguard Worker        # It might need to be changed.
498*a65addddSAndroid Build Coastguard Worker        if not disable_error_line_number_check and (actual_fruit_error_line_number > 6 or actual_static_assert_error_line_number > 6):
499*a65addddSAndroid Build Coastguard Worker            raise Exception(textwrap.dedent('''\
500*a65addddSAndroid Build Coastguard Worker                The compilation failed with the expected message, but the error message contained too many lines before the relevant ones.
501*a65addddSAndroid Build Coastguard Worker                The error type was reported on line {actual_fruit_error_line_number} of the message (should be <=6).
502*a65addddSAndroid Build Coastguard Worker                The static assert was reported on line {actual_static_assert_error_line_number} of the message (should be <=6).
503*a65addddSAndroid Build Coastguard Worker                Error message:
504*a65addddSAndroid Build Coastguard Worker                {error_message}
505*a65addddSAndroid Build Coastguard Worker                '''.format(
506*a65addddSAndroid Build Coastguard Worker                actual_fruit_error_line_number = actual_fruit_error_line_number,
507*a65addddSAndroid Build Coastguard Worker                actual_static_assert_error_line_number = actual_static_assert_error_line_number,
508*a65addddSAndroid Build Coastguard Worker                error_message = error_message_head)))
509*a65addddSAndroid Build Coastguard Worker
510*a65addddSAndroid Build Coastguard Worker        for line in error_message_lines[:max(actual_fruit_error_line_number, actual_static_assert_error_line_number)]:
511*a65addddSAndroid Build Coastguard Worker            if re.search('fruit::impl::meta', line):
512*a65addddSAndroid Build Coastguard Worker                raise Exception(
513*a65addddSAndroid Build Coastguard Worker                    'The compilation failed with the expected message, but the error message contained some metaprogramming types in the output (besides Error). Error message:\n%s' + error_message_head)
514*a65addddSAndroid Build Coastguard Worker
515*a65addddSAndroid Build Coastguard Worker    expect_compile_error_helper(check_error, setup_source_code, source_code, test_params, ignore_deprecation_warnings, ignore_warnings)
516*a65addddSAndroid Build Coastguard Worker
517*a65addddSAndroid Build Coastguard Worker
518*a65addddSAndroid Build Coastguard Workerdef expect_runtime_error(
519*a65addddSAndroid Build Coastguard Worker        expected_error_regex,
520*a65addddSAndroid Build Coastguard Worker        setup_source_code,
521*a65addddSAndroid Build Coastguard Worker        source_code,
522*a65addddSAndroid Build Coastguard Worker        test_params={},
523*a65addddSAndroid Build Coastguard Worker        ignore_deprecation_warnings=False):
524*a65addddSAndroid Build Coastguard Worker    """
525*a65addddSAndroid Build Coastguard Worker    Tests that the given source (compiles successfully and) produces the expected error at runtime.
526*a65addddSAndroid Build Coastguard Worker
527*a65addddSAndroid Build Coastguard Worker    :param expected_error_regex: A regex used to match the content of stderr.
528*a65addddSAndroid Build Coastguard Worker           Any identifiers contained in the regex will be replaced using test_params (where a replacement is defined).
529*a65addddSAndroid Build Coastguard Worker    :param setup_source_code: The first part of the source code. This is dedented separately from source_code and it's
530*a65addddSAndroid Build Coastguard Worker           *not* subject to test_params, unlike source_code.
531*a65addddSAndroid Build Coastguard Worker    :param source_code: The second part of the source code. Any identifiers will be replaced using test_params
532*a65addddSAndroid Build Coastguard Worker           (where a replacement is defined). This will be dedented.
533*a65addddSAndroid Build Coastguard Worker    :param test_params: A dict containing the definition of some identifiers. Each identifier in
534*a65addddSAndroid Build Coastguard Worker           expected_error_regex and source_code will be replaced (textually) with its definition (if a definition
535*a65addddSAndroid Build Coastguard Worker           was provided).
536*a65addddSAndroid Build Coastguard Worker    """
537*a65addddSAndroid Build Coastguard Worker    expected_error_regex = _replace_using_test_params(expected_error_regex, test_params)
538*a65addddSAndroid Build Coastguard Worker    source_code = _construct_final_source_code(setup_source_code, source_code, test_params)
539*a65addddSAndroid Build Coastguard Worker
540*a65addddSAndroid Build Coastguard Worker    source_file_name = _create_temporary_file(source_code, file_name_suffix='.cpp')
541*a65addddSAndroid Build Coastguard Worker    executable_suffix = {'posix': '', 'nt': '.exe'}[os.name]
542*a65addddSAndroid Build Coastguard Worker    output_file_name = _create_temporary_file('', executable_suffix)
543*a65addddSAndroid Build Coastguard Worker
544*a65addddSAndroid Build Coastguard Worker    args = fruit_tests_linker_flags.copy()
545*a65addddSAndroid Build Coastguard Worker    if ignore_deprecation_warnings:
546*a65addddSAndroid Build Coastguard Worker        args += compiler.get_disable_deprecation_warning_flags()
547*a65addddSAndroid Build Coastguard Worker    compiler.compile_and_link(
548*a65addddSAndroid Build Coastguard Worker        source=source_file_name,
549*a65addddSAndroid Build Coastguard Worker        include_dirs=fruit_tests_include_dirs,
550*a65addddSAndroid Build Coastguard Worker        output_file_name=output_file_name,
551*a65addddSAndroid Build Coastguard Worker        args=args)
552*a65addddSAndroid Build Coastguard Worker
553*a65addddSAndroid Build Coastguard Worker    try:
554*a65addddSAndroid Build Coastguard Worker        run_compiled_executable(output_file_name)
555*a65addddSAndroid Build Coastguard Worker        raise Exception('The test should have failed at runtime, but it ran successfully')
556*a65addddSAndroid Build Coastguard Worker    except CommandFailedException as e1:
557*a65addddSAndroid Build Coastguard Worker        e = e1
558*a65addddSAndroid Build Coastguard Worker
559*a65addddSAndroid Build Coastguard Worker    stderr = e.stderr
560*a65addddSAndroid Build Coastguard Worker    stderr_head = _cap_to_lines(stderr, 40)
561*a65addddSAndroid Build Coastguard Worker
562*a65addddSAndroid Build Coastguard Worker    if '\n' in expected_error_regex:
563*a65addddSAndroid Build Coastguard Worker        regex_flags = re.MULTILINE
564*a65addddSAndroid Build Coastguard Worker    else:
565*a65addddSAndroid Build Coastguard Worker        regex_flags = 0
566*a65addddSAndroid Build Coastguard Worker
567*a65addddSAndroid Build Coastguard Worker    try:
568*a65addddSAndroid Build Coastguard Worker        regex_search_result = re.search(expected_error_regex, stderr, flags=regex_flags)
569*a65addddSAndroid Build Coastguard Worker    except Exception as e:
570*a65addddSAndroid Build Coastguard Worker        raise Exception('re.search() failed for regex \'%s\'' % expected_error_regex) from e
571*a65addddSAndroid Build Coastguard Worker    if not regex_search_result:
572*a65addddSAndroid Build Coastguard Worker        raise Exception(textwrap.dedent('''\
573*a65addddSAndroid Build Coastguard Worker            The test failed as expected, but with a different message.
574*a65addddSAndroid Build Coastguard Worker            Expected: {expected_error_regex}
575*a65addddSAndroid Build Coastguard Worker            Was:
576*a65addddSAndroid Build Coastguard Worker            {stderr}
577*a65addddSAndroid Build Coastguard Worker            '''.format(expected_error_regex = expected_error_regex, stderr = stderr_head)))
578*a65addddSAndroid Build Coastguard Worker
579*a65addddSAndroid Build Coastguard Worker    # Note that we don't delete the temporary files if the test failed. This is intentional, keeping them around helps debugging the failure.
580*a65addddSAndroid Build Coastguard Worker    if not ENABLE_COVERAGE:
581*a65addddSAndroid Build Coastguard Worker        try_remove_temporary_file(source_file_name)
582*a65addddSAndroid Build Coastguard Worker        try_remove_temporary_file(output_file_name)
583*a65addddSAndroid Build Coastguard Worker
584*a65addddSAndroid Build Coastguard Worker
585*a65addddSAndroid Build Coastguard Workerdef expect_success(setup_source_code, source_code, test_params={}, ignore_deprecation_warnings=False):
586*a65addddSAndroid Build Coastguard Worker    """
587*a65addddSAndroid Build Coastguard Worker    Tests that the given source compiles and runs successfully.
588*a65addddSAndroid Build Coastguard Worker
589*a65addddSAndroid Build Coastguard Worker    :param setup_source_code: The first part of the source code. This is dedented separately from source_code and it's
590*a65addddSAndroid Build Coastguard Worker           *not* subject to test_params, unlike source_code.
591*a65addddSAndroid Build Coastguard Worker    :param source_code: The second part of the source code. Any identifiers will be replaced using test_params
592*a65addddSAndroid Build Coastguard Worker           (where a replacement is defined). This will be dedented.
593*a65addddSAndroid Build Coastguard Worker    :param test_params: A dict containing the definition of some identifiers. Each identifier in
594*a65addddSAndroid Build Coastguard Worker           source_code will be replaced (textually) with its definition (if a definition was provided).
595*a65addddSAndroid Build Coastguard Worker    """
596*a65addddSAndroid Build Coastguard Worker    source_code = _construct_final_source_code(setup_source_code, source_code, test_params)
597*a65addddSAndroid Build Coastguard Worker
598*a65addddSAndroid Build Coastguard Worker    if 'main(' not in source_code:
599*a65addddSAndroid Build Coastguard Worker        source_code += textwrap.dedent('''
600*a65addddSAndroid Build Coastguard Worker            int main() {
601*a65addddSAndroid Build Coastguard Worker            }
602*a65addddSAndroid Build Coastguard Worker            ''')
603*a65addddSAndroid Build Coastguard Worker
604*a65addddSAndroid Build Coastguard Worker    source_file_name = _create_temporary_file(source_code, file_name_suffix='.cpp')
605*a65addddSAndroid Build Coastguard Worker    executable_suffix = {'posix': '', 'nt': '.exe'}[os.name]
606*a65addddSAndroid Build Coastguard Worker    output_file_name = _create_temporary_file('', executable_suffix)
607*a65addddSAndroid Build Coastguard Worker
608*a65addddSAndroid Build Coastguard Worker    args = fruit_tests_linker_flags.copy()
609*a65addddSAndroid Build Coastguard Worker    if ignore_deprecation_warnings:
610*a65addddSAndroid Build Coastguard Worker        args += compiler.get_disable_deprecation_warning_flags()
611*a65addddSAndroid Build Coastguard Worker    compiler.compile_and_link(
612*a65addddSAndroid Build Coastguard Worker        source=source_file_name,
613*a65addddSAndroid Build Coastguard Worker        include_dirs=fruit_tests_include_dirs,
614*a65addddSAndroid Build Coastguard Worker        output_file_name=output_file_name,
615*a65addddSAndroid Build Coastguard Worker        args=args)
616*a65addddSAndroid Build Coastguard Worker
617*a65addddSAndroid Build Coastguard Worker    run_compiled_executable(output_file_name)
618*a65addddSAndroid Build Coastguard Worker
619*a65addddSAndroid Build Coastguard Worker    # Note that we don't delete the temporary files if the test failed. This is intentional, keeping them around helps debugging the failure.
620*a65addddSAndroid Build Coastguard Worker    if not ENABLE_COVERAGE:
621*a65addddSAndroid Build Coastguard Worker        try_remove_temporary_file(source_file_name)
622*a65addddSAndroid Build Coastguard Worker        try_remove_temporary_file(output_file_name)
623*a65addddSAndroid Build Coastguard Worker
624*a65addddSAndroid Build Coastguard Worker
625*a65addddSAndroid Build Coastguard Worker# Note: this is not the main function of this file, it's meant to be used as main function from test_*.py files.
626*a65addddSAndroid Build Coastguard Workerdef main():
627*a65addddSAndroid Build Coastguard Worker    absltest.main(*sys.argv)
628