Files
klammertext/tst/modulepath_test.sh
T
ack fe475e774a Klammertext runs natively on Windows; a Windows source-install guide; the bundled sh for @eval :shell
Assembled from klammertext-dev f344a37d0f6e. The commands, the library,
the Standard Klammer Set, the reflection klammerset and the Python
binding build and run natively on Windows (MSYS2 UCRT64 gcc, python.org
Python), and both test tiers pass there. doc/install/windows_source_install.md
is the fifth install guide: a source install parallel to the Linux and
macOS ones, verified by following it on a pristine Windows 11.

Behaviour on every system: paths Klammertext prints use forward slashes;
output is LF; the command line is UTF-8 on Windows; @eval :shell is a
POSIX shell command everywhere -- on Windows it runs the sh Klammertext
ships, BusyBox for Windows (win/busybox/, GPLv2, with its licence and the
source pointer). KLAMMERTEXT_FONTS and KLAMMERTEXT_KLAMMERSETS are lists in
the system's PATH convention (';' on Windows). On Linux and macOS nothing
observable changes.
2026-09-25 00:32:55 +02:00

138 lines
5.8 KiB
Bash
Executable File

#!/bin/bash
#
# modulepath_test.sh — @eval pathname resolution (Klammermachine engine
# tier): module resolution and the :cwd option.
#
# A Python module lives NEXT TO THE FILE whose @eval names it: the directory
# of every file the Machine reads — input files, klammer sets, @read targets
# — joins the Python sys.path (after the SKS directories), so resolution is
# independent of the cwd. Before 2026-07-27 modules were found only via
# PYTHONPATH or the cwd, so `ktext /path/doc.kt` worked from the document's
# directory and failed from anywhere else.
#
# The same directories are searched for a relative `:cpp` library not found
# from the cwd (Eval::eval_command); that path is not exercised here because
# it would mean compiling a DSO inside the test — the directory list is the
# same one these cases prove.
#
# Pass-ordering caveat (deliberate, untested here): at one nesting level
# @eval is processed before @read expands, so a TOP-LEVEL @eval sees only
# files read earlier. A klammer DEFINED in a read file is applied later and
# always sees its own directory — the realistic case, tested below.
#
# Engine tier: --klammersets none, fixtures created inline in a temp tree, no SKS.
# Usage: ./modulepath_test.sh (ktext on PATH)
PASS=0
FAIL=0
red=$'\033[31m'
green=$'\033[32m'
bold=$'\033[1m'
reset=$'\033[0m'
# Resolve the temporary directory to its physical path. On macOS /var is a
# symlink to /private/var, so `mktemp -d` hands back an unresolved
# /var/folders/... while Python's os.getcwd() reports the resolved
# /private/var/folders/... — case 5 would then compare two spellings of the
# same directory and fail on the Mac only. `pwd -P` is POSIX; macOS has no
# GNU realpath by default.
T="$(cd "$(mktemp -d)" && pwd -P)"
# Under MSYS2 the physical path comes back in POSIX form (/tmp/...), which a
# native ktext cannot open; the Windows spelling is what the fixtures and the
# expectations must carry.
command -v cygpath >/dev/null 2>&1 && T="$(cygpath -m "$T")"
trap 'rm -rf "$T"' EXIT
mkdir -p "$T/seta" "$T/setb" "$T/elsewhere"
printf 'def hello():\n return "module-next-to-read-file"\n' > "$T/seta/pmod.py"
printf '@@desc : @eval pmod.hello() @ @@#-\n' > "$T/seta/defs.k"
printf 'def here():\n return "module-next-to-input"\n' > "$T/setb/imod.py"
printf '@read %s/seta/defs.k @#-@desc@ / @eval imod.here() @\n' "$T" > "$T/setb/doc.kt"
printf '@eval nosuch_module_xyz.f() @\n' > "$T/setb/missing.kt"
check() { # check NAME EXPECTED ARGS...
local name="$1" expected="$2"; shift 2
local out
out=$(ktext "$@" --klammersets none -d 2>/dev/null)
# A working directory Python reports on Windows has backslashes; the
# expectation, built from the shell's Windows-form path, has slashes.
case "$(uname -s)" in MINGW*|MSYS*) out=${out//\\//};; esac
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}@eval module resolution tests${reset}"
echo "======================="
echo
cd "$T/elsewhere"
check " 1. modules beside the @read file and the input file (absolute path)" \
"module-next-to-read-file / module-next-to-input" \
"$T/setb/doc.kt"
check " 2. the same, input given as a relative path" \
"module-next-to-read-file / module-next-to-input" \
"../setb/doc.kt"
name=" 3. an unknown module still reports cleanly"
err=$(ktext "$T/setb/missing.kt" --klammersets none -d 2>&1 >/dev/null)
case "$err" in
*'Cannot import module "nosuch_module_xyz"'*)
echo "${green}PASS${reset} $name"; PASS=$((PASS + 1)) ;;
*)
echo "${red}FAIL${reset} $name"
echo " stderr: [$(echo "$err" | head -3)]"; FAIL=$((FAIL + 1)) ;;
esac
# --- the :cwd option --------------------------------------------------------
# @eval :cwd DIR runs the eval (any mode) with DIR as the working directory
# and restores the process cwd afterwards; *K_input_dir* names the
# document's directory; whitespace-separated tokens are joined until they
# name an existing directory (the filenames-with-spaces convention).
printf 'hello from data file\n' > "$T/setb/data.txt"
printf '@eval :cwd *K_input_dir* :shell cat data.txt @\n' > "$T/setb/shellcwd.kt"
check " 4. :cwd *K_input_dir* for :shell, run from elsewhere" \
"hello from data file" "$T/setb/shellcwd.kt"
printf '@eval :cwd *K_input_dir* os.getcwd() @\n' > "$T/setb/pycwd.kt"
check " 5. :cwd changes the Python working directory" \
"$T/setb" "$T/setb/pycwd.kt"
# The first @eval renders nothing, so the document begins with the space
# the author wrote before the "/": ktext keeps it (it trims only newlines
# from the result, as Machine::apply and the Python binding do -- a leading
# space is the indent of a txt block that opens a document; TODO #60).
printf '@eval :cwd *K_input_dir* :shell true @ / @eval :shell pwd @\n' > "$T/setb/restore.kt"
check " 6. the cwd is restored after the eval" \
" / $T/elsewhere" "$T/setb/restore.kt"
mkdir -p "$T/sp ace"
printf 'spaced\n' > "$T/sp ace/f.txt"
printf '@eval :cwd %s/sp ace :shell cat f.txt @\n' "$T" > "$T/setb/spaces.kt"
check " 7. a :cwd directory containing spaces" \
"spaced" "$T/setb/spaces.kt"
name=" 8. a nonexistent :cwd is a clean argument error"
printf '@eval :cwd /nonexistent_kt_dir :shell true @\n' > "$T/setb/bad.kt"
err=$(ktext "$T/setb/bad.kt" --klammersets none -d 2>&1 >/dev/null)
case "$err" in
*'The :cwd directory does not exist'*)
echo "${green}PASS${reset} $name"; PASS=$((PASS + 1)) ;;
*)
echo "${red}FAIL${reset} $name"
echo " stderr: [$(echo "$err" | head -2)]"; FAIL=$((FAIL + 1)) ;;
esac
echo
echo "======================="
echo "Results: ${green}$PASS passed${reset}, ${red}$FAIL failed${reset}"
[ $FAIL -eq 0 ]