#!/usr/bin/env bash
# 实验 2 全量测试脚本 (改进版)
# 逻辑参考 verify_ir.sh 与 verify_asm.sh
# 增加了批量测试与统计功能，并确保链接 SysY 运行库 (sylib.c)

set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
COMPILER="$PROJECT_ROOT/build/bin/compiler"
SYLIB="$PROJECT_ROOT/sylib/sylib.c"
RESULT_DIR="$PROJECT_ROOT/test/test_result/lab2_full"

# 检查依赖
if [[ ! -x "$COMPILER" ]]; then
  echo "错误：编译器不存在，请先构建项目。"
  exit 1
fi

if [[ ! -f "$SYLIB" ]]; then
  echo "错误：未找到运行库 $SYLIB"
  exit 1
fi

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

mkdir -p "$RESULT_DIR"

total=0
passed=0
failed=0

run_test() {
  local input=$1
  local base=$(basename "$input")
  local stem=${base%.sy}
  local input_dir=$(dirname "$input")
  
  local out_file="$RESULT_DIR/$stem.ll"
  local obj_file="$RESULT_DIR/$stem.o"
  local exe_file="$RESULT_DIR/$stem"
  local stdin_file="$input_dir/$stem.in"
  local expected_file="$input_dir/$stem.out"
  local actual_file="$RESULT_DIR/$stem.actual.out"
  local stdout_file="$RESULT_DIR/$stem.stdout"

  ((total++)) || true
  echo -n "[$total] 测试 $base ... "

  # 1. 生成 IR
  if ! "$COMPILER" --emit-ir "$input" > "$out_file" 2>&1; then
    echo -e "${RED}IR 生成失败${NC}"
    ((failed++)) || true
    return 1
  fi

  # 2. 编译 IR 到对象文件 (llc)
  if ! llc -filetype=obj "$out_file" -o "$obj_file" > /dev/null 2>&1; then
    echo -e "${RED}LLVM 编译失败 (llc)${NC}"
    ((failed++)) || true
    return 1
  fi

  # 3. 链接运行库 (借鉴 verify_asm.sh 逻辑，但明确包含 sylib.c)
  if ! clang "$obj_file" "$SYLIB" -o "$exe_file" > /dev/null 2>&1; then
    echo -e "${RED}链接失败 (clang)${NC}"
    ((failed++)) || true
    return 1
  fi

  # 4. 运行程序并捕获输出与退出码 (增加栈空间限制)
  local status=0
  ulimit -s unlimited 2>/dev/null || true
  if [[ -f "$stdin_file" ]]; then
    "$exe_file" < "$stdin_file" > "$stdout_file" 2>/dev/null || status=$?
  else
    "$exe_file" > "$stdout_file" 2>/dev/null || status=$?
  fi

  # 格式化实际输出 (借鉴 verify_ir.sh 格式)
  {
    cat "$stdout_file"
    if [[ -s "$stdout_file" ]] && [[ "$(tail -c 1 "$stdout_file" | wc -l)" -eq 0 ]]; then
      printf '\n'
    fi
    printf '%s\n' "$status"
  } > "$actual_file"

  # 5. 比对结果
  if [[ -f "$expected_file" ]]; then
    # 忽略空格差异 (-b -w)
    if diff -q -b -w "$expected_file" "$actual_file" > /dev/null 2>&1; then
      echo -e "${GREEN} 通过${NC}"
      ((passed++)) || true
    else
      echo -e "${RED} 输出不匹配${NC}"
      ((failed++)) || true
    fi
  else
    echo -e "${YELLOW}! 缺少预期输出文件${NC}"
    ((passed++)) || true
  fi
}

# 批量运行
echo "========================================="
echo "实验 2 全量测试开始 (IR 语义验证)"
echo "========================================="
echo ""

run_batch() {
  local dir=$1
  if [[ ! -d "$dir" ]]; then return; fi
  echo "正在测试目录: $dir"
  for sy_file in $(ls "$dir"/*.sy | sort); do
    run_test "$sy_file"
  done
  echo ""
}

run_batch "$PROJECT_ROOT/test/test_case/functional"
run_batch "$PROJECT_ROOT/test/test_case/performance"

echo "========================================="
echo "测试结果统计"
echo "========================================="
echo -e "总数：$total"
echo -e "通过：${GREEN}$passed${NC}"
echo -e "失败：${RED}$failed${NC}"
echo ""

if [[ $failed -eq 0 ]]; then
  echo -e "${GREEN} 所有测试通过！实验 2 任务完成。${NC}"
  exit 0
else
  echo -e "${RED} 有 $failed 个测试失败，请检查逻辑。${NC}"
  exit 1
fi
