-
Notifications
You must be signed in to change notification settings - Fork 956
Expand file tree
/
Copy pathcoverage-report.sh
More file actions
executable file
·161 lines (147 loc) · 5.13 KB
/
Copy pathcoverage-report.sh
File metadata and controls
executable file
·161 lines (147 loc) · 5.13 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
#!/usr/bin/env bash
# Generate an HTML coverage report at coverage-html/index.html
# Run from anywhere; defaults: build dir = build-coverage, output = coverage-html/
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BUILD_DIR="${COVERAGE_BUILD_DIR:-$ROOT/build-coverage}"
HTML_DIR="${COVERAGE_HTML_DIR:-$ROOT/coverage-html}"
INFO_FILE="${COVERAGE_INFO_FILE:-$ROOT/lcov.info}"
JOBS="${JOBS:-$(nproc)}"
need_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "Error: required command not found: $1" >&2
exit 1
}
}
need_cmd cmake
need_cmd lcov
need_cmd genhtml
need_cmd gcc
# lcov defaults to gcov-11 on Ubuntu; use gcov matching the active compiler.
detect_gcov_tool() {
local ver
ver="$(gcc -dumpversion 2>/dev/null | cut -d. -f1)"
if [[ -n "$ver" ]] && command -v "gcov-${ver}" >/dev/null 2>&1; then
echo "gcov-${ver}"
else
echo "gcov"
fi
}
GCOV_TOOL="$(detect_gcov_tool)"
# lcov 1.14 (Ubuntu 22.04) supports different --ignore-errors vocabularies
# per tool: geninfo (gcov,source,graph), genhtml (source only), lcov also
# gcov,source,graph. lcov 1.15+ adds mismatch,unused,format,deprecated.
# Probe each tool's own help and pick the intersection with what we want.
detect_ignore_categories_for() {
local tool="$1"
local wanted=(gcov source graph mismatch unused)
local help_line
# Each tool prints "(gcov, source, graph)" style inside its --help.
help_line="$("$tool" --help 2>&1 | grep -m1 -- '--ignore-errors')"
local available=()
if [[ "$help_line" =~ \(([^\)]+)\) ]]; then
IFS=', ' read -r -a available <<<"${BASH_REMATCH[1]}"
fi
local supported=()
for w in "${wanted[@]}"; do
for a in "${available[@]}"; do
if [[ "$w" == "$a" ]]; then
supported+=("$w")
break
fi
done
done
# Fallback if parsing failed: source is the only one universally accepted.
if [[ ${#supported[@]} -eq 0 ]]; then
supported=(source)
fi
(IFS=,; echo "${supported[*]}")
}
LCOV_IGNORE=(--ignore-errors "$(detect_ignore_categories_for lcov)")
GENHTML_IGNORE=(--ignore-errors "$(detect_ignore_categories_for genhtml)")
configure_coverage_build() {
local -a gtest_args=()
if [[ -d "$ROOT/build/_deps/googletest-src" ]]; then
gtest_args+=(
"-DFETCHCONTENT_SOURCE_DIR_GOOGLETEST=$ROOT/build/_deps/googletest-src"
-DFETCHCONTENT_UPDATES_DISCONNECTED=ON
)
fi
cmake -B "$BUILD_DIR" \
-DCMAKE_BUILD_TYPE=Debug \
-DENABLE_COVERAGE=ON \
-DBUILD_TESTING=ON \
-DBUILD_APP=OFF \
-DBUILD_TOOLS=OFF \
-DBUILD_EXAMPLES=OFF \
-DWITH_QT=OFF \
-DWITH_PYTHON=OFF \
-DWITH_CERES=OFF \
-DWITH_G2O=OFF \
-DWITH_GTSAM=OFF \
-DWITH_MRPT=OFF \
-DWITH_VERTIGO=OFF \
-DWITH_CVSBA=OFF \
-DWITH_POINTMATCHER=OFF \
-DWITH_CCCORELIB=OFF \
-DWITH_OPEN3D=OFF \
-DWITH_LOAM=OFF \
-DWITH_FLOAM=OFF \
-DWITH_LIOSAM=OFF \
-DWITH_FLYCAPTURE2=OFF \
-DWITH_ZED=OFF \
-DWITH_ZEDOC=OFF \
-DWITH_REALSENSE=OFF \
"${gtest_args[@]}"
}
if [[ ! -f "$BUILD_DIR/CMakeCache.txt" ]]; then
echo "Configuring $BUILD_DIR (Debug + ENABLE_COVERAGE)..."
configure_coverage_build
elif ! grep -q '^ENABLE_COVERAGE:BOOL=ON' "$BUILD_DIR/CMakeCache.txt" 2>/dev/null; then
echo "Reconfiguring $BUILD_DIR with ENABLE_COVERAGE=ON..."
configure_coverage_build
fi
echo "Building $BUILD_DIR (gcov tool: $GCOV_TOOL)..."
cmake --build "$BUILD_DIR" -j"$JOBS"
echo "Clearing old coverage runtime data..."
find "$BUILD_DIR" -name '*.gcda' -delete
echo "Running tests..."
# Prepend coverage libs: otherwise LD_LIBRARY_PATH (e.g. ROS) can load
# librtabmap from another build tree and .gcda is never written for corelib/src.
(
export LD_LIBRARY_PATH="$BUILD_DIR/bin${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
cd "$BUILD_DIR" && ctest --output-on-failure
)
echo "Capturing coverage..."
# The whole of corelib/utilite, test objects included, not just their src/. An inline
# function defined in a header is emitted in whichever translation unit wins comdat
# folding, which is often a test one, and its counters then live in that unit's .gcda:
# capturing only src/ reports such a function as uncovered however often it is called.
# The test sources themselves are dropped below, after the counters are read.
lcov --gcov-tool "$GCOV_TOOL" "${LCOV_IGNORE[@]}" \
--capture \
--directory "$BUILD_DIR/corelib" \
--directory "$BUILD_DIR/utilite" \
--output-file "$INFO_FILE"
echo "Filtering coverage data (repo sources only)..."
lcov "${LCOV_IGNORE[@]}" --extract "$INFO_FILE" \
"${ROOT}/*" \
--output-file "$INFO_FILE"
# The test sources are the instrument, not the subject: a line in a test counts
# as uncovered only when the test skipped it (a defensive cleanup branch, a
# platform guard), which says nothing about the library. They are also
# near-fully covered by construction, so leaving them in inflates the overall
# number. Kept in sync with the same list in .github/workflows/coverage.yml.
lcov "${LCOV_IGNORE[@]}" --remove "$INFO_FILE" \
'*/sqlite3/*' \
'*/rtflann/*' \
'*/corelib/test/*' \
'*/utilite/test/*' \
'*/_deps/*' \
--output-file "$INFO_FILE"
echo "Generating HTML..."
rm -rf "$HTML_DIR"
genhtml "${GENHTML_IGNORE[@]}" "$INFO_FILE" --output-directory "$HTML_DIR" --legend --demangle-cpp
echo ""
echo "Done: $HTML_DIR/index.html"
lcov --summary "$INFO_FILE" 2>/dev/null || true