Browse Source

G-040 proposed (punk::args -choicealiases); choice-flow characterization tests; -choice* doc clarifications

- GOALS.md: G-040 punk::args choice aliasing with parse normalization, display
  folding, and doc-lookup parity (user-approved); detail file records the
  prefix/deny/reserve collapse analysis from the punk::help work, the
  cmd_traverse divergence, the c/to/tc minimum-prefix policy question, and the
  test-first sequencing
- new punk/ns cmdflow.test (10 tests): cmdwhich/cmdinfo/cmd_traverse docid
  flow - direct, via-alias and subhelp-choiceinfo resolution (exact + unique
  prefix), unknown-word fallback to parent docid, -choiceprefix 0 exact-only,
  space-delimited ids, cmdhelp -return string smoke; the parse-vs-doc-walk
  divergence (deny/reserve lists honoured by punk::args::parse, ignored by the
  cmd_traverse walk) pinned as GAP tests pending G-040
- choices.test: 4 new unrestricted-mode (-choicerestricted 0) tests - prefix
  normalization to the canonical choice, unknown/ambiguous passthrough,
  denylist and reservelist passthrough, and the punk::help collapse recipe
  (prefix+deny+reserve on a -multiple leader)
- punk::args 0.2.2 (doc-only): define doc -choice* fields now state the
  -choicerestricted 0 passthrough semantics, -choiceprefix result
  normalization + minimal-prefix display highlighting, denylist behaviour for
  shorter prefixes in both restricted modes, and the reservelist phantom-entry
  idiom for per-choice minimum-prefix control
- suites: punk/args 74 pass + 1 skip (was 70+1), punk/ns 18 pass (was 8)

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 week ago
parent
commit
e45fea9b16
  1. 1
      CHANGELOG.md
  2. 6
      GOALS.md
  3. 102
      goals/G-040-punkargs-choicealiases.md
  4. 27
      src/modules/punk/args-999999.0a1.0.tm
  5. 3
      src/modules/punk/args-buildversion.txt
  6. 105
      src/tests/modules/punk/args/testsuites/args/choices.test
  7. 243
      src/tests/modules/punk/ns/testsuites/ns/cmdflow.test

1
CHANGELOG.md

