-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathcommand_test.go
158 lines (135 loc) · 4.52 KB
/
command_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package ff_test
import (
"context"
"errors"
"reflect"
"strings"
"testing"
"time"
"github.com/peterbourgon/ff/v4"
)
func TestCommandNoFlags(t *testing.T) {
t.Parallel()
var (
cmd = &ff.Command{Name: "root"}
ctx = context.Background()
)
if err := cmd.ParseAndRun(ctx, []string{"-h"}); !errors.Is(err, ff.ErrHelp) {
t.Errorf("err: want %v, have %v", ff.ErrHelp, err)
}
if err := cmd.ParseAndRun(ctx, []string{"--help"}); !errors.Is(err, ff.ErrHelp) {
t.Errorf("err: want %v, have %v", ff.ErrHelp, err)
}
if err := cmd.ParseAndRun(ctx, []string{}); !errors.Is(err, ff.ErrNoExec) {
t.Errorf("err: want %v, have %v", ff.ErrNoExec, err)
}
}
func TestCommandReset(t *testing.T) {
t.Parallel()
ctx := context.Background()
rootcmd, testvars := makeTestCommand(t)
defaults := *testvars
t.Run("first run", func(t *testing.T) {
args := []string{"--verbose", "foo", "-b", "hello world"}
if err := rootcmd.ParseAndRun(ctx, args); err != nil {
t.Fatalf("first run: %v", err)
}
want := defaults // copy
want.Verbose = true
want.Beta = true
compareTestCommandVars(t, want, *testvars)
})
t.Run("second run without reset", func(t *testing.T) {
want := ff.ErrAlreadyParsed
have := rootcmd.ParseAndRun(ctx, nil)
if !errors.Is(have, want) {
t.Errorf("second run without reset: want error %v, have %v", want, have)
}
})
t.Run("reset", func(t *testing.T) {
if err := rootcmd.Reset(); err != nil {
t.Fatalf("reset: %s: %v", rootcmd.Name, err)
}
})
t.Run("second run after reset", func(t *testing.T) {
args := []string{"--config-file=my.conf", "foo", "bar", "-a3", "hello world"}
if err := rootcmd.ParseAndRun(ctx, args); err != nil {
t.Fatalf("second run: %v", err)
}
want := defaults // copy
want.ConfigFile = "my.conf"
want.Alpha = 3
compareTestCommandVars(t, want, *testvars)
})
}
func makeTestCommand(t *testing.T) (*ff.Command, *testCommandVars) {
t.Helper()
var vars testCommandVars
rootFlags := ff.NewFlagSet("root")
rootFlags.BoolVar(&vars.Verbose, 'v', "verbose", "verbose logging")
rootFlags.StringVar(&vars.ConfigFile, 0, "config-file", "", "config file")
rootCommand := &ff.Command{
Name: "testcmd",
Usage: "testcmd [FLAGS] <SUBCOMMAND> ...",
LongHelp: loremIpsum,
Flags: rootFlags,
}
fooFlags := ff.NewFlagSet("foo").SetParent(rootFlags)
fooFlags.IntVar(&vars.Alpha, 'a', "alpha", 10, "alpha integer")
fooFlags.BoolVar(&vars.Beta, 'b', "beta", "beta boolean")
fooCommand := &ff.Command{
Name: "foo",
Usage: "foo [FLAGS] <SUBCOMMAND> ...",
ShortHelp: "the foo subcommand",
Flags: fooFlags,
Exec: func(_ context.Context, args []string) error { t.Logf("foo %+v %#v", vars, args); return nil },
}
rootCommand.Subcommands = append(rootCommand.Subcommands, fooCommand)
barFlags := ff.NewFlagSet("bar").SetParent(fooFlags)
barFlags.DurationVar(&vars.Delta, 'd', "delta", 3*time.Second, "delta `δ` duration")
barFlags.Float64Var(&vars.Epsilon, 'e', "epsilon", 3.21, "epsilon float")
barCommand := &ff.Command{
Name: "bar",
Usage: "bar [FLAGS] ...",
ShortHelp: "the bar subcommand",
Flags: barFlags,
Exec: func(_ context.Context, args []string) error { t.Logf("bar %+v %#v", vars, args); return nil },
}
fooCommand.Subcommands = append(fooCommand.Subcommands, barCommand)
return rootCommand, &vars
}
type testCommandVars struct {
Verbose bool
ConfigFile string
Alpha int
Beta bool
Delta time.Duration
Epsilon float64
}
var loremIpsum = strings.TrimSpace(`
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam diam eros,
vestibulum at pulvinar vulputate, vehicula id lacus. Class aptent taciti
sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
Mauris venenatis felis orci, ac consectetur mi molestie ac. Integer pharetra
pharetra odio. Maecenas metus eros, viverra eget efficitur ut, feugiat in
tortor. Quisque elit nibh, rhoncus in posuere et, bibendum non turpis.
Maecenas eget dui malesuada, pretium tellus quis, bibendum felis. Duis erat
enim, faucibus id auctor ac, ornare sed metus.
`)
func compareTestCommandVars(t *testing.T, want, have testCommandVars) {
t.Helper()
var (
structType = reflect.TypeOf(testCommandVars{})
wantStruct = reflect.ValueOf(want)
haveStruct = reflect.ValueOf(have)
)
for _, f := range reflect.VisibleFields(structType) {
var (
wantValue = wantStruct.FieldByIndex(f.Index)
haveValue = haveStruct.FieldByIndex(f.Index)
)
if !wantValue.Equal(haveValue) {
t.Errorf("%s: want %#v, have %#v", f.Name, wantValue, haveValue)
}
}
}