You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9.6 KiB
9.6 KiB
src/tests/shell — Shell Behavior Tests
Purpose
Tests for shell-level behavior, command-line execution, and stdin/stdout interaction that are not owned by a specific source module namespace.
Ownership
- Agents may update this subtree when changing shell behavior, command execution, or interactive stream handling.
- Keep module API behavior tests in
src/tests/modules/unless shell invocation is the behavior under test.
Local Contracts
- Tests here may exercise process execution, stdin, stdout, stderr, and shell filtering behavior.
- Keep command inputs and expected outputs explicit so failures can be reproduced outside the aggregate runner.
- Avoid relying on installed packages or root-level build outputs unless the test explicitly targets a built executable.
testsuites/punkexe/targets a built punk executable: resolved fromenv(PUNK_SHELL_TEST_EXE), else<projectroot>/bin/punk902z.exe, else<projectroot>/bin/punkshell902; tests auto-skip via thepunkexeavailableconstraint when none is found.- Tests that spawn the built executable must be hang-proof: use the event-loop
punk_runpattern (pipe stdin, half-close for EOF, timeout then force-kill) rather than plainexec, because known failure modes leave the child waiting on a reopened console. testsuites/punkexe/shellexit.testguards piped-stdin termination behaviour of the built executable (noinvalid thread handleon shutdown races, no console-reopen hang on eof/error paths, exitcode propagation); do not weaken these tests - a red result means a regression in punk::repl shutdown or app-punkshell eof handling.testsuites/punkexe/shellnavns.testproves the namespace-navigation session contract end-to-end over a piped 'src'-mode session (dev modules - deliberate, so current punk::repl/nav source is exercised without a rebuild): n/ sets ns_current, the current namespace continues intosubshell punkand back out (currently via the documented first-subshell shared-code-interp asymmetry - the SHARED marker pins it; the repl::start seeding template for genuinely separate interps is proven in modules/punk/repl nscurrent.test), the punk::repl 0.5.2 stray-namespace fix holds live, and the session exits cleanly. KNOWN GAP pinned there: piped submissions evaluate at :: despite ns_current (interactive and module-level inscope behaviour differ) - investigate alongside G-038.testsuites/punkexe/scriptexec.testcovers thescriptsubcommand (app-punkscript, G-015): piped execution + honest exit codes, result echo, file-form argv, thelib:<name>scriptlib-resolution mechanism (incl. punk::path 0.3.0 extensionless-tcl matching: first-line identification, called-spelling precedence over a.tclsibling, sh-trampoline shebang acceptance, and the non-tcl skip note on not-found), and the tclsh-matching Tk main-loop behaviour. Thelib:and Tk cases resolve committed fixtures underscriptlib/_punktest/(test-owned; alib:-resolvable fixture cannot live in a tcltest temp dir since resolution only searches scriptlib locations relative to the exe). Tk cases are gated by thepunktkconstraint, auto-detected by probing whether the kit can load Tk.- punkexe tests run against the built binary: after changing punk::repl or app-punkshell source, rebuild via
make.tcl packages,make.tcl vfscommonupdate -confirm 0(unattended runs must pass the flag - the REPLACE confirmation aborts fast on non-interactive stdin instead of reading a pipedy), thenmake.tcl bakebefore trusting results;make.tcl bake/bakehousealone does not refresh_vfscommon.vfs(vfscommonupdate is the promotion gate). testsuites/punkexe/tclshcmd.testcovers thetclshsubcommand (punk_main.tcl dispatch): script-file sourcing (argv0/argv/info-script state, honest exit codes incl. explicit exit), piped no-arg stdin evaluation, stock argument forms (leading-arg = no script, all args stay in::argv;-encoding name filesources with the named encoding, incomplete-encodingforms fall through to argv; verified byte-level via a utf-8/iso8859-1 fixture), thelib:refusal (plain-tclsh semantics - pointer to thescriptsubcommand, exit 1), and - on kits built on a TCLSH_PIPEREPL-patched runtime (G-096/G-103, seesrc/buildsuites/suite_tcl90/patches/README.md) - the piperepl launch-state contract: ::tclsh(istty) published, piped script-arg launch state all-zero, unconsumed piped input NOT evaluated unless the script sets::tclsh(evalinput) 1, and the script's right to consume stdin itself; plus the degraded-mode notice on unpatched runtimes. Patched-kit resolution:env(PUNK_PIPEREPL_TEST_EXE)if it probes as patched, else the punkexe if patched, elsebin/punk9_beta.exe/bin/punk9bi_beta.exe. HANG RULE: no PIPED test or fixture may set::tclsh(dorepl)- that path reopens stdin from the console (CONIN$) and blocks under the piped punk_run harness. Console-reopen coverage exists but is env-gated (G-118 item 11; constraintpunkconsole= windows + envPUNK_TEST_CONSOLE=1, normal runs skip): two tests drive the dorepl path end-to-end in the child's OWN hidden console per the G-106 recipe - an outerStart-Process -WindowStyle Hiddenpowershell wrapper owns a fresh console and runs<kit> tclshthere with std handles redirected to files, thentestsupport/consoleinject.ps1attaches to that console and types the verification lines +exit 0as key events. They pin:::tclsh(reopened)flips 0 -> 1 at reopen whileisttystays 0 (immutable launch fact),::tclsh(inputbuffer)appears empty (the repl loop consumed all piped input), the reopen notice is silent by default and appears on STDERR only underTCLSH_PIPEREPL_DEBUG=1, and the injected exit completes the process (exit code 0). Deadlines plus wrapper-tree kill keep them hang-proof.testsuites/binscripts/runtimebash_wsl.test(G-059) exercises the punk-runtime.cmd unix payload (src/scriptapps/bin/punk-runtime.bash) through WSL: active/use/run resolution, env override, stale-active guidance, single-candidate fallback, andlist -remotelocal-vs-server comparison (offline via a crafted cached sha1sums.txt +PUNKBIN_URLpointed at an unreachable address). Gated by thewsllinuxcapability constraint fromsrc/tests/testsupport/wslprobe.tcl; all execution happens in a WSL-native staging dir, and a final test asserts the Windows checkout's git status is unchanged by the run.testsuites/binscripts/runtimecmd_freshness.test(G-119) exercises the punk-runtime freshness verdict (active-vs-server-default: current/ahead/behind/incomparable) in BOTH payloads against a fixture punkbin server: a child-process http file server (testsupport/httpfixture.tcl) serves a crafted layout (defaults.txt, sha1sums, artifacts + metadata tomls) via thePUNKBIN_URLoverride, with all execution in a tempdir staging area on a fixture platform folder (testplat-x86_64- the realbin/runtimestore is untouched). The powershell payload runs as the staged committedbin/punk-runtime.cmdvia cmd.exe (the wrap-pinned path); the bash payload is driven DIRECTLY under a probed msys/git bash (uname MINGW*/MSYS*; WSL bash is rejected - under WSL2 it cannot reach the 127.0.0.1 fixture server, and on windows the polyglot routes unix shells to the powershell payload anyway). Asserts the G-119 acceptance scenarios (ahead/behind+guidance/current-annotation/pre-family no-basis and hash-identity/no-name-fetch note) with ps1-vs-bash verdict-line parity, plus the identity middle column row shapes (2026-07-25 follow-on):from=<artifact>working-copy rows with content-verified Remote statuses (Same version / CONTENT DIFFERS / artifact-not-listed),sha1=<name>byte-copy strays, and the identity-following(server default)row annotation. Gated by capability constraints (windows, committed cmd, bash source, certutil, msys bash, fixture server started); skips cleanly elsewhere.testsuites/punkexe/staticruntime.test(G-058) targets a kit built on a runtime with statically-linked packages: resolved fromenv(PUNK_STATICKIT_TEST_EXE), else<projectroot>/bin/punk91.exe, gated by the capability-probedstatickitavailableconstraint (a probe run must show a captured::punkboot::static_packagesbaseline including Thread - not mere file existence). It asserts repl boot without the codethread Thread failure, Thread resolution in the code interp / fabricated interps / snapshot-seeded threads, and twapi resolution per the static-vs-bundled policy. The verification runtime (tclsfe-x64.exe) is pinned in the punkbin artifact repo so the constraint is satisfiable off the original dev machine. Kit script-exec paths must be passed with forward slashes.- GOAL tests (constraint
punkgoals, enabled by envPUNK_TEST_GOALS=1) cover the piped-stdin-then-interactive-shell drop-in (shellpipe_eof_then_interactive_shell,shellpipe_script_and_eof_then_interactive_shell); they are excluded from normal runs because they require an openable console in the test environment and briefly attach a live shell to it - they pass in console-attached environments against a current build. - The eof-policy discriminator is
env(PUNK_PIPE_EOF)(exit|interactive|unset=console heuristic) implemented in app-punkshell; termination-guard tests spawn children withexit, goal tests spawn with it unset.
Work Guidance
- Use focused harness runs with
-report compact -show-passes 0 -include-paths shell/***when editing this subtree. - Include enough failure output to identify the launched command and stream comparison.
- Keep platform-sensitive assumptions visible in the test body.
Verification
<tcl_interpreter> src/tests/runtests.tcl -report compact -show-passes 0 -include-paths shell/***passes for changes in this subtree.