@ -7,6 +7,7 @@ Entries are newest-first; one bullet per notable change. See the root `AGENTS.md
## [0.4.4] - 2026-07-08
- punk::args 0.2.2 (doc-only): the `punk::args::define` documentation for the -choice* fields now spells out the verified interplay semantics — `-choicerestricted 0` passthrough of non-matching/ambiguous/denied/reserved words, `-choiceprefix` normalization of accepted prefixes to the canonical choice in parse results (with minimal-prefix highlighting in usage display), and the `-choiceprefixreservelist` phantom-entry idiom for per-choice minimum-prefix control. Characterization tests added (choices.test unrestricted-mode tests; new punk/ns cmdflow.test for the cmdwhich/cmdinfo/cmd_traverse docid flow, pinning the parse-vs-doc-walk deny/reserve divergence as GAP pending G-040).
- help system restructured onto a topic registry (punk module 0.2.0, `::punk::helptopic`): each topic (`topics|help`, `tcl`, `env|environment`, `console|term|terminal`) is a handler proc with its own punk::args definition, and the `::punk::help`/`::punk::help_chunks` definitions are (re)generated from the registry — `i help` now renders a documented usage table with topic choices and summaries, and `i help <topic>` shows per-topic documented usage (previously an autogenerated stub). `help topics` is derived from the registry (lists all aliases, fits 80 columns). No-arg overview and command-fallthrough (`help <cmdname>`) output byte-identical to before; 80-column layout preserved; verified on both generations, script and shell subcommands. `help env` without an initialised punk::config (e.g. script contexts) degrades to a one-line notice instead of an error stack. The registry is the intended seam for future subshell-declared topics (punk::config-gated — not yet a goal).
## [0.4.3] - 2026-07-08

6
GOALS.md

@ -284,3 +284,9 @@ Scope: src/modules/punk/repl-999999.0a1.0.tm (console reader/event loop and EOF/
Detail: goals/G-039-orphan-console-spin.md
Goal: the observed failure mode - an interactive punk902z left running after its hosting terminal/console went away spins roughly a full core indefinitely (observed 2026-07-08: a 37-minute orphan with a single hard-looping thread) - is reliably reproduced and root-caused, then fixed or mitigated so a shell whose console dies exits or reaches zero-CPU idle cleanly.
Acceptance: a documented procedure reproduces the spin on the current kit (e.g. launch an interactive shell in a terminal, then kill/close the hosting terminal or conhost), or the investigation records the attempts made and what evidence would reopen it; the spinning code path is identified (prime suspect: a console read/event loop treating a dead console's immediate EOF/error as retryable without backoff or termination - adjacent to the console-EOF restart path G-038 takes ownership of); after fix/mitigation, the same procedure shows the orphaned process exiting or settling at effectively zero CPU within a short grace period, with live-console interactive behaviour unchanged; the wedge-scoring hazard note (orphans polluting process-liveness checks in test harnesses) is updated to match the outcome.
### G-040 [proposed] punk::args choice aliasing (-choicealiases) with parse normalization, display folding, and doc-lookup parity
Scope: src/modules/punk/args-999999.0a1.0.tm (parse + usage rendering), src/modules/punk/ns-999999.0a1.0.tm (cmdinfo/cmd_traverse choice resolution parity), src/modules/punk-999999.0a1.0.tm (punk::help topic argdoc as first consumer), src/tests/modules/punk/args/testsuites/, src/tests/modules/punk/ns/testsuites/
Detail: goals/G-040-punkargs-choicealiases.md
Goal: punk::args supports choice aliases (-choicealiases {alias canonical ...}) accepted at parse and normalized to the canonical choice in results, folded into the canonical entry in usage display - and the punk::ns doc-lookup walk resolves choice words by the same rules as the parser (aliases, -choiceprefix, -choiceprefixdenylist, -choiceprefixreservelist) - so alias sets like punk::help's topics|help and console|term|terminal collapse to one displayed entry per topic with `help X` and `i help X` agreeing.
Acceptance: a definition using -choicealiases parses an alias (and an alias prefix where -choiceprefix allows) to its canonical choice in the parse result, with -choicerestricted 0 passthrough and the deny/reserve lists honoured unchanged; usage display shows one entry per canonical choice with aliases folded (no duplicate rows; -choicelabels attach to the canonical); punk::ns::cmdinfo/cmd_traverse resolve subcommand words to docids with the same outcome as the parser for alias, prefix, denied, reserved and unknown words (the pre-goal characterization tests updated from pinned-GAP to fixed); punk::help's topic definition adopts the feature so `i help` lists one entry per registered topic while `help h`/`help e` still fall through to command lookup; definitions without -choicealiases behave unchanged (existing punk::args and punk::ns suites pass).

102
goals/G-040-punkargs-choicealiases.md

@ -0,0 +1,102 @@
# G-040 punk::args choice aliasing (-choicealiases) with parse normalization, display folding, and doc-lookup parity
Status: proposed
Scope: src/modules/punk/args-999999.0a1.0.tm (parse + usage rendering), src/modules/punk/ns-999999.0a1.0.tm (cmdinfo/cmd_traverse choice resolution parity), src/modules/punk-999999.0a1.0.tm (punk::help topic argdoc as first consumer), src/tests/modules/punk/args/testsuites/, src/tests/modules/punk/ns/testsuites/
Acceptance: a definition using -choicealiases parses an alias (and an alias prefix where -choiceprefix allows) to its canonical choice in the parse result, with -choicerestricted 0 passthrough and the deny/reserve lists honoured unchanged; usage display shows one entry per canonical choice with aliases folded (no duplicate rows; -choicelabels attach to the canonical); punk::ns::cmdinfo/cmd_traverse resolve subcommand words to docids with the same outcome as the parser for alias, prefix, denied, reserved and unknown words (the pre-goal characterization tests updated from pinned-GAP to fixed); punk::help's topic definition adopts the feature so `i help` lists one entry per registered topic while `help h`/`help e` still fall through to command lookup; definitions without -choicealiases behave unchanged (existing punk::args and punk::ns suites pass).
## Context
Arose from the 2026-07-08 punk::help topic-registry restructure. The `::punk::help` argdoc
declares the topic leader with `-choices {topics help tcl env environment console term
terminal}` (`-choiceprefix 0 -choicerestricted 0`): every alias is its own choice entry, so
the `i help` usage table shows 8 entries for 4 topics, with duplicated -choicelabels.
What the existing -choice* machinery already expresses (all verified 2026-07-08 on the dev
tree, punk902z src, tcl 9.0.2):
- Prefix-shaped alias pairs collapse completely via `-choiceprefix 1` plus the two lists:
topic ... -choicerestricted 0 -choiceprefix 1
-choices {topics help tcl environment console terminal}
-choiceprefixdenylist {help}
-choiceprefixreservelist {en ter}
gives: `env`..`environment` -> normalized to `environment` in the parse result (the
parser returns the canonical choice, so downstream alias resolution needs no prefix
logic); `e`/`en` pass through to the unrestricted fallthrough (the reserved phantom `en`
blocks them without becoming selectable); `term`+ -> `terminal` with `t`/`te`/`ter`
passing through; `help` requires the full word (denylist) so `h`/`he`/`hel` stay
available as command-fallthrough words; unknown words (`lindex`) pass through unchanged.
- The usage renderer self-documents the scheme: each choice cell highlights its minimal
accepted prefix (bright green `env` in `environment`, `c` in `console`), and a denied
choice renders fully highlighted (type all of it).
- Minimum-prefix policy is fully controllable per word by reserving each shorter phantom
(e.g. reserve `c` and `co` to require `con` for console). Open policy question for
punk::help: whether to allow the free extra prefixes `c`->console, `to`->topics,
`tc`->tcl, which mildly shadow those words as command-fallthrough candidates.
What it cannot express - the actual feature gap:
- Aliases with no prefix relation to their canonical (`help` -> `topics`) must remain
separate displayed choice entries with duplicated labels.
- Even prefix-related aliases remain separate *display* entries when both full words are
listed (`console` and `terminal` both render, same label), because a choice entry is an
atomic string with no canonicalization link.
Hence `-choicealiases {alias canonical ...}`: alias accepted at parse (participating in
prefix calculation like a reservelist entry, but selectable), normalized to its canonical
in the parse result, and folded in usage display (shown as an annotation on the canonical
entry - e.g. dimmed `help` beneath/beside `topics` - not as its own row). -choicelabels
keys stay canonical-only.
## Approach
1. punk::args::define: accept and validate `-choicealiases` (each value must name an
existing choice; alias must not collide with a choice or another alias). Parse layer:
alias hits (exact, or unique prefix when -choiceprefix and not denied/reserved)
normalize to the canonical, before -choicemultiple/-multiple accounting so duplicates
collapse predictably. Usage/arg_error rendering: fold alias names into the canonical
entry's cell; extend the minimal-prefix highlighting to alias words.
2. punk::ns cmd_traverse parity: the subcommand walk currently does its own
`tcl::prefix::match` over -choices/-choicegroups and honours only `-choiceprefix` -
`-choiceprefixdenylist` and `-choiceprefixreservelist` are ignored (divergence proven:
`i help en`-style lookups prefix-match where `help en` execution falls through).
Factor the choice-word resolution into one shared punk::args helper (choices + groups +
aliases + prefix + deny/reserve -> canonical-or-miss) consumed by both the parser and
cmd_traverse, rather than a second implementation. choiceinfo lookups (subhelp et al)
then key on the canonical.
3. punk::help adoption: registry aliases map onto -choicealiases (topics/help,
env/environment, console/term/terminal); decide and record the minimum-prefix policy
(reservelist phantoms) including the c/to/tc question above; `help topics` output and
`helptopic::resolve` stay as-is (resolve receives canonicals from the parse).
4. Test-first sequencing (user-directed): characterization tests for the current parse
choice behaviour (prefix/deny/reserve under -choicerestricted 0, normalization) and the
punk::ns cmdinfo/cmd_traverse docid flow land BEFORE this goal's implementation, with
the parse-vs-traverse divergence pinned as a GAP test (fossilmove pattern). This goal
flips those GAP pins to the fixed behaviour.
## Alternatives considered
- Prefix mechanics alone (no new feature) - covers env|environment and term|terminal but
cannot fold topics|help or unify console/terminal display; rejected as the full answer,
retained as the interim option for punk::help if the feature is deferred.
- Synthesising alias folding in punk::help only (custom display, registry-side resolution)
- rejected: the duplication belongs to every ensemble-style argdoc with alias words, and
cmd_traverse would still diverge; solve it in punk::args once.
- Documenting subcommand aliases via duplicate -choices entries with shared -choicelabels
(status quo) - works but scales the display linearly with alias count and lets labels
drift; this is the shortcoming that motivated the goal.
## Notes
- Session probe scripts (scratchpad, 2026-07-08): choicecollapse.tcl (parse behaviour
table for the deny/reserve/prefix recipe), choicedisplay.tcl (usage rendering of the
collapsed def, minimal-prefix highlighting).
- cmd_traverse divergence site: src/modules/punk/ns-999999.0a1.0.tm ~5157 (subcommand walk
`tcl::prefix::match` over allchoices; consults -choiceprefix at ~5162, never the
deny/reserve lists).
- Parser reservelist/denylist semantics doc: 'i punk::args::define' -choice* section
(clarified 2026-07-08 alongside this goal's creation).
- Related: the punk::help topic registry (punk module 0.2.0) is the intended first
consumer; the possible future punk::config-declared subshell topic sets (not yet a
goal) would inherit the folding for free.

27
src/modules/punk/args-999999.0a1.0.tm

@ -871,19 +871,46 @@ tcl::namespace::eval punk::args {
-choicerestricted <bool>
Whether values not specified in -choices or -choicegroups are
allowed. Defaults to true.
When false, an input that matches no choice - including an
ambiguous prefix, a prefix of a -choiceprefixdenylist entry,
or a -choiceprefixreservelist word - is accepted unchanged as
an ordinary value (subject to -type validation) instead of
raising an error. This passthrough is the pattern for
arguments that mix a known choice set with free-form values
(e.g. a help topic word falling through to command lookup).
-choiceprefix <bool>
This specifies whether unique prefixes are able to be used
instead of the complete string. This is calculated using
tcl::prefix::match - and will display in the autogenerated
usage output. Defaults to true.
A matching prefix is normalized: the parse result contains
the full choice string, never the typed prefix - so callers
switch on canonical choice values only. The usage display
highlights each choice's minimal accepted prefix (a choice
in -choiceprefixdenylist displays fully highlighted - the
whole word is required).
-choiceprefixdenylist {<choices>}
These choices should match exactly a choice entry in one of
the settings -choices or -choicegroups.
These will still be used in prefix calculation - but the full
choice argument must be entered to select the choice.
A shorter prefix of a denied choice is an error when
-choicerestricted is true, and passes through as an ordinary
(non-choice) value when -choicerestricted is false - use this
to keep short words available for other purposes (e.g. with
'help' denied, h/he/hel remain free-form values).
-choiceprefixreservelist {<choices>}
These choices are additional values used in prefix calculation.
The values will not be added to the list of available choices.
A reserved word never matches: entered exactly it is an error
when -choicerestricted is true and passes through when false,
as do any shorter words it shadows into ambiguity. This gives
per-choice control of the minimum accepted prefix by reserving
phantom entries: e.g. -choices {environment}
-choiceprefixreservelist {en} means e/en do not match while
env, envi, ... environment all normalize to environment.
(To require a longer minimum, reserve each shorter form:
reserving {en env} raises the minimum to envi.)
-choicegroups {<dict>}
Generally this would be used instead of -choices to allow
usage display of choices grouped by some name (or the empty

3
src/modules/punk/args-buildversion.txt

@ -1,3 +1,4 @@
0.2.1
0.2.2
#First line must be a semantic version number
#all other lines are ignored.
#0.2.2 - documentation-only: define doc clarifies -choicerestricted 0 passthrough (non-matching/ambiguous/denied/reserved words accepted as ordinary values), -choiceprefix result normalization to the canonical choice + minimal-prefix display highlighting, -choiceprefixdenylist behaviour for shorter prefixes in both restricted modes, and -choiceprefixreservelist phantom-entry idiom for per-choice minimum-prefix control

105
src/tests/modules/punk/args/testsuites/args/choices.test

@ -247,6 +247,111 @@ namespace eval ::testspace {
{leftright {heavy x}}\
{leftright {arc heavy}}\
]
# ---- unrestricted (-choicerestricted 0) interplay with prefix/deny/reserve ----
# Characterization added 2026-07-08 ahead of G-040 (choice aliasing).
# Key properties pinned here:
# - a matching prefix is NORMALIZED to the full (canonical) choice in the parse result
# - non-matching words (unknown, ambiguous prefix, denied prefix, reserved word) pass
# through unchanged instead of erroring - the pattern used by ::punk::help's topic
# leader where unrecognised words fall through to command lookup
test choiceprefix_unrestricted_normalizes_to_canonical {prefix input normalized to the full choice in the parse result when -choicerestricted 0}\
-setup $common -body {
#unique prefix -> canonical choice in result
set argd [punk::args::parse {env} withdef @values {topic -choices {topics environment console} -choiceprefix 1 -choicerestricted 0}]
lappend result [dict get $argd values]
#unknown word passes through unchanged
set argd [punk::args::parse {lindex} withdef @values {topic -choices {topics environment console} -choiceprefix 1 -choicerestricted 0}]
lappend result [dict get $argd values]
#ambiguous prefix passes through unchanged (no error when unrestricted)
set argd [punk::args::parse {t} withdef @values {topic -choices {topics tcl environment} -choiceprefix 1 -choicerestricted 0}]
lappend result [dict get $argd values]
}\
-cleanup {
}\
-result [list\
{topic environment}\
{topic lindex}\
{topic t}\
]
test choiceprefix_denylist_unrestricted_passthrough {denied prefix falls through as an ordinary value when -choicerestricted 0}\
-setup $common -body {
set docid ::testspace::choiceprefix_denylist_unrestricted_passthrough
punk::args::define [list @id -id $docid] @values {action -choices {delete describe} -choiceprefixdenylist {delete} -choicerestricted 0}
#denied prefix -> passthrough, not an error and not a match
set argd [punk::args::parse {del} withid $docid]
lappend result [dict get $argd values]
#full denied word still matches
set argd [punk::args::parse {delete} withid $docid]
lappend result [dict get $argd values]
#undenied choice still prefix-matches and normalizes
set argd [punk::args::parse {des} withid $docid]
lappend result [dict get $argd values]
}\
-cleanup {
punk::args::undefine $docid 1
}\
-result [list\
{action del}\
{action delete}\
{action describe}\
]
test choiceprefix_reservelist_unrestricted_passthrough {reserved word and shorter prefixes fall through when -choicerestricted 0; longer prefixes normalize}\
-setup $common -body {
set docid ::testspace::choiceprefix_reservelist_unrestricted_passthrough
punk::args::define [list @id -id $docid] @values {state -choices {environment} -choiceprefixreservelist {en} -choicerestricted 0}
#shorter than the reserved phantom: ambiguous -> passthrough
set argd [punk::args::parse {e} withid $docid]
lappend result [dict get $argd values]
#the reserved word itself: not a selectable choice -> passthrough
set argd [punk::args::parse {en} withid $docid]
lappend result [dict get $argd values]
#beyond the phantom: unique prefix -> canonical
set argd [punk::args::parse {env} withid $docid]
lappend result [dict get $argd values]
set argd [punk::args::parse {environment} withid $docid]
lappend result [dict get $argd values]
}\
-cleanup {
punk::args::undefine $docid 1
}\
-result [list\
{state e}\
{state en}\
{state environment}\
{state environment}\
]
test choiceprefix_collapse_recipe_multi_leader {combined prefix+deny+reserve on an unrestricted -multiple leader (the punk::help topic pattern)}\
-setup $common -body {
set docid ::testspace::choiceprefix_collapse_recipe_multi_leader
punk::args::define [list @id -id $docid] {@leaders -min 0 -max -1} {topic -optional 1 -multiple 1 -type string -choicerestricted 0 -choiceprefix 1 -choiceprefixdenylist {help} -choiceprefixreservelist {en ter} -choices {topics help tcl environment console terminal}} {@values -min 0 -max 0}
foreach word {env environment en term ter help hel to lindex} {
set argd [punk::args::parse [list $word] withid $docid]
lappend result [dict get [dict get $argd leaders] topic]
}
set result
}\
-cleanup {
punk::args::undefine $docid 1
}\
-result [list\
environment\
environment\
en\
terminal\
ter\
help\
hel\
topics\
lindex\
]
}
tcltest::cleanupTests ;#needed to produce test summary line.

243
src/tests/modules/punk/ns/testsuites/ns/cmdflow.test

@ -0,0 +1,243 @@
package require tcltest
package require punk::args
package require punk::ns
#Tests for the command help/doc-lookup flow: punk::ns::cmdwhich -> cmdinfo -> cmd_traverse
#docid resolution, including punk::args choiceinfo subhelp mapping and the -choiceprefix /
#-choiceprefixdenylist / -choiceprefixreservelist handling of subcommand words.
#Characterization added 2026-07-08 ahead of G-040 (choice aliasing + parse/doc-lookup parity):
#tests marked GAP pin the CURRENT divergence between punk::args::parse and the cmd_traverse
#doc walk (deny/reserve lists honoured by parse, ignored by the walk). G-040 flips those pins.
namespace eval ::testspace {
namespace import ::tcltest::*
variable common {
set result ""
}
#--- fixtures: commands + argdocs exercised by the flow tests ---------------------------
proc flowcmd {args} {}
punk::args::define {
@id -id ::testspace::flowcmd
@cmd -name testspace::flowcmd -summary "flowcmd summary" -help "flowcmd help"
@opts
-flag -type none
@values -min 0 -max -1
item -type string -optional 1 -multiple 1
}
interp alias {} ::testspace::flowalias {} ::testspace::flowcmd
#documented parent with subhelp choiceinfo mapping subcommand words to child docids
proc flowparent {args} {}
punk::args::define {
@id -id ::testspace::flowparent
@cmd -name testspace::flowparent -summary "parent" -help "parent"
@leaders -min 1 -max 1
subcmd -choices {alpha beta} -choiceinfo {
alpha {{doctype punkargs} {subhelp ::testspace::flowsub_alpha}}
beta {{doctype punkargs} {subhelp ::testspace::flowsub_beta}}
}
@values -min 0 -max 0
}
punk::args::define {
@id -id ::testspace::flowsub_alpha
@cmd -name "testspace::flowparent alpha" -summary "alpha subcommand" -help "alpha subcommand"
@values -min 0 -max 0
}
punk::args::define {
@id -id ::testspace::flowsub_beta
@cmd -name "testspace::flowparent beta" -summary "beta subcommand" -help "beta subcommand"
@values -min 0 -max 0
}
#as flowparent but prefixes disallowed on the subcommand word
proc flownoprefix {args} {}
punk::args::define {
@id -id ::testspace::flownoprefix
@cmd -name testspace::flownoprefix -summary "parent noprefix" -help "parent noprefix"
@leaders -min 1 -max 1
subcmd -choiceprefix 0 -choices {alpha beta} -choiceinfo {
alpha {{doctype punkargs} {subhelp ::testspace::flowsub_alpha}}
beta {{doctype punkargs} {subhelp ::testspace::flowsub_beta}}
}
@values -min 0 -max 0
}
#as flowparent but 'alpha' must be typed in full (denylist)
proc flowdeny {args} {}
punk::args::define {
@id -id ::testspace::flowdeny
@cmd -name testspace::flowdeny -summary "parent deny" -help "parent deny"
@leaders -min 1 -max 1
subcmd -choices {alpha beta} -choiceprefixdenylist {alpha} -choiceinfo {
alpha {{doctype punkargs} {subhelp ::testspace::flowsub_alpha}}
beta {{doctype punkargs} {subhelp ::testspace::flowsub_beta}}
}
@values -min 0 -max 0
}
#reserved phantom 'en' raises environment's minimum accepted prefix to 'env'
proc flowreserve {args} {}
punk::args::define {
@id -id ::testspace::flowreserve
@cmd -name testspace::flowreserve -summary "parent reserve" -help "parent reserve"
@leaders -min 1 -max 1
subcmd -choices {environment} -choiceprefixreservelist {en} -choiceinfo {
environment {{doctype punkargs} {subhelp ::testspace::flowsub_env}}
}
@values -min 0 -max 0
}
punk::args::define {
@id -id ::testspace::flowsub_env
@cmd -name "testspace::flowreserve environment" -summary "environment subcommand" -help "environment subcommand"
@values -min 0 -max 0
}
#undocumented command whose subcommand is documented via a space-delimited id
proc flowgap {args} {}
punk::args::define {
@id -id "::testspace::flowgap deep"
@cmd -name "testspace::flowgap deep" -summary "deep subcommand of undocumented parent" -help "deep subcommand"
@values -min 0 -max 0
}
#--- cmdwhich ---------------------------------------------------------------------------
test cmdwhich_proc_alias_notfound {cmdwhich whichtype/origin for proc, alias and missing command}\
-setup $common -body {
set w [punk::ns::cmdwhich ::testspace::flowcmd]
lappend result [dict get $w whichtype]
set w [punk::ns::cmdwhich ::testspace::flowalias]
lappend result [dict get $w whichtype] [dict get $w origin]
set w [punk::ns::cmdwhich ::testspace::no_such_cmd]
lappend result [dict get $w whichtype]
}\
-cleanup {
}\
-result [list proc alias ::testspace::flowcmd notfound]
#--- cmdinfo docid resolution -----------------------------------------------------------
test cmdinfo_docid_direct {cmdinfo returns the explicit punk::args id for a documented proc}\
-setup $common -body {
set cinfo [punk::ns::cmdinfo ::testspace::flowcmd]
lappend result [dict get $cinfo docid] [dict get $cinfo args_remaining]
}\
-cleanup {
}\
-result [list ::testspace::flowcmd {}]
test cmdinfo_docid_via_alias {cmdinfo resolves an alias to its target's docid}\
-setup $common -body {
set cinfo [punk::ns::cmdinfo ::testspace::flowalias]
lappend result [dict get $cinfo docid]
}\
-cleanup {
}\
-result [list ::testspace::flowcmd]
test cmdinfo_subhelp_choiceinfo {a subcommand word maps to its subhelp docid; unique prefix accepted when -choiceprefix 1 (default)}\
-setup $common -body {
set cinfo [punk::ns::cmdinfo ::testspace::flowparent alpha]
lappend result [dict get $cinfo docid]
set cinfo [punk::ns::cmdinfo ::testspace::flowparent beta]
lappend result [dict get $cinfo docid]
#unique prefix of a choice resolves to the same subhelp docid
set cinfo [punk::ns::cmdinfo ::testspace::flowparent al]
lappend result [dict get $cinfo docid]
}\
-cleanup {
}\
-result [list ::testspace::flowsub_alpha ::testspace::flowsub_beta ::testspace::flowsub_alpha]
test cmdinfo_unknown_subword_returns_parent {a word matching no choice leaves docid at the parent with the word in args_remaining}\
-setup $common -body {
set cinfo [punk::ns::cmdinfo ::testspace::flowparent zzz]
lappend result [dict get $cinfo docid] [dict get $cinfo args_remaining]
}\
-cleanup {
}\
-result [list ::testspace::flowparent zzz]
test cmdinfo_choiceprefix0_requires_exact {with -choiceprefix 0 a prefix is not accepted by the doc walk - docid stays at the parent}\
-setup $common -body {
set cinfo [punk::ns::cmdinfo ::testspace::flownoprefix alpha]
lappend result [dict get $cinfo docid]
set cinfo [punk::ns::cmdinfo ::testspace::flownoprefix al]
lappend result [dict get $cinfo docid] [dict get $cinfo args_remaining]
}\
-cleanup {
}\
-result [list ::testspace::flowsub_alpha ::testspace::flownoprefix al]
test cmdinfo_spaceform_id {a space-delimited id documents a subcommand of an undocumented parent}\
-setup $common -body {
set cinfo [punk::ns::cmdinfo ::testspace::flowgap deep]
lappend result [dict get $cinfo docid]
}\
-cleanup {
}\
-result [list {::testspace::flowgap deep}]
#--- parse vs doc-walk parity (GAP pins pending G-040) -----------------------------------
#punk::args::parse honours -choiceprefixdenylist/-choiceprefixreservelist; the cmd_traverse
#doc walk (punk::ns) consults only -choiceprefix and ignores both lists. These tests pin
#the CURRENT divergent behaviour; G-040's parity work flips them to agreement.
test cmdinfo_parity_denylist_GAP {GAP (G-040): parse rejects a denied prefix but the doc walk still resolves it}\
-setup $common -body {
#parse side: denied prefix is an error (restricted choices)
if {[catch {punk::args::parse {al} withid ::testspace::flowdeny}]} {
lappend result parse-rejects-denied-prefix
} else {
lappend result parse-UNEXPECTEDLY-accepted-denied-prefix
}
#full word accepted by parse
set argd [punk::args::parse {alpha} withid ::testspace::flowdeny]
lappend result [dict get [dict get $argd leaders] subcmd]
#doc-walk side: the same denied prefix currently resolves to the subhelp docid
set cinfo [punk::ns::cmdinfo ::testspace::flowdeny al]
lappend result [dict get $cinfo docid]
}\
-cleanup {
}\
-result [list parse-rejects-denied-prefix alpha ::testspace::flowsub_alpha]
test cmdinfo_parity_reservelist_GAP {GAP (G-040): parse blocks a reserved prefix but the doc walk still resolves it}\
-setup $common -body {
#parse side: reserved word blocks itself and shorter prefixes
if {[catch {punk::args::parse {en} withid ::testspace::flowreserve}]} {
lappend result parse-rejects-reserved-word
} else {
lappend result parse-UNEXPECTEDLY-accepted-reserved-word
}
#parse side: a prefix beyond the reserved phantom resolves
set argd [punk::args::parse {env} withid ::testspace::flowreserve]
lappend result [dict get [dict get $argd leaders] subcmd]
#doc-walk side agreement for the beyond-phantom prefix
set cinfo [punk::ns::cmdinfo ::testspace::flowreserve env]
lappend result [dict get $cinfo docid]
#doc-walk side: the reserved word currently resolves anyway
set cinfo [punk::ns::cmdinfo ::testspace::flowreserve en]
lappend result [dict get $cinfo docid]
}\
-cleanup {
}\
-result [list parse-rejects-reserved-word environment ::testspace::flowsub_env ::testspace::flowsub_env]
#--- cmdhelp smoke ------------------------------------------------------------------------
test cmdhelp_string_smoke {cmdhelp -return string renders usage for a documented proc and a subhelp subcommand}\
-setup $common -body {
set out [punk::ns::cmdhelp -return string ::testspace::flowcmd]
lappend result [string match "*flowcmd summary*" $out]
set out [punk::ns::cmdhelp -return string ::testspace::flowparent alpha]
lappend result [string match "*alpha subcommand*" $out]
}\
-cleanup {
}\
-result [list 1 1]
}
tcltest::cleanupTests ;#needed to produce test summary line.
Loading…
Cancel
Save