Skip to content

Commit 48ff28a

Browse files
etc: add etc/code-coverage-test-*.py
1 parent 76d4c59 commit 48ff28a

File tree

2 files changed

+258
-0
lines changed

2 files changed

+258
-0
lines changed

etc/code-coverage-test-c.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#!/usr/bin/env python
2+
"""
3+
"""
4+
5+
# pylint: disable=invalid-name, broad-except
6+
7+
import argparse
8+
import tempfile
9+
import subprocess
10+
import sys
11+
import os
12+
import webbrowser
13+
14+
from os.path import exists, isfile
15+
16+
_ERR_PREFIX = '\033[31merror: '
17+
18+
def exec_string(string):
19+
'execute the string in a subprocess.'
20+
try:
21+
subprocess.check_call(string, shell=True)
22+
except KeyboardInterrupt:
23+
sys.exit('\033[31m\nKilled!\033[0m')
24+
except (subprocess.CalledProcessError, OSError):
25+
sys.exit(_ERR_PREFIX + 'executing:\n' + string + '\n failed!\033[0m')
26+
27+
_PARSER = argparse.ArgumentParser(prog='code-coverage-test-c.py',
28+
usage='%(prog)s [options]')
29+
_PARSER.add_argument('files', nargs='+', type=str,
30+
help='the test files you want to check code coverage for'
31+
+ '(must be at least one)')
32+
_PARSER.add_argument('--gap-root', nargs='?', type=str,
33+
help='the gap root directory (default: ~/gap)',
34+
default='~/gap/')
35+
_PARSER.add_argument('--pkg', nargs='?', type=str,
36+
help='the package to profile (default: None)',
37+
default=None)
38+
_PARSER.add_argument('--build', dest='build', action='store_true',
39+
help='rebuild GAP (default: False)')
40+
_PARSER.set_defaults(build=False)
41+
_PARSER.add_argument('--open', nargs='?', type=str,
42+
help=('open the lcov html page for this file ' +
43+
'(default: None)'),
44+
default=None)
45+
_PARSER.add_argument('--line', nargs='?', type=str,
46+
help=('open the html page for the file specified by --open' +
47+
' at this line (default: None)'),
48+
default=None)
49+
_ARGS = _PARSER.parse_args()
50+
51+
if not _ARGS.gap_root[-1] == '/':
52+
_ARGS.gap_root += '/'
53+
54+
_ARGS.gap_root = os.path.expanduser(_ARGS.gap_root)
55+
if _ARGS.pkg != None:
56+
_ARGS.pkg = _ARGS.gap_root + '/pkg/' + _ARGS.pkg
57+
58+
if not (os.path.exists(_ARGS.gap_root) and os.path.isdir(_ARGS.gap_root)):
59+
sys.exit('\033[31mcode-coverage-test-c.py: error: can\'t find gap root' +
60+
' directory!\033[0m')
61+
if (_ARGS.pkg != None and not (os.path.exists(_ARGS.pkg) and
62+
os.path.isdir(_ARGS.pkg))):
63+
sys.exit('\033[31mcode-coverage-test-c.py: error: can\'t find the pkg' +
64+
' directory %s\033[0m' % _ARGS.pkg)
65+
for f in _ARGS.files:
66+
if not (os.path.exists(f) and os.path.isfile(f)):
67+
sys.exit('\033[31mcode-coverage-test-c.py: error: ' + f +
68+
' does not exist!\033[0m')
69+
70+
_DIR = tempfile.mkdtemp()
71+
print('\033[35musing temporary directory: ' + _DIR + '\033[0m')
72+
73+
_COMMANDS = 'echo "'
74+
for f in _ARGS.files:
75+
_COMMANDS += 'Test(\\"' + f + '\\");;'
76+
_COMMANDS += '"'
77+
78+
# TODO build if files changed since last build or built with the wrong flags,
79+
# by looking in config.log
80+
81+
# for source in :
82+
# if time.ctime(os.path.getmtime(file))
83+
84+
if _ARGS.build:
85+
cwd = os.getcwd()
86+
os.chdir(_ARGS.gap_root)
87+
exec_string('''rm -rf bin/ && \
88+
make clean && \
89+
./configure CFLAGS="-O0 -g --coverage" \
90+
CXXFLAGS="-O0 -g --coverage" \
91+
LDFLAGS="-O0 -g --coverage" && \
92+
make -j8''')
93+
if _ARGS.pkg != None:
94+
os.chdir(_ARGS.pkg)
95+
exec_string('rm -rf bin/ && \
96+
make clean && \
97+
./configure CFLAGS="-O0 -g --coverage" \
98+
CXXFLAGS="-O0 -g --coverage" \
99+
LDFLAGS="-O0 -g --coverage" && \
100+
make -j8''')
101+
os.chdir(cwd)
102+
103+
pro1 = subprocess.Popen(_COMMANDS, stdout=subprocess.PIPE, shell=True)
104+
_RUN_GAP = _ARGS.gap_root + 'bin/gap.sh -A -m 1g -T'
105+
106+
try:
107+
pro2 = subprocess.Popen(_RUN_GAP,
108+
stdin=pro1.stdout,
109+
shell=True)
110+
pro2.wait()
111+
print('')
112+
except KeyboardInterrupt:
113+
pro1.terminate()
114+
pro1.wait()
115+
pro2.terminate()
116+
pro2.wait()
117+
print('\033[31mKilled!\033[0m')
118+
sys.exit(1)
119+
except Exception:
120+
sys.exit('\033[31mcode-coverage-test-c.py: error: something went wrong '
121+
+ 'calling GAP!\033[0m''')
122+
if _ARGS.pkg != None:
123+
exec_string('lcov --capture --directory ' + _ARGS.pkg +
124+
'/src --output-file ' + _DIR + '/lcov.info')
125+
else:
126+
exec_string('lcov --capture --directory ' + _ARGS.gap_root +
127+
'/src --output-file ' + _DIR + '/lcov.info')
128+
129+
exec_string('genhtml ' + _DIR + '/lcov.info --output-directory ' + _DIR +
130+
'/lcov-out')
131+
132+
filename = _DIR + '/lcov-out/'
133+
if _ARGS.open:
134+
filename += _ARGS.open + '.gcov.html'
135+
else:
136+
filename += '/index.html'
137+
138+
if exists(filename) and isfile(filename):
139+
if _ARGS.open and _ARGS.line:
140+
filename += '#' + _ARGS.line
141+
print('file://' + filename)
142+
try:
143+
webbrowser.get('chrome').open('file://' + filename, new=2)
144+
except Exception:
145+
webbrowser.open('file://' + filename, new=2)
146+
else:
147+
sys.exit('\n' + _ERR_PREFIX + 'Failed to open file://' + filename +
148+
'\033[0m')
149+
150+
print('\n\033[32mSUCCESS!\033[0m')
151+
sys.exit(0)

