#!/bin/bash
#
# filename_test.sh — Regression tests for filenames containing spaces.
#
# Filenames may contain spaces.  The rules (see CLAUDE.md "Output directory
# policy" and the filename-list functions in mac/file.cpp):
#   - argv boundaries are authoritative: a shell-quoted "my file.kt" is one
#     filename (Argv stores the original argv vector; nothing re-splits it).
#   - A filename LIST is separated by a standalone "/" token (whitespace on
#     both sides) — never a legal input filename, since "/" alone is the
#     root directory.
#   - Rescue: without a separator, whitespace-split names that do not exist
#     are greedily rejoined with their neighbors into names that do; the
#     regrouping is announced on stderr.
#   - A leading "~/" expands to $HOME (shells do not expand a quoted tilde).
#
# Engine tier: uses --klammersets none; no SKS.
#
# Usage: ./filename_test.sh
# Exit code: 0 if all tests pass, 1 otherwise.

PASS=0
FAIL=0
KTEXT=ktext
K=${KLAMMERTEXT_HOME:?KLAMMERTEXT_HOME must be set}

red=$'\033[31m'
green=$'\033[32m'
bold=$'\033[1m'
reset=$'\033[0m'

# Scratch input files
DIR=$(mktemp -d)
trap 'rm -rf "$DIR"' EXIT
mkdir "$DIR/my dir"
printf 'ALPHA\n' > "$DIR/my file.kt"
printf 'BETA\n'  > "$DIR/b.kt"
printf 'GAMMA\n' > "$DIR/my dir/c.kt"
cd "$DIR" || exit 1

# check TEST_NAME EXPECTED_STDOUT EXPECTED_STDERR_SUBSTRING KTEXT_ARGS...
#   EXPECTED_STDERR_SUBSTRING may be "" (no stderr requirement).
check() {
    local test_name="$1" expected="$2" err_needle="$3"
    shift 3
    local output status errfile=$DIR/.stderr
    output=$("$KTEXT" "$@" 2>"$errfile")
    status=$?
    output=$(printf '%s' "$output" | sed -e 's/[ \t]*$//' | grep -v '^$')
    if [ $status -ne 0 ]; then
        echo "${red}FAIL${reset} $test_name — ktext exited $status"
        echo "       stderr: $(head -3 "$errfile")"
        FAIL=$((FAIL + 1))
        return
    fi
    if [ "$output" != "$expected" ]; then
        echo "${red}FAIL${reset} $test_name"
        echo "       expected: [$expected]"
        echo "       got:      [$output]"
        FAIL=$((FAIL + 1))
        return
    fi
    if [ -n "$err_needle" ] && ! grep -qF "$err_needle" "$errfile"; then
        echo "${red}FAIL${reset} $test_name — expected stderr to contain [$err_needle]"
        echo "       stderr: $(head -3 "$errfile")"
        FAIL=$((FAIL + 1))
        return
    fi
    echo "${green}PASS${reset} $test_name"
    PASS=$((PASS + 1))
}

# check_error TEST_NAME EXPECTED_SUBSTRING KTEXT_ARGS...
#   Expects a nonzero exit whose combined output contains EXPECTED_SUBSTRING.
check_error() {
    local test_name="$1" needle="$2"
    shift 2
    local output status
    output=$("$KTEXT" "$@" 2>&1)
    status=$?
    if [ $status -eq 0 ]; then
        echo "${red}FAIL${reset} $test_name — expected an error, got exit 0"
        FAIL=$((FAIL + 1))
        return
    fi
    if echo "$output" | grep -qF "$needle"; then
        echo "${green}PASS${reset} $test_name"
        PASS=$((PASS + 1))
    else
        echo "${red}FAIL${reset} $test_name — expected output to contain [$needle]"
        echo "       output: $(echo "$output" | head -3)"
        FAIL=$((FAIL + 1))
    fi
}

echo "${bold}Filename-with-spaces tests${reset}"
echo "======================="

check "1. quoted filename with a space is one file" \
      "ALPHA" "" \
      "my file.kt" -d --klammersets none

# The regrouping is a DERIVED value -- the command completed a name the input
# left ambiguous -- so since 2026-08-15 it is reported at "-v 1" and the
# default run is silent.  Silence is safe because a rescue only succeeds when
# the joined name names an existing file: a mistyped name fails instead of
# resolving to something else.
check "2. unquoted spaces are rescued into an existing file" \
      "ALPHA" "" \
      my file.kt -d --klammersets none

check "2a. ... silently at the default verbosity" \
      "ALPHA" "" \
      my file.kt -d --klammersets none

check "2b. ... and reported at -v 1" \
      "ALPHA" "interpreting \"my file.kt\" as one filename" \
      my file.kt -d --klammersets none -v 1

check "3. standalone / separates a filename list" \
      "ALPHA
BETA" "" \
      my file.kt / b.kt -d --klammersets none

check "4. space in a directory component" \
      "GAMMA" "" \
      "my dir/c.kt" -d --klammersets none

check "5. quoted name that exists is never split (b.kt also exists)" \
      "ALPHA" "" \
      "my file.kt" -d --klammersets none

HOME="$DIR" check "6. quoted ~/ expands to \$HOME inside ktext" \
      "BETA" "" \
      "~/b.kt" -d --klammersets none

check "7. @read argument keeps its internal space" \
      "ALPHA" "" \
      -s '@read my file.kt @' -d --klammersets none

check_error "8. unrescuable name is reported as written" \
      "no such.kt" \
      "no such.kt" -d --klammersets none

echo
echo "======================="
echo "Results: ${green}$PASS passed${reset}, ${red}$FAIL failed${reset}"
[ $FAIL -eq 0 ]
