76 lines
3.7 KiB
Go
76 lines
3.7 KiB
Go
package commandkit
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
commandmeta "gitea.maximumdirect.net/eric/CommandKit/internal/commandmeta"
|
|
)
|
|
|
|
func TestCompletionCommandContext(t *testing.T) {
|
|
parse := func(value string) (string, error) { return value, nil }
|
|
mixed := NewCommand(CommandSpec[struct{}]{
|
|
Name: "mixed", Children: []Command{simpleRunnable("child")},
|
|
Arguments: []Argument[struct{}]{ValueArgument(ArgumentMeta{Name: "item"}, false, parse, func(*struct{}, Supplied[string]) {})},
|
|
Run: func(Invocation, struct{}) Outcome { return Success() },
|
|
})
|
|
app, err := New(Identity{Name: "example"},
|
|
Group("workspace", "", Group("list", "", simpleRunnable("shadow"), simpleRunnable("show"))),
|
|
simpleRunnable("other"), mixed, Completion("example"),
|
|
Alias("ws", "workspace"), Alias("w", "ws"), Alias("ws list shadow", "other"),
|
|
Alias("legacy inspect", "workspace list"), FlagAlias("--silent", "--quiet"),
|
|
FlagAliasFor("workspace list", "--detail", "--verbose"),
|
|
)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
snapshot := app.routeSnapshot()
|
|
for _, tc := range []struct {
|
|
name string
|
|
completed []string
|
|
current string
|
|
path string
|
|
position bool
|
|
choices []string
|
|
kind routeKind
|
|
}{
|
|
{"root", nil, "work", "", true, []string{"workspace"}, routeCanonical},
|
|
{"group", []string{"workspace"}, "li", "workspace", true, []string{"list"}, routeCanonical},
|
|
{"entered alias", []string{"ws", "list"}, "sh", "workspace list", true, []string{"show"}, routeCanonical},
|
|
{"alias chain", []string{"w", "list"}, "sh", "workspace list", true, []string{"show"}, routeCanonical},
|
|
{"discovery", []string{"legacy"}, "in", "", false, nil, routeDiscovery},
|
|
{"complete alias", []string{"legacy", "inspect"}, "sh", "workspace list", true, []string{"shadow", "show"}, routeCanonical},
|
|
{"runnable child", []string{"mixed"}, "ch", "mixed", true, []string{"child"}, routeCanonical},
|
|
{"unmatched child", []string{"mixed"}, "other", "mixed", true, nil, routeCanonical},
|
|
{"runnable operand", []string{"mixed", "value"}, "ch", "mixed", false, nil, routeCanonical},
|
|
{"flag ends path", []string{"mixed", "--quiet"}, "ch", "mixed", false, nil, routeCanonical},
|
|
{"flag before child", []string{"workspace", "--quiet"}, "li", "workspace", false, nil, routeCanonical},
|
|
{"unknown", []string{"missing"}, "x", "", false, nil, routeUnknown},
|
|
{"hidden endpoint", nil, "__comp", "", true, nil, routeCanonical},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
original := append([]string(nil), tc.completed...)
|
|
context := resolveCompletionContext(snapshot, tc.completed, tc.current)
|
|
if context.route.kind != tc.kind || context.route.canonicalPath.String() != tc.path || context.commandPosition != tc.position || !reflect.DeepEqual(tc.completed, original) {
|
|
t.Fatalf("context=%#v completed=%q", context, tc.completed)
|
|
}
|
|
var names []string
|
|
for _, choice := range completionChildren(snapshot, context) {
|
|
names = append(names, choice.Value)
|
|
}
|
|
if !reflect.DeepEqual(names, tc.choices) {
|
|
t.Fatalf("children=%q, want %q", names, tc.choices)
|
|
}
|
|
if tc.kind == routeDiscovery && !reflect.DeepEqual(context.aliases, []commandmeta.FlagAlias{{Source: "--silent", Target: "--quiet"}}) {
|
|
t.Fatalf("discovery aliases=%#v", context.aliases)
|
|
}
|
|
if (tc.name == "runnable child" || tc.name == "unmatched child") && (context.command == nil || len(context.command.Arguments) != 1) {
|
|
t.Fatalf("runnable operand metadata missing: %#v", context.command)
|
|
}
|
|
if tc.name == "entered alias" && !reflect.DeepEqual(context.aliases, []commandmeta.FlagAlias{{Source: "--detail", Target: "--verbose"}, {Source: "--silent", Target: "--quiet"}}) {
|
|
t.Fatalf("canonical aliases=%#v", context.aliases)
|
|
}
|
|
})
|
|
}
|
|
}
|