#!/usr/bin/env bash set -euo pipefail if [[ $# -lt 1 || $# -gt 2 ]]; then echo "用法: $0 [output_dir]" >&2 exit 1 fi test_dir=${1%/} out_dir="test/test_result/function/asm_time" shift while [[ $# -gt 0 ]]; do out_dir="$1" shift done if [[ ! -d "$test_dir" ]]; then echo "测试目录不存在: $test_dir" >&2 exit 1 fi compiler="./build/bin/compiler" if [[ ! -x "$compiler" ]]; then echo "未找到编译器: $compiler ,请先构建。" >&2 exit 1 fi if ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then echo "未找到 aarch64-linux-gnu-gcc,无法汇编/链接。" >&2 exit 1 fi if ! command -v qemu-aarch64 >/dev/null 2>&1; then echo "未找到 qemu-aarch64,无法运行生成的可执行文件。" >&2 exit 1 fi sylib_c="sylib/sylib.c" if [[ ! -f "$sylib_c" ]]; then echo "未找到 sylib: $sylib_c" >&2 exit 1 fi mkdir -p "$out_dir" sylib_obj="$out_dir/sylib.o" aarch64-linux-gnu-gcc -c "$sylib_c" -I sylib -o "$sylib_obj" mapfile -t inputs < <(find "$test_dir" -type f -name '*.sy' | sort) if [[ ${#inputs[@]} -eq 0 ]]; then echo "测试目录下未找到 .sy 文件: $test_dir" >&2 exit 1 fi failures=0 normalize() { tr -d '\r' < "$1" | sed -e '${ /^$/d; }' | perl -pe 'chomp if eof' } run_case() { local input=$1 local input_dir base stem rel_path rel_dir case_out_dir asm_file exe local stdin_file expected_file stdout_file actual_file time_file elapsed status input_dir=$(dirname "$input") base=$(basename "$input") stem=${base%.sy} rel_path=${input#"$test_dir"/} rel_dir=$(dirname "$rel_path") case_out_dir="$out_dir" if [[ "$rel_dir" != "." ]]; then case_out_dir="$out_dir/$rel_dir" fi mkdir -p "$case_out_dir" asm_file="$case_out_dir/$stem.s" exe="$case_out_dir/$stem" stdin_file="$input_dir/$stem.in" expected_file="$input_dir/$stem.out" stdout_file="$case_out_dir/$stem.stdout" actual_file="$case_out_dir/$stem.actual.out" time_file="$case_out_dir/$stem.time" if ! "$compiler" --emit-asm "$input" > "$asm_file" 2>"$case_out_dir/$stem.err"; then echo "$stem: 编译失败" cat "$case_out_dir/$stem.err" >&2 return 1 fi if ! aarch64-linux-gnu-gcc "$asm_file" "$sylib_obj" -o "$exe" 2>"$case_out_dir/$stem.link.err"; then echo "$stem: 链接失败" cat "$case_out_dir/$stem.link.err" >&2 return 1 fi set +e if [[ -f "$stdin_file" ]]; then /usr/bin/time -f "%e" -o "$time_file" \ qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe" < "$stdin_file" > "$stdout_file" else /usr/bin/time -f "%e" -o "$time_file" \ qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe" > "$stdout_file" fi status=$? set -e elapsed=$(tail -1 "$time_file") { 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 if diff <(normalize "$expected_file") <(normalize "$actual_file") >/dev/null 2>&1; then printf "%s: PASS (%.3fs)\n" "$stem" "$elapsed" printf '%s\t%s\n' "$elapsed" "$stem" >> "$out_dir/elapsed.log" return 0 else printf "%s: FAIL (退出码: %d, 耗时: %.3fs)\n" "$stem" "$status" "$elapsed" diff -u --strip-trailing-cr "$expected_file" "$actual_file" >&2 || true return 1 fi else printf "%s: SKIP (无预期输出, %.3fs, 退出码: %d)\n" "$stem" "$elapsed" "$status" printf '%s\t%s\n' "$elapsed" "$stem" >> "$out_dir/elapsed.log" return 0 fi } rm -f "$out_dir/elapsed.log" for input in "${inputs[@]}"; do if ! run_case "$input"; then ((failures+=1)) fi done total=${#inputs[@]} passed=$((total - failures)) if [[ -f "$out_dir/elapsed.log" && -s "$out_dir/elapsed.log" ]]; then total_elapsed=$(awk '{s+=$1} END {printf "%.3f", s}' "$out_dir/elapsed.log") else total_elapsed="0.000" fi echo "总计: $total, 通过: $passed, 失败: $failures" echo "通过用例总耗时: $total_elapsed s" if (( failures > 0 )); then exit 1 fi