File: run_unittests.py

package info (click to toggle)
meson 1.10.0-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 24,680 kB
  • sloc: python: 90,528; ansic: 7,377; cpp: 2,434; f90: 482; asm: 218; sh: 143; xml: 109; java: 97; cs: 62; objc: 33; lex: 13; fortran: 12; makefile: 10; yacc: 9; javascript: 6
file content (137 lines) | stat: -rwxr-xr-x 4,609 bytes parent folder | download
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))