Skip to content

Commit 2b9bf5b

Browse files
committed
coverage: fix lcov baseline
1 parent 8ce740a commit 2b9bf5b

File tree

1 file changed

+114
-72
lines changed

1 file changed

+114
-72
lines changed

tools/coverage/lcov.sh

Lines changed: 114 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,29 @@ set -euo pipefail
44
set -o noglob
55

66
usage() {
7-
echo " -b TARGET_BASELINE The target used to collect the baseline"
8-
echo " -t TARGET_TESTS The test target"
9-
echo " -c CACHE The path to the bazel cache"
7+
echo "Usage:"
8+
echo " -b TARGET_BASELINE The target used to collect the baseline (-b \"target_1 target_2\")"
9+
echo " -t TARGET_TESTS The test target (-t \"target_1 target_2\")"
10+
echo " -c GCNO_DIR The path to the gcno files"
11+
echo " -d GCDA_DIR The path to the gcda files"
1012
echo " -s SKIP_HTML_REPORT Skip generation of HTML coverage report (default: false)."
1113
echo " -o OUTPUT_DIR Directory for output (default is temp directory)"
1214
echo " -h Display this help message"
1315
}
1416

17+
create_directory() {
18+
local dir="$1"
19+
if [ ! -d "$dir" ]; then
20+
echo "INFO: Creating directory: $dir"
21+
mkdir -p "$dir"
22+
fi
23+
}
24+
25+
# Parse options
1526
while getopts "b:t:c:d:o:sh" option; do
1627
case "${option}" in
17-
b) TARGET_BASELINE=${OPTARG} ;;
18-
t) TARGET_TESTS=${OPTARG} ;;
28+
b) TARGET_BASELINE+=(${OPTARG}) ;;
29+
t) TARGET_TESTS+=(${OPTARG}) ;;
1930
c) GCNO_DIR=${OPTARG} ;;
2031
d) GCDA_DIR=${OPTARG} ;;
2132
s) SKIP_HTML_REPORT=true ;;
@@ -27,120 +38,151 @@ while getopts "b:t:c:d:o:sh" option; do
2738
esac
2839
done
2940

30-
if [[ -z "${TARGET_TESTS+x}" ]]; then
41+
# Validate required arguments
42+
if [[ -z "${TARGET_TESTS+x}" || -z "${GCNO_DIR+x}" || -z "${GCDA_DIR+x}" ]]; then
3143
echo "ERROR: Missing required arguments."
3244
usage
3345
exit 1
3446
fi
3547

36-
if [[ -z "${GCNO_DIR+x}" || -z "${GCDA_DIR+x}" ]]; then
37-
echo "ERROR: Missing required directories for .gcno or .gcda files."
38-
usage
39-
exit 1
40-
fi
41-
48+
# Set defaults
4249
SKIP_HTML_REPORT="${SKIP_HTML_REPORT:-false}"
43-
EXCLUDE_PATTERN="external/*|*gtest/*|/usr/*"
50+
EXCLUDE_PATTERN="external|gtest|/usr"
4451
TARGET_BASELINE="${TARGET_BASELINE:-"${TARGET_TESTS}"}"
4552
OUTPUT_DIR="${OUTPUT_DIR:-"$(mktemp -d)/cov_report"}"
46-
TARGET_DIR="${OUTPUT_DIR}/gcno_gcda"
47-
mkdir -p "${TARGET_DIR}"
53+
FILTERED_GCNO_DIR="${OUTPUT_DIR}/gcno"
54+
FILTERED_GCDA_DIR="${OUTPUT_DIR}/gcda"
55+
56+
create_directory "$OUTPUT_DIR"
57+
create_directory "$FILTERED_GCNO_DIR"
58+
create_directory "$FILTERED_GCDA_DIR"
4859

4960
echo "INFO: Baseline target: ${TARGET_BASELINE}"
50-
echo "INFO: Tests target: ${TARGET_TESTS}"
61+
echo "INFO: Test target: ${TARGET_TESTS}"
5162
echo "INFO: Output directory: ${OUTPUT_DIR}"
5263

5364
readonly WORKSPACE=$(cd "$(dirname "$(readlink -f "${0}")")" && bazel info workspace)
5465

