-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathparser_refactor_regression_test.go
More file actions
244 lines (205 loc) · 8.04 KB
/
parser_refactor_regression_test.go
File metadata and controls
244 lines (205 loc) · 8.04 KB
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
package flaggy
import (
"strings"
"testing"
)
func TestNestedSubcommandsParseLocalFlags(t *testing.T) {
// Command: ./app subcommandA subcommandB -flagA 5
// Expect: subcommandA and subcommandB used; flagA parsed as int 5 on subcommandB.
t.Parallel()
// Setup root parser and nested subcommands to mirror the CLI hierarchy.
p := NewParser("app")
subA := NewSubcommand("subcommandA")
subB := NewSubcommand("subcommandB")
p.AttachSubcommand(subA, 1)
subA.AttachSubcommand(subB, 1)
// Define flagA on subcommandB with storage for the parsed integer.
var flagA int
subB.Int(&flagA, "", "flagA", "int flag scoped to subcommandB")
// Parse the CLI input exactly as described in the command comment.
if err := p.ParseArgs([]string{"subcommandA", "subcommandB", "-flagA", "5"}); err != nil {
t.Fatalf("parse failed: %v", err)
}
// Assert both subcommands are marked as used and the flag value is correct.
if !subA.Used || !subB.Used {
t.Fatalf("expected subcommands to be marked used: subA=%v subB=%v", subA.Used, subB.Used)
}
if flagA != 5 {
t.Fatalf("expected flagA to be 5, got %d", flagA)
}
}
func TestRootAndChildFlagsAreIsolated(t *testing.T) {
// Command: ./app -flagA=5 --flagB 5 subcommandA --flagC hello
// Expect: root flagA=5, root flagB=5, subcommandA used with flagC="hello".
t.Parallel()
// Setup root parser with a single subcommand to host child-scoped flags.
p := NewParser("app")
subA := NewSubcommand("subcommandA")
p.AttachSubcommand(subA, 1)
// Define storage locations for the root and child flag values.
var flagA int
var flagB int
var flagC string
// Register two root flags and one child flag matching the command contract.
p.Int(&flagA, "", "flagA", "root int flag")
p.Int(&flagB, "", "flagB", "second root int flag")
subA.String(&flagC, "", "flagC", "child string flag")
// Parse the CLI input exactly as described in the command comment.
args := []string{"-flagA=5", "--flagB", "5", "subcommandA", "--flagC", "hello"}
if err := p.ParseArgs(args); err != nil {
t.Fatalf("parse failed: %v", err)
}
// Verify root flags resolve correctly and the child flag receives "hello".
if flagA != 5 {
t.Fatalf("expected flagA to be 5, got %d", flagA)
}
if flagB != 5 {
t.Fatalf("expected flagB to be 5, got %d", flagB)
}
if flagC != "hello" {
t.Fatalf("expected flagC to be hello, got %q", flagC)
}
// Confirm the subcommand was invoked during parsing.
if !subA.Used {
t.Fatalf("expected subcommandA to be used")
}
}
func TestFlagNameCollisionWithSubcommand(t *testing.T) {
// Command: ./app -flagA=test flagA
// Expect: root flagA string set to "test" while flagA subcommand is used.
t.Parallel()
// Setup root parser with a subcommand whose name collides with a root flag.
p := NewParser("app")
subFlagA := NewSubcommand("flagA")
p.AttachSubcommand(subFlagA, 1)
// Register the root-level string flag sharing the subcommand's name.
var rootFlag string
p.String(&rootFlag, "", "flagA", "root string flag")
// Parse the CLI input exactly as described in the command comment.
if err := p.ParseArgs([]string{"-flagA=test", "flagA"}); err != nil {
t.Fatalf("parse failed: %v", err)
}
// Validate both the root flag value and the subcommand usage status.
if rootFlag != "test" {
t.Fatalf("expected root flag to be \"test\", got %q", rootFlag)
}
if !subFlagA.Used {
t.Fatalf("expected subcommand flagA to be used")
}
}
func TestBlankAndWhitespaceValues(t *testing.T) {
// Command: ./app -flagA "" subcommandA -a "" -b " " -c XYZ
// Expect: root flagA blank, -a blank, -b single space, -c "XYZ", subcommandA used.
t.Parallel()
// Setup root parser with subcommandA to hold scoped string flags.
p := NewParser("app")
subA := NewSubcommand("subcommandA")
p.AttachSubcommand(subA, 1)
// Define storage for root and subcommand flag values.
var rootFlag string
var flagA string
var flagB string
var flagC string
// Register the root flag and subcommand flags matching the CLI usage.
p.String(&rootFlag, "", "flagA", "root string flag")
subA.String(&flagA, "a", "", "blank string flag")
subA.String(&flagB, "b", "", "single space flag")
subA.String(&flagC, "c", "", "non blank flag")
// Parse the CLI input exactly as described in the command comment.
args := []string{"-flagA", "", "subcommandA", "-a", "", "-b", " ", "-c", "XYZ"}
if err := p.ParseArgs(args); err != nil {
t.Fatalf("parse failed: %v", err)
}
// Assert blank and whitespace values were preserved for each flag.
if rootFlag != "" {
t.Fatalf("expected root flagA to be blank, got %q", rootFlag)
}
if flagA != "" {
t.Fatalf("expected -a flag to be blank, got %q", flagA)
}
if flagB != " " {
t.Fatalf("expected -b flag to be a single space, got %q", flagB)
}
if flagC != "XYZ" {
t.Fatalf("expected -c flag to be XYZ, got %q", flagC)
}
// Confirm the subcommand was invoked during parsing.
if !subA.Used {
t.Fatalf("expected subcommandA to be used")
}
}
func TestIssue96EmptyStringShortFlagValue(t *testing.T) {
// Issue 96: ./app -log.file.dir "" -log.logstash.level INFO
// Expect: no parse error, log.file.dir stored as "", log.logstash.level stored as "INFO".
t.Parallel()
// Setup parser mirroring the issue-96 configuration with dotted short flag names.
p := NewParser("app")
var fileDir string
var logstashLevel string
// Register both flags using the same short/long names as the regression report.
p.String(&fileDir, "log.file.dir", "logFileDir", "Directory for log files (issue 96)")
p.String(&logstashLevel, "log.logstash.level", "logLogstashLevel", "Logstash level (issue 96)")
// Parse the exact CLI from the GitHub issue to guard against regression.
args := []string{"-log.file.dir", "", "-log.logstash.level", "INFO"}
if err := p.ParseArgs(args); err != nil {
t.Fatalf("parse failed for issue 96 reproduction: %v", err)
}
if fileDir != "" {
t.Fatalf("expected log.file.dir to remain an empty string, got %q", fileDir)
}
if logstashLevel != "INFO" {
t.Fatalf("expected log.logstash.level to be \"INFO\", got %q", logstashLevel)
}
}
func TestRootBoolAfterSubcommand(t *testing.T) {
// Command: ./app subcommandA --output
// Expect: subcommandA used; root --output bool flag set to true.
t.Parallel()
// Setup root parser with subcommandA to mirror the CLI input.
p := NewParser("app")
subA := NewSubcommand("subcommandA")
p.AttachSubcommand(subA, 1)
// Register the root-level bool flag that follows the subcommand.
var output bool
p.Bool(&output, "", "output", "root bool flag")
// Parse the CLI input exactly as described in the command comment.
if err := p.ParseArgs([]string{"subcommandA", "--output"}); err != nil {
t.Fatalf("parse failed: %v", err)
}
// Assert the bool flag is true and the subcommand is marked as used.
if !output {
t.Fatalf("expected --output to set output to true")
}
if !subA.Used {
t.Fatalf("expected subcommandA to be used")
}
}
func TestNestedSubcommandTrailingArguments(t *testing.T) {
// Command: ./app one two --test -- abc 123 xyz
// Expect: subcommands one & two used; --test bool true; trailing args joined to "abc 123 xyz".
t.Parallel()
// Setup root parser with nested subcommands to reflect the CLI command.
p := NewParser("app")
subOne := NewSubcommand("one")
subTwo := NewSubcommand("two")
p.AttachSubcommand(subOne, 1)
subOne.AttachSubcommand(subTwo, 1)
// Register the bool flag on the deepest subcommand per the command contract.
var test bool
subTwo.Bool(&test, "", "test", "bool flag on nested subcommand")
// Parse the CLI input exactly as described in the command comment.
args := []string{"one", "two", "--test", "--", "abc", "123", "xyz"}
if err := p.ParseArgs(args); err != nil {
t.Fatalf("parse failed: %v", err)
}
// Validate subcommands were used, flag set to true, and trailing args preserved.
if !subOne.Used || !subTwo.Used {
t.Fatalf("expected nested subcommands to be used: one=%v two=%v", subOne.Used, subTwo.Used)
}
if !test {
t.Fatalf("expected --test to set the nested bool flag to true")
}
if got := strings.Join(p.TrailingArguments, " "); got != "abc 123 xyz" {
t.Fatalf("expected trailing arguments to join to %q, got %q", "abc 123 xyz", got)
}
}