Skip to content

Commit 02da0a0

Browse files
authored
Merge pull request #1463 from centricular/test-has-include-fallback
tests/37 has header: Also test the fallback include check
2 parents 1612dbd + f427603 commit 02da0a0

File tree

3 files changed

+101
-59
lines changed

3 files changed

+101
-59
lines changed

run_project_tests.py

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import os, subprocess, shutil, sys, signal
1919
from io import StringIO
2020
from ast import literal_eval
21+
from enum import Enum
2122
import tempfile
2223
import mesontest
2324
from mesonbuild import environment
@@ -33,9 +34,17 @@
3334

3435
from mesonbuild.coredata import backendlist
3536

37+
class BuildStep(Enum):
38+
configure = 1
39+
build = 2
40+
test = 3
41+
install = 4
42+
clean = 5
43+
3644
class TestResult:
37-
def __init__(self, msg, stdo, stde, mlog, conftime=0, buildtime=0, testtime=0):
45+
def __init__(self, msg, step, stdo, stde, mlog, conftime=0, buildtime=0, testtime=0):
3846
self.msg = msg
47+
self.step = step
3948
self.stdo = stdo
4049
self.stde = stde
4150
self.mlog = mlog
@@ -74,6 +83,7 @@ def __exit__(self, _type, value, traceback):
7483
failing_logs = []
7584
print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ
7685
do_debug = not {'MESON_PRINT_TEST_OUTPUT', 'TRAVIS', 'APPVEYOR'}.isdisjoint(os.environ)
86+
no_meson_log_msg = 'No meson-log.txt found.'
7787

7888
meson_command = os.path.join(os.getcwd(), 'meson')
7989
if not os.path.exists(meson_command):
@@ -270,14 +280,14 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_c
270280
with open(logfile, errors='ignore') as f:
271281
mesonlog = f.read()
272282
except Exception:
273-
mesonlog = 'No meson-log.txt found.'
283+
mesonlog = no_meson_log_msg
274284
gen_time = time.time() - gen_start
275285
if should_fail == 'meson':
276286
if returncode != 0:
277-
return TestResult('', stdo, stde, mesonlog, gen_time)
278-
return TestResult('Test that should have failed succeeded', stdo, stde, mesonlog, gen_time)
287+
return TestResult('', BuildStep.configure, stdo, stde, mesonlog, gen_time)
288+
return TestResult('Test that should have failed succeeded', BuildStep.configure, stdo, stde, mesonlog, gen_time)
279289
if returncode != 0:
280-
return TestResult('Generating the build system failed.', stdo, stde, mesonlog, gen_time)
290+
return TestResult('Generating the build system failed.', BuildStep.configure, stdo, stde, mesonlog, gen_time)
281291
# Build with subprocess
282292
comp = get_compile_commands_for_dir(compile_commands, test_build_dir)
283293
build_start = time.time()
@@ -287,10 +297,10 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_c
287297
stde += e
288298
if should_fail == 'build':
289299
if pc.returncode != 0:
290-
return TestResult('', stdo, stde, mesonlog, gen_time)
291-
return TestResult('Test that should have failed to build succeeded', stdo, stde, mesonlog, gen_time)
300+
return TestResult('', BuildStep.build, stdo, stde, mesonlog, gen_time)
301+
return TestResult('Test that should have failed to build succeeded', BuildStep.build, stdo, stde, mesonlog, gen_time)
292302
if pc.returncode != 0:
293-
return TestResult('Compiling source code failed.', stdo, stde, mesonlog, gen_time, build_time)
303+
return TestResult('Compiling source code failed.', BuildStep.build, stdo, stde, mesonlog, gen_time, build_time)
294304
# Touch the meson.build file to force a regenerate so we can test that
295305
# regeneration works. We need to sleep for 0.2s because Ninja tracks mtimes
296306
# at a low resolution: https://github.com/ninja-build/ninja/issues/371
@@ -304,29 +314,29 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_c
304314
stde += tstde
305315
if should_fail == 'test':
306316
if returncode != 0:
307-
return TestResult('', stdo, stde, mesonlog, gen_time)
308-
return TestResult('Test that should have failed to run unit tests succeeded', stdo, stde, mesonlog, gen_time)
317+
return TestResult('', BuildStep.test, stdo, stde, mesonlog, gen_time)
318+
return TestResult('Test that should have failed to run unit tests succeeded', BuildStep.test, stdo, stde, mesonlog, gen_time)
309319
if returncode != 0:
310-
return TestResult('Running unit tests failed.', stdo, stde, mesonlog, gen_time, build_time, test_time)
320+
return TestResult('Running unit tests failed.', BuildStep.test, stdo, stde, mesonlog, gen_time, build_time, test_time)
311321
if len(install_commands) == 0:
312-
return TestResult('', '', '', gen_time, build_time, test_time)
322+
return TestResult('', BuildStep.install, '', '', mesonlog, gen_time, build_time, test_time)
313323
env = os.environ.copy()
314324
env['DESTDIR'] = install_dir
315325
# Install with subprocess
316326
pi, o, e = Popen_safe(install_commands, cwd=test_build_dir, env=env)
317327
stdo += o
318328
stde += e
319329
if pi.returncode != 0:
320-
return TestResult('Running install failed.', stdo, stde, mesonlog, gen_time, build_time, test_time)
330+
return TestResult('Running install failed.', BuildStep.install, stdo, stde, mesonlog, gen_time, build_time, test_time)
321331
if len(clean_commands) != 0:
322332
env = os.environ.copy()
323333
# Clean with subprocess
324334
pi, o, e = Popen_safe(clean_commands, cwd=test_build_dir, env=env)
325335
stdo += o
326336
stde += e
327337
if pi.returncode != 0:
328-
return TestResult('Running clean failed.', stdo, stde, mesonlog, gen_time, build_time, test_time)
329-
return TestResult(validate_install(testdir, install_dir), stdo, stde, mesonlog, gen_time, build_time, test_time)
338+
return TestResult('Running clean failed.', BuildStep.clean, stdo, stde, mesonlog, gen_time, build_time, test_time)
339+
return TestResult(validate_install(testdir, install_dir), BuildStep.clean, stdo, stde, mesonlog, gen_time, build_time, test_time)
330340