55-
function run_baseline() {
56-
echo "\nINFO: Build baseline"
57-
echo "Baseline target: ${TARGET_BASELINE}"
66+
run_baseline() {
67+
echo -e "\nINFO: Building baseline target: ${TARGET_BASELINE}"
5868
bazel build \
5969
--collect_code_coverage \
6070
--experimental_fetch_all_coverage_outputs \
61-
-- ${TARGET_BASELINE}
71+
--cxxopt="-O0" \
72+
-- "${TARGET_BASELINE}"
6273
}
6374

64-
function run_coverage_tests() {
65-
echo "\nINFO: Run test"
66-
echo "Test target: ${TARGET_TESTS}"
75+
run_coverage_tests() {
76+
echo -e "\nINFO: Running test target: ${TARGET_TESTS}"
6777
bazel coverage \
6878
--nocache_test_results \
6979
--experimental_fetch_all_coverage_outputs \
7080
--cxxopt="-O0" \
71-
-- ${TARGET_TESTS}
81+
--instrumentation_filter="[/:]" \
82+
-- "${TARGET_TESTS}"
7283
}
7384

74-
function generate_hashed_name() {
75-
local file_path="$1"
76-
local extension="${file_path##*.}" # Get the file extension (e.g., .gcno or .gcda)
77-
local path_no_extension="${file_path%".$extension"}" # Remove extension
78-
path_in_root=$(echo "$path_no_extension" | sed 's/.*\(bin\/.*\)/\1/') # Get file name from bin
79-
local hash=$(echo -n "$path_in_root" | sha256sum | awk '{print $1}') # Apply hash
80-
echo "$hash.$extension" # Return the hashed name with the original extension
85+
delete_coverage_files() {
86+
echo -e "\nINFO: Cleaning old .gcno and .gcda files"
87+
local directories=("${GCNO_DIR}" "${GCDA_DIR}" "${FILTERED_GCNO_DIR}" "${FILTERED_GCDA_DIR}")
88+
for dir in "${directories[@]}"; do
89+
find "$dir" -name "*.gcno" -exec chmod +w {} \; || true
90+
find "$dir" -name "*.gcda" -exec chmod +w {} \; || true
91+
find "$dir" -name "*.gcno" -exec rm -f {} \; || true
92+
find "$dir" -name "*.gcda" -exec rm -f {} \; || true
93+
done
8194
}
8295

83-
function delete_coverage_files() {
84-
echo "\nINFO: Clean old .gcno and .gcda files"
85-
echo "Input directory: $TARGET_DIR"
86-
find "$TARGET_DIR" -name "*.gcno" -exec rm -f {} \;
87-
find "$TARGET_DIR" -name "*.gcda" -exec rm -f {} \;
96+
generate_hashed_name() {
97+
local file_path="$1"
98+
local extension="${file_path##*.}"
99+
local path_no_extension="${file_path%.$extension}"
100+
local path_in_bin=$(echo "$path_no_extension" | awk -F"bin" "{print substr(\$0, length(\$1\"bin\") + 1)}")
101+
local hash=$(echo -n "$path_in_bin" | sha256sum | awk "{print \$1}")
102+
echo "$hash.$extension"
88103
}
89104

90-
function collect_coverage_data() {
91-
echo "\nINFO: Copy hashed .gcno and .gcda files"
92-
echo "Input gcno directory: $GCNO_DIR"
93-
echo "Input gcda directory: $GCDA_DIR"
94-
echo "Output dir: $TARGET_DIR"
105+
copy_coverage_files() {
106+
echo -e "\nINFO: Copy hashed .gcno and .gcda files"
107+
echo "Input directory: $1"
108+
echo "Output dir: $2"
95109
echo "Exclude pattern: $EXCLUDE_PATTERN"
96110

97-
find "$GCDA_DIR" -name "*.gcda" ! -path "$EXCLUDE_PATTERN" | while read -r file; do
98-
new_name=$(generate_hashed_name "$file" "$GCDA_DIR")
99-
cp "$file" "$TARGET_DIR/$new_name"
100-
echo "Copied gcda: $file -> $TARGET_DIR/$new_name"
101-
done
111+
mkdir -p "$2"
102112

103-
find "$GCNO_DIR" -name "*.gcno" ! -path "$EXCLUDE_PATTERN" | while read -r file; do
104-
new_name=$(generate_hashed_name "$file" "$GCNO_DIR")
105-
cp "$file" "$TARGET_DIR/$new_name"
106-
echo "Copied gcno: $file -> $TARGET_DIR/$new_name"
113+
find "$1" -type f \( -name "*.gcda" -o -name "*.gcno" \) ! -path "*/external/*" ! -path "*gtest*" ! -path "*test*" | while IFS= read -r file; do
114+
new_name=$(generate_hashed_name "$file" "$1")
115+
cp "$file" "$2/$new_name"
116+
echo "Copied: $file -> $2/$new_name"
107117
done
108118
}
109119

110-
function calculate_coverage() {
111-
echo "\nINFO: Generate coverage data"
112-
echo "Output directory: $OUTPUT_DIR"
113-
lcov --directory "$TARGET_DIR" \
120+
main() {
121+
pushd "${WORKSPACE}" || return
122+
123+
bazel clean
124+
delete_coverage_files
125+
run_baseline
126+
# copy_coverage_files "${GCNO_DIR}" "${FILTERED_GCNO_DIR}"
127+
FILTERED_GCNO_DIR="${GCNO_DIR}"
128+
FILTERED_GCDA_DIR="${GCDA_DIR}"
129+
130+
echo -e "\nINFO: Create baseline.info"
131+
lcov \
132+
--directory "${FILTERED_GCNO_DIR}" \
133+
--capture \
134+
-i \
135+
--output-file "${OUTPUT_DIR}/baseline.info"
136+
137+
echo -e "\nINFO: Filter baseline.info"
138+
lcov \
139+
--directory "${FILTERED_GCNO_DIR}" \
140+
--remove "${OUTPUT_DIR}/baseline.info" \
141+
'/usr/*' \
142+
'*external/*' \
143+
'*gtest*' \
144+
--ignore-errors unused \
145+
--ignore-errors empty \
146+
--output-file "${OUTPUT_DIR}/baseline_filtered.info"
147+
sed -i 's|/proc/self/cwd/||g' "${OUTPUT_DIR}/baseline_filtered.info"
148+
149+
run_coverage_tests
150+
# copy_coverage_files "${GCDA_DIR}" "${FILTERED_GCDA_DIR}"
151+
152+
echo -e "\nINFO: Create tests.info"
153+
lcov \
154+
--directory "${FILTERED_GCDA_DIR}" \
114155
--capture \
115156
--ignore-errors source \
116-
--output-file "${OUTPUT_DIR}/coverage.info"
117-
lcov --remove "${OUTPUT_DIR}/coverage.info" \
157+
--output-file "${OUTPUT_DIR}/tests.info"
158+
159+
echo -e "\nINFO: Filter tests.info"
160+
lcov \
161+
--directory "${FILTERED_GCDA_DIR}" \
162+
--remove "${OUTPUT_DIR}/tests.info" \
118163
'/usr/*' \
119164
'external/*' \
120165
'*gtest*' \
121166
--ignore-errors unused \
122167
--ignore-errors source \
123-
--output-file "${OUTPUT_DIR}/coverage_filtered.info"
124-
sed -i 's|/proc/self/cwd/||g' "${OUTPUT_DIR}/coverage_filtered.info" # Remove file prefix
168+
--output-file "${OUTPUT_DIR}/tests_filtered.info"
169+
sed -i 's|/proc/self/cwd/||g' "${OUTPUT_DIR}/tests_filtered.info"
170+
171+
echo -e "\nINFO: Merge baseline and tests coverage report"
172+
lcov \
173+
-a "${OUTPUT_DIR}/baseline_filtered.info" \
174+
-a "${OUTPUT_DIR}/tests_filtered.info" \
175+
-o "${OUTPUT_DIR}/coverage.info"
125176

126177
if [ "${SKIP_HTML_REPORT}" = false ]; then
127-
echo "\nINFO: Generate HTML coverage report"
128-
genhtml "${OUTPUT_DIR}/coverage_filtered.info" \
129-
--ignore-errors source \
130-
--output-directory "$OUTPUT_DIR"
178+
echo -e "\nINFO: Generating HTML coverage report"
179+
genhtml "${OUTPUT_DIR}/coverage.info" \
180+
--output-directory "${OUTPUT_DIR}"
131181
else
132-
echo "\nINFO: Generate coverage summary"
133-
lcov --summary "${OUTPUT_DIR}/coverage_filtered.info"
182+
echo -e "\nINFO: Generating coverage summary"
183+
lcov --summary "${OUTPUT_DIR}/coverage.info"
134184
fi
135-
}
136185

137-
function main() {
138-
pushd "${WORKSPACE}" || return
139-
run_baseline
140-
run_coverage_tests
141-
delete_coverage_files
142-
collect_coverage_data
143-
calculate_coverage
144186
popd || return
145187
}
146188

0 commit comments

Comments
 (0)