mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 23:13:26 +00:00
* Implement coverage for Windows/Linux/MacOS (#126) * reverted --------- Co-authored-by: Saikari <lin@sz.cn.eu.org>
170 lines
5.2 KiB
Bash
Executable File
170 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# scripts/coverage-llvm.sh
|
|
# LLVM coverage script that generates LCOV-style reports
|
|
|
|
set -e
|
|
|
|
SOURCE_DIR="${1:-.}"
|
|
BINARY_DIR="${2:-cmake-build/build}"
|
|
TEST_BINARY="${3:-}"
|
|
OUTPUT_DIR="${4:-${BINARY_DIR}/coverage}"
|
|
|
|
echo "[*] Source dir: ${SOURCE_DIR}"
|
|
echo "[*] Binary dir: ${BINARY_DIR}"
|
|
echo "[*] Output dir: ${OUTPUT_DIR}"
|
|
|
|
# Find llvm tools - handle versioned names (Linux) and xcrun (macOS)
|
|
find_llvm_tool() {
|
|
local tool_name="$1"
|
|
|
|
# macOS: use xcrun
|
|
if [[ "$(uname)" == "Darwin" ]]; then
|
|
if xcrun --find "${tool_name}" &>/dev/null; then
|
|
echo "xcrun ${tool_name}"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
# Try versioned names (Linux with LLVM 21, 20, 19, etc.)
|
|
for version in 21 20 19 18 17 ""; do
|
|
local versioned_name="${tool_name}${version:+-$version}"
|
|
if command -v "${versioned_name}" &>/dev/null; then
|
|
echo "${versioned_name}"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
return 1
|
|
}
|
|
|
|
LLVM_PROFDATA=$(find_llvm_tool "llvm-profdata")
|
|
LLVM_COV=$(find_llvm_tool "llvm-cov")
|
|
|
|
if [[ -z "${LLVM_PROFDATA}" ]] || [[ -z "${LLVM_COV}" ]]; then
|
|
echo "Error: llvm-profdata or llvm-cov not found" >&2
|
|
echo "On Linux, install llvm or clang package" >&2
|
|
echo "On macOS, Xcode command line tools should provide these" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "[*] Using: ${LLVM_PROFDATA}"
|
|
echo "[*] Using: ${LLVM_COV}"
|
|
|
|
# Find test binary
|
|
if [[ -z "${TEST_BINARY}" ]]; then
|
|
for path in \
|
|
"${SOURCE_DIR}/out/Debug/unit_tests" \
|
|
"${SOURCE_DIR}/out/Release/unit_tests" \
|
|
"${BINARY_DIR}/unit_tests" \
|
|
"${BINARY_DIR}/tests/unit_tests"; do
|
|
if [[ -x "${path}" ]]; then
|
|
TEST_BINARY="${path}"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
if [[ -z "${TEST_BINARY}" ]] || [[ ! -x "${TEST_BINARY}" ]]; then
|
|
echo "Error: unit_tests binary not found" >&2
|
|
echo "Searched in: out/Debug, out/Release, ${BINARY_DIR}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "[*] Test binary: ${TEST_BINARY}"
|
|
|
|
# Clean previous coverage data
|
|
rm -rf "${OUTPUT_DIR}"
|
|
rm -f "${BINARY_DIR}"/*.profraw "${BINARY_DIR}"/*.profdata
|
|
mkdir -p "${OUTPUT_DIR}"
|
|
|
|
# Run tests with profiling enabled
|
|
PROFILE_FILE="${BINARY_DIR}/default_%p.profraw"
|
|
echo "[*] Running tests with LLVM_PROFILE_FILE=${PROFILE_FILE}"
|
|
|
|
export LLVM_PROFILE_FILE="${PROFILE_FILE}"
|
|
"${TEST_BINARY}" || echo "[!] Some tests failed, continuing with coverage..."
|
|
|
|
# Find all generated .profraw files
|
|
PROFRAW_FILES=$(find "${BINARY_DIR}" -name "*.profraw" -type f 2>/dev/null)
|
|
if [[ -z "${PROFRAW_FILES}" ]]; then
|
|
# Also check current directory
|
|
PROFRAW_FILES=$(find . -maxdepth 3 -name "*.profraw" -type f 2>/dev/null)
|
|
fi
|
|
|
|
if [[ -z "${PROFRAW_FILES}" ]]; then
|
|
echo "Error: No .profraw files generated" >&2
|
|
echo "Make sure the binary was built with -fprofile-instr-generate -fcoverage-mapping" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "[*] Found profraw files:"
|
|
echo "${PROFRAW_FILES}"
|
|
|
|
# Merge profiles
|
|
PROFDATA_FILE="${BINARY_DIR}/coverage.profdata"
|
|
echo "[*] Merging profiles into ${PROFDATA_FILE}"
|
|
${LLVM_PROFDATA} merge -sparse ${PROFRAW_FILES} -o "${PROFDATA_FILE}"
|
|
|
|
# Generate text summary
|
|
echo "[*] Coverage Summary:"
|
|
${LLVM_COV} report "${TEST_BINARY}" \
|
|
-instr-profile="${PROFDATA_FILE}" \
|
|
-ignore-filename-regex="tests/.*" \
|
|
-ignore-filename-regex="googletest/.*" \
|
|
-ignore-filename-regex="gtest/.*" \
|
|
-ignore-filename-regex="_deps/.*" \
|
|
-ignore-filename-regex="vcpkg_installed/.*"
|
|
|
|
# Export lcov format (for tools like codecov)
|
|
LCOV_FILE="${OUTPUT_DIR}/coverage.lcov"
|
|
echo "[*] Exporting LCOV format to ${LCOV_FILE}"
|
|
${LLVM_COV} export "${TEST_BINARY}" \
|
|
-instr-profile="${PROFDATA_FILE}" \
|
|
-format=lcov \
|
|
-ignore-filename-regex="tests/.*" \
|
|
-ignore-filename-regex="googletest/.*" \
|
|
-ignore-filename-regex="gtest/.*" \
|
|
-ignore-filename-regex="_deps/.*" \
|
|
-ignore-filename-regex="vcpkg_installed/.*" \
|
|
> "${LCOV_FILE}" || true
|
|
|
|
# Generate LCOV-style HTML report using genhtml
|
|
if command -v genhtml >/dev/null 2>&1; then
|
|
echo "[*] Generating LCOV-style HTML report using genhtml"
|
|
genhtml "${LCOV_FILE}" \
|
|
--ignore-errors inconsistent,corrupt \
|
|
--output-directory "${OUTPUT_DIR}" \
|
|
--title "Omath Coverage Report" \
|
|
--show-details \
|
|
--legend \
|
|
--demangle-cpp \
|
|
--num-spaces 4 \
|
|
--sort \
|
|
--function-coverage \
|
|
--branch-coverage
|
|
|
|
echo "[*] LCOV-style HTML report generated at: ${OUTPUT_DIR}/index.html"
|
|
else
|
|
echo "[!] genhtml not found. Installing lcov package..."
|
|
echo "[!] On Ubuntu/Debian: sudo apt-get install lcov"
|
|
echo "[!] On macOS: brew install lcov"
|
|
echo "[!] Falling back to LLVM HTML report..."
|
|
|
|
# Fall back to LLVM HTML report
|
|
${LLVM_COV} show "${TEST_BINARY}" \
|
|
-instr-profile="${PROFDATA_FILE}" \
|
|
-format=html \
|
|
-output-dir="${OUTPUT_DIR}" \
|
|
-show-line-counts-or-regions \
|
|
-show-instantiations=false \
|
|
-ignore-filename-regex="tests/.*" \
|
|
-ignore-filename-regex="googletest/.*" \
|
|
-ignore-filename-regex="gtest/.*" \
|
|
-ignore-filename-regex="_deps/.*" \
|
|
-ignore-filename-regex="vcpkg_installed/.*"
|
|
fi
|
|
|
|
echo "[*] Coverage report generated at: ${OUTPUT_DIR}/index.html"
|
|
echo "[*] LCOV file at: ${LCOV_FILE}"
|