Verify typed alias composition in integrations
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package commandkit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
@@ -245,3 +247,90 @@ func TestIncompletePreparationSkipsMissingRequirementsAndInputFactory(t *testing
|
||||
t.Fatalf("preparation invoked NewInput %d times", factoryCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteBindsMixedFlagSpellingsWithFreshPresence(t *testing.T) {
|
||||
type input struct {
|
||||
count Supplied[int]
|
||||
enabled Supplied[bool]
|
||||
message Supplied[string]
|
||||
tags Supplied[[]string]
|
||||
required Supplied[string]
|
||||
instance int
|
||||
}
|
||||
type observed struct {
|
||||
count Supplied[int]
|
||||
enabled Supplied[bool]
|
||||
message Supplied[string]
|
||||
tags Supplied[[]string]
|
||||
required Supplied[string]
|
||||
instance int
|
||||
}
|
||||
defaultCount := 9
|
||||
defaultMessage := "fallback"
|
||||
defaultTags := []string{"base"}
|
||||
countParses, inputFactories := 0, 0
|
||||
var calls []observed
|
||||
command := NewCommand(CommandSpec[input]{
|
||||
Name: "run",
|
||||
NewInput: func() input {
|
||||
inputFactories++
|
||||
return input{instance: inputFactories}
|
||||
},
|
||||
Flags: []Flag[input]{
|
||||
ValueFlag(FlagMeta{Name: "count"}, &defaultCount, func(value string) (int, error) {
|
||||
countParses++
|
||||
return strconv.Atoi(value)
|
||||
}, func(target *input, value Supplied[int]) { target.count = value }),
|
||||
BoolFlag(FlagMeta{Name: "enabled"}, true, func(target *input, value Supplied[bool]) { target.enabled = value }),
|
||||
ValueFlag(FlagMeta{Name: "message"}, &defaultMessage, func(value string) (string, error) { return value, nil }, func(target *input, value Supplied[string]) { target.message = value }),
|
||||
RepeatFlag(FlagMeta{Name: "tag"}, defaultTags, func(value string) (string, error) { return value, nil }, func(target *input, value Supplied[[]string]) { target.tags = value }),
|
||||
ValueFlag(FlagMeta{Name: "required", Required: true}, (*string)(nil), func(value string) (string, error) { return value, nil }, func(target *input, value Supplied[string]) { target.required = value }),
|
||||
},
|
||||
Run: func(_ Invocation, value input) Outcome {
|
||||
value.tags.Value = append([]string(nil), value.tags.Value...)
|
||||
calls = append(calls, observed(value))
|
||||
return Success()
|
||||
},
|
||||
})
|
||||
app, err := New(Identity{Name: "Example"}, command,
|
||||
Alias("shortcut", "run"),
|
||||
FlagAliasFor("run", "--number", "--count"),
|
||||
FlagAliasFor("run", "--active", "--enabled"),
|
||||
FlagAliasFor("run", "--text", "--message"),
|
||||
FlagAliasFor("run", "--label", "--tag"),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, args := range [][]string{
|
||||
{"shortcut", "--number=0", "--count=5", "--active=false", "--enabled=true", "--text=", "--message=last", "--label=a", "--tag=b", "--required=first"},
|
||||
{"run", "--number=0", "--active=false", "--text=", "--label=c", "--required=second"},
|
||||
} {
|
||||
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)
|
||||
}
|
||||
}
|
||||
if countParses != 3 {
|
||||
t.Fatalf("count conversions = %d, want every one of three occurrences", countParses)
|
||||
}
|
||||
if len(calls) != 2 || calls[0].count != (Supplied[int]{Value: 5, Set: true}) || calls[0].enabled != (Supplied[bool]{Value: true, Set: true}) || calls[0].message != (Supplied[string]{Value: "last", Set: true}) || !reflect.DeepEqual(calls[0].tags, Supplied[[]string]{Value: []string{"a", "b"}, Set: true}) || calls[0].required != (Supplied[string]{Value: "first", Set: true}) {
|
||||
t.Fatalf("first mixed-spelling invocation = %#v", calls)
|
||||
}
|
||||
if calls[1].count != (Supplied[int]{Value: 0, Set: true}) || calls[1].enabled != (Supplied[bool]{Value: false, Set: true}) || calls[1].message != (Supplied[string]{Value: "", Set: true}) || !reflect.DeepEqual(calls[1].tags, Supplied[[]string]{Value: []string{"c"}, Set: true}) || calls[1].required != (Supplied[string]{Value: "second", Set: true}) || calls[0].instance == calls[1].instance {
|
||||
t.Fatalf("second mixed-spelling invocation = %#v", calls[1])
|
||||
}
|
||||
|
||||
if outcome := app.Execute(context.Background(), []string{"shortcut", "--count=7"}, Streams{Out: io.Discard, Err: io.Discard}); outcome.Kind != OutcomeUsage {
|
||||
t.Fatalf("missing required flag outcome = %#v, want usage", outcome)
|
||||
}
|
||||
if inputFactories != 2 || len(calls) != 2 {
|
||||
t.Fatalf("missing required flag created or ran input: factories=%d calls=%d", inputFactories, len(calls))
|
||||
}
|
||||
if outcome := app.Execute(context.Background(), []string{"shortcut", "--required=defaults"}, Streams{Out: io.Discard, Err: io.Discard}); outcome.Kind != OutcomeSuccess {
|
||||
t.Fatalf("defaulted invocation = %#v, want success", outcome)
|
||||
}
|
||||
if len(calls) != 3 || calls[2].count != (Supplied[int]{Value: 9}) || calls[2].enabled != (Supplied[bool]{Value: true}) || calls[2].message != (Supplied[string]{Value: "fallback"}) || !reflect.DeepEqual(calls[2].tags, Supplied[[]string]{Value: []string{"base"}}) || calls[2].required != (Supplied[string]{Value: "defaults", Set: true}) || calls[2].instance == calls[1].instance {
|
||||
t.Fatalf("omitted values reused prior invocation state: %#v", calls[2])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user