Protect canonical operand prefixes from aliases

This commit is contained in:
2026-10-20 00:20:40 +00:00
parent c225a66c97
commit ccf8acd861
3 changed files with 48 additions and 7 deletions

View File

@@ -203,6 +203,40 @@ func TestCommandAliasesRejectCanonicalRoutesAndOperands(t *testing.T) {
}
}
func TestCommandAliasesProtectIncompleteCanonicalOperandPrefixes(t *testing.T) {
for _, bounds := range []struct{ min, max int }{{2, 2}, {3, -1}} {
t.Run(fmt.Sprintf("%d_%d", bounds.min, bounds.max), func(t *testing.T) {
run := runnableWithOperands("run", bounds.min, bounds.max)
mapping := Alias("run first", "inspect")
if _, err := New(Identity{Name: "Example"}, run, simpleRunnable("inspect"), mapping); err == nil {
t.Fatal("construction accepted an alias intercepting an operand prefix")
}
for _, aliasFirst := range []bool{false, true} {
app, err := New(Identity{Name: "Example"}, simpleRunnable("inspect"))
if err != nil {
t.Fatal(err)
}
var first, second Declaration = run, mapping
if aliasFirst {
first, second = second, first
}
if err := app.Register(first); err != nil {
t.Fatal(err)
}
if err := app.Register(second, simpleRunnable("unrelated")); err == nil {
t.Fatal("later registration accepted an operand interception")
}
if app.commands["unrelated"] != nil || (app.commands["run"] != nil) == aliasFirst {
t.Fatal("rejected batch changed canonical registration")
}
if (len(app.routingRules) == 1) != aliasFirst {
t.Fatal("rejected batch changed alias registration")
}
}
})
}
}
func TestLongerAliasBeneathAlternateSpellingCanUseOperandWords(t *testing.T) {
app, err := New(Identity{Name: "Example"},
runnableWithOperands("run", 1, 1),