-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtestcoverage.sh
More file actions
executable file
·163 lines (141 loc) · 5.4 KB
/
Copy pathtestcoverage.sh
File metadata and controls
executable file
·163 lines (141 loc) · 5.4 KB
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
#!/bin/sh
# SPDX-FileCopyrightText: © 2017-2026 Adrian Johnston.
# SPDX-License-Identifier: MIT
# This file is licensed under the terms of the LICENSE.md file.
trap 'trap "" INT; pkill -9 -P $$ 2>/dev/null; wait 2>/dev/null; exit 1' INT
set -eu
HX_DIR_=$PWD
HX_GCOV_=gcov-$(gcc -dumpversion)
# Uncalled functions are kept because dead code in a template library is missing
# line coverage waiting to bite.
HX_COVERAGE_="--coverage -O0 -g -fprofile-update=atomic -fno-inline -fkeep-static-functions"
HX_COVERAGE_CXX_="$HX_COVERAGE_ -fno-elide-constructors -fkeep-inline-functions"
HXUSAGE_="usage: $0 [--verbose] [destination-directory]"
HX_VERBOSE_=
HX_DEST_DIR_=
for HX_ARG_ in "$@"; do
if [ "$HX_ARG_" = "--verbose" ]; then
HX_VERBOSE_=1
elif [ -n "$HX_ARG_" ]; then
case "$HX_ARG_" in
-*)
echo "$HXUSAGE_" >&2
exit 1 ;;
/*) HX_DEST_DIR_="$HX_ARG_" ;;
*) HX_DEST_DIR_="$HX_DIR_/$HX_ARG_" ;;
esac
case "$HX_DEST_DIR_" in
*/) ;;
*) HX_DEST_DIR_="$HX_DEST_DIR_/" ;;
esac
fi
done
[ -n "$HX_DEST_DIR_" ] || HX_DEST_DIR_="$HX_DIR_/build/"
if [ -n "$HX_VERBOSE_" ]; then
set -o xtrace
fi
# Build artifacts are not retained.
rm -rf "$(readlink -f build)" build; ln -s "$(mktemp -d)" build && cd build
gcc -I"$HX_DIR_"/include $HX_COVERAGE_ -DHX_HARDENING_MODE=HX_HARDENING_MODE_DEBUG \
-DHX_USE_INLINING_ATTR=0 -std=c99 -Wall -Werror -Wfatal-errors -pthread -c \
"$HX_DIR_"/test/*.c & HX_PIDS_="$!"
for HX_FILE_ in "$HX_DIR_"/src/*.cpp "$HX_DIR_"/test/*.cpp; do
g++ -I"$HX_DIR_"/include $HX_COVERAGE_CXX_ -DHX_HARDENING_MODE=HX_HARDENING_MODE_DEBUG \
-DHX_TEST_ERROR_HANDLING=1 -DHX_USE_CONSOLE=2 -DHX_USE_PROFILER=1 -DHX_USE_LIBCXX=0 \
-DHX_USE_INLINING_ATTR=0 -std=c++23 -Wall -Werror -Wextra -Wfatal-errors \
-fno-exceptions -Wno-c2y-extensions -Wno-unknown-warning-option -pthread -nostdinc++ \
-c "$HX_FILE_" -o "$(basename "$HX_FILE_" .cpp).o" & HX_PIDS_="$HX_PIDS_ $!"
done
for HX_PID_ in $HX_PIDS_; do wait "$HX_PID_" || exit 1; done
g++ --coverage *.o -lpthread -o hxtest
if [ -n "$HX_VERBOSE_" ]; then
echo runtests | ./hxtest help execstdin
else
if ! echo runtests | ./hxtest help execstdin > console_output.txt 2>&1; then
cat console_output.txt
echo "error: hxtest non-zero exit."
exit 1
fi
fi
mkdir -p "$HX_DEST_DIR_"
# Line coverage.
HX_STATUS_=0
gcovr --gcov-executable $HX_GCOV_ --gcov-object-directory . --exclude-throw-branches \
--exclude-unreachable-branches --exclude-noncode-lines --exclude-lines-by-pattern \
.*hxassert.* --exclude-branches-by-pattern .*hxassert.* --root $HX_DIR_ \
--html-details "${HX_DEST_DIR_}0coverage.html" --html-self-contained --json \
coverage.json --txt-metric branch --print-summary --fail-under-line 100 . || HX_STATUS_=$?
{ set +o xtrace; } 2> /dev/null
# Branch coverage. Restricted to .gcda files produced by test/*.cpp and test/*.c
# translation units.
mkdir branches_only
for HX_SRC_ in "$HX_DIR_"/test/*.cpp "$HX_DIR_"/test/*.c; do
HX_BASE_=$(basename "$HX_SRC_")
HX_BASE_=${HX_BASE_%.*}
for HX_GCDA_ in *"$HX_BASE_".gcda; do
[ -e "$HX_GCDA_" ] && ln -s "../$HX_GCDA_" "branches_only/$HX_GCDA_"
HX_GCNO_=${HX_GCDA_%.gcda}.gcno
[ -e "$HX_GCNO_" ] && ln -s "../$HX_GCNO_" "branches_only/$HX_GCNO_"
done
done
gcovr --gcov-executable "$HX_GCOV_" --gcov-object-directory branches_only \
--exclude-throw-branches --exclude-unreachable-branches --exclude-noncode-lines \
--exclude-lines-by-pattern .*hxassert.* --exclude-branches-by-pattern .*hxassert.* \
--root "$HX_DIR_" --json coverage_test_branches.json . > /dev/null || HX_STATUS_=$?
# Line coverage. A script is required because the gcovr text output includes
# remarks about suppressed lines.
if [ "$HX_STATUS_" -ne 0 ]; then
python3 - coverage.json <<'EOF'
import json, sys
files = json.load(open(sys.argv[1]))["files"]
for f in sorted(files, key=lambda x: x["file"]):
numbers = sorted(l["line_number"] for l in f["lines"]
if l["count"] == 0 and not l.get("gcovr/excluded"))
if not numbers:
continue
spans, start, prev = [], numbers[0], numbers[0]
for n in numbers[1:] + [None]:
if n == prev + 1:
prev = n
continue
spans.append(str(start) if start == prev else "%d-%d" % (start, prev))
start = prev = n
print("%s:%s" % (f["file"], ",".join(spans)))
EOF
fi
# Branch coverage. Post-processing is required to merge multiple instantiations.
# This is load bearing.
python3 - coverage_test_branches.json <<'HX_EOF_' || HX_STATUS_=$?
import json, sys
files = json.load(open(sys.argv[1]))["files"]
missing = False
for f in sorted(files, key=lambda x: x["file"]):
if "/include/" not in ("/" + f["file"]) and "/src/" not in ("/" + f["file"]):
continue
numbers = sorted(l["line_number"] for l in f["lines"]
if not l.get("gcovr/excluded")
and any(b["count"] == 0 for b in l.get("branches", [])))
if not numbers:
continue
missing = True
spans, start, prev = [], numbers[0], numbers[0]
for n in numbers[1:] + [None]:
if n == prev + 1:
prev = n
continue
spans.append(str(start) if start == prev else "%d-%d" % (start, prev))
start = prev = n
print("%s:%s" % (f["file"], ",".join(spans)))
sys.exit(1 if missing else 0)
HX_EOF_
if [ "$HX_STATUS_" -ne 0 ]; then
echo "error: Missing coverage."
exit 1
fi
# Launch Chrome if it is installed.
if [ -n "$HX_VERBOSE_" ] && which google-chrome; then
set -o xtrace
google-chrome "${HX_DEST_DIR_}coverage_details.html" >/dev/null 2>&1;
fi
# Make sure the script returns 0.
echo "🪓🪓🪓"