Files
commandkit/route_operands_test.go

78 lines
3.7 KiB
Go

package commandkit
import (
"bytes"
"context"
"io"
"reflect"
"strings"
"testing"
)
func TestRunnableParentKeepsNonCommandTokensAsOperands(t *testing.T) {
type input struct {
words []string
format Supplied[string]
}
var received input
var entered, canonical string
built, parentRuns, childRuns := 0, 0, 0
child := NewCommand(CommandSpec[struct{}]{Name: "child", Run: func(inv Invocation, _ struct{}) Outcome {
childRuns++
entered, canonical = inv.EnteredPath(), inv.CanonicalPath()
return Success()
}})
parent := NewCommand(CommandSpec[input]{
Name: "run", Children: []Command{child}, NewInput: func() input { built++; return input{} },
Arguments: []Argument[input]{RepeatArgument(ArgumentMeta{Name: "ARG"}, 0, -1,
func(value string) (string, error) { return value, nil },
func(target *input, value Supplied[[]string]) { target.words = value.Value })},
Flags: []Flag[input]{ValueFlag(FlagMeta{Name: "format", Short: "f"}, (*string)(nil),
func(value string) (string, error) { return value, nil },
func(target *input, value Supplied[string]) { target.format = value })},
Run: func(inv Invocation, value input) Outcome {
parentRuns++
received, entered, canonical = value, inv.EnteredPath(), inv.CanonicalPath()
return Success()
},
})
app, err := New(Identity{Name: "Demo"}, parent, Alias("r", "run"), FlagAliasFor("run", "--fmt", "--format"))
if err != nil {
t.Fatal(err)
}
for _, spelling := range []string{"run", "r"} {
for _, operand := range []string{"", "-"} {
t.Run(spelling+"/"+operand, func(t *testing.T) {
beforeBuilt, beforeRuns := built, parentRuns
args := []string{spelling, operand, "child", "--fmt=yaml"}
var output, diagnostics bytes.Buffer
outcome := app.Execute(context.Background(), args, Streams{Out: &output, Err: &diagnostics})
if outcome.Kind != OutcomeSuccess || built != beforeBuilt+1 || parentRuns != beforeRuns+1 || childRuns != 0 {
t.Fatalf("outcome = %#v, builds/runs = %d/%d/%d, diagnostics %q", outcome, built, parentRuns, childRuns, diagnostics.String())
}
if !reflect.DeepEqual(received.words, []string{operand, "child"}) || received.format != (Supplied[string]{Value: "yaml", Set: true}) ||
entered != spelling || canonical != "run" {
t.Fatalf("parent input = %#v, paths = %q/%q", received, entered, canonical)
}
outcome = app.Execute(context.Background(), append(args, "--help"), Streams{Out: &output, Err: &diagnostics})
if outcome.Kind != OutcomeSuccess || built != beforeBuilt+1 || parentRuns != beforeRuns+1 ||
!strings.Contains(output.String(), "Demo "+spelling+" [ARG...]") || !strings.Contains(output.String(), "--fmt → --format") {
t.Fatalf("parent help = %#v, output %q, diagnostics %q", outcome, output.String(), diagnostics.String())
}
outcome = app.Execute(context.Background(), []string{spelling, "--", operand, "child", "--fmt=yaml"}, Streams{Out: io.Discard, Err: &diagnostics})
if outcome.Kind != OutcomeSuccess || !reflect.DeepEqual(received.words, []string{operand, "child", "--fmt=yaml"}) || received.format.Set {
t.Fatalf("terminated parent invocation = %#v, input %#v, diagnostics %q", outcome, received, diagnostics.String())
}
})
}
}
for _, spelling := range []string{"run", "r"} {
beforeBuilt, beforeRuns, beforeChildren := built, parentRuns, childRuns
outcome := app.Execute(context.Background(), []string{spelling, "child"}, Streams{Out: io.Discard, Err: io.Discard})
if outcome.Kind != OutcomeSuccess || built != beforeBuilt || parentRuns != beforeRuns || childRuns != beforeChildren+1 ||
entered != spelling+" child" || canonical != "run child" {
t.Fatalf("genuine child selection = %#v, paths %q/%q, builds/runs %d/%d/%d", outcome, entered, canonical, built, parentRuns, childRuns)
}
}
}