109 lines
4.4 KiB
Go
109 lines
4.4 KiB
Go
package commandkit
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestCompletionDeclarationGeneratesScripts(t *testing.T) {
|
|
for _, name := range []string{"app", "my-app", "tool.exe", "café"} {
|
|
if !validCompletionExecutable(name) {
|
|
t.Fatalf("supported executable rejected: %q", name)
|
|
}
|
|
}
|
|
app, err := New(Identity{Name: "Human Readable Name"}, Completion("my-app"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !app.routeSnapshot().completion {
|
|
t.Fatal("completion not present in snapshot")
|
|
}
|
|
for _, shell := range []string{"bash", "zsh", "fish"} {
|
|
var output, diagnostics bytes.Buffer
|
|
outcome := app.Execute(context.Background(), []string{"completion", shell}, Streams{Out: &output, Err: &diagnostics})
|
|
if outcome.Status != 0 || !strings.Contains(output.String(), "my-app") || strings.Contains(output.String(), "Human Readable Name") {
|
|
t.Fatalf("%s outcome=%#v output=%q diagnostics=%q", shell, outcome, output.String(), diagnostics.String())
|
|
}
|
|
output.Reset()
|
|
outcome = app.Execute(context.Background(), []string{"completion", shell, "--quiet"}, Streams{Out: &output, Err: &diagnostics})
|
|
if outcome.Status != 0 || output.Len() != 0 {
|
|
t.Fatalf("quiet %s outcome=%#v output=%q", shell, outcome, output.String())
|
|
}
|
|
}
|
|
var help bytes.Buffer
|
|
outcome := app.Execute(context.Background(), []string{"--help"}, Streams{Out: &help})
|
|
if outcome.Status != 0 || !strings.Contains(help.String(), "completion") || strings.Contains(help.String(), "__complete") {
|
|
t.Fatalf("help outcome=%#v output=%q", outcome, help.String())
|
|
}
|
|
writeErr := errors.New("destination failed")
|
|
outcome = app.Execute(context.Background(), []string{"completion", "bash"}, Streams{Out: completionErrorWriter{writeErr}, Err: io.Discard})
|
|
if outcome.Status != 1 || !errors.Is(outcome.Presentation.Output.WriteError, writeErr) {
|
|
t.Fatalf("script delivery failure: %#v", outcome)
|
|
}
|
|
}
|
|
|
|
type completionErrorWriter struct{ err error }
|
|
|
|
func (w completionErrorWriter) Write([]byte) (int, error) { return 0, w.err }
|
|
|
|
func TestCompletionInstallationCollisionsAndRollback(t *testing.T) {
|
|
run := NewCommand(CommandSpec[struct{}]{Name: "run", Run: func(Invocation, struct{}) Outcome { return Success() }})
|
|
query := NewCommand(CommandSpec[struct{}]{Name: "__complete", Run: func(Invocation, struct{}) Outcome { return Success() }})
|
|
for _, declarations := range [][]Declaration{
|
|
{Completion("app"), query},
|
|
{query, Completion("app")},
|
|
{Completion("app"), run, Alias("__complete nested", "run")},
|
|
{run, Alias("__complete nested", "run"), Completion("app")},
|
|
{Completion("app"), Group("completion", "collision")},
|
|
{Group("outer", "", Completion("app"))},
|
|
{Completion("dir/app")},
|
|
{Completion("two words")},
|
|
} {
|
|
if _, err := New(Identity{Name: "example"}, declarations...); err == nil {
|
|
t.Fatalf("accepted conflicting declarations: %#v", declarations)
|
|
}
|
|
}
|
|
app, err := New(Identity{Name: "example"}, run)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
before := app.routeSnapshot()
|
|
if err := app.Register(Completion("app"), query); err == nil || app.routeSnapshot() != before {
|
|
t.Fatalf("failed batch changed snapshot: %v", err)
|
|
}
|
|
if err := app.Register(Completion("app")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if app.routeSnapshot() == before || !app.routeSnapshot().completion {
|
|
t.Fatal("late completion installation did not refresh snapshot")
|
|
}
|
|
if err := app.Register(query); err == nil {
|
|
t.Fatal("query command accepted after completion installation")
|
|
}
|
|
if err := app.Register(Alias("__complete nested", "run")); err == nil {
|
|
t.Fatal("query alias accepted after completion installation")
|
|
}
|
|
|
|
withoutCompletion, err := New(Identity{Name: "example"}, query)
|
|
if err != nil || withoutCompletion.routeSnapshot().completion {
|
|
t.Fatalf("ordinary query-named command: %v", err)
|
|
}
|
|
if outcome := withoutCompletion.Execute(context.Background(), []string{"__complete"}, Streams{}); outcome.Status != 0 {
|
|
t.Fatalf("ordinary command outcome: %#v", outcome)
|
|
}
|
|
if err := withoutCompletion.Register(Completion("app")); err == nil || withoutCompletion.routeSnapshot().completion {
|
|
t.Fatal("completion accepted an existing query command")
|
|
}
|
|
aliased, err := New(Identity{Name: "example"}, run, Alias("__complete nested", "run"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := aliased.Register(Completion("app")); err == nil || aliased.routeSnapshot().completion {
|
|
t.Fatal("completion accepted an existing query alias")
|
|
}
|
|
}
|