331341
def gather_tests(testdir):
332342
tests = [t.replace('\\', '/').split('/', 2)[2] for t in glob(os.path.join(testdir, '*'))]
@@ -441,10 +451,16 @@ def run_tests(all_tests, log_name_base, extra_args):
441451
else:
442452
without_install = "" if len(install_commands) > 0 else " (without install)"
443453
if result.msg != '':
444-
print('Failed test%s: %s' % (without_install, t))
454+
print('Failed test{} during {}: {!r}'.format(without_install, result.step.name, t))
445455
print('Reason:', result.msg)
446456
failing_tests += 1
447-
failing_logs.append(result.stdo)
457+
if result.step == BuildStep.configure and result.mlog != no_meson_log_msg:
458+
# For configure failures, instead of printing stdout,
459+
# print the meson log if available since it's a superset
460+
# of stdout and often has very useful information.
461+
failing_logs.append(result.mlog)
462+
else:
463+
failing_logs.append(result.stdo)
448464
failing_logs.append(result.stde)
449465
else:
450466
print('Succeeded test%s: %s' % (without_install, t))

run_unittests.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -356,16 +356,31 @@ def setUp(self):
356356
self.unit_test_dir = os.path.join(src_root, 'test cases/unit')
357357
self.orig_env = os.environ.copy()
358358

359+
def _print_meson_log(self):
360+
log = os.path.join(self.logdir, 'meson-log.txt')
361+
if not os.path.isfile(log):
362+
print("{!r} doesn't exist".format(log))
363+
return
364+
with open(log, 'r', encoding='utf-8') as f:
365+
print(f.read())
366+
359367
def tearDown(self):
360368
shutil.rmtree(self.builddir)
361369
os.environ = self.orig_env
362370
super().tearDown()
363371

364372
def _run(self, command):
365-
output = subprocess.check_output(command, stderr=subprocess.STDOUT,
366-
env=os.environ.copy(),
367-
universal_newlines=True)
373+
'''
374+
Run a command while printing the stdout and stderr to stdout,
375+
and also return a copy of it
376+
'''
377+
p = subprocess.Popen(command, stdout=subprocess.PIPE,
378+
stderr=subprocess.STDOUT, env=os.environ.copy(),
379+
universal_newlines=True)
380+
output = p.communicate()[0]
368381
print(output)
382+
if p.returncode != 0:
383+
raise subprocess.CalledProcessError(p.returncode, command)
369384
return output
370385

371386
def init(self, srcdir, extra_args=None, default_args=True):
@@ -375,7 +390,11 @@ def init(self, srcdir, extra_args=None, default_args=True):
375390
if default_args:
376391
args += ['--prefix', self.prefix,
377392
'--libdir', self.libdir]
378-
self._run(self.meson_command + args + extra_args)
393+
try:
394+
self._run(self.meson_command + args + extra_args)
395+
except:
396+
self._print_meson_log()
397+
raise
379398
self.privatedir = os.path.join(self.builddir, 'meson-private')
380399

