- Command.Passthrough turns off cobra flag parsing and uses arbitrary args, so every argument after the command name, including --help, -h and --, reaches Run through Input.Args unchanged - Command.Long sets cobra's Long text for the help command; without it the description is shown as before - both fields are additive: commands without Passthrough parse flags and reject unknown ones exactly as before - README and docs/console/writing-commands.md describe both fields
118 lines
3.2 KiB
Go
118 lines
3.2 KiB
Go
package bonfire
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestValidBareRuntimeCommandNames(t *testing.T) {
|
|
for _, name := range []string{"serve", "migrate", "migrate:rollback", "migrate:status", "build", "dev", "new"} {
|
|
if _, err := NewRoot("app", []Command{{Name: name}}, io.Discard); err != nil {
|
|
t.Fatalf("%s: %v", name, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func capturingCommand(name string, got *[]string) Command {
|
|
return Command{
|
|
Name: name,
|
|
Description: "Capture args",
|
|
Passthrough: true,
|
|
Run: func(ctx context.Context, in Input, out Output) error {
|
|
*got = append([]string(nil), in.Args()...)
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestPassthroughCommandReceivesRawArgs(t *testing.T) {
|
|
var got []string
|
|
var out, errW bytes.Buffer
|
|
root, err := NewRootIO("app", []Command{capturingCommand("serve", &got)}, strings.NewReader(""), &out, &errW)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
args := []string{"--addr", ":8123", "-p", "--help", "-h", "--", "x"}
|
|
root.SetArgs(append([]string{"serve"}, args...))
|
|
if err := root.Execute(); err != nil {
|
|
t.Fatalf("Execute: %v", err)
|
|
}
|
|
if !slices.Equal(got, args) {
|
|
t.Fatalf("args = %q, want %q", got, args)
|
|
}
|
|
if out.Len() != 0 || errW.Len() != 0 {
|
|
t.Fatalf("passthrough printed output: stdout=%q stderr=%q", out.String(), errW.String())
|
|
}
|
|
}
|
|
|
|
func TestPassthroughCommandThroughCall(t *testing.T) {
|
|
var got []string
|
|
var buf bytes.Buffer
|
|
args := []string{"--addr", ":8123", "--help"}
|
|
if err := Call(context.Background(), []Command{capturingCommand("serve", &got)}, "serve", args, &buf); err != nil {
|
|
t.Fatalf("Call: %v", err)
|
|
}
|
|
if !slices.Equal(got, args) {
|
|
t.Fatalf("args = %q, want %q", got, args)
|
|
}
|
|
}
|
|
|
|
func TestPassthroughCommandIgnoresArgCount(t *testing.T) {
|
|
var got []string
|
|
cmd := capturingCommand("queue:clear", &got)
|
|
cmd.Args = []Arg{{Name: "queue", Required: true}}
|
|
root, err := NewRoot("app", []Command{cmd}, io.Discard)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root.SetArgs([]string{"queue:clear"})
|
|
if err := root.Execute(); err != nil {
|
|
t.Fatalf("passthrough with zero args: %v", err)
|
|
}
|
|
if len(got) != 0 {
|
|
t.Fatalf("args = %q, want none", got)
|
|
}
|
|
}
|
|
|
|
func TestNonPassthroughCommandRejectsUnknownFlag(t *testing.T) {
|
|
root, err := NewRoot("app", []Command{{Name: "migrate", Run: func(context.Context, Input, Output) error { return nil }}}, io.Discard)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root.SetArgs([]string{"migrate", "--addr", ":8123"})
|
|
err = root.Execute()
|
|
if err == nil || !strings.Contains(err.Error(), "unknown flag: --addr") {
|
|
t.Fatalf("err = %v, want unknown flag: --addr", err)
|
|
}
|
|
}
|
|
|
|
func TestHelpShowsLongOrDescription(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
cmd Command
|
|
want string
|
|
}{
|
|
{"long", Command{Name: "serve", Description: "Short text", Long: "Long text"}, "Long text"},
|
|
{"description", Command{Name: "serve", Description: "Short text"}, "Short text"},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
root, err := NewRoot("app", []Command{tc.cmd}, &buf)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root.SetArgs([]string{"help", "serve"})
|
|
if err := root.Execute(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(buf.String(), tc.want) {
|
|
t.Fatalf("help missing %q:\n%s", tc.want, buf.String())
|
|
}
|
|
})
|
|
}
|
|
}
|