Expose canonical paths on command invocations

This commit is contained in:
2026-10-19 19:33:49 +00:00
parent 75fc45f072
commit 451a0c483f
5 changed files with 128 additions and 3 deletions

View File

@@ -190,6 +190,104 @@ func TestExecuteDispatchesEnteredAliasToCanonicalRunner(t *testing.T) {
}
}
func TestInvocationReportsEnteredAndCanonicalPathsPerCall(t *testing.T) {
type input struct {
label Supplied[string]
values Supplied[[]string]
}
type observed struct {
entered string
canonical string
label string
values []string
}
var calls []observed
command := NewCommand(CommandSpec[input]{
Name: "run",
Flags: []Flag[input]{ValueFlag(FlagMeta{Name: "label"}, (*string)(nil),
func(value string) (string, error) { return value, nil },
func(target *input, label Supplied[string]) { target.label = label },
)},
Arguments: []Argument[input]{RepeatArgument(ArgumentMeta{Name: "value"}, 0, -1,
func(value string) (string, error) { return value, nil },
func(target *input, values Supplied[[]string]) { target.values = values },
)},
Run: func(inv Invocation, value input) Outcome {
calls = append(calls, observed{
entered: inv.EnteredPath(),
canonical: inv.CanonicalPath(),
label: value.label.Value,
values: append([]string(nil), value.values.Value...),
})
return Success()
},
})
shortcut := Alias("shortcut", "workspace run")
app, err := New(Identity{Name: "Example"}, Group("workspace", "Workspace", command), shortcut)
if err != nil {
t.Fatal(err)
}
for _, args := range [][]string{{"workspace", "run", "--label=first", "first"}, {"shortcut", "--label=second", "second"}, {"workspace", "run"}} {
if outcome := app.Execute(context.Background(), args, Streams{Out: io.Discard, Err: io.Discard}); outcome.Kind != OutcomeSuccess {
t.Fatalf("Execute(%q) = %v, want success", args, outcome.Kind)
}
}
if len(calls) != 3 {
t.Fatalf("handler calls = %d, want 3", len(calls))
}
want := []observed{
{entered: "workspace run", canonical: "workspace run", label: "first", values: []string{"first"}},
{entered: "shortcut", canonical: "workspace run", label: "second", values: []string{"second"}},
{entered: "workspace run", canonical: "workspace run"},
}
if !reflect.DeepEqual(calls, want) {
t.Fatalf("handler invocations = %#v, want %#v", calls, want)
}
secondApp, err := New(Identity{Name: "Another"}, Group("workspace", "Workspace", command), shortcut)
if err != nil {
t.Fatal(err)
}
if outcome := secondApp.Execute(context.Background(), []string{"shortcut"}, Streams{Out: io.Discard, Err: io.Discard}); outcome.Kind != OutcomeSuccess {
t.Fatalf("reused declaration execution = %v, want success", outcome.Kind)
}
if got := calls[3]; got.entered != "shortcut" || got.canonical != "workspace run" || len(got.values) != 0 {
t.Fatalf("reused declaration invocation = %#v", got)
}
var zero Invocation
if zero.EnteredPath() != "" || zero.CanonicalPath() != "" {
t.Fatalf("zero Invocation paths = (%q, %q), want empty paths", zero.EnteredPath(), zero.CanonicalPath())
}
}
func TestPrivateCommandCallbacksReceiveResolvedInvocationPaths(t *testing.T) {
var calls []Invocation
command := Command{record: &commandRecord{
name: "inspect",
payload: typedCommand[struct{}]{
spec: CommandSpec[struct{}]{Name: "inspect"},
privateRun: func(exec commandExecution, _ struct{}) Outcome {
calls = append(calls, exec.invocation)
return Success()
},
},
}}
app, err := New(Identity{Name: "Example"}, command, Alias("shortcut", "inspect"))
if err != nil {
t.Fatal(err)
}
for _, args := range [][]string{{"inspect"}, {"shortcut"}} {
if outcome := app.Execute(context.Background(), args, Streams{Out: io.Discard, Err: io.Discard}); outcome.Kind != OutcomeSuccess {
t.Fatalf("Execute(%q) = %v, want success", args, outcome.Kind)
}
}
if len(calls) != 2 || calls[0].EnteredPath() != "inspect" || calls[0].CanonicalPath() != "inspect" || calls[1].EnteredPath() != "shortcut" || calls[1].CanonicalPath() != "inspect" {
t.Fatalf("private callback invocations = %#v", calls)
}
}
func TestExecuteAppliesCanonicalCommandFlagAliasesAfterRouting(t *testing.T) {
type input struct{ color string }
var got string