#!/bin/bash # # state_test.sh — The @@@state system command and *name* substitution. # # Added 2026-08-22 by the error-gallery coverage review, which found that no # suite covered @@@state at all: its two error messages had never been # printed by any test. What is pinned here, each by outcome: # # * :value sets a variable and *name* substitutes it in a klammer BODY # (bodies are processed at application time). A top-level *name* of a # document-declared variable does NOT substitute — the same read-time # asymmetry @cond had before 2026-08-15; if that is ever changed, case 2 # documents today's behaviour and should change with it. # * :replace replaces an existing value. # * Redefining WITHOUT :replace is an error that names the remedy. # * An undefined variable's error lists the frames it searched. # * A shell environment variable substitutes like any state variable. # # NOT to be confused with "state_test", the C++ diagnostic program built from # state_test.cpp in this directory: that one constructs engine objects and # prints what it gets, for a person to read, and asserts nothing (see the # `smoke` target in tst/Makefile). This is the regression suite. The ".sh" # is the only thing distinguishing them — the same collision as # eval_test/eval_test.sh, documented there first. # # Usage: ./state_test.sh (needs ktext on PATH) # Exit code: 0 if all tests pass, 1 otherwise. PASS=0 FAIL=0 KTEXT=ktext export KT_STATE_PROBE="probe-value" # for the environment-variable case red=$'\033[31m' green=$'\033[32m' bold=$'\033[1m' reset=$'\033[0m' # check_eq NAME EXPECTED KTEXT_ARGS... — trimmed stdout equals EXPECTED. check_eq() { local name="$1" expected="$2" shift 2 local out status out=$("$KTEXT" "$@" 2>/dev/null) status=$? out=$(printf '%s' "$out" | sed -e 's/[ \t]*$//' | grep -v '^$') if [ $status -eq 0 ] && [ "$out" = "$expected" ]; then echo "${green}PASS${reset} $name"; PASS=$((PASS+1)) else echo "${red}FAIL${reset} $name" echo " expected: [$expected]"; echo " got: [$out] (exit $status)" FAIL=$((FAIL+1)) fi } # check_error NAME PATTERN KTEXT_ARGS... — nonzero exit, PATTERN in the # message. Wrap-insensitive: error prose is justified to 80 columns, so a # phrase may wrap anywhere. check_error() { local name="$1" pattern="$2" shift 2 local out status out=$("$KTEXT" "$@" 2>&1) status=$? if [ $status -eq 0 ]; then echo "${red}FAIL${reset} $name — expected an error but ktext succeeded" FAIL=$((FAIL+1)); return fi if printf '%s' "$out" | tr '\n' ' ' | tr -s ' ' | grep -qF "$pattern"; then echo "${green}PASS${reset} $name"; PASS=$((PASS+1)) else echo "${red}FAIL${reset} $name — expected error to contain [$pattern]" echo " got: $(printf '%s' "$out" | sed 's/\x1b\[[0-9;]*m//g' | tr '\n' ' ' | head -c 200)" FAIL=$((FAIL+1)) fi } echo "${bold}@@@state tests${reset}" echo "==============" echo echo "-- setting and substituting --" check_eq " 1. :value sets; *name* substitutes in a body" \ "[hello]" \ --klammersets none -s '@@@state V :value hello @@@ @@f : [*V*] @@ @f@' -d # Documents TODAY'S behaviour: a top-level *name* of a document-declared # variable is left as written (bodies substitute; the top level does not). check_eq " 2. a top-level *name* does not substitute (current behaviour)" \ "[*V*]" \ --klammersets none -s '@@@state V :value hello @@@ [*V*]' -d check_eq " 3. an environment variable substitutes" \ "[probe-value]" \ --klammersets none -s '@@f : [*KT_STATE_PROBE*] @@ @f@' -d echo echo "-- replacing --" check_eq " 4. :replace replaces an existing value" \ "[b]" \ --klammersets none \ -s '@@@state V :value a @@@ @@@state V :replace b @@@ @@f : [*V*] @@ @f@' -d check_error " 5. redefining without :replace is an error naming the remedy" \ "Use ':replace ' to replace the current value" \ --klammersets none -s '@@@state V :value a @@@ @@@state V :value b @@@' -d echo echo "-- the undefined variable --" check_error " 6. an undefined *name* in a body is a located error" \ 'Variable "Missing" not defined' \ --klammersets none -s '@@f : [*Missing*] @@ @f@' -d check_error " 7. ... that lists the frames it searched" \ "(searched:" \ --klammersets none -s '@@f : [*Missing*] @@ @f@' -d echo echo "==============" echo "Results: ${green}$PASS passed${reset}, ${red}$FAIL failed${reset}" [ $FAIL -eq 0 ]