2026-10-19 17:33:39 +00:00
package commandkit
import (
"strings"
"testing"
2026-10-26 02:50:54 +00:00
commandmeta "gitea.maximumdirect.net/eric/CommandKit/internal/commandmeta"
2026-10-19 17:33:39 +00:00
"gitea.maximumdirect.net/eric/CommandKit/internal/commandpath"
)
func flagAliasCommand ( name string , flags ... Flag [ struct { } ] ) Command {
return NewCommand ( CommandSpec [ struct { } ] {
Name : name , Summary : name , Flags : flags ,
Run : func ( Invocation , struct { } ) Outcome { return Success ( ) } ,
} )
}
func stringFlag ( name , short string ) Flag [ struct { } ] {
return ValueFlag ( FlagMeta { Name : name , Short : short } , ( * string ) ( nil ) ,
func ( value string ) ( string , error ) { return value , nil } ,
func ( * struct { } , Supplied [ string ] ) { } ,
)
}
func TestFlagAliasChainsUseScopedOverridesAndCanonicalEndpoints ( t * testing . T ) {
inspect := flagAliasCommand ( "inspect" , stringFlag ( "color" , "c" ) , stringFlag ( "format" , "f" ) )
show := flagAliasCommand ( "show" , stringFlag ( "color" , "c" ) , stringFlag ( "format" , "f" ) )
group := Group ( "Tools" , "tools" , show )
app , err := New ( Identity { Name : "Example" } ,
inspect ,
group ,
Alias ( "look" , "inspect" ) ,
FlagAlias ( "--colour" , "--hue" ) ,
FlagAlias ( "--hue" , "--color" ) ,
FlagAlias ( "-x" , "--color" ) ,
FlagAlias ( "--tint" , "-c" ) ,
FlagAliasFor ( "Tools" , "--group-help" , "--help" ) ,
FlagAliasFor ( "inspect" , "--hue" , "--format" ) ,
FlagAliasFor ( "inspect" , "--local" , "--format" ) ,
)
if err != nil {
t . Fatal ( err )
}
inspectAliases := app . flagAliases [ commandpath . Path { "inspect" } . Key ( ) ] . bySpelling
for source , target := range map [ string ] string {
"--colour" : "--format" ,
"--hue" : "--format" ,
"-x" : "--color" ,
"--tint" : "-c" ,
"--local" : "--format" ,
} {
alias , ok := inspectAliases [ flagSpellingKey ( capturedSpelling ( source ) ) ]
if ! ok || alias . target . token ( ) != target {
t . Errorf ( "inspect alias %s = (%s, %v), want %s" , source , alias . target . token ( ) , ok , target )
}
}
groupAliases := app . flagAliases [ commandpath . Path { "Tools" } . Key ( ) ] . bySpelling
if _ , active := groupAliases [ flagSpellingKey ( capturedFlagSpelling { name : "colour" } ) ] ; active {
t . Error ( "global alias was active on a group without its destination flag" )
}
if _ , inherited := groupAliases [ flagSpellingKey ( capturedFlagSpelling { name : "local" } ) ] ; inherited {
t . Fatal ( "command-scoped alias was inherited by its parent group" )
}
if _ , inherited := app . flagAliases [ commandpath . Path { "Tools" , "show" } . Key ( ) ] . bySpelling [ flagSpellingKey ( capturedFlagSpelling { name : "local" } ) ] ; inherited {
t . Fatal ( "command-scoped alias was inherited by a different command" )
}
groupHelp := flagSpellingKey ( capturedFlagSpelling { name : "group-help" } )
if got := groupAliases [ groupHelp ] . target . token ( ) ; got != "--help" {
t . Fatalf ( "group-scoped help alias target = %s, want --help" , got )
}
if _ , inherited := app . flagAliases [ commandpath . Path { "Tools" , "show" } . Key ( ) ] . bySpelling [ groupHelp ] ; inherited {
t . Fatal ( "group-scoped alias was inherited by its child command" )
}
}
2026-10-26 02:50:54 +00:00
func TestFlagAliasDiscoveryContextsUseGlobalReportingAliases ( t * testing . T ) {
2026-10-19 17:33:39 +00:00
show := flagAliasCommand ( "show" )
app , err := New ( Identity { Name : "Example" } ,
Group ( "Tools" , "tools" , show ) ,
Alias ( "shortcut show" , "Tools show" ) ,
FlagAlias ( "--hlep" , "--help" ) ,
2026-10-26 02:50:54 +00:00
FlagAlias ( "--silent" , "--quiet" ) ,
FlagAlias ( "--chatty" , "--verbose" ) ,
FlagAlias ( "--trace" , "--debug" ) ,
FlagAlias ( "--show-progress" , "--progress" ) ,
2026-10-19 17:33:39 +00:00
FlagAliasFor ( "Tools show" , "--local-help" , "--help" ) ,
)
if err != nil {
t . Fatal ( err )
}
globalHelp := flagSpellingKey ( capturedFlagSpelling { name : "hlep" } )
if got := app . flagAliases [ commandpath . Path ( nil ) . Key ( ) ] . bySpelling [ globalHelp ] . target . token ( ) ; got != "--help" {
t . Fatalf ( "root --hlep target = %s, want --help" , got )
}
if got := app . flagAliases [ commandpath . Path { "Tools" } . Key ( ) ] . bySpelling [ globalHelp ] . target . token ( ) ; got != "--help" {
t . Fatalf ( "group --hlep target = %s, want --help" , got )
}
discovery := app . discoveryFlags [ commandpath . Path { "shortcut" } . Key ( ) ] . bySpelling
if got := discovery [ globalHelp ] . target . token ( ) ; got != "--help" {
t . Fatalf ( "discovery --hlep target = %s, want --help" , got )
}
2026-10-26 02:50:54 +00:00
for label , aliases := range map [ string ] resolvedFlagAliases {
"root" : app . flagAliases [ commandpath . Path ( nil ) . Key ( ) ] ,
"group" : app . flagAliases [ commandpath . Path { "Tools" } . Key ( ) ] ,
"command" : app . flagAliases [ commandpath . Path { "Tools" , "show" } . Key ( ) ] ,
"discovery" : app . discoveryFlags [ commandpath . Path { "shortcut" } . Key ( ) ] ,
} {
for source , target := range map [ string ] string {
"silent" : "quiet" ,
"chatty" : "verbose" ,
"trace" : "debug" ,
"show-progress" : "progress" ,
} {
key := flagSpellingKey ( capturedFlagSpelling { name : source } )
if got := aliases . bySpelling [ key ] . target . token ( ) ; got != "--" + target {
t . Errorf ( "%s --%s target = %s, want --%s" , label , source , got , target )
}
}
}
2026-10-19 17:33:39 +00:00
if _ , inherited := discovery [ flagSpellingKey ( capturedFlagSpelling { name : "local-help" } ) ] ; inherited {
t . Fatal ( "discovery context inherited a command-scoped alias" )
}
}
2026-10-26 02:50:54 +00:00
func TestReportingFlagsAreReservedAndAcceptApplicationShortAliases ( t * testing . T ) {
for _ , name := range [ ] string { "quiet" , "verbose" , "debug" , "progress" } {
command := flagAliasCommand ( "reserved" , stringFlag ( name , "" ) )
if len ( command . record . issues ) == 0 {
t . Errorf ( "capturing --%s did not retain a declaration error" , name )
}
app , err := New ( Identity { Name : "Example" } , flagAliasCommand ( "safe" ) )
if err != nil {
t . Fatal ( err )
}
snapshot := app . routeSnapshot ( )
if err := app . Register ( command , Alias ( "reserved-shortcut" , "reserved" ) ) ; err == nil || ! strings . Contains ( err . Error ( ) , "reserved for reporting" ) {
t . Errorf ( "registering --%s returned %v, want a retained reporting reservation error" , name , err )
}
if app . routeSnapshot ( ) != snapshot || app . commands [ "reserved" ] != nil || app . commands [ "safe" ] == nil || len ( app . routingRules ) != 0 {
t . Fatalf ( "failed registration of --%s changed the installed commands" , name )
}
}
declarations := [ ] Declaration { flagAliasCommand ( "run" ) }
for short , target := range map [ string ] string { "q" : "quiet" , "v" : "verbose" , "d" : "debug" } {
declarations = append ( declarations , FlagAlias ( "-" + short , "--" + target ) )
}
if _ , err := New ( Identity { Name : "Example" } , declarations ... ) ; err != nil {
t . Fatalf ( "application short aliases for reporting flags were rejected: %v" , err )
}
}
func TestReportingFlagSpellingsConflictWithAliasSources ( t * testing . T ) {
for _ , name := range [ ] string { "quiet" , "verbose" , "debug" , "progress" } {
if _ , err := New ( Identity { Name : "Example" } , FlagAlias ( "--" + name , "--help" ) ) ; err == nil || ! strings . Contains ( err . Error ( ) , "conflicts with a canonical spelling" ) {
t . Errorf ( "alias source --%s returned %v, want a canonical spelling collision" , name , err )
}
}
if _ , err := New ( Identity { Name : "Example" } , Group ( "tools" , "" , flagAliasCommand ( "show" ) ) , FlagAliasFor ( "tools" , "--quiet" , "--help" ) ) ; err == nil || ! strings . Contains ( err . Error ( ) , "conflicts with a canonical spelling" ) {
t . Errorf ( "group-scoped canonical reporting spelling returned %v, want a collision" , err )
}
}
func TestRoutingSnapshotCarriesReportingMetadataOutsideConsumerBindings ( t * testing . T ) {
app , err := New ( Identity { Name : "Example" } ,
flagAliasCommand ( "run" , stringFlag ( "format" , "f" ) ) ,
Group ( "tools" , "" , flagAliasCommand ( "show" ) ) ,
)
if err != nil {
t . Fatal ( err )
}
var check func ( * commandmeta . Command )
check = func ( node * commandmeta . Command ) {
if len ( node . CoreFlags ) != 4 {
t . Errorf ( "%s core reporting flags = %#v" , node . Name , node . CoreFlags )
}
for _ , flag := range node . Flags {
if commandmeta . IsReportingFlag ( flag . Name ) {
t . Errorf ( "%s reporting flag %q was added to consumer bindings" , node . Name , flag . Name )
}
}
for _ , child := range node . Children {
check ( child )
}
}
check ( app . routeSnapshot ( ) . metadata )
}
2026-10-19 17:33:39 +00:00
func TestFlagAliasDuplicatesAndScopesAreDeterministic ( t * testing . T ) {
command := flagAliasCommand ( "inspect" , stringFlag ( "color" , "c" ) , stringFlag ( "format" , "f" ) )
duplicate := FlagAlias ( "--colour" , "--color" )
app , err := New ( Identity { Name : "Example" } , command , flagAliasCommand ( "plain" , stringFlag ( "color" , "c" ) ) , duplicate , FlagAlias ( "--colour" , "--color" ) ,
FlagAliasFor ( "inspect" , "--colour" , "--format" ) )
if err != nil {
t . Fatalf ( "identical duplicates and scoped override were rejected: %v" , err )
}
if got := app . flagAliases [ commandpath . Path { "inspect" } . Key ( ) ] . bySpelling [ flagSpellingKey ( capturedFlagSpelling { name : "colour" } ) ] . target . token ( ) ; got != "--format" {
t . Fatalf ( "scoped alias target = %s, want --format" , got )
}
if got := app . flagAliases [ commandpath . Path { "plain" } . Key ( ) ] . bySpelling [ flagSpellingKey ( capturedFlagSpelling { name : "colour" } ) ] . target . token ( ) ; got != "--color" {
t . Fatalf ( "effective global alias target = %s, want --color" , got )
}
for name , rules := range map [ string ] [ ] RoutingRule {
"competing global targets" : {
FlagAlias ( "--colour" , "--color" ) ,
FlagAlias ( "--colour" , "--format" ) ,
} ,
"competing scoped targets" : {
FlagAliasFor ( "inspect" , "--colour" , "--color" ) ,
FlagAliasFor ( "inspect" , "--colour" , "--format" ) ,
} ,
"unknown scope" : { FlagAliasFor ( "missing" , "--colour" , "--color" ) } ,
"missing scoped destination" : { FlagAliasFor ( "inspect" , "--colour" , "--missing" ) } ,
} {
t . Run ( name , func ( t * testing . T ) {
declarations := [ ] Declaration { command }
for _ , rule := range rules {
declarations = append ( declarations , rule )
}
if _ , err := New ( Identity { Name : "Example" } , declarations ... ) ; err == nil {
t . Fatal ( "New() accepted invalid flag alias rules" )
}
} )
}
}
func TestFlagAliasCyclesIdentifyParticipatingSpellings ( t * testing . T ) {
for name , declarations := range map [ string ] [ ] Declaration {
"global" : {
FlagAlias ( "--first" , "--second" ) ,
FlagAlias ( "--second" , "--first" ) ,
} ,
"scoped" : {
flagAliasCommand ( "inspect" ) ,
FlagAliasFor ( "inspect" , "-a" , "--second" ) ,
FlagAliasFor ( "inspect" , "--second" , "-a" ) ,
} ,
} {
t . Run ( name , func ( t * testing . T ) {
_ , err := New ( Identity { Name : "Example" } , declarations ... )
if err == nil {
t . Fatal ( "New() accepted a flag alias cycle" )
}
message := err . Error ( )
for _ , spelling := range [ ] string { "--first" , "--second" } {
if name == "scoped" {
continue
}
if ! strings . Contains ( message , spelling ) {
t . Errorf ( "cycle error %q does not identify %s" , message , spelling )
}
}
if name == "scoped" && ( ! strings . Contains ( message , "-a" ) || ! strings . Contains ( message , "--second" ) ) {
t . Errorf ( "scoped cycle error %q does not identify both spellings" , message )
}
} )
}
}
func TestInactiveGlobalAliasesActivateAtomicallyWhenDestinationAppears ( t * testing . T ) {
command := flagAliasCommand ( "inspect" , stringFlag ( "color" , "c" ) )
app , err := New ( Identity { Name : "Example" } , command ,
FlagAlias ( "--color" , "--missing" ) ,
FlagAlias ( "--colour" , "--color" ) ,
)
if err != nil {
t . Fatal ( err )
}
aliases := app . flagAliases [ commandpath . Path { "inspect" } . Key ( ) ] . bySpelling
if _ , active := aliases [ flagSpellingKey ( capturedFlagSpelling { name : "color" } ) ] ; active {
t . Fatal ( "global alias with an unavailable destination became active" )
}
if got := aliases [ flagSpellingKey ( capturedFlagSpelling { name : "colour" } ) ] . target . token ( ) ; got != "--color" {
t . Fatalf ( "--colour endpoint = %s, want canonical --color" , got )
}
snapshot := app . routeSnapshot ( )
commands := len ( app . commands )
rules := len ( app . routingRules )
originalAlias := aliases [ flagSpellingKey ( capturedFlagSpelling { name : "colour" } ) ]
if err := app . Register ( flagAliasCommand ( "later" , stringFlag ( "color" , "c" ) , stringFlag ( "missing" , "" ) ) ) ; err == nil {
t . Fatal ( "Register() accepted a newly active global source collision" )
}
currentAlias := app . flagAliases [ commandpath . Path { "inspect" } . Key ( ) ] . bySpelling [ flagSpellingKey ( capturedFlagSpelling { name : "colour" } ) ]
if app . routeSnapshot ( ) != snapshot || len ( app . commands ) != commands || len ( app . routingRules ) != rules || currentAlias != originalAlias {
t . Fatal ( "failed registration changed the existing command or routing state" )
}
}
func capturedSpelling ( token string ) capturedFlagSpelling {
issues := [ ] error ( nil )
return captureFlagSpelling ( "test" , token , & issues )
}