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.
 
 
 
 
 
 

255 lines
13 KiB

package require tcltest
#Piped characterization of the make.tcl bakelist report and the bake-side selective
#kit-name validation (goal G-121). Runs the WORKING TREE's src/make.tcl under the
#built punk executable's 'script' subcommand with output captured through a pipe,
#and pins:
# - 'bakelist' exits 0, output is ESC-free (G-113 piped policy), the stable header
# row is present and the punk91 row carries the expected type/runtime/vfs columns
# with a deployed state from the documented vocabulary
# - 'bakelist <kitname>' filters to the named entry and appends the per-kit detail
# block; unfiltered rows do not appear
# - 'bakelist <unknown>' exits 1 naming the unknown and listing the configured names
# - 'bake <unknown>' exits 1 BEFORE any build ("nothing built"), listing the
# configured names - the no-build guarantee of selective bake
#The row pins are characterization of the current src/runtime/mapvfs.toml kit
#matrix (punk91 = tclsfe-x64 + punk9wintk903.vfs, zip) - a deliberate config change
#legitimately updates them.
#G-024 additions: @group selection, toml parsing exercised through the
#PUNK_MAPVFS_CONFIG env seam (fixture configs - the real mapping is never edited):
#versioned-scheme expansion, strict entry-named config errors, and the legacy
#mapvfs.config deprecation NOTE.
#
#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)]
}
proc esc_count {text} {
return [regexp -all {\x1b} $text]
}
#added 2026-07-26 (agent, G-121)
test maketcl_bakelist_full_report {piped make.tcl bakelist: exit 0, ESC-free, header row + punk91 row with documented deployed vocabulary} -constraints {punkexeavailable} -body {
set r [maketcl_run {bakelist}]
set out [dict get $r output]
set result [list]
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode]
lappend result esc [esc_count $out]
lappend result header [regexp {(?n)^kit\s+type\s+runtime\s+vfs\s+deployed\s*$} $out]
lappend result punk91row [regexp {(?n)^punk91\s+zip\s+tclsfe-x64\s+punk9wintk903\.vfs\s+(current|stale|absent|nobuild)\y} $out]
set result
} -result {timedout 0 exitcode 0 esc 0 header 1 punk91row 1}
#added 2026-07-26 (agent, G-121)
test maketcl_bakelist_filtered_detail {bakelist punk91 filters to the named entry and appends the per-kit detail block} -constraints {punkexeavailable} -body {
set r [maketcl_run {bakelist punk91}]
set out [dict get $r output]
set result [list]
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode]
lappend result punk91row [regexp {(?n)^punk91\s+zip\s+} $out]
lappend result otherrows [regexp {(?n)^(punk905|punkbi|punksys|punk86)\s} $out]
lappend result detailblock [regexp {(?n)^detail: punk91\s*$} $out]
lappend result detailpaths [regexp {(?n)^\s+build product: src/_build/punk91} $out]
set result
} -result {timedout 0 exitcode 0 punk91row 1 otherrows 0 detailblock 1 detailpaths 1}
#added 2026-07-26 (agent, G-121)
test maketcl_bakelist_unknown_name {bakelist with an unknown kit name exits 1 naming it and listing the configured names} -constraints {punkexeavailable} -body {
set r [maketcl_run {bakelist nosuchkitxyz}]
set out [dict get $r output]
set result [list]
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode]
lappend result named [regexp {bakelist: unknown kit name\(s\): nosuchkitxyz} $out]
lappend result confignames [regexp {configured kit outputs: .*punk91} $out]
set result
} -result {timedout 0 exitcode 1 named 1 confignames 1}
#added 2026-07-26 (agent, G-121)
test maketcl_bake_unknown_name_no_build {bake with an unknown kit name exits 1 before any build, listing the configured names} -constraints {punkexeavailable} -body {
set r [maketcl_run {bake nosuchkitxyz}]
set out [dict get $r output]
set result [list]
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode]
lappend result nothingbuilt [regexp {make\.tcl bake: unknown kit name\(s\): nosuchkitxyz - nothing built} $out]
lappend result confignames [regexp {configured kit outputs: .*punk91} $out]
#the run must never reach the kit machinery (no vfs scan / kit processing output)
lappend result nomachinery [expr {![regexp {processing targetkit:} $out]}]
set result
} -result {timedout 0 exitcode 1 nothingbuilt 1 confignames 1 nomachinery 1}
#added 2026-07-31 (agent, G-024)
test maketcl_bakelist_group_filter {bakelist @verify-ix86 selects the group's rows and no others} -constraints {punkexeavailable} -body {
set r [maketcl_run {bakelist @verify-ix86}]
set out [dict get $r output]
set result [list]
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode]
lappend result luckrow [regexp {(?n)^punkluck86\s+zip\s+} $out]
lappend result sferow [regexp {(?n)^punk91ix86\s+zip\s+} $out]
lappend result groupnote [regexp {group=verify-ix86} $out]
lappend result otherrows [regexp {(?n)^(punk91|punk905|punkbi|punksys|punk86)\s} $out]
set result
} -result {timedout 0 exitcode 0 luckrow 1 sferow 1 groupnote 1 otherrows 0}
#G-024 toml characterization runs through the PUNK_MAPVFS_CONFIG env seam so the
#REAL kit mapping is never edited (fixture files in the tcltest temp dir).
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-024)
test maketcl_bakelist_toml_scheme_expansion {fixture toml via PUNK_MAPVFS_CONFIG: one versioned scheme entry expands to <prefix>-<version> + <prefix>-dev + release-gated <prefix> rows} -constraints {punkexeavailable} -body {
set r [maketcl_run_mapseam fixture_scheme.toml {
{[kit.fixkit]}
{runtime = "tclsfe-x64"}
{vfs = "punk9wintk903.vfs"}
{type = "zip"}
{group = "fixg"}
{}
{[scheme.fixscheme]}
{scheme = "versioned"}
{prefix = "fixv"}
{runtime = "tclsfe-x64"}
{vfs = "punk9wintk903.vfs"}
{type = "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 fixkitrow [regexp {(?n)^fixkit\s+zip\s+tclsfe-x64\s+punk9wintk903\.vfs\s} $out]
lappend result groupnote [regexp {(?n)^fixkit\s.*group=fixg} $out]
#version derives from punkproject.toml at parse time - pin the shape, not the number
lappend result versionedrow [regexp {(?n)^fixv-\d+[^ ]*\s+zip\s+.*scheme=versioned} $out]
lappend result devrow [regexp {(?n)^fixv-dev\s+zip\s+.*scheme=dev} $out]
lappend result releaserow [regexp {(?n)^fixv\s+zip\s+.*scheme=release} $out]
#the real config's rows must not appear - the seam fully replaces the mapping
lappend result realrows [regexp {(?n)^punk91\s} $out]
set result
} -result {timedout 0 exitcode 0 fixkitrow 1 groupnote 1 versionedrow 1 devrow 1 releaserow 1 realrows 0}
#added 2026-07-31 (agent, G-024)
test maketcl_bakelist_toml_configerror_names_entry {fixture toml with an unknown key: CONFIG FILE ERROR names the offending [kit.<name>] entry and the key} -constraints {punkexeavailable} -body {
set r [maketcl_run_mapseam fixture_badkey.toml {
{[kit.badkit]}
{runtime = "tclsfe-x64"}
{vfs = "punk9wintk903.vfs"}
{typo_key = "zip"}
} {bakelist}]
set out [dict get $r output]
set result [list]
lappend result timedout [dict get $r timedout]
lappend result entrynamed [regexp {CONFIG FILE ERROR\. entry kit\.badkit .*unknown key 'typo_key'} $out]
set result
} -result {timedout 0 entrynamed 1}
#added 2026-07-31 (agent, G-024)
test maketcl_bake_toml_configerror_aborts {bake against a fixture toml with an unknown scheme kind exits 3 before any build, naming the entry} -constraints {punkexeavailable} -body {
set r [maketcl_run_mapseam fixture_badscheme.toml {
{[scheme.badscheme]}
{scheme = "nosuchscheme"}
{runtime = "tclsfe-x64"}
{vfs = "punk9wintk903.vfs"}
{type = "zip"}
} {bake badname}]
set out [dict get $r output]
set result [list]
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode]
lappend result entrynamed [regexp {CONFIG FILE ERROR\. entry scheme\.badscheme .*unknown scheme 'nosuchscheme'} $out]
lappend result nomachinery [expr {![regexp {processing targetkit:} $out]}]
set result
} -result {timedout 0 exitcode 3 entrynamed 1 nomachinery 1}
#added 2026-07-31 (agent, G-024)
test maketcl_bakelist_legacy_deprecation_note {fixture legacy line-format config via the seam: parsed with the deprecation NOTE, rows still resolve} -constraints {punkexeavailable} -body {
set r [maketcl_run_mapseam fixture_legacy.config {
{tclsfe-x64.exe {punk9wintk903.vfs fixlegacy 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 depnote [regexp {NOTE: .*deprecated mapvfs\.config line format} $out]
lappend result legacyrow [regexp {(?n)^fixlegacy\s+zip\s+tclsfe-x64\s+punk9wintk903\.vfs\s} $out]
set result
} -result {timedout 0 exitcode 0 depnote 1 legacyrow 1}
cleanupTests
}
namespace delete ::testspace