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.

207 lines
4.9 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
set -uo pipefail
repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
cd "$repo_root"
cases_dir="test/test_case"
result_root="test/test_result/run_tests"
asm_dir="$result_root/asm"
compiler="./build/bin/compiler"
cross_gcc="aarch64-linux-gnu-gcc"
qemu_bin="qemu-aarch64"
qemu_sysroot="/usr/aarch64-linux-gnu"
usage() {
cat <<'EOF'
用法: ./test/run_tests.sh [case ...]
参数:
case 可选。支持以下两种写法:
- test/test_case/foo.sy
- foo (自动解析为 test/test_case/foo.sy)
行为:
- 批量编译 test/test_case/*.sy 为 AArch64 汇编并链接可执行文件
- 若存在同名 .in则将其作为标准输入喂给程序
- 采集程序标准输出,并将退出码追加为最后一行
- 与同名 .out 做精确 diff比对结果写入 test/test_result/run_tests/
EOF
}
require_tool() {
local tool=$1
if ! command -v "$tool" >/dev/null 2>&1; then
echo "未找到依赖工具: $tool" >&2
exit 1
fi
}
resolve_case() {
local arg=$1
if [[ -f "$arg" ]]; then
printf '%s\n' "$arg"
return 0
fi
if [[ -f "$cases_dir/$arg.sy" ]]; then
printf '%s\n' "$cases_dir/$arg.sy"
return 0
fi
return 1
}
append_exit_code() {
local stdout_file=$1
local actual_file=$2
local status=$3
: > "$actual_file"
if [[ -f "$stdout_file" ]]; then
cat "$stdout_file" >> "$actual_file"
if [[ -s "$stdout_file" ]]; then
local last_byte
last_byte=$(tail -c 1 "$stdout_file" | od -An -t x1 | tr -d ' \n')
if [[ "$last_byte" != "0a" ]]; then
printf '\n' >> "$actual_file"
fi
fi
fi
printf '%s\n' "$status" >> "$actual_file"
}
run_case() {
local input_sy=$1
local base stem expected input_txt case_dir asm_file exe_file
local compile_log link_log stderr_log stdout_log actual_out diff_log
local status
base=$(basename "$input_sy")
stem=${base%.sy}
expected="${input_sy%.sy}.out"
input_txt="${input_sy%.sy}.in"
case_dir="$result_root/$stem"
asm_file="$asm_dir/$stem.s"
exe_file="$asm_dir/$stem"
compile_log="$case_dir/compiler.log"
link_log="$case_dir/link.log"
stderr_log="$case_dir/stderr.log"
stdout_log="$case_dir/stdout.log"
actual_out="$case_dir/actual.out"
diff_log="$case_dir/diff.log"
rm -rf "$case_dir"
mkdir -p "$case_dir"
rm -f "$asm_file" "$exe_file"
if [[ ! -f "$expected" ]]; then
echo "[FAIL] $stem: 缺少预期输出文件 $expected"
((missing_expected_count += 1))
failed_cases+=("$stem")
return
fi
if ! "$compiler" --emit-asm "$input_sy" >"$asm_file" 2>"$compile_log"; then
echo "[FAIL] $stem: 编译失败,详见 $compile_log"
((compile_fail_count += 1))
failed_cases+=("$stem")
return
fi
if ! "$cross_gcc" "$asm_file" -o "$exe_file" >"$link_log" 2>&1; then
echo "[FAIL] $stem: 链接失败,详见 $link_log"
((link_fail_count += 1))
failed_cases+=("$stem")
return
fi
: > "$stdout_log"
: > "$stderr_log"
if [[ -f "$input_txt" ]]; then
"$qemu_bin" -L "$qemu_sysroot" "$exe_file" <"$input_txt" >"$stdout_log" 2>"$stderr_log"
status=$?
else
"$qemu_bin" -L "$qemu_sysroot" "$exe_file" >"$stdout_log" 2>"$stderr_log"
status=$?
fi
append_exit_code "$stdout_log" "$actual_out" "$status"
if diff -u "$expected" "$actual_out" >"$diff_log"; then
rm -f "$diff_log"
echo "[PASS] $stem"
((pass_count += 1))
else
echo "[FAIL] $stem: 输出不匹配,详见 $diff_log"
((diff_fail_count += 1))
failed_cases+=("$stem")
fi
}
if [[ ${1:-} == "-h" || ${1:-} == "--help" ]]; then
usage
exit 0
fi
if [[ ! -x "$compiler" ]]; then
echo "未找到编译器: $compiler ,请先构建。" >&2
exit 1
fi
require_tool "$cross_gcc"
require_tool "$qemu_bin"
mkdir -p "$asm_dir"
declare -a cases=()
declare -a failed_cases=()
if [[ $# -gt 0 ]]; then
for arg in "$@"; do
if ! resolved=$(resolve_case "$arg"); then
echo "未找到测试用例: $arg" >&2
exit 1
fi
cases+=("$resolved")
done
else
while IFS= read -r -d '' file; do
cases+=("$file")
done < <(find "$cases_dir" -maxdepth 1 -type f -name '*.sy' -print0 | sort -z)
fi
if [[ ${#cases[@]} -eq 0 ]]; then
echo "未找到任何 .sy 测试用例。" >&2
exit 1
fi
pass_count=0
compile_fail_count=0
link_fail_count=0
diff_fail_count=0
missing_expected_count=0
for case_path in "${cases[@]}"; do
run_case "$case_path"
done
total_count=${#cases[@]}
fail_count=$((compile_fail_count + link_fail_count + diff_fail_count + missing_expected_count))
echo
echo "测试完成: $total_count 个用例"
echo "通过: $pass_count"
echo "失败: $fail_count"
echo " 编译失败: $compile_fail_count"
echo " 链接失败: $link_fail_count"
echo " 输出不匹配: $diff_fail_count"
echo " 缺少预期输出: $missing_expected_count"
if [[ ${#failed_cases[@]} -gt 0 ]]; then
echo "失败用例: ${failed_cases[*]}"
exit 1
fi
exit 0