-
Notifications
You must be signed in to change notification settings - Fork 0
/
make_test.py
executable file
·170 lines (125 loc) · 4.63 KB
/
make_test.py
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
#!/bin/python
from os import listdir, isatty
from os.path import splitext, join, getmtime
from subprocess import Popen, PIPE, check_output, run
from sys import stderr as err
from ansi2html import Ansi2HTMLConverter as Converter
from html import unescape
from bs4 import BeautifulSoup
import pytest_html
TEST_DIR = "tests"
PKG = check_output(("pkg-config", "--cflags", "--libs", "python3")).decode().split(' ')[:-1]
MAKE_CMD = ("g++", "-g3", "-Wall", "-Wextra", "-Werror", "-pedantic", "-std=c++17", \
"-I.", "-DTRACEBACK", "-fdiagnostics-color=always", *PKG)
#MAKE_CMD += ("-DPYDEBUG_CONST",)
# files used in every test and that need to be compiled and liked statically
invariant_files = ("python.hh", "backtrace.hh", "backtrace.cc")
invariant_time = max([getmtime(file) for file in invariant_files])
# convert .cc -> .o with error check
def make_o(cc: str, dir: str = "") -> str:
if dir:
cc = join(dir, cc)
name = "%s.o" %splitext(cc)[0]
# just compile if doesn't exist
try:
t = getmtime(cc)
# if file not changed, don't compile back
if t >= invariant_time and t >= getmtime(cc):
return name
except:
pass
cmd = MAKE_CMD + ("-c", "-o", name, cc)
p = Popen(cmd, stderr = PIPE)
stderr = p.communicate()[1]
if p.returncode != 0:
print(stderr.decode(), file = err)
exit(1)
if dir:
return join(dir, name)
return name
# source files in the invariant files
o_files = ("backtrace.cc",)
o_compiled = [make_o(file) for file in o_files]
header = """
from os import isatty
from os.path import splitext, join, getmtime
from subprocess import Popen, PIPE
from sys import stdout as out, stderr as err
from pytest import fail
from logging import info, INFO
# return the content in green bold if fd is a tty
def green(content: str, fd: int):
if isatty(fd):
return "\033[38;5;35;1m%s\033[0m" %content
return content
# return the content in red bold if fd is a tty
def red(content: str, fd: int):
if isatty(fd):
return "\033[38;5;196;1m%s\033[0m" %content
return content
# report a failed test
def fail_test(name: str, content: str):
print("%s: %s" %(name, red("FAILED", out.fileno())))
fail("In test %s:\\n%s" %(name, content))
# generate .cc -> binary with error check
def make_binary(cc: str, dir: str = ""):
if dir:
cc = join(dir, cc)
name = splitext(cc)[0]
# just compile if file doesn't exist
try:
t = getmtime(name)
# if file not changed, don't compile back
if t >= invariant_time and t >= getmtime(cc):
return name
except FileNotFoundError:
pass
cmd = MAKE_CMD + ("-o", name, cc, *o_compiled)
p = Popen(cmd, stderr = PIPE)
stderr = p.communicate()[1]
if p.returncode != 0:
fail_test(name, stderr.decode())
if dir:
join(dir, name)
return name
# execute binary with error check
def exec(binary: str):
# FIXME: some outputs are not passed (like print or err)
p = Popen(("./%s" %binary), stdout = PIPE, stderr = PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
fail_test(binary, "\\n%s" %stderr.decode())
print("%s: %s" %(binary, green("PASSED", out.fileno())))
info("\\n%s" %stdout.decode())
"""
# generate tests.py, the file in which all tests are put
with open("tests.py", 'w') as f:
print("MAKE_CMD = %s" %str(MAKE_CMD), file = f)
print("o_compiled = %s" %o_compiled, file = f)
print("invariant_time = %s" %invariant_time, file = f)
print("")
print(header, file = f)
for file in listdir(TEST_DIR):
parts = splitext(file)
if parts[1] == ".cc":
print("def test_%s():" %parts[0], file = f)
print("\tbin = make_binary(\"%s\", \"%s\")" %(file, TEST_DIR), file = f)
print("\texec(bin)\n", file = f)
run(["pytest",
"-s", # disable capturing
"--tb=no", # disable traceback (we only care about stderr)
"--disable-pytest-warnings", # disable internal warnings
"--html=test_report.html", # enable html output
"tests.py"])
# rewrite the html report to transform ansi into html
with open("test_report.html") as f:
report = f.read()
with open("test_report.html", 'w') as f:
c = Converter()
page = BeautifulSoup(report, "html.parser")
head = page.find("head")
for e in page.find_all("div"):
converted = BeautifulSoup(unescape(c.convert(str(e))), "html.parser")
head.contents.extend(converted.find("head").contents)
e.contents = converted.find("div").contents
f.write(str(page))