etc/code-coverage-test-gap.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env python3
2+
"""
3+
This is a simple script to run code coverage for some test files.
4+
"""
5+
# pylint: disable=invalid-name
6+
7+
import argparse
8+
import os
9+
import re
10+
import subprocess
11+
import sys
12+
import tempfile
13+
14+
from os.path import exists, isdir, isfile
15+
from os import getcwd
16+
17+
_ERR_PREFIX = "\033[31mcode-coverage-test-gap.py: error: "
18+
_INFO_PREFIX = "\033[0m\033[1m"
19+
20+
_PARSER = argparse.ArgumentParser(
21+
prog="code-coverage-test-gap.py", usage="%(prog)s [options]"
22+
)
23+
_PARSER.add_argument(
24+
"tstfiles",
25+
nargs="+",
26+
type=str,
27+
help="the test files you want to check code coverage for"
28+
+ "(must be at least one)",
29+
)
30+
_PARSER.add_argument(
31+
"--gap-root",
32+
nargs="?",
33+
type=str,
34+
help="the gap root directory (default: ~/gap)",
35+
default="~/gap/",
36+
)
37+
_PARSER.add_argument(
38+
"--open",
39+
nargs="?",
40+
type=str,
41+
help=("open the html page for this file (default: None)"),
42+
default=None,
43+
)
44+
45+
_ARGS = _PARSER.parse_args()
46+
if not _ARGS.gap_root[-1] == "/":
47+
_ARGS.gap_root += "/"
48+
49+
if exists("gap") and isdir("gap"):
50+
_PROFILE_DIR = "/gap/"
51+
elif exists("lib") and isdir("lib"):
52+
_PROFILE_DIR = "/lib/"
53+
else:
54+
sys.exit(f"{_ERR_PREFIX}no directory gap or lib to profile!\033[0m")
55+
56+
_ARGS.gap_root = os.path.expanduser(_ARGS.gap_root)
57+
if not (exists(_ARGS.gap_root) and isdir(_ARGS.gap_root)):
58+
sys.exit(f"{_ERR_PREFIX}can't find GAP root directory!\033[0m")
59+
60+
for f in _ARGS.tstfiles:
61+
if not (exists(f) and isfile(f)):
62+
sys.exit(f"{_ERR_PREFIX}{f} does not exist!\033[0m")
63+
64+
_DIR = tempfile.mkdtemp()
65+
print(f"{_INFO_PREFIX}Using temporary directory: {_DIR}\033[0m")
66+
67+
_COMMANDS = 'echo "'
68+
_COMMANDS += "".join(rf"Test(\"{f}\");;\n" for f in _ARGS.tstfiles)
69+
_COMMANDS += rf"""UncoverageLineByLine();;
70+
LoadPackage(\"profiling\", false);;
71+
filesdir := \"{getcwd()}{_PROFILE_DIR}\";;\n"""
72+
73+
_COMMANDS += rf"outdir := \"{_DIR}\";;\n"
74+
_COMMANDS += rf"x := ReadLineByLineProfile(\"{_DIR}/profile.gz\");;\n"
75+
_COMMANDS += 'OutputAnnotatedCodeCoverageFiles(x, filesdir, outdir);"'
76+
77+
_RUN_GAP = f"{_ARGS.gap_root}/gap -A -m 1g -T --cover {_DIR}/profile.gz"
78+
79+
with subprocess.Popen(_COMMANDS, stdout=subprocess.PIPE, shell=True) as pro1:
80+
try:
81+
with subprocess.Popen(_RUN_GAP, stdin=pro1.stdout, shell=True) as pro2:
82+
pro2.wait()
83+
except KeyboardInterrupt:
84+
pro1.terminate()
85+
pro1.wait()
86+
sys.exit("\033[31mKilled!\033[0m")
87+
except (subprocess.CalledProcessError, IOError, OSError):
88+
sys.exit(_ERR_PREFIX + "Something went wrong calling GAP!\033[0m")
89+
90+
91+
def rewrite_fname(fname: str) -> str:
92+
return fname.replace("/", "_")
93+
94+
95+
suffix = ""
96+
if _ARGS.open:
97+
filename = f"{_DIR}/{rewrite_fname(getcwd())}/{rewrite_fname(_ARGS.open)}.html"
98+
p = re.compile(r"<tr class='missed'><td><a name=\"line(\d+)\">")
99+
with open(filename, "r", encoding="utf-8") as f:
100+
m = p.search(f.read())
101+
if m:
102+
suffix += "#line" + m.group(1)
103+
else:
104+
filename = _DIR + "/index.html"
105+
print(f"{_INFO_PREFIX}\nSUCCESS!\033[0m")
106+
print(f"{_INFO_PREFIX} See {filename}")
107+
sys.exit(0)

0 commit comments

Comments
 (0)