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/scripts/run_all_tests.sh

267 lines
6.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
# 批量回归测试脚本:对 test/test_case 下全部 .sy 用例执行 IR 语义验证。
# 用法:./scripts/run_all_tests.sh [--ir | --asm | --both]
#
# 默认只测 IR通过 llc + clang 编译运行)。
# --asm 只测汇编(需要 aarch64-linux-gnu-gcc + qemu-aarch64
# --both 同时测 IR 和汇编。
set -uo pipefail
mode="ir"
if [[ "${1:-}" == "--asm" ]]; then
mode="asm"
elif [[ "${1:-}" == "--both" ]]; then
mode="both"
fi
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$ROOT_DIR"
compiler="./build/bin/compiler"
if [[ ! -x "$compiler" ]]; then
echo "❌ 未找到编译器: $compiler" >&2
echo "请先构建cmake -S . -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j \$(nproc)" >&2
exit 1
fi
total=0
passed=0
failed=0
skipped=0
fail_list=()
run_ir_test() {
local sy="$1"
local dir
dir=$(dirname "$sy")
local stem
stem=$(basename "$sy" .sy)
local out_dir="test/test_result/ir_batch"
mkdir -p "$out_dir"
local out_file="$out_dir/$stem.ll"
local stdin_file="$dir/$stem.in"
local expected_file="$dir/$stem.out"
local stdout_file="$out_dir/$stem.stdout"
local actual_file="$out_dir/$stem.actual.out"
# 生成 IR
if ! timeout 30 "$compiler" --emit-ir "$sy" > "$out_file" 2>/dev/null; then
echo " [SKIP-IR] $sy (编译器报错或超时)"
return 2
fi
# 需要 llc + clang
if ! command -v llc >/dev/null 2>&1 || ! command -v clang >/dev/null 2>&1; then
echo " [SKIP-IR] $sy (缺少 llc/clang)"
return 2
fi
local obj="$out_dir/$stem.o"
local exe="$out_dir/$stem"
if ! llc -filetype=obj "$out_file" -o "$obj" 2>/dev/null; then
echo " [SKIP-IR] $sy (llc 编译失败)"
return 2
fi
if ! clang -no-pie "$obj" sylib/sylib.c -o "$exe" -lm 2>/dev/null; then
echo " [SKIP-IR] $sy (clang 链接失败)"
return 2
fi
set +e
# performance 用例给更长的超时时间
local run_timeout=30
if [[ "$sy" == *"performance"* ]]; then
run_timeout=300
fi
if [[ -f "$stdin_file" ]]; then
timeout $run_timeout "$exe" < "$stdin_file" > "$stdout_file" 2>/dev/null
else
timeout $run_timeout "$exe" > "$stdout_file" 2>/dev/null
fi
local status=$?
set -e
# timeout 返回 124 表示超时,标记为 SKIP
if [[ $status -eq 124 ]]; then
echo " [SKIP-IR] $sy (运行超时)"
return 2
fi
# 组装实际输出
{
cat "$stdout_file"
if [[ -s "$stdout_file" ]] && (( $(tail -c 1 "$stdout_file" | wc -l) == 0 )); then
printf '\n'
fi
printf '%s\n' "$status"
} > "$actual_file"
if [[ ! -f "$expected_file" ]]; then
echo " [SKIP-IR] $sy (无预期输出)"
return 2
fi
if diff -q <(sed -e 's/\r$//' -e '$a\\' "$expected_file") \
<(sed -e 's/\r$//' -e '$a\\' "$actual_file") >/dev/null 2>&1; then
return 0
else
return 1
fi
}
run_asm_test() {
local sy="$1"
local dir
dir=$(dirname "$sy")
local stem
stem=$(basename "$sy" .sy)
local out_dir="test/test_result/asm_batch"
mkdir -p "$out_dir"
local asm_file="$out_dir/$stem.s"
local stdin_file="$dir/$stem.in"
local expected_file="$dir/$stem.out"
local stdout_file="$out_dir/$stem.stdout"
local actual_file="$out_dir/$stem.actual.out"
local exe="$out_dir/$stem"
# 生成汇编
if ! timeout 30 "$compiler" --emit-asm "$sy" > "$asm_file" 2>/dev/null; then
echo " [SKIP-ASM] $sy (编译器报错或超时)"
return 2
fi
if ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then
echo " [SKIP-ASM] $sy (缺少 aarch64-linux-gnu-gcc)"
return 2
fi
if ! timeout 30 aarch64-linux-gnu-gcc "$asm_file" sylib/sylib.c -o "$exe" -static 2>/dev/null; then
echo " [SKIP-ASM] $sy (汇编/链接失败)"
return 2
fi
if ! command -v qemu-aarch64 >/dev/null 2>&1; then
echo " [SKIP-ASM] $sy (缺少 qemu-aarch64)"
return 2
fi
set +e
# performance 用例给更长的超时时间
local run_timeout=30
if [[ "$sy" == *"performance"* ]]; then
run_timeout=300
fi
if [[ -f "$stdin_file" ]]; then
timeout $run_timeout qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe" < "$stdin_file" > "$stdout_file" 2>/dev/null
else
timeout $run_timeout qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe" > "$stdout_file" 2>/dev/null
fi
local status=$?
set -e
# timeout 返回 124 表示超时,标记为 SKIP
if [[ $status -eq 124 ]]; then
echo " [SKIP-ASM] $sy (运行超时)"
return 2
fi
{
cat "$stdout_file"
if [[ -s "$stdout_file" ]] && (( $(tail -c 1 "$stdout_file" | wc -l) == 0 )); then
printf '\n'
fi
printf '%s\n' "$status"
} > "$actual_file"
if [[ ! -f "$expected_file" ]]; then
echo " [SKIP-ASM] $sy (无预期输出)"
return 2
fi
if diff -q <(sed -e 's/\r$//' -e '$a\\' "$expected_file") \
<(sed -e 's/\r$//' -e '$a\\' "$actual_file") >/dev/null 2>&1; then
return 0
else
return 1
fi
}
echo "========================================"
echo " Lab4 批量回归测试 (mode: $mode)"
echo "========================================"
echo ""
# 收集所有测试文件
mapfile -t test_files < <(find test/test_case -name '*.sy' | sort)
for sy in "${test_files[@]}"; do
total=$((total + 1))
if [[ "$mode" == "ir" || "$mode" == "both" ]]; then
run_ir_test "$sy"
rc=$?
if [[ $rc -eq 0 ]]; then
echo " [PASS-IR] $sy"
passed=$((passed + 1))
elif [[ $rc -eq 1 ]]; then
echo " [FAIL-IR] $sy"
failed=$((failed + 1))
fail_list+=("$sy (IR)")
else
skipped=$((skipped + 1))
fi
fi
if [[ "$mode" == "asm" || "$mode" == "both" ]]; then
run_asm_test "$sy"
rc=$?
if [[ $rc -eq 0 ]]; then
echo " [PASS-ASM] $sy"
if [[ "$mode" == "asm" ]]; then
passed=$((passed + 1))
fi
elif [[ $rc -eq 1 ]]; then
echo " [FAIL-ASM] $sy"
if [[ "$mode" == "asm" ]]; then
failed=$((failed + 1))
fi
fail_list+=("$sy (ASM)")
else
if [[ "$mode" == "asm" ]]; then
skipped=$((skipped + 1))
fi
fi
fi
done
echo ""
echo "========================================"
echo " 测试结果汇总"
echo "========================================"
echo " 总计: $total"
echo " 通过: $passed"
echo " 失败: $failed"
echo " 跳过: $skipped"
echo ""
if [[ ${#fail_list[@]} -gt 0 ]]; then
echo " 失败用例:"
for f in "${fail_list[@]}"; do
echo " - $f"
done
echo ""
fi
if [[ $failed -gt 0 ]]; then
echo "❌ 存在失败用例"
exit 1
else
echo "✅ 全部通过(跳过 $skipped 个)"
exit 0
fi