1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
# Copyright 2016-2021 The Meson development team
# Work around some pathlib bugs...
from mesonbuild import _pathlib
import sys
sys.modules['pathlib'] = _pathlib
import time
import subprocess
import os
import unittest
import importlib
import typing as T
import mesonbuild.coredata
from mesonbuild.mesonlib import python_command, setup_vsenv
def convert_args(argv):
# If we got passed a list of tests, pass it on
pytest_args = ['-v'] if '-v' in argv else []
test_list = []
for arg in argv:
if arg.startswith('-'):
if arg in ('-f', '--failfast'):
arg = '--exitfirst'
pytest_args.append(arg)
continue
# ClassName.test_name => 'ClassName and test_name'
if '.' in arg:
arg = ' and '.join(arg.split('.'))
test_list.append(arg)
if test_list:
pytest_args += ['-k', ' or '.join(test_list)]
return pytest_args
def running_single_tests(argv, cases):
'''
Check whether we only got arguments for running individual tests, not
entire testcases, and not all testcases (no test args).
'''
got_test_arg = False
for arg in argv:
if arg.startswith('-'):
continue
for case in cases:
if not arg.startswith(case):
continue
if '.' not in arg:
# Got a testcase, done
return False
got_test_arg = True
return got_test_arg
def setup_backend():
filtered = []
be = 'ninja'
for a in sys.argv:
if a.startswith('--backend'):
be = a.split('=')[1]
else:
filtered.append(a)
# Since we invoke the tests via unittest or xtest test runner
# we need to pass the backend to use to the spawned process via
# this side channel. Yes it sucks, but at least is is fully
# internal to this file.
os.environ['MESON_UNIT_TEST_BACKEND'] = be
sys.argv = filtered
def import_test_cases(suite: unittest.TestSuite) -> T.Set[str]:
'''
Imports all test classes into the current module and returns their names
'''
classes = set()
for test in suite:
if isinstance(test, unittest.TestSuite):
classes.update(import_test_cases(test))
elif isinstance(test, unittest.TestCase):
mod = importlib.import_module(test.__module__)
class_name = test.__class__.__name__
test_class = getattr(mod, class_name)
classes.add(class_name)
setattr(sys.modules[__name__], class_name, test_class)
return classes
def discover_test_cases() -> T.Set[str]:
current_dir = os.path.dirname(os.path.realpath(__file__))
loader = unittest.TestLoader()
suite = loader.discover(os.path.join(current_dir, 'unittests'), '*tests.py', current_dir)
if loader.errors:
raise SystemExit(loader.errors)
return import_test_cases(suite)
def main():
cases = sorted(discover_test_cases())
setup_backend()
try:
import pytest # noqa: F401
pytest_args = []
try:
# Need pytest-xdist for `-n` arg
import xdist # noqa: F401
# Don't use pytest-xdist when running single unit tests since it wastes
# time spawning a lot of processes to distribute tests to in that case.
if not running_single_tests(sys.argv, cases):
pytest_args += ['-n', 'auto']
except ImportError:
print('pytest-xdist not found, tests will not be distributed across CPU cores')
# Let there be colors!
if 'CI' in os.environ:
pytest_args += ['--color=yes']
pytest_args += ['unittests']
pytest_args += convert_args(sys.argv[1:])
# Always disable pytest-cov because we use a custom setup
try:
import pytest_cov # noqa: F401
print('Disabling pytest-cov')
pytest_args += ['-p' 'no:cov']
except ImportError:
pass
return subprocess.run(python_command + ['-m', 'pytest'] + pytest_args).returncode
except ImportError:
print('pytest not found, using unittest instead')
# Fallback to plain unittest.
return unittest.main(defaultTest=cases, buffer=True)
if __name__ == '__main__':
setup_vsenv()
print('Meson build system', mesonbuild.coredata.version, 'Unit Tests')
start = time.monotonic()
try:
raise SystemExit(main())
finally:
print('Total time: {:.3f} seconds'.format(time.monotonic() - start))
|