Browse Source
- new punk::args::parse_status: documented status structure from a parse attempt (overall ok / status valid|invalid|incomplete / scheme / message / errorcode minus -argspecs / failureclass / badarg / form / receivednames + per-argument argstatus with class, status ok|bad|unparsed, received count/positions, value-in-effect incl -default fill); validation failures reported in the structure, not raised
- arg_error -parsestatus: both renderers derive goodarg/badarg row marking and choice value-in-effect highlighting from the structure (transient goodargs/badarg locals replaced; built internally from -badarg/-parsedargs when not supplied)
- per-render scheme colour resolution: documented -scheme choice value 'nocolour' now takes effect and scheme renders no longer mutate the shared arg_error_CLR array (strike-only goodarg leak fixed)
- parse: new -caller option overriding the %caller% frame-walk substitution (included in parse cache key); get_dict missingrequiredvalue/missingrequiredleader now carry -badarg (type/allocation failures get badarg marking, not just choice violations)
- punk::ns::cmdhelp: -return dict {origin docid cmdtype args_remaining parsestatus}; advisory parse via parse_status on both alias and main paths; explicit -scheme honoured on the parse-failure render; failure messages name the queried command instead of leaking the internal parse source line at top call depth
- tests: parsestatus.test new (12); usagemarking.test G-049 GAP pins flipped + -parsestatus parity/badarg render tests (17); cmdhelp.test G-049 GAP pins flipped + cmdhelp_return_dict_* (25); punk/args + punk/ns trees green on Tcl 9.0.3 and 8.7; full source-tree suite baseline unchanged (exec-14.3 only)
- punkshell 0.5.0: CHANGELOG entry; src/tests/modules/AGENTS.md test-index blurbs updated
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
10 changed files with 820 additions and 179 deletions
@ -1,3 +1,3 @@
|
||||
[project] |
||||
name = "punkshell" |
||||
version = "0.4.15" |
||||
version = "0.5.0" |
||||
|
||||
@ -0,0 +1,188 @@
|
||||
package require tcltest |
||||
|
||||
package require punk::args |
||||
|
||||
#Unit coverage of the G-049 parse-status data model: punk::args::parse_status runs a |
||||
#parse attempt and returns the documented status structure (validation failures are |
||||
#reported in the structure, not raised). The rendering side - arg_error consuming the |
||||
#structure via -parsestatus and the goodarg/badarg/goodchoice marking derived from it - |
||||
#is covered in usagemarking.test; integration through punk::ns::cmdhelp -return dict in |
||||
#src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test. |
||||
|
||||
namespace eval ::testspace { |
||||
namespace import ::tcltest::* |
||||
variable common { |
||||
set result "" |
||||
} |
||||
|
||||
#--- fixtures ---------------------------------------------------------------------------- |
||||
|
||||
punk::args::define { |
||||
@id -id ::testspace::psfix |
||||
@cmd -name testspace::psfix -summary "psfix summary" -help "psfix help" |
||||
@leaders -min 1 -max 1 |
||||
lvarname -type string |
||||
@opts |
||||
-sh|--shape -type string -default square |
||||
-flag -type none |
||||
@values -min 2 -max 2 |
||||
firstval -type int |
||||
lastval -type int |
||||
} |
||||
|
||||
punk::args::define { |
||||
@id -id ::testspace::pschoosy |
||||
@cmd -name testspace::pschoosy -summary "pschoosy summary" -help "pschoosy help" |
||||
@leaders -min 1 -max 1 |
||||
animal -choices {cat dog emu} |
||||
@opts |
||||
-shade -choices {light dark} -default dark |
||||
@values -min 1 -max 1 |
||||
volume -type int |
||||
} |
||||
|
||||
#--- success ----------------------------------------------------------------------------- |
||||
|
||||
test parsestatus_valid_overall {a fully-valid argument set reports ok/valid/info with empty failure fields}\ |
||||
-setup $common -body { |
||||
set ps [punk::args::parse_status {v1 -flag 0 1} withid ::testspace::psfix] |
||||
lappend result [dict get $ps ok] [dict get $ps status] [dict get $ps scheme] |
||||
lappend result [dict get $ps message] [dict get $ps errorcode] [dict get $ps failureclass] [dict get $ps badarg] |
||||
lappend result [dict get $ps id] [dict get $ps form] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 valid info {} {} {} {} ::testspace::psfix _default] |
||||
|
||||
test parsestatus_valid_argstatus {received arguments report status ok with positions and value-in-effect; an unreceived opt reports unparsed}\ |
||||
-setup $common -body { |
||||
set ps [punk::args::parse_status {v1 -flag 0 1} withid ::testspace::psfix] |
||||
set as [dict get $ps argstatus] |
||||
lappend result [dict keys $as] |
||||
lappend result [dict get $as lvarname status] [dict get $as lvarname class] [dict get $as lvarname value] |
||||
lappend result [dict get $as firstval status] [dict get $as firstval value] [dict get $as firstval positions] |
||||
#-sh|--shape not received: unparsed, received count 0 |
||||
lappend result [dict get $as -sh|--shape status] [dict get $as -sh|--shape received] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list {lvarname -sh|--shape -flag firstval lastval} ok leader v1 ok 0 2 unparsed 0] |
||||
|
||||
test parsestatus_optionset_alias_folding {an opt received via an alias of an -alias|--fullname optionset is folded to the optionset name}\ |
||||
-setup $common -body { |
||||
set ps [punk::args::parse_status {v1 -sh circle 0 1} withid ::testspace::psfix] |
||||
lappend result [expr {"-sh|--shape" in [dict get $ps receivednames]}] |
||||
lappend result [dict get $ps argstatus -sh|--shape status] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 ok] |
||||
|
||||
test parsestatus_default_value_in_effect {an unsupplied argument filled from -default carries the value-in-effect with status unparsed}\ |
||||
-setup $common -body { |
||||
set ps [punk::args::parse_status {cat 5} withid ::testspace::pschoosy] |
||||
set shade [dict get $ps argstatus -shade] |
||||
lappend result [dict get $shade status] [dict get $shade hasvalue] [dict get $shade value] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list unparsed 1 dark] |
||||
|
||||
#--- validation failures ----------------------------------------------------------------- |
||||
|
||||
test parsestatus_choiceviolation_invalid {a choice violation reports invalid with the offending argument status bad and its failure class}\ |
||||
-setup $common -body { |
||||
set ps [punk::args::parse_status {horse 5} withid ::testspace::pschoosy] |
||||
lappend result [dict get $ps ok] [dict get $ps status] [dict get $ps scheme] |
||||
lappend result [dict get $ps badarg] [dict get $ps failureclass] |
||||
lappend result [dict get $ps argstatus animal status] [dict get $ps argstatus animal failureclass] |
||||
lappend result [dict get $ps argstatus volume status] |
||||
lappend result [expr {[dict get $ps message] ne ""}] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 0 invalid error animal choiceviolation bad choiceviolation unparsed 1] |
||||
|
||||
test parsestatus_typed_value_allocation_failure {a supplied word failing its -type check surfaces as an allocation shortfall WITH the unfillable argument as badarg}\ |
||||
-setup $common -body { |
||||
set ps [punk::args::parse_status {v1 x x} withid ::testspace::psfix] |
||||
lappend result [dict get $ps ok] [dict get $ps failureclass] [dict get $ps badarg] |
||||
lappend result [dict get $ps argstatus firstval status] |
||||
lappend result [dict get $ps argstatus lastval status] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 0 missingrequiredvalue firstval bad unparsed] |
||||
|
||||
test parsestatus_count_shortfall_incomplete {too few values reports incomplete with no offending argument}\ |
||||
-setup $common -body { |
||||
set ps [punk::args::parse_status {v1} withid ::testspace::psfix] |
||||
lappend result [dict get $ps ok] [dict get $ps status] [dict get $ps failureclass] [dict get $ps badarg] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 0 incomplete trailingvaluecount {}] |
||||
|
||||
test parsestatus_count_excess_invalid {too many values reports invalid (the count classes only classify as incomplete below the minimum)}\ |
||||
-setup $common -body { |
||||
set ps [punk::args::parse_status {v1 0 1 2} withid ::testspace::psfix] |
||||
lappend result [dict get $ps ok] [dict get $ps status] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 0 invalid] |
||||
|
||||
test parsestatus_errorcode_argspecs_stripped {the reported errorcode keeps classification and custom keys but not the bulky -argspecs payload}\ |
||||
-setup $common -body { |
||||
set ps [punk::args::parse_status {horse 5} withid ::testspace::pschoosy] |
||||
set ecode [dict get $ps errorcode] |
||||
lappend result [lrange $ecode 0 1] |
||||
lappend result [lindex [lindex $ecode 2] 0] |
||||
lappend result [expr {"-argspecs" in $ecode}] |
||||
lappend result [expr {"-badarg" in $ecode}] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list {PUNKARGS VALIDATION} choiceviolation 0 1] |
||||
|
||||
#--- caller attribution ------------------------------------------------------------------ |
||||
|
||||
test parsestatus_caller_attribution {-caller replaces %caller% in the failure message; the default is the definition's @cmd -name}\ |
||||
-setup $common -body { |
||||
set ps [punk::args::parse_status {v1} -caller "my queried command" withid ::testspace::psfix] |
||||
lappend result [string match "*my queried command*" [dict get $ps message]] |
||||
set ps [punk::args::parse_status {v1} withid ::testspace::psfix] |
||||
lappend result [string match "*testspace::psfix*" [dict get $ps message]] |
||||
lappend result [string match {*punk::args::parse*} [dict get $ps message]] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 1 0] |
||||
|
||||
#--- withdef form ------------------------------------------------------------------------ |
||||
|
||||
test parsestatus_withdef {parse_status accepts an inline definition via withdef}\ |
||||
-setup $common -body { |
||||
set ps [punk::args::parse_status {-x 5} withdef { |
||||
@id -id ::testspace::psinline |
||||
@opts |
||||
-x -type int |
||||
}] |
||||
lappend result [dict get $ps ok] [dict get $ps argstatus -x status] [dict get $ps argstatus -x value] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 ok 5] |
||||
|
||||
#--- non-validation errors still raise --------------------------------------------------- |
||||
|
||||
test parsestatus_unknown_id_raises {an unknown definition id raises rather than being reported in the structure}\ |
||||
-setup $common -body { |
||||
lappend result [catch {punk::args::parse_status {a b} withid ::testspace::no_such_definition} emsg] |
||||
lappend result [string match "*no such id*" $emsg] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 1] |
||||
} |
||||
tcltest::cleanupTests ;#needed to produce test summary line. |
||||
Loading…
Reference in new issue