Verbatim-safe typography, ^-punctuation quoting, full-range ^UUUU^, polyglot html
Typographic transforms (---, quote pairs, ~) no longer touch verbatim text: @c/@code/@source_listing content and ^'...'^ spans show exactly the characters written. "^" before any punctuation character quotes it in every target (the apostrophe excepted: ^' opens a literal span), with the new :resolve option on @@@target declaring per-target renderings. The ^UUUU^ code-point form accepts 4-6 hex digits, the full Unicode range. The html output and transform spellings are polyglot (XML-valid), in preparation for an EPUB target. New suites: transform_test, character_test (engine), typography_test (SKS). (from dev 07ce5ea86a0a)
This commit is contained in:
133
tst/target_test.sh
Executable file
133
tst/target_test.sh
Executable file
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# target_test.sh — The @@@target system command's :after_apply phase list.
|
||||
#
|
||||
# Added 2026-08-22, when the txt target became the first to declare TWO
|
||||
# phases and found the list separator undocumented and unguarded: two bare
|
||||
# specs written without " ; " were glued into one Python call and failed at
|
||||
# render time with a SyntaxError located at "phase, line 1" rather than at
|
||||
# the declaration. What is pinned here:
|
||||
#
|
||||
# * several phases separated by " ; " run, in order, each seeing its
|
||||
# predecessor's result;
|
||||
# * a bare spec containing whitespace is a DEFINITION-TIME error naming
|
||||
# the " ; " convention (the guard in Target::add_after_apply);
|
||||
# * a mode-tagged spec (":cpp <library> <function>") is exempt from the
|
||||
# whitespace guard -- its library is a filename, and filenames may
|
||||
# contain spaces, which is why the separator is ";" at all.
|
||||
#
|
||||
# SKS-independent: --klammersets none, an inline fixture target, and a
|
||||
# fixture Python module placed next to the input file (the module-resolution
|
||||
# rule adds the input file's directory to sys.path).
|
||||
#
|
||||
# NOT to be confused with "target_test", the C++ diagnostic program built
|
||||
# from target_test.cpp in this directory (asserts nothing; see the `smoke`
|
||||
# target in tst/Makefile). The ".sh" is the only distinguisher -- the third
|
||||
# such collision, after eval_test and state_test.
|
||||
#
|
||||
# Usage: ./target_test.sh (needs ktext on PATH)
|
||||
# Exit code: 0 if all tests pass, 1 otherwise.
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
KTEXT=ktext
|
||||
|
||||
red=$'\033[31m'
|
||||
green=$'\033[32m'
|
||||
bold=$'\033[1m'
|
||||
reset=$'\033[0m'
|
||||
|
||||
DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$DIR"' EXIT
|
||||
|
||||
# Two phases that mark their passage; order is observable in the output.
|
||||
cat > "$DIR/phasefix.py" <<'EOF'
|
||||
def one(text, K=None):
|
||||
return text + "+ONE"
|
||||
|
||||
def two(text, K=None):
|
||||
return text + "+TWO"
|
||||
|
||||
def width(text, K=None):
|
||||
# K is the state's "class K"; a fixture state variable proves the phase
|
||||
# receives it (attributes arrive as strings unless the argtype is typed).
|
||||
return text + "|" + str(K.Fixture_width)
|
||||
EOF
|
||||
|
||||
check_eq() { # check_eq NAME EXPECTED INPUT_FILE_TEXT TARGET_DECL
|
||||
local name="$1" expected="$2" body="$3" decl="$4"
|
||||
printf '%s' "$body" > "$DIR/in.kt"
|
||||
local out status
|
||||
out=$("$KTEXT" "$DIR/in.kt" --klammersets none -s "$decl" -t t -d 2>/dev/null)
|
||||
status=$?
|
||||
out=$(printf '%s' "$out" | tr -d '\n')
|
||||
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_def_error() { # check_def_error NAME PATTERN TARGET_DECL
|
||||
local name="$1" pattern="$2" decl="$3"
|
||||
local out status
|
||||
out=$("$KTEXT" --klammersets none -s "$decl hello" -t t -d 2>&1)
|
||||
status=$?
|
||||
if [ $status -eq 0 ]; then
|
||||
echo "${red}FAIL${reset} $name — expected a definition 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}@@@target :after_apply tests${reset}"
|
||||
echo "============================"
|
||||
echo
|
||||
|
||||
echo "-- several phases: ';'-separated, run in declared order --"
|
||||
check_eq " 1. one phase runs" \
|
||||
"text+ONE" "text" \
|
||||
'@@@target t | test | :after_apply phasefix.one @@@'
|
||||
check_eq " 2. two phases run in order (ONE then TWO)" \
|
||||
"text+ONE+TWO" "text" \
|
||||
'@@@target t | test | :after_apply phasefix.one ; phasefix.two @@@'
|
||||
check_eq " 3. ... and reversing the list reverses the order" \
|
||||
"text+TWO+ONE" "text" \
|
||||
'@@@target t | test | :after_apply phasefix.two ; phasefix.one @@@'
|
||||
|
||||
echo
|
||||
echo "-- a phase receives the state as K --"
|
||||
check_eq " 4. K.<state variable> is readable inside a phase" \
|
||||
"text|42" "text" \
|
||||
'@@@state Fixture_width :value 42 @@@ @@@target t | test | :after_apply phasefix.width @@@'
|
||||
|
||||
echo
|
||||
echo "-- the missing separator is a DEFINITION-time error --"
|
||||
check_def_error " 5. two bare specs without ';' are rejected at the declaration" \
|
||||
"separated by \" ; \"" \
|
||||
'@@@target t | test | :after_apply phasefix.one phasefix.two @@@'
|
||||
check_def_error " 6. ... and the error names the offending spec" \
|
||||
"phasefix.one phasefix.two" \
|
||||
'@@@target t | test | :after_apply phasefix.one phasefix.two @@@'
|
||||
|
||||
echo
|
||||
echo "-- a mode-tagged spec may contain spaces (its library is a filename) --"
|
||||
# Declaration-time only: the :cpp library is never dlopened unless the
|
||||
# target renders, so declaring it under another name proves the exemption
|
||||
# without needing a real library.
|
||||
check_eq " 7. a ':cpp lib func' spec passes the declaration guard" \
|
||||
"text+ONE" "text" \
|
||||
'@@@target u | unused | :after_apply ^:cpp some lib func @@@ @@@target t | test | :after_apply phasefix.one @@@'
|
||||
|
||||
echo
|
||||
echo "============================"
|
||||
echo "Results: ${green}$PASS passed${reset}, ${red}$FAIL failed${reset}"
|
||||
[ $FAIL -eq 0 ]
|
||||
Reference in New Issue
Block a user