#!/bin/sh
# Run binary tests.
# Usage: test/run [<test.rad|test.ras>...]
#
# If no arguments are provided, runs all `.rad` and `.ras` tests in
# `test/tests/`.
#
# For each test:
#   - If a `.ril` file exists alongside it, the IL output is checked
#     against it via the runner binary.
#   - If `//! returns: N` appears in the file, the test is compiled to
#     a binary and executed; the exit code must match N.
#   - If `//! rw-data-size: N` appears in the file, the emitted `.rw.data`
#     sidecar size must match N bytes. Missing sidecars count as zero bytes.

RUNNER="test/runner.rv64"
TEST_DIR="test/tests"
EMU="${RAD_EMULATOR:-emulator} -stack-size=1024 -run"
EMU_RUN="${RAD_EMULATOR:-emulator} -no-jit -run"

if [ ! -f "$RUNNER" ]; then
  echo "error: runner binary not found: $RUNNER" >&2
  echo "hint: run 'make test' first" >&2
  exit 1
fi

# Disable core dumps for tests.
ulimit -c 0

# Collect tests.
if [ $# -eq 0 ]; then
  tests=$(find "$TEST_DIR" \( -name '*.rad' -o -name '*.ras' \) | sort)
else
  tests="$*"
fi

if [ -z "$tests" ]; then
  echo "error: no tests found" >&2
  exit 1
fi

passed=0
failed=0

for test in $tests; do
  case "$test" in
    *.rad) base="${test%.rad}" ;;
    *.ras) base="${test%.ras}" ;;
    *) base="$test" ;;
  esac

  ril="${base}.ril"
  bin="${base}.rv64"
  rw_data="${bin}.rw.data"

  # IL check: run the runner if a .ril file exists.
  if [ -f "$ril" ]; then
    if $EMU "$RUNNER" -- "$test"; then
      passed=$((passed + 1))
    else
      failed=$((failed + 1))
    fi
  fi

  # Execution check: run the binary if //! returns: is present.
  returns=$(grep -m1 '^//! returns:' "$test" | sed 's/^\/\/! returns: *//')
  if [ -n "$returns" ]; then
    echo -n "test $test ... "

    if [ ! -f "$bin" ]; then
      echo "FAILED (binary not found: $bin)"
      failed=$((failed + 1))
      continue
    fi

    $EMU_RUN "$bin" >/dev/null 2>&1
    ret=$?

    if [ "$ret" -eq "$returns" ]; then
      echo "ok"
      passed=$((passed + 1))
    else
      echo "FAILED (expected: $returns, got: $ret)"
      failed=$((failed + 1))
    fi
  fi

  rw_data_size=$(grep -m1 '^//! rw-data-size:' "$test" | sed 's/^\/\/! rw-data-size: *//')
  if [ -n "$rw_data_size" ]; then
    echo -n "test $test rw.data ... "

    if [ ! -f "$bin" ]; then
      echo "FAILED (binary not found: $bin)"
      failed=$((failed + 1))
      continue
    fi

    if [ -f "$rw_data" ]; then
      actual_rw_data_size=$(wc -c < "$rw_data" | tr -d ' ')
    else
      actual_rw_data_size=0
    fi

    if [ "$actual_rw_data_size" -eq "$rw_data_size" ]; then
      echo "ok"
      passed=$((passed + 1))
    else
      echo "FAILED (expected: $rw_data_size, got: $actual_rw_data_size)"
      failed=$((failed + 1))
    fi
  fi
done
echo

if [ "$failed" -eq 0 ]; then
  echo "test result: ok. $passed passed; $failed failed"
  exit 0
else
  echo "test result: FAILED. $passed passed; $failed failed"
  exit 1
fi
