#!/bin/bash
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
COVERAGE_THRESHOLD=${1:-50}
TIMEOUT=240
OUTPUT_FORMAT="Html"
REPORT_FILE="tarpaulin-report.html"
CHECKLIST_FILE="docs/coverage/checklist.md"
print_info() {
echo -e "${BLUE}ℹ️ $1${NC}"
}
print_success() {
echo -e "${GREEN}✅ $1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_error() {
echo -e "${RED}❌ $1${NC}"
}
print_header() {
echo ""
echo -e "${BLUE}================================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}================================================${NC}"
echo ""
}
show_help() {
echo "用法: $0 [覆盖率阈值]"
echo ""
echo "参数:"
echo " 覆盖率阈值 期望的最低覆盖率百分比 (默认: 50)"
echo ""
echo "示例:"
echo " $0 # 使用默认阈值 50%"
echo " $0 80 # 要求覆盖率 >= 80%"
echo " $0 90 # 要求覆盖率 >= 90%"
echo ""
echo "环境变量:"
echo " TIMEOUT Tarpaulin 超时时间 (秒, 默认: 240)"
echo " OUTPUT_FORMAT 输出格式 (默认: Html)"
echo " SKIP_THRESHOLD_CHECK 跳过阈值检查 (设置为 1)"
exit 0
}
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
show_help
fi
if ! [[ "$COVERAGE_THRESHOLD" =~ ^[0-9]+$ ]] || [ "$COVERAGE_THRESHOLD" -lt 0 ] || [ "$COVERAGE_THRESHOLD" -gt 100 ]; then
print_error "无效的覆盖率阈值: $COVERAGE_THRESHOLD"
echo "阈值必须是 0-100 之间的整数"
exit 1
fi
print_header "TRACK-SYSTEM 测试覆盖率检查"
print_info "覆盖率阈值: ${COVERAGE_THRESHOLD}%"
print_info "超时时间: ${TIMEOUT} 秒"
print_info "输出格式: ${OUTPUT_FORMAT}"
echo ""
print_info "检查 cargo-tarpaulin 是否已安装..."
if ! command -v cargo-tarpaulin &> /dev/null; then
print_warning "cargo-tarpaulin 未安装,正在安装..."
cargo install cargo-tarpaulin || {
print_error "cargo-tarpaulin 安装失败"
echo ""
echo "请手动安装: cargo install cargo-tarpaulin"
exit 1
}
print_success "cargo-tarpaulin 安装成功"
else
TARPAULIN_VERSION=$(cargo tarpaulin --version | head -1)
print_success "已安装: $TARPAULIN_VERSION"
fi
echo ""
print_info "清理旧的报告文件..."
if [ -f "$REPORT_FILE" ]; then
rm -f "$REPORT_FILE"
print_success "已删除旧报告: $REPORT_FILE"
fi
echo ""
print_header "运行 Tarpaulin 测试覆盖率分析"
print_info "这可能需要几分钟时间,请耐心等待..."
echo ""
START_TIME=$(date +%s)
TARPAULIN_OUTPUT=$(cargo tarpaulin \
--workspace \
--timeout $TIMEOUT \
--out $OUTPUT_FORMAT \
--engine llvm \
--verbose \
--exclude-files "migration/*"
2>&1) || {
TARPAULIN_EXIT_CODE=$?
print_error "Tarpaulin 运行失败 (退出码: $TARPAULIN_EXIT_CODE)"
echo ""
echo "错误输出:"
echo "$TARPAULIN_OUTPUT" | tail -20
exit $TARPAULIN_EXIT_CODE
}
END_TIME=$(date +%s)
ELAPSED_TIME=$((END_TIME - START_TIME))
echo "$TARPAULIN_OUTPUT"
echo ""
print_success "Tarpaulin 运行完成 (耗时: ${ELAPSED_TIME}s)"
echo ""
print_info "解析覆盖率结果..."
COVERAGE_LINE=$(echo "$TARPAULIN_OUTPUT" | grep -E "[0-9]+\.[0-9]+% coverage" | tail -1)
if [ -z "$COVERAGE_LINE" ]; then
print_error "无法从 Tarpaulin 输出中解析覆盖率"
echo ""
echo "Tarpaulin 输出末尾:"
echo "$TARPAULIN_OUTPUT" | tail -10
exit 1
fi
COVERAGE_PERCENT=$(echo "$COVERAGE_LINE" | grep -oE "[0-9]+\.[0-9]+" | head -1)
COVERAGE_LINES=$(echo "$COVERAGE_LINE" | grep -oE "[0-9]+/[0-9]+ lines" | sed 's/ lines//')
print_success "当前覆盖率: ${COVERAGE_PERCENT}% ($COVERAGE_LINES 行)"
echo ""
print_info "检查报告文件..."
if [ -f "$REPORT_FILE" ]; then
REPORT_SIZE=$(ls -lh "$REPORT_FILE" | awk '{print $5}')
print_success "报告已生成: $REPORT_FILE (大小: $REPORT_SIZE)"
print_info "在浏览器中打开: file://$(pwd)/$REPORT_FILE"
else
print_warning "HTML 报告文件未找到: $REPORT_FILE"
fi
echo ""
print_info "更新覆盖率检查清单..."
if [ ! -f "$CHECKLIST_FILE" ]; then
print_error "检查清单文件不存在: $CHECKLIST_FILE"
echo "请先创建文档框架 (任务 1)"
exit 1
fi
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
RUNNER="${USER:-CI}"
PHASE="Phase1"
if (( $(echo "$COVERAGE_PERCENT >= 80" | bc -l) )); then
PHASE="Phase3"
elif (( $(echo "$COVERAGE_PERCENT >= 50" | bc -l) )); then
PHASE="Phase2"
fi
PASS_EMOJI="❌"
PASS_TEXT="未达标 (目标 ≥${COVERAGE_THRESHOLD}%)"
if (( $(echo "$COVERAGE_PERCENT >= $COVERAGE_THRESHOLD" | bc -l) )); then
PASS_EMOJI="✅"
PASS_TEXT="达标"
fi
cat >> "$CHECKLIST_FILE" << EOF
---
**日期**: $TIMESTAMP
**覆盖率**: ${COVERAGE_PERCENT}% ($COVERAGE_LINES 行)
**阶段**: $PHASE
**是否达标**: $PASS_EMOJI ($PASS_TEXT)
**运行者**: $RUNNER
**运行时间**: ${ELAPSED_TIME}s
**备注**: 自动化脚本运行
EOF
print_success "覆盖率记录已追加到 $CHECKLIST_FILE"
echo ""
if [ "${SKIP_THRESHOLD_CHECK:-0}" != "1" ]; then
print_header "覆盖率阈值检查"
print_info "期望阈值: ≥${COVERAGE_THRESHOLD}%"
print_info "实际覆盖率: ${COVERAGE_PERCENT}%"
echo ""
if (( $(echo "$COVERAGE_PERCENT >= $COVERAGE_THRESHOLD" | bc -l) )); then
print_success "覆盖率达标! 🎉"
echo ""
echo "当前覆盖率 ${COVERAGE_PERCENT}% 已达到或超过阈值 ${COVERAGE_THRESHOLD}%"
EXIT_CODE=0
else
print_error "覆盖率未达标! ⚠️"
echo ""
echo "当前覆盖率 ${COVERAGE_PERCENT}% 低于阈值 ${COVERAGE_THRESHOLD}%"
echo ""
COVERAGE_GAP=$(echo "$COVERAGE_THRESHOLD - $COVERAGE_PERCENT" | bc)
print_warning "还需提升 ${COVERAGE_GAP}% 的覆盖率"
echo ""
echo "建议:"
echo " 1. 打开报告文件查看未覆盖的代码: $REPORT_FILE"
echo " 2. 优先为 0% 覆盖率的文件添加测试"
echo " 3. 参考测试指南: docs/coverage/guide.md"
EXIT_CODE=1
fi
else
print_info "跳过阈值检查 (SKIP_THRESHOLD_CHECK=1)"
EXIT_CODE=0
fi
echo ""
print_header "测试覆盖率检查完成"
echo "📊 覆盖率摘要:"
echo " 覆盖率: ${COVERAGE_PERCENT}%"
echo " 覆盖行数: $COVERAGE_LINES"
echo " 阈值: ≥${COVERAGE_THRESHOLD}%"
echo " 运行时间: ${ELAPSED_TIME}s"
echo " 报告文件: $REPORT_FILE"
echo ""
exit $EXIT_CODE