#!/usr/bin/env bash # test2.sh - Lab2(IR生成)批量测试脚本 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_todo" OUTPUT_DIR="./lab2_results" COMPILER="./build/bin/compiler" VERIFY_SCRIPT="./scripts/verify_ir.sh" MAX_CASES=0 STOP_ON_FIRST_FAILURE=false show_help() { cat << 'EOF' 用法: ./test2.sh [选项] 说明: 批量执行 Lab2(IR 生成)测试。 默认会递归扫描 test/test_case 下所有 .sy 文件, 调用 scripts/verify_ir.sh 生成 IR 并运行校验。 选项: -m, --max N 最多执行 N 个用例(0 表示不限制,默认: 0) -x, --stop-on-fail 遇到第一个失败时停止 -h, --help 显示帮助 示例: ./test2.sh ./test2.sh --max 20 ./test2.sh --stop-on-fail 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 ;; -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" # 删除旧的输出目录,确保每次运行都是全新的 if [[ -d "$OUTPUT_DIR" ]]; then echo "正在删除旧的输出目录..." rm -rf "$OUTPUT_DIR"/* echo "已删除旧的输出目录" fi mkdir -p "$OUTPUT_DIR" LOG_FILE="$OUTPUT_DIR/lab2_batch.log" FAIL_FILE="$OUTPUT_DIR/failed_cases.txt" ERROR_LOG_FILE="$OUTPUT_DIR/error_log.txt" : > "$LOG_FILE" : > "$FAIL_FILE" : > "$ERROR_LOG_FILE" echo "Lab2 批量测试日志 - $(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" 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}Lab2 批量测试开始${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 [[ $MAX_CASES -gt 0 && $TOTAL -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.ll" 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" echo -ne "${YELLOW}[$TOTAL] $filename ... ${NC}" # 捕获验证脚本的输出,用于错误日志 "$VERIFY_SCRIPT" "$file" "$case_out_dir" --run >> "$LOG_FILE" 2>&1 code=$? if [[ $code -eq 0 ]]; then SUCCESS=$((SUCCESS + 1)) echo -e "${GREEN}成功${NC}" 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" "$VERIFY_SCRIPT" "$file" "$case_out_dir" --run 2>&1 >> "$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}Lab2 批量测试完成${NC}" echo -e "${BLUE}执行用例: $TOTAL${NC}" echo -e "${GREEN}成功: $SUCCESS${NC}" echo -e "${RED}失败: $FAILED${NC}" echo -e "${BLUE}成功率: ${RATE}%${NC}" 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