File: run_tests.py

package info (click to toggle)
clazy 1.17-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,248 kB
  • sloc: cpp: 23,552; python: 1,450; xml: 450; sh: 237; makefile: 46
file content (182 lines) | stat: -rwxr-xr-x 6,612 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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/usr/bin/env python3
import queue
import sys
import os
import re
import threading
import multiprocessing
import argparse
from threading import Thread

from testutils.checks import Check
from testutils import Args
from testutils.commands import dump_ast_command
from testutils.run_unittest import run_unit_tests
from testutils.run_fixit import run_fixit_tests
from testutils.os_utils import get_command_output, run_command
from testutils.checks import load_checks
from testutils.qtinstallation import qt_installation


# cd into the folder containing this script
os.chdir(os.path.realpath(os.path.dirname(sys.argv[0])))

def compiler_name():
    if 'CLAZY_CXX' in os.environ:
        return os.environ['CLAZY_CXX']  # so we can set clazy.bat instead
    return os.getenv('CLANGXX', 'clang')

# Setup argparse
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", action='store_true')
parser.add_argument("--no-standalone", action='store_true',
                    help="Don\'t run clazy-standalone")
parser.add_argument("--no-clang-tidy", action='store_true',
                    help="Don\'t run clang-tidy")
parser.add_argument("--no-fixits", action='store_true',
                    help='Don\'t run fixits')
parser.add_argument("--only-standalone", action='store_true',
                    help='Only run clazy-standalone')
parser.add_argument("--dump-ast", action='store_true',
                    help='Dump a unit-test AST to file')
parser.add_argument("--qt-versions", type=int, choices=[5, 6], nargs='+', default=[5, 6],
                    help='Specify one or more Qt versions to use (default: 5 and 6)')
parser.add_argument(
    "--exclude", help='Comma separated list of checks to ignore')
parser.add_argument("-j", "--jobs", type=int, default=multiprocessing.cpu_count(),
                    help='Parallel jobs to run (defaults to %(default)s)')
parser.add_argument("check_names", nargs='*',
                    help="The name of the check whose unit-tests will be run. Defaults to running all checks.")
parser.add_argument("--cxx-args", type=str, default="",
                    help="Compiler arguments as a single string")
parser.add_argument("--qt-namespaced", action="store_true",
                    help="Compile tests pretending Qt is namespaced using QT_NAMESPACE")
args = Args(**vars(parser.parse_args()))
if args.only_standalone and args.no_standalone:
    print("Error: --only-standalone is incompatible with --no-standalone")
    sys.exit(1)
# -------------------------------------------------------------------------------
# Global variables

_num_threads = args.jobs
_lock = threading.Lock()
any_version_found = False
if 6 in args.qt_versions and qt_installation(6, args.verbose).int_version != 0:
    any_version_found = True
if 5 in args.qt_versions and qt_installation(5, args.verbose).int_version != 0:
    any_version_found = True
if not any_version_found:
    sys.exit(1)

_excluded_checks = args.exclude.split(',') if args.exclude is not None else []

# -------------------------------------------------------------------------------
# utility functions #2

version, success = get_command_output(compiler_name() + ' --version', args.verbose)
match = re.search('clang version ([^\\s-]+)', version)
try:
    version = match.group(1)
except:
    # Now try the Clazy.AppImage way
    match = re.search('clang version: (.*)', version)
    try:
        version = match.group(1)
    except:
        splitted = version.split()
        if len(splitted) > 2:
            version = splitted[2]
        else:
            print("Could not determine clang version, is it in PATH?")
            sys.exit(-1)

if args.verbose:
    print('Found clang version: ' + str(version))

CLANG_VERSION = int(version.replace('git', '').replace('.', ''))
args.clang_version = CLANG_VERSION


def get_check_names():
    return list(filter(lambda entry: os.path.isdir(entry), os.listdir(".")))

def cleanup_fixit_files(checks):
    for check in checks:
        filestodelete = list(filter(lambda entry: entry.endswith(
            '.fixed') or entry.endswith('.yaml'), os.listdir(check.name)))
        for f in filestodelete:
            os.remove(check.name + '/' + f)

def dump_ast(check: Check):
    for test in check.tests:
        for cppStandard in test.cppStandards:
            for version in test.qt_major_versions:
                if version == 6 and cppStandard == "c++14":
                    continue # Qt6 requires C++17
                ast_filename = test.filename + f"_{cppStandard}_{version}.ast"
                run_command(dump_ast_command(test, cppStandard, version) + " > " + ast_filename)
                print("Dumped AST to " + os.getcwd() + "/" + ast_filename)


if 'CLAZY_NO_WERROR' in os.environ:
    del os.environ['CLAZY_NO_WERROR']

os.environ['CLAZY_CHECKS'] = ''

all_check_names = get_check_names()
all_checks = load_checks(all_check_names, CLANG_VERSION)
requested_check_names = args.check_names
requested_check_names = list(
    map(lambda x: x.strip("/\\"), requested_check_names))

for check_name in requested_check_names:
    if check_name not in all_check_names:
        print("Unknown check: " + check_name)
        sys.exit(-1)

if not requested_check_names:
    requested_check_names = all_check_names

requested_checks = list(filter(
    lambda check: check.name in requested_check_names and check.name not in _excluded_checks, all_checks))
requested_checks = list(filter(
    lambda check: check.minimum_clang_version <= CLANG_VERSION, requested_checks))

threads = []
finished_job_results: queue.Queue[bool] = queue.Queue()
if args.dump_ast:
    for check in requested_checks:
        os.chdir(check.name)
        dump_ast(check)
        os.chdir("..")
else:
    cleanup_fixit_files(requested_checks)
    # Each list is a list of Test to be worked on by a thread
    list_of_chunks = [[] for _ in range(_num_threads)]
    i = _num_threads
    for check in requested_checks:
        for test in check.tests:
            i = (i + 1) % _num_threads
            list_of_chunks[i].append(test)

    for tests in list_of_chunks:
        if not tests:
            continue

        t = Thread(target=run_unit_tests, args=(tests, args, finished_job_results))
        t.start()
        threads.append(t)

for thread in threads:
    thread.join()

if not args.no_fixits and not run_fixit_tests(requested_checks, args):
    finished_job_results.put(False)

overall_success = all(finished_job_results.get() for _ in range(finished_job_results.qsize()))
if overall_success:
    print("SUCCESS")
    sys.exit(0)
else:
    print("FAIL")
    sys.exit(-1)