mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 07:03:25 +00:00
* Implement coverage for Windows/Linux/MacOS (#126) * reverted --------- Co-authored-by: Saikari <lin@sz.cn.eu.org>
This commit is contained in:
169
scripts/coverage-llvm.sh
Executable file
169
scripts/coverage-llvm.sh
Executable file
@@ -0,0 +1,169 @@
|
||||
#!/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}"
|
||||
Reference in New Issue
Block a user