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
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
|
|
|