#!/bin/bash # # kdesc_test.sh — the kdesc command's interface. # # The flag structure was reorganised 2026-08-11 # (notes/modifying_the_kdesc_arguments.md) on two rules: # # * a flag a user reaches for often gets a single letter (-k klammers, # -t targets, -c character codes, -i input); a more specialised topic gets # a multi-letter name (--argtypes, --katoms, --rewrite, --optionsets, # --coverage, --klammerset, --font); # * -v says how much to show about the command's PROCESSING and never what # its RESULT contains. So the katom regex column is "--katoms full" and # the coverage file column is "--coverage all", not verbosity levels. # # "-k" is the one rename that changes a name's MEANING rather than retiring # it: it used to show katom types (now --katoms). A name-based guard cannot # catch that -- the old spelling still works and does something else -- so # these tests pin the new meaning down. # # Usage: ./kdesc_test.sh (needs KLAMMERTEXT_HOME set; kdesc on PATH) # Exit code: 0 if all tests pass, 1 otherwise. PASS=0 FAIL=0 KDESC=kdesc K=${KLAMMERTEXT_HOME:?KLAMMERTEXT_HOME must be set} DIR="$(cd "$(dirname "$0")" && pwd)/coverage" red=$'\033[31m' green=$'\033[32m' bold=$'\033[1m' reset=$'\033[0m' plain() { sed 's/\x1b\[[0-9;]*m//g'; } # shows NAME PATTERN CMD... — exits 0 and the output matches PATTERN. shows() { local name="$1" pattern="$2"; shift 2 local out status out=$(timeout 60 "$@" 2>&1 | plain); status=$? if [ $status -gt 128 ]; then echo "${red}FAIL${reset} $name — died by signal $((status-128))"; FAIL=$((FAIL+1)); return fi if printf '%s' "$out" | grep -Eq -- "$pattern"; then echo "${green}PASS${reset} $name"; PASS=$((PASS+1)) else echo "${red}FAIL${reset} $name — no line matching [$pattern]" echo " got: $(printf '%s' "$out" | head -2)"; FAIL=$((FAIL+1)) fi } # absent NAME PATTERN CMD... — the output does NOT match PATTERN. absent() { local name="$1" pattern="$2"; shift 2 if timeout 60 "$@" 2>&1 | plain | grep -Eq -- "$pattern"; then echo "${red}FAIL${reset} $name — unexpected match [$pattern]"; FAIL=$((FAIL+1)) else echo "${green}PASS${reset} $name"; PASS=$((PASS+1)) fi } echo "${bold}kdesc interface tests${reset}" echo "=====================" echo echo "-- the single-letter flags --" shows " 1. -k lists klammers" '@table' "$KDESC" -k shows " 2. -t lists targets" 'html' "$KDESC" -t shows " 3. -c lists character codes" '.' "$KDESC" -c shows " 4. -i reads the named input" '@x' "$KDESC" -i "$DIR/split.k" -k echo echo "-- the multi-letter topics --" shows " 5. --katoms lists katom types" 'katom' "$KDESC" --katoms shows " 6. --argtypes lists argtypes" 'fraction' "$KDESC" --argtypes shows " 7. --rewrite lists rewrites" '.' "$KDESC" --rewrite shows " 8. --optionsets lists sets" 'caption_args' "$KDESC" --optionsets echo echo "-- result detail is a word, not a verbosity level --" shows " 9. --katoms full adds the regex column" 'Regex' "$KDESC" --katoms full absent "10. --katoms alone omits it" 'Regex' "$KDESC" --katoms shows "11. --coverage all adds the file column" 'sks/table/table\.k' "$KDESC" --coverage all absent "12. --coverage alone omits it" 'sks/table/table\.k' "$KDESC" --coverage # "all" is one word for both kinds of missing information: if you want some of # it you probably want all of it. It shows an empty REPORTING category -- a # designer's checklist of the shapes a klammer set can have -- but not an # empty PROBLEM one, which would state the opposite of the "Needs attention" # banner above it. # Against a FIXTURE, not the SKS: which categories are empty there changes as # the klammer set is worked on, and a test pinned to that state fails for a # reason that has nothing to do with what it is testing. (It did: adopting # ".*" in the SKS made "All targets, declared" non-empty.) shows "12a. --coverage all shows an empty reporting category" \ 'All targets, declared \(0\)' "$KDESC" -i "$DIR/cycle.k" --coverage all absent "12b. ... hidden without it" \ 'All targets, declared \(0\)' "$KDESC" -i "$DIR/cycle.k" --coverage absent "12c. an empty problem category stays hidden" \ 'Declared but never defined \(0\)' "$KDESC" -i "$DIR/cycle.k" --coverage all absent "13. -v adds no result detail" 'Regex' "$KDESC" --katoms -v 3 echo echo "-- -v is about processing only --" shows "14. -v names the input it read" 'input_filenames' "$KDESC" -t -v 1 absent "15. ... and is silent without it" 'input_filenames' "$KDESC" -t echo echo "-- the klammer search --" shows "16. a name matches" '@table' "$KDESC" -k table absent "17. ... and others are excluded" '@document' "$KDESC" -k table shows "18. matching is case-insensitive" '@table' "$KDESC" -k TABLE shows "19. a description word matches" '@' "$KDESC" -k verbatim # The words after -k are one phrase, and whitespace is collapsed on both # sides -- a description written across several lines in a .k file must still # match a phrase typed on one. shows "20. several words are one phrase" '@' "$KDESC" -k displayed verbatim shows "21. ... with runs of space collapsed" '@' "$KDESC" -k displayed verbatim shows "22. no match says so" 'No klammer names or descriptions contained "zzqq"\.' "$KDESC" -k zzqq absent "23. ... and lists nothing" '^ @' "$KDESC" -k zzqq echo echo "-- the subcommand words --" shows "24. --coverage help explains" 'Coverage commands' "$KDESC" --coverage help shows "25. --katoms help explains" 'Katom commands' "$KDESC" --katoms help shows "26. an unknown coverage word" 'Unrecognized coverage command' "$KDESC" --coverage nonsense shows "27. an unknown katom word" 'Unrecognized katom command' "$KDESC" --katoms nonsense echo echo "-- the usage text --" shows "28. -k shows its optional argument" '\-k \[\]' "$KDESC" shows "29. -i shows its filename" '\-i ' "$KDESC" # Ordered by likely use: the single letters come before the long names. # Line numbers, not a multi-line pattern -- grep is line-oriented. usage=$(timeout 60 "$KDESC" 2>&1 | plain) k_line=$(printf '%s\n' "$usage" | grep -n -- '-k \[\]' | head -1 | cut -d: -f1) katoms_line=$(printf '%s\n' "$usage" | grep -n -- '--katoms' | head -1 | cut -d: -f1) if [ -n "$k_line" ] && [ -n "$katoms_line" ] && [ "$k_line" -lt "$katoms_line" ]; then echo "${green}PASS${reset} 30. -k is listed before --katoms"; PASS=$((PASS+1)) else echo "${red}FAIL${reset} 30. usage order: -k at line $k_line, --katoms at $katoms_line" FAIL=$((FAIL+1)) fi echo echo "-- a no-result search is not an error --" timeout 60 "$KDESC" -k zzqq >/dev/null 2>&1 if [ $? -eq 0 ]; then echo "${green}PASS${reset} 31. finding nothing exits 0"; PASS=$((PASS+1)) else echo "${red}FAIL${reset} 31. finding nothing exits nonzero"; FAIL=$((FAIL+1)) fi echo echo "=====================" echo "Results: ${PASS} passed, ${FAIL} failed" [ "$FAIL" -eq 0 ] || exit 1 exit 0