Browse Source
- new punkexe/maketclkitlocations.test (PUNK_MAPVFS_CONFIG fixtures, nothing built): two-target one-vfs distinct locations (flat vs kits/<platform>/), same-name two-non-native coexistence without runtime-rename, same-target duplicate keeps <name>_<runtime>; mismatch clause referenced as G-133 regression pin (binaryarch.test + maketclpayloadcheck.test) - mapvfs_match_outputs: a plain kit name now selects ALL matching records (one per target) instead of the first hit - pre-G-127 uniqueness assumption removed; filtered bakelist + selective bake cover every target of a shared name - full punkexe subtree pass: 15 files, 101 tests, 0 failed (4 constraint skips) Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.commaster
3 changed files with 213 additions and 10 deletions
@ -0,0 +1,183 @@ |
|||||||
|
package require tcltest |
||||||
|
|
||||||
|
#Piped characterization of the G-127 target-keyed kit OUTPUT LOCATION model, through |
||||||
|
#the make.tcl bakelist report against fixture kit mappings (PUNK_MAPVFS_CONFIG env |
||||||
|
#seam - the real mapping is never edited, nothing is built). Runs the WORKING TREE's |
||||||
|
#src/make.tcl under the built punk executable's 'script' subcommand and pins: |
||||||
|
# - one vfs definition paired with two different targets resolves to DISTINCT |
||||||
|
# output locations in one report: the default-target kit at the flat |
||||||
|
# src/_build/<kit> + bin/<kit> every launcher expects, the non-default-target kit |
||||||
|
# under the kits/<platform>/ tier in both, with the row carrying target= and |
||||||
|
# out= notes (location is a pure function of (name, target), which is what makes |
||||||
|
# the pre-G-127 cross-run overwrite impossible by construction) |
||||||
|
# - two NON-NATIVE targets sharing one kit name coexist as two rows whose locations |
||||||
|
# differ by platform tier (and by target-driven .exe suffixing) with NO |
||||||
|
# runtime-name disambiguation rename |
||||||
|
# - a same-NAME same-TARGET duplicate still gets the historical <name>_<runtime> |
||||||
|
# disambiguation - the guard's remaining job after G-127 scoped it per target |
||||||
|
#The payload/target MISMATCH clause of G-127's Acceptance is a regression pin on |
||||||
|
#G-133 behaviour characterized elsewhere: the scan verdict in |
||||||
|
#modules/punkboot/utils/testsuites/utils/binaryarch.test, the advisory contract in |
||||||
|
#maketclpayloadcheck.test. Real cross-target ARTIFACT evidence (bake punkshell902 -> |
||||||
|
#bin/kits/linux-x86_64/punkshell902, per-platform %platform% payload selection) is |
||||||
|
#recorded in goals/G-127-crosstarget-vfs-bake.md Progress - a full bake is too heavy |
||||||
|
#for this suite by design (see the G-125 precedent note in maketclbootgate.test). |
||||||
|
# |
||||||
|
#Target executable resolved from env(PUNK_SHELL_TEST_EXE), else <projectroot>/bin/punk902z.exe |
||||||
|
#then <projectroot>/bin/punkshell902. Skipped (constraint punkexeavailable) if none found. |
||||||
|
|
||||||
|
namespace eval ::testspace { |
||||||
|
namespace import ::tcltest::* |
||||||
|
|
||||||
|
variable testdir [file dirname [file normalize [info script]]] |
||||||
|
#<projectroot>/src/tests/shell/testsuites/punkexe -> 5 levels up to <projectroot> |
||||||
|
variable projectroot [file normalize [file join $testdir .. .. .. .. ..]] |
||||||
|
variable maketcl [file join $projectroot src make.tcl] |
||||||
|
|
||||||
|
variable punkexe "" |
||||||
|
if {[info exists ::env(PUNK_SHELL_TEST_EXE)] && $::env(PUNK_SHELL_TEST_EXE) ne ""} { |
||||||
|
set punkexe [file normalize $::env(PUNK_SHELL_TEST_EXE)] |
||||||
|
} else { |
||||||
|
foreach candidate [list [file join $projectroot bin punk902z.exe] [file join $projectroot bin punkshell902]] { |
||||||
|
if {[file exists $candidate]} { |
||||||
|
set punkexe $candidate |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
testConstraint punkexeavailable [expr {$punkexe ne "" && [file exists $punkexe]}] |
||||||
|
|
||||||
|
variable maketcl_run_timeout_ms 60000 |
||||||
|
|
||||||
|
variable runstate |
||||||
|
array set runstate {} |
||||||
|
|
||||||
|
proc maketcl_run_read {chan} { |
||||||
|
variable runstate |
||||||
|
append runstate(output) [read $chan] |
||||||
|
if {[chan eof $chan]} { |
||||||
|
chan event $chan readable {} |
||||||
|
set runstate(done) eof |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#Run <punkexe> script src/make.tcl <subcommand...> with output captured through a |
||||||
|
#pipe (stdin half-closed for immediate EOF - make.tcl must never wait on stdin for |
||||||
|
#these subcommands). Returns dict: timedout 0|1, exitcode <int|"">, output |
||||||
|
#<combined stdout+stderr>. |
||||||
|
proc maketcl_run {cmdargs} { |
||||||
|
variable runstate |
||||||
|
variable maketcl_run_timeout_ms |
||||||
|
variable punkexe |
||||||
|
variable maketcl |
||||||
|
array unset runstate |
||||||
|
set runstate(output) "" |
||||||
|
set runstate(done) "" |
||||||
|
|
||||||
|
set chan [open |[list $punkexe script $maketcl {*}$cmdargs 2>@1] r+] |
||||||
|
chan configure $chan -blocking 0 -translation binary |
||||||
|
catch {chan close $chan write} ;#no stdin for the child - immediate EOF |
||||||
|
set timerid [after $maketcl_run_timeout_ms [list set [namespace current]::runstate(done) timeout]] |
||||||
|
chan event $chan readable [list [namespace current]::maketcl_run_read $chan] |
||||||
|
while {$runstate(done) eq ""} { |
||||||
|
vwait [namespace current]::runstate(done) |
||||||
|
} |
||||||
|
after cancel $timerid |
||||||
|
set timedout [expr {$runstate(done) eq "timeout"}] |
||||||
|
set exitcode "" |
||||||
|
if {$timedout} { |
||||||
|
catch {exec {*}[auto_execok taskkill] /F /T /PID [lindex [pid $chan] 0]} |
||||||
|
catch {chan close $chan} |
||||||
|
} else { |
||||||
|
chan configure $chan -blocking 1 |
||||||
|
if {[catch {chan close $chan} errdata errdict]} { |
||||||
|
set exitcode [lindex [dict get $errdict -errorcode] end] |
||||||
|
} else { |
||||||
|
set exitcode 0 |
||||||
|
} |
||||||
|
} |
||||||
|
return [dict create timedout $timedout exitcode $exitcode output $runstate(output)] |
||||||
|
} |
||||||
|
|
||||||
|
#Fixture kit mappings through the PUNK_MAPVFS_CONFIG env seam (fixture files in |
||||||
|
#the tcltest temp dir - the real mapping is never edited). Same helper shape as |
||||||
|
#maketclbakelist.test. |
||||||
|
proc maketcl_run_mapseam {fixturename fixturelines cmdargs} { |
||||||
|
set fixture [tcltest::makeFile [join $fixturelines \n] $fixturename] |
||||||
|
set ::env(PUNK_MAPVFS_CONFIG) [file normalize $fixture] |
||||||
|
try { |
||||||
|
return [maketcl_run $cmdargs] |
||||||
|
} finally { |
||||||
|
unset -nocomplain ::env(PUNK_MAPVFS_CONFIG) |
||||||
|
tcltest::removeFile $fixturename |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#added 2026-07-31 (agent, G-127) |
||||||
|
test maketcl_bakelist_twotarget_onevfs_distinct_locations {one vfs definition under two targets: default-target kit keeps flat locations (no target=/out= notes), non-default-target kit resolves under kits/<platform>/ in both src/_build and bin} -constraints {punkexeavailable} -body { |
||||||
|
set r [maketcl_run_mapseam fixture_twotarget.toml { |
||||||
|
{[kit.fixnat]} |
||||||
|
{runtime = "tclsfe-x64"} |
||||||
|
{vfs = "punk9wintk903.vfs"} |
||||||
|
{type = "zip"} |
||||||
|
{} |
||||||
|
{[kit.fixlin]} |
||||||
|
{runtime = "tclkit-902-Linux64-intel-dyn"} |
||||||
|
{vfs = "punk9wintk903.vfs"} |
||||||
|
{type = "kit"} |
||||||
|
{target = "linux-x86_64"} |
||||||
|
} {bakelist fixnat fixlin}] |
||||||
|
set out [dict get $r output] |
||||||
|
set result [list] |
||||||
|
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode] |
||||||
|
#default-target row: flat locations, no target=/out= notes (runtime=missing may |
||||||
|
#legitimately appear on a host without the runtime - only the location notes matter) |
||||||
|
lappend result natrow [regexp {(?n)^fixnat\s+zip\s+tclsfe-x64\s+punk9wintk903\.vfs\s} $out] |
||||||
|
lappend result natnonotes [expr {![regexp {(?n)^fixnat\s.*(target=|out=)} $out]}] |
||||||
|
lappend result natbuild [regexp {(?n)^\s+build product: src/_build/fixnat\.exe } $out] |
||||||
|
lappend result natdeploy [regexp {(?n)^\s+deployed:\s+bin/fixnat\.exe } $out] |
||||||
|
#non-default-target row: kits/<platform>/ tier both sides, suffixless for linux |
||||||
|
lappend result linrow [regexp {(?n)^fixlin\s+kit\s+tclkit-902-Linux64-intel-dyn\s+punk9wintk903\.vfs\s+\S+\s.*target=linux-x86_64 out=kits/linux-x86_64/} $out] |
||||||
|
lappend result linbuild [regexp {(?n)^\s+build product: src/_build/kits/linux-x86_64/fixlin } $out] |
||||||
|
lappend result lindeploy [regexp {(?n)^\s+deployed:\s+bin/kits/linux-x86_64/fixlin } $out] |
||||||
|
set result |
||||||
|
} -result {timedout 0 exitcode 0 natrow 1 natnonotes 1 natbuild 1 natdeploy 1 linrow 1 linbuild 1 lindeploy 1} |
||||||
|
|
||||||
|
#added 2026-07-31 (agent, G-127) |
||||||
|
test maketcl_bakelist_same_name_two_nonnative_coexist {two NON-NATIVE targets sharing one kit name: two rows, locations split by platform tier (and target-driven .exe suffix), no runtime-name rename} -constraints {punkexeavailable} -body { |
||||||
|
#legacy line format carries an explicit kitname element, letting two entries |
||||||
|
#declare the SAME output name for different targets |
||||||
|
set r [maketcl_run_mapseam fixture_samename.config { |
||||||
|
{tclkit-902-Linux64-intel-dyn {punk9wintk903.vfs fixsame kit linux-x86_64}} |
||||||
|
{tclsh8.6.10-luck-zip.exe {punk9wintk903.vfs fixsame zip win32-ix86}} |
||||||
|
} {bakelist fixsame}] |
||||||
|
set out [dict get $r output] |
||||||
|
set result [list] |
||||||
|
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode] |
||||||
|
lappend result linrow [regexp {(?n)^fixsame\s+kit\s+tclkit-902-Linux64-intel-dyn\s+punk9wintk903\.vfs\s+\S+\s.*out=kits/linux-x86_64/} $out] |
||||||
|
lappend result ixrow [regexp {(?n)^fixsame\s+zip\s+tclsh8\.6\.10-luck-zip\s+punk9wintk903\.vfs\s+\S+\s.*out=kits/win32-ix86/} $out] |
||||||
|
#the pre-G-127 behaviour disambiguated the second row by RUNTIME name - pin its absence |
||||||
|
lappend result norename [expr {![regexp {(?n)^fixsame_} $out]}] |
||||||
|
#distinct artifacts by construction: same name, two tiers, suffix follows target |
||||||
|
lappend result linbuild [regexp {(?n)^\s+build product: src/_build/kits/linux-x86_64/fixsame } $out] |
||||||
|
lappend result ixbuild [regexp {(?n)^\s+build product: src/_build/kits/win32-ix86/fixsame\.exe } $out] |
||||||
|
set result |
||||||
|
} -result {timedout 0 exitcode 0 linrow 1 ixrow 1 norename 1 linbuild 1 ixbuild 1} |
||||||
|
|
||||||
|
#added 2026-07-31 (agent, G-127) |
||||||
|
test maketcl_bakelist_same_name_same_target_still_renamed {a same-name SAME-target duplicate keeps the historical <name>_<runtime> disambiguation} -constraints {punkexeavailable} -body { |
||||||
|
set r [maketcl_run_mapseam fixture_sametarget.config { |
||||||
|
{tclsfe-x64.exe {punk9wintk903.vfs fixdup zip}} |
||||||
|
{tclsh905.exe {punk9wintk905.vfs fixdup zip}} |
||||||
|
} {bakelist}] |
||||||
|
set out [dict get $r output] |
||||||
|
set result [list] |
||||||
|
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode] |
||||||
|
lappend result firstrow [regexp {(?n)^fixdup\s+zip\s+tclsfe-x64\s} $out] |
||||||
|
lappend result renamedrow [regexp {(?n)^fixdup_tclsh905\s+zip\s+tclsh905\s} $out] |
||||||
|
set result |
||||||
|
} -result {timedout 0 exitcode 0 firstrow 1 renamedrow 1} |
||||||
|
|
||||||
|
cleanupTests |
||||||
|
} |
||||||
|
namespace delete ::testspace |
||||||
Loading…
Reference in new issue