#!/bin/bash
#
# transform_test.sh — Regression tests for the Klammermachine's typographic
# TRANSFORM pass (the third positional of @@@target).
#
# Kept SKS-INDEPENDENT on purpose: a target is a Machine construct, so the
# fixture target is declared inline and no klammer set is loaded.  The SKS's
# own transform tables (html, txt, tex) are exercised by
# sks/tst/typography_test.sh.
#
# What the pass IS: each pair replaces a source character sequence in the
# final output with its target spelling (the LaTeX input conventions carried
# to other targets: --- to an em dash, quote pairs, ~ to a non-breaking
# space).  Since 2026-08-23 it runs PER KATOM at final processing, not over
# the joined result string, which is what these cases pin:
#
#   - ordinary writer text                    -> transformed
#   - ^'...'^ literal span (katom_t::literal) -> NEVER transformed
#   - a KTESC marker in the text              -> never matched; decodes after
#     the pass (this is the contract hide_typographic() in the SKS's
#     klammer_base.py relies on to protect @c/@code verbatim text)
#   - a plain-text @eval result (a renderer)  -> transformed like writer text
#   - a source split across a katom boundary  -> NOT transformed (the writer
#     separated the characters structurally; they are not a dash)
#   - :includes                               -> transforms are inherited,
#     as escapes are
#   - the pairs run in declared order
#
# The transform/escape interplay is also pinned: escapes become markers
# before klammer application, transforms run at final processing, markers
# resolve last — so the two mechanisms cannot corrupt each other's output.
#
# Usage: ./transform_test.sh   (needs KLAMMERTEXT_HOME set; ktext 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}
ERR=/tmp/transform_test_err.$$

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

# strip leading/trailing blank lines and trailing whitespace
trim() { awk '{ sub(/[ \t\r]+$/, "") } { line[NR]=$0 } END { f=1; while (f<=NR && line[f]=="") f++; l=NR; while (l>=1 && line[l]=="") l--; for (i=f;i<=l;i++) print line[i] }'; }

# check_eq NAME EXPECTED KTEXT_ARGS... — exit 0 and stdout==EXPECTED.
check_eq() {
    local name="$1" expected="$2"; shift 2
    local out status err
    out=$("$KTEXT" "$@" 2>"$ERR"); status=$?
    err=$(cat "$ERR")
    out=$(printf '%s' "$out" | trim)
    if [ $status -ne 0 ]; then
        echo "${red}FAIL${reset} $name — ktext exited $status"
        echo "       stderr: $(echo "$err" | head -2)"; FAIL=$((FAIL+1)); return
    fi
    if [ "$out" = "$expected" ]; then
        echo "${green}PASS${reset} $name"; PASS=$((PASS+1))
    else
        echo "${red}FAIL${reset} $name"
        echo "       expected: [$expected]"; echo "       got:      [$out]"; FAIL=$((FAIL+1))
    fi
}

echo "${bold}Typographic transform tests (Machine mechanism, fixture target 't')${reset}"
echo "==================================================================="
echo

# The fixture target: one escape (& -> AMP) and two transforms, whose
# replacements are distinct tokens that are easy to assert.
T='@@@target t | test target :escape & AMP | --- MDASH | -- NDASH @@@'

check_eq " 1. writer text: --- transformed"        'a MDASH b'   --klammersets none -t t -s "$T a --- b"
check_eq " 2. pairs in declared order: -- after ---" 'a NDASH b'  --klammersets none -t t -s "$T a -- b"
check_eq " 3. literal span: NOT transformed"       'a -- b'      --klammersets none -t t -s "$T ^'a -- b'^"
check_eq " 4. escape and transform coexist"        'x AMP y NDASH' --klammersets none -t t -s "$T x & y --"
# 5-6: the @eval sits in a klammer BODY, applied after the fixture target
# is extracted — a top-level @eval runs at read time, before same-input
# @@@ extraction (the documented pass-ordering caveat), and would not
# find target t.
check_eq " 5. renderer @eval result: transformed"  'aNDASHb'     --klammersets none -t t -s "$T @@e.t : @eval \"a--b\" @ @@ @e@"
check_eq " 6. KTESC marker: skipped, then decoded" '--'          --klammersets none -t t -s "$T @@e.t : @eval \"KTESC002dKTESC\" * 2 @ @@ @e@"
check_eq " 7. source across a katom boundary: NOT transformed" '- x -' --klammersets none -t t -s "$T @@g : x @@ - @g@ -"

# 8. :includes — an including target inherits the included target's
# transforms (and escapes), so a target built over another renders the
# same writer conventions.
T2="$T @@@target t2 | over t :includes t @@@"
check_eq " 8. :includes inherits transforms"       'a NDASH b AMP c' --klammersets none -t t2 -s "$T2 a -- b & c"

# 9-12: "^" before any punctuation character quotes it
# (hide_quoted_punctuation, 2026-08-23): the pair becomes the KTESC marker
# of the character, which the transform pass cannot match.  The target
# decides the rendering — a :resolve entry, an :escape entry, or (neither)
# the raw character.  Inside an @eval span the code keeps its carets.
check_eq " 9. quoted hyphens: no transform, decode raw" '--'  --klammersets none -t t -s "$T ^-^-"
check_eq "10. :resolve maps a quoted character"    'LIT-'     --klammersets none -t r -s '@@@target r | r :resolve - LIT- @@@ ^-'
check_eq "11. quoted char with an :escape entry takes its replacement" 'AMP' --klammersets none -t t -s "$T ^&"
check_eq "12. @eval code keeps its carets"         '2'        --klammersets none -t t -s "$T @@e.t : @eval 3 ^(1) @ @@ @e@"

echo
echo "===================================================================="
echo "${bold}Results: $PASS passed, $FAIL failed${reset}"
rm -f "$ERR"
[ $FAIL -eq 0 ] && exit 0 || exit 1
