You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nudt-compiler-cpp/test3.sh

273 lines
7.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env bash
# test3.sh - Lab3(代码生成)批量测试脚本
set -u
set -o pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
TEST_ROOT="./test_merged"
OUTPUT_DIR="./lab3_results"
COMPILER="./build/bin/compiler"
VERIFY_SCRIPT="./scripts/verify_asm.sh"
MAX_CASES=0
STOP_ON_FIRST_FAILURE=false
START_FROM=1
KEEP_OLD=true
# 时间统计相关变量
total_time_sum=0
time_cases_count=0
show_help() {
cat << 'EOF'
用法: ./test3.sh [选项]
说明:
批量执行 Lab3(代码生成)测试。
默认会递归扫描 test/test_case 下所有 .sy 文件,
调用 scripts/verify_asm.sh 生成汇编并运行校验。
选项:
-m, --max N 最多执行 N 个用例0 表示不限制,默认: 0
-x, --stop-on-fail 遇到第一个失败时停止
-s, --start-from N 从第 N 个测试用例开始执行(默认: 1
-k, --keep 保留旧输出目录不删除error_log.txt 追加写入
-h, --help 显示帮助
示例:
./test3.sh
./test3.sh --max 20 --start 5
./test3.sh --stop-on-fail --start 10
./test3.sh --keep # 保留旧输出,增量测试
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
-m|--max)
MAX_CASES="$2"
shift 2
;;
-x|--stop-on-fail)
STOP_ON_FIRST_FAILURE=true
shift
;;
-s|--start-from)
START_FROM="$2"
shift 2
;;
-k|--keep)
KEEP_OLD=true
shift
;;
-h|--help)
show_help
exit 0
;;
*)
echo -e "${RED}错误: 未知选项 $1${NC}"
show_help
exit 1
;;
esac
done
if [[ ! -d "$TEST_ROOT" ]]; then
echo -e "${RED}错误: 测试目录不存在: $TEST_ROOT${NC}"
exit 1
fi
if [[ ! -x "$COMPILER" ]]; then
echo -e "${RED}错误: 编译器不可执行: $COMPILER${NC}"
echo -e "${YELLOW}提示: 请先构建: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j \"\$(nproc)\"${NC}"
exit 1
fi
if [[ ! -x "$VERIFY_SCRIPT" ]]; then
echo -e "${RED}错误: verify脚本不可执行: $VERIFY_SCRIPT${NC}"
exit 1
fi
if ! [[ "$MAX_CASES" =~ ^[0-9]+$ ]]; then
echo -e "${RED}错误: --max 需要非负整数${NC}"
exit 1
fi
mkdir -p "$OUTPUT_DIR"
# 根据 --keep 选项决定是否删除旧的输出目录
if [[ "$KEEP_OLD" = true ]]; then
echo "保留旧输出目录模式: 不删除旧文件"
else
if [[ -d "$OUTPUT_DIR" ]]; then
echo "正在删除旧的输出目录..."
rm -rf "$OUTPUT_DIR"/*
echo "已删除旧的输出目录"
fi
fi
mkdir -p "$OUTPUT_DIR"
LOG_FILE="$OUTPUT_DIR/lab3_batch.log"
FAIL_FILE="$OUTPUT_DIR/failed_cases.txt"
ERROR_LOG_FILE="$OUTPUT_DIR/error_log.txt"
TIME_SUMMARY_FILE="$OUTPUT_DIR/time_summary.txt"
if [[ "$KEEP_OLD" = true ]]; then
# 追加模式:不覆盖日志文件
echo "" >> "$LOG_FILE"
echo "========================================" >> "$LOG_FILE"
echo "Lab3 批量测试日志 (续) - $(date)" >> "$LOG_FILE"
echo "TEST_ROOT=$TEST_ROOT" >> "$LOG_FILE"
echo "OUTPUT_DIR=$OUTPUT_DIR" >> "$LOG_FILE"
echo "MAX_CASES=$MAX_CASES" >> "$LOG_FILE"
echo "================================================" >> "$LOG_FILE"
else
# 覆盖模式:清空日志文件
: > "$LOG_FILE"
: > "$FAIL_FILE"
: > "$ERROR_LOG_FILE"
: > "$TIME_SUMMARY_FILE"
echo "Lab3 批量测试日志 - $(date)" >> "$LOG_FILE"
echo "TEST_ROOT=$TEST_ROOT" >> "$LOG_FILE"
echo "OUTPUT_DIR=$OUTPUT_DIR" >> "$LOG_FILE"
echo "MAX_CASES=$MAX_CASES" >> "$LOG_FILE"
echo "================================================" >> "$LOG_FILE"
fi
mapfile -d '' -t CASES < <(find "$TEST_ROOT" -type f -name '*.sy' -print0 | sort -z)
TOTAL_FOUND=${#CASES[@]}
if [[ $TOTAL_FOUND -eq 0 ]]; then
echo -e "${YELLOW}未找到任何 .sy 用例,请检查目录: $TEST_ROOT${NC}"
exit 0
fi
TOTAL=0
SUCCESS=0
FAILED=0
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Lab3 批量测试开始${NC}"
echo -e "${BLUE}测试根目录: $TEST_ROOT${NC}"
echo -e "${BLUE}找到用例数: $TOTAL_FOUND${NC}"
echo -e "${BLUE}输出目录: $OUTPUT_DIR${NC}"
echo -e "${BLUE}========================================${NC}"
for file in "${CASES[@]}"; do
# 跳过前面的测试用例
if [[ $TOTAL -lt $((START_FROM - 1)) ]]; then
TOTAL=$((TOTAL + 1))
continue
fi
if [[ $MAX_CASES -gt 0 && $((TOTAL - START_FROM + 1)) -ge $MAX_CASES ]]; then
break
fi
rel_path="${file#$TEST_ROOT/}"
filename="$(basename "$file")"
base_name="${filename%.sy}"
rel_dir="$(dirname "$rel_path")"
case_out_dir="$OUTPUT_DIR/$rel_dir"
TOTAL=$((TOTAL + 1))
mkdir -p "$case_out_dir"
# 删除已有的输出文件,确保重新生成
rm -f "$case_out_dir/$base_name.s"
rm -f "$case_out_dir/$base_name.o"
rm -f "$case_out_dir/$base_name"
rm -f "$case_out_dir/$base_name.stdout"
rm -f "$case_out_dir/$base_name.actual.out"
rm -f "$case_out_dir/${base_name}_time.txt"
echo -ne "${YELLOW}[$TOTAL] $filename ... ${NC}"
# 调用 verify 脚本,指定输出目录为 case_out_dir
"$VERIFY_SCRIPT" "$file" "$case_out_dir" --run > /dev/null 2>&1
code=$?
# 从 case_out_dir 读取运行时间文件
time_file="$case_out_dir/${base_name}_time.txt"
run_time=""
if [[ -f "$time_file" ]]; then
run_time=$(cat "$time_file")
fi
if [[ $code -eq 0 ]]; then
SUCCESS=$((SUCCESS + 1))
# 显示运行时间
if [[ -n "$run_time" && "$run_time" =~ ^[0-9]+$ ]]; then
echo -e "${GREEN}成功${NC} (${run_time}ms)"
# 累加统计
total_time_sum=$((total_time_sum + run_time))
time_cases_count=$((time_cases_count + 1))
# 写入汇总文件
echo "$rel_path: ${run_time}ms" >> "$TIME_SUMMARY_FILE"
else
echo -e "${GREEN}成功${NC} (运行时间: N/A)"
fi
echo "[SUCCESS] $file" >> "$LOG_FILE"
else
FAILED=$((FAILED + 1))
echo "$file" >> "$FAIL_FILE"
echo -e "${RED}失败${NC}"
echo "[FAILED] $file (exit=$code)" >> "$LOG_FILE"
# 写入详细错误信息到错误日志
echo "========================================" >> "$ERROR_LOG_FILE"
echo "测试失败: $file" >> "$ERROR_LOG_FILE"
echo "退出码: $code" >> "$ERROR_LOG_FILE"
echo "时间: $(date)" >> "$ERROR_LOG_FILE"
echo "========================================" >> "$ERROR_LOG_FILE"
if [[ "$STOP_ON_FIRST_FAILURE" = true ]]; then
echo -e "${RED}========================================${NC}"
echo -e "${RED}在第一个失败处停止测试${NC}"
echo -e "${RED}失败文件: $file${NC}"
echo -e "${RED}日志: $LOG_FILE${NC}"
echo -e "${RED}错误日志: $ERROR_LOG_FILE${NC}"
echo -e "${RED}========================================${NC}"
break
fi
fi
done
RATE="0.00"
if [[ $TOTAL -gt 0 ]]; then
RATE=$(awk -v s="$SUCCESS" -v t="$TOTAL" 'BEGIN { printf "%.2f", (s*100.0)/t }')
fi
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Lab3 批量测试完成${NC}"
echo -e "${BLUE}执行用例: $TOTAL${NC}"
echo -e "${GREEN}成功: $SUCCESS${NC}"
echo -e "${RED}失败: $FAILED${NC}"
echo -e "${BLUE}成功率: ${RATE}%${NC}"
# 显示平均运行时间
if [[ $time_cases_count -gt 0 ]]; then
avg_time=$((total_time_sum / time_cases_count))
echo -e "${BLUE}平均运行时间: ${avg_time}ms (基于 ${time_cases_count} 个成功用例)${NC}"
echo -e "${BLUE}时间汇总: $TIME_SUMMARY_FILE${NC}"
fi
echo -e "${BLUE}日志: $LOG_FILE${NC}"
if [[ $FAILED -gt 0 ]]; then
echo -e "${RED}失败清单: $FAIL_FILE${NC}"
echo -e "${RED}错误日志: $ERROR_LOG_FILE${NC}"
fi
echo -e "${BLUE}========================================${NC}"
exit 0