#!/bin/bash
#
# verbosity_test.sh — what "-v" says, and what it must not say.
#
# The output policy (CLAUDE.md, "Command output policy") fixes what each
# verbosity level is FOR, and a policy with no test drifts back — which is how
# the suites this session repaired got where they were.  The rule:
#
#   -v 0   silent.  Nothing but the result.
#   -v 1   every decision whose outcome the user COULD NOT HAVE READ OFF THEIR
#          OWN INPUT: a klammerset symbol resolved to a file, a default applied,
#          "-o" expanded into a directory and a basename, a filename regrouped,
#          a klammer overridden by a definition in another klammer set.
#   -v 2+  the trace: what the command DID, for someone reading the code.
#
# The boundary is the part worth testing.  Andy's first formulation was "-v 1
# describes a change of state", and taken literally that swallows -v 2 — every
# definition is a change of state.  So the test for -v 1 is not "did something
# happen" but "could the user have predicted the outcome from what they wrote".
# Registering a klammer the user wrote, in the file they wrote, is NOT -v 1
# material; resolving a symbol through a three-stage search path with shadowing
# is.
#
# Engine tier: no klammerset beyond what a case loads deliberately.  The SKS
# half of this policy — font resolution and ":files" resolution — is in
# sks/tst/verbosity_test.sh, because those are @document's decisions.
#
# Usage: ./verbosity_test.sh   (needs KLAMMERTEXT_HOME set; commands on PATH)
# 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'

OUTF=$(mktemp /tmp/verb_out.XXXXXX)
ERRF=$(mktemp /tmp/verb_err.XXXXXX)
TMPD=$(mktemp -d /tmp/verb_dir.XXXXXX)
trap 'rm -f "$OUTF" "$ERRF"; rm -rf "$TMPD"' EXIT

plain() { sed 's/\x1b\[[0-9;]*m//g'; }

pass() { echo "${green}PASS${reset} $1"; PASS=$((PASS + 1)); }
fail() { echo "${red}FAIL${reset} $1"; [ -n "$2" ] && echo "       $2"; FAIL=$((FAIL + 1)); }

# run CMD ARGS... — fills OUTF/ERRF, sets STATUS.
STATUS=0
run() { "$@" >"$OUTF" 2>"$ERRF"; STATUS=$?; }

# reports NAME PATTERN — ERRF matches PATTERN (the log is on stderr, always).
reports() {
    if plain < "$ERRF" | grep -Eq -- "$2"; then pass "$1"
    else fail "$1" "no [$2] in: $(plain < "$ERRF" | head -3 | tr '\n' ' ')"; fi
}
absent() {
    if plain < "$ERRF" | grep -Eq -- "$2"; then fail "$1" "unexpected [$2]"
    else pass "$1"; fi
}

echo "${bold}Verbosity tests${reset}"
echo "==============="
echo

echo "-- -v 0 is silent --"
run "$KTEXT" --klammersets none -s 'hello' -d
if [ $STATUS -eq 0 ] && [ "$(cat "$OUTF")" = "hello" ] && [ ! -s "$ERRF" ]; then
    pass " 1. a successful run says nothing but its result"
else
    fail " 1. exit $STATUS, stdout [$(cat "$OUTF")], stderr [$(head -1 "$ERRF")]"
fi

echo
echo "-- -v 1 answers \"what did the command think I asked for?\" --"
run "$KTEXT" --klammersets none -s 'hello' -d -v 1
reports " 2. the resolved argument list is shown"   '\-s +: hello'
reports " 3. ... including a default the user did not write" '\-v +: 1'
# The document is on stdout and nothing shares it, whatever -v says.
if [ "$(cat "$OUTF")" = "hello" ]; then
    pass " 4. and the result is still the only thing on stdout"
else
    fail " 4. stdout carried [$(head -c 60 "$OUTF")]"
fi

echo
echo "-- -v 1 reports DERIVED values --"
# The output path: the user gave a target and an input name; the directory, the
# basename and the final filename were all constructed.
printf 'hello\n' > "$TMPD/doc.kt"
run "$KTEXT" "$TMPD/doc.kt" -t txt --klammersets none -v 1
reports " 5. the output directory it constructed" 'Output directory: '
reports " 6. the output basename it constructed"  'Output basename: doc'
reports " 7. the output filename it constructed"  'Output filename: .*doc\.txt'

# A klammerset symbol resolves through a three-stage search path with
# shadowing, so the FILE it landed on is the derived value.  Both branches are
# checked: the default (no --klammersets at all) reported nothing until
# 2026-08-15, which was the commonest case of all.
run "$KTEXT" -s 'x' -d -v 1
reports " 8. the DEFAULT klammerset names the file it loaded" 'Klammerset \(default\): .*sks/sks\.k'
mkdir -p "$TMPD/kset"
printf '@@@klammerset kset | A set @@@\n' > "$TMPD/kset/kset.k"
run env KLAMMERTEXT_KLAMMERSETS="$TMPD" "$KTEXT" -s 'x' -d --klammersets kset -v 1
reports " 9. a symbol names the file it resolved to" 'Klammerset "kset": .*kset/kset\.k'
run "$KTEXT" -s 'x' -d --klammersets none -v 1
reports "10. and \"none\" says that none was loaded" 'Klammersets: none'

# An override: the definition being replaced usually lives somewhere the user
# cannot see, which is what earns it a place here rather than a warning.
run "$KTEXT" --klammersets none -t fx -d -v 1 \
    -s '@@@target fx | F @@@ @@w.k : W @@ @@w.fx :: A @@ @@w.fx ::: B @@ @w@'
reports "11. a klammer overridden by a later definition" 'overridden'

echo
echo "-- the boundary: -v 2 is the trace, -v 1 is not --"
run "$KTEXT" --klammersets none -s 'hello' -d -v 1
v1=$(wc -l < "$ERRF")
run "$KTEXT" --klammersets none -s 'hello' -d -v 2
v2=$(wc -l < "$ERRF")
if [ "$v2" -gt "$v1" ]; then
    pass "12. -v 2 says more than -v 1 ($v1 lines -> $v2)"
else
    fail "12. -v 2 added nothing ($v1 -> $v2)"
fi
# The trace names the code; the -v 1 report never should.  A source location in
# a level-1 line means a msg() or a stray log level, not a decision.
run "$KTEXT" --klammersets none -s 'hello' -d -v 1
absent "13. -v 1 does not name source files"  '\[[a-z_]+\.cpp:[0-9]+\]'
run "$KTEXT" --klammersets none -s 'hello' -d -v 2
reports "14. ... while -v 2 does"             '\[[a-z_]+\.(cpp|h):[0-9]+\]'

echo
echo "-- the other two commands honour -v as well --"
run kdesc --katoms -v 1
if [ $STATUS -eq 0 ] && [ -s "$OUTF" ]; then
    pass "15. kdesc -v 1 still produces its result on stdout"
else
    fail "15. exit $STATUS, stdout $(wc -c < "$OUTF") bytes"
fi
run kdiag -v 1 '@i-x'
if [ $STATUS -eq 0 ] && [ -s "$OUTF" ]; then
    pass "16. kdiag -v 1 still produces its result on stdout"
else
    fail "16. exit $STATUS, stdout $(wc -c < "$OUTF") bytes"
fi

echo
echo "==============="
echo "Results: ${PASS} passed, ${FAIL} failed"
[ "$FAIL" -eq 0 ] || exit 1
exit 0