381400
def build(self, extra_args=None):
@@ -394,11 +413,11 @@ def uninstall(self):
394413
self._run(self.ninja_command + ['uninstall'])
395414

396415
def run_target(self, target):
397-
output = subprocess.check_output(self.ninja_command + [target],
398-
stderr=subprocess.STDOUT,
399-
universal_newlines=True)
400-
print(output)
401-
return output
416+
'''
417+
Run a Ninja target while printing the stdout and stderr to stdout,
418+
and also return a copy of it
419+
'''
420+
return self._run(self.ninja_command + [target])
402421

403422
def setconf(self, arg, will_build=True):
404423
# This is needed to increase the difference between build.ninja's

test cases/common/37 has header/meson.build

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,46 @@ configure_file(input : non_existant_header,
99
output : non_existant_header,
1010
configuration : configuration_data())
1111

12-
foreach comp : [meson.get_compiler('c'), meson.get_compiler('cpp')]
13-
if not comp.has_header('stdio.h')
14-
error('Stdio missing.')
15-
endif
16-
17-
# stdio.h doesn't actually need stdlib.h, but just test that setting the
18-
# prefix does not result in an error.
19-
if not comp.has_header('stdio.h', prefix : '#include <stdlib.h>')
20-
error('Stdio missing.')
21-
endif
22-
23-
# XInput.h should not require type definitions from windows.h, but it does
24-
# require macro definitions. Specifically, it requires an arch setting for
25-
# VS2015 at least.
26-
# We only do this check on MSVC because MinGW often defines its own wrappers
27-
# that pre-include windows.h
28-
if comp.get_id() == 'msvc'
29-
if not comp.has_header('XInput.h', prefix : '#include <windows.h>')
30-
error('XInput.h should not be missing on Windows')
12+
# Test that the fallback to __has_include also works on all compilers
13+
if host_system != 'darwin'
14+
args = [[], ['-U__has_include']]
15+
else
16+
# On Darwin's clang you can't redefine builtin macros so the above doesn't work
17+
args = [[]]
18+
endif
19+
20+
foreach arg : args
21+
foreach comp : [meson.get_compiler('c'), meson.get_compiler('cpp')]
22+
assert(comp.has_header('stdio.h', args : arg), 'Stdio missing.')
23+
24+
# stdio.h doesn't actually need stdlib.h, but just test that setting the
25+
# prefix does not result in an error.
26+
assert(comp.has_header('stdio.h', prefix : '#include <stdlib.h>', args : arg),
27+
'Stdio missing.')
28+
29+
# XInput.h should not require type definitions from windows.h, but it does
30+
# require macro definitions. Specifically, it requires an arch setting for
31+
# VS2015 at least.
32+
# We only do this check on MSVC because MinGW often defines its own wrappers
33+
# that pre-include windows.h
34+
if comp.get_id() == 'msvc'
35+
assert(comp.has_header('XInput.h', prefix : '#include <windows.h>', args : arg),
36+
'XInput.h should not be missing on Windows')
37+
assert(comp.has_header('XInput.h', prefix : '#define _X86_', args : arg),
38+
'XInput.h should not need windows.h')
3139
endif
32-
if not comp.has_header('XInput.h', prefix : '#define _X86_')
33-
error('XInput.h should not need windows.h')
40+
41+
# Test that the following GCC bug doesn't happen:
42+
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80005
43+
# https://github.com/mesonbuild/meson/issues/1458
44+
if host_system == 'linux'
45+
assert(comp.has_header('linux/if.h', args : arg),
46+
'Could not find <linux/if.h>')
3447
endif
35-
endif
36-
37-
# Test that the following GCC bug doesn't happen:
38-
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80005
39-
# https://github.com/mesonbuild/meson/issues/1458
40-
if host_system == 'linux'
41-
assert(comp.has_header('linux/if.h'), 'Could not find <linux/if.h>')
42-
endif
43-
44-
# This header exists in the source and the builddir, but we still must not
45-
# find it since we are looking in the system directories.
46-
assert(not comp.has_header(non_existant_header), 'Found non-existant header.')
48+
49+
# This header exists in the source and the builddir, but we still must not
50+
# find it since we are looking in the system directories.
51+
assert(not comp.has_header(non_existant_header, args : arg),
52+
'Found non-existant header.')
53+
endforeach
4754
endforeach

0 commit comments

Comments
 (0)