1package flags
2
3import (
4	"fmt"
5	"testing"
6)
7
8func TestCommandInline(t *testing.T) {
9	var opts = struct {
10		Value bool `short:"v"`
11
12		Command struct {
13			G bool `short:"g"`
14		} `command:"cmd"`
15	}{}
16
17	p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g")
18
19	assertStringArray(t, ret, []string{})
20
21	if p.Active == nil {
22		t.Errorf("Expected active command")
23	}
24
25	if !opts.Value {
26		t.Errorf("Expected Value to be true")
27	}
28
29	if !opts.Command.G {
30		t.Errorf("Expected Command.G to be true")
31	}
32
33	if p.Command.Find("cmd") != p.Active {
34		t.Errorf("Expected to find command `cmd' to be active")
35	}
36}
37
38func TestCommandInlineMulti(t *testing.T) {
39	var opts = struct {
40		Value bool `short:"v"`
41
42		C1 struct {
43		} `command:"c1"`
44
45		C2 struct {
46			G bool `short:"g"`
47		} `command:"c2"`
48	}{}
49
50	p, ret := assertParserSuccess(t, &opts, "-v", "c2", "-g")
51
52	assertStringArray(t, ret, []string{})
53
54	if p.Active == nil {
55		t.Errorf("Expected active command")
56	}
57
58	if !opts.Value {
59		t.Errorf("Expected Value to be true")
60	}
61
62	if !opts.C2.G {
63		t.Errorf("Expected C2.G to be true")
64	}
65
66	if p.Command.Find("c1") == nil {
67		t.Errorf("Expected to find command `c1'")
68	}
69
70	if c2 := p.Command.Find("c2"); c2 == nil {
71		t.Errorf("Expected to find command `c2'")
72	} else if c2 != p.Active {
73		t.Errorf("Expected to find command `c2' to be active")
74	}
75}
76
77func TestCommandFlagOrder1(t *testing.T) {
78	var opts = struct {
79		Value bool `short:"v"`
80
81		Command struct {
82			G bool `short:"g"`
83		} `command:"cmd"`
84	}{}
85
86	assertParseFail(t, ErrUnknownFlag, "unknown flag `g'", &opts, "-v", "-g", "cmd")
87}
88
89func TestCommandFlagOrder2(t *testing.T) {
90	var opts = struct {
91		Value bool `short:"v"`
92
93		Command struct {
94			G bool `short:"g"`
95		} `command:"cmd"`
96	}{}
97
98	assertParseSuccess(t, &opts, "cmd", "-v", "-g")
99
100	if !opts.Value {
101		t.Errorf("Expected Value to be true")
102	}
103
104	if !opts.Command.G {
105		t.Errorf("Expected Command.G to be true")
106	}
107}
108
109func TestCommandFlagOrderSub(t *testing.T) {
110	var opts = struct {
111		Value bool `short:"v"`
112
113		Command struct {
114			G bool `short:"g"`
115
116			SubCommand struct {
117				B bool `short:"b"`
118			} `command:"sub"`
119		} `command:"cmd"`
120	}{}
121
122	assertParseSuccess(t, &opts, "cmd", "sub", "-v", "-g", "-b")
123
124	if !opts.Value {
125		t.Errorf("Expected Value to be true")
126	}
127
128	if !opts.Command.G {
129		t.Errorf("Expected Command.G to be true")
130	}
131
132	if !opts.Command.SubCommand.B {
133		t.Errorf("Expected Command.SubCommand.B to be true")
134	}
135}
136
137func TestCommandFlagOverride1(t *testing.T) {
138	var opts = struct {
139		Value bool `short:"v"`
140
141		Command struct {
142			Value bool `short:"v"`
143		} `command:"cmd"`
144	}{}
145
146	assertParseSuccess(t, &opts, "-v", "cmd")
147
148	if !opts.Value {
149		t.Errorf("Expected Value to be true")
150	}
151
152	if opts.Command.Value {
153		t.Errorf("Expected Command.Value to be false")
154	}
155}
156
157func TestCommandFlagOverride2(t *testing.T) {
158	var opts = struct {
159		Value bool `short:"v"`
160
161		Command struct {
162			Value bool `short:"v"`
163		} `command:"cmd"`
164	}{}
165
166	assertParseSuccess(t, &opts, "cmd", "-v")
167
168	if opts.Value {
169		t.Errorf("Expected Value to be false")
170	}
171
172	if !opts.Command.Value {
173		t.Errorf("Expected Command.Value to be true")
174	}
175}
176
177func TestCommandFlagOverrideSub(t *testing.T) {
178	var opts = struct {
179		Value bool `short:"v"`
180
181		Command struct {
182			Value bool `short:"v"`
183
184			SubCommand struct {
185				Value bool `short:"v"`
186			} `command:"sub"`
187		} `command:"cmd"`
188	}{}
189
190	assertParseSuccess(t, &opts, "cmd", "sub", "-v")
191
192	if opts.Value {
193		t.Errorf("Expected Value to be false")
194	}
195
196	if opts.Command.Value {
197		t.Errorf("Expected Command.Value to be false")
198	}
199
200	if !opts.Command.SubCommand.Value {
201		t.Errorf("Expected Command.Value to be true")
202	}
203}
204
205func TestCommandFlagOverrideSub2(t *testing.T) {
206	var opts = struct {
207		Value bool `short:"v"`
208
209		Command struct {
210			Value bool `short:"v"`
211
212			SubCommand struct {
213				G bool `short:"g"`
214			} `command:"sub"`
215		} `command:"cmd"`
216	}{}
217
218	assertParseSuccess(t, &opts, "cmd", "sub", "-v")
219
220	if opts.Value {
221		t.Errorf("Expected Value to be false")
222	}
223
224	if !opts.Command.Value {
225		t.Errorf("Expected Command.Value to be true")
226	}
227}
228
229func TestCommandEstimate(t *testing.T) {
230	var opts = struct {
231		Value bool `short:"v"`
232
233		Cmd1 struct {
234		} `command:"remove"`
235
236		Cmd2 struct {
237		} `command:"add"`
238	}{}
239
240	p := NewParser(&opts, None)
241	_, err := p.ParseArgs([]string{})
242
243	assertError(t, err, ErrCommandRequired, "Please specify one command of: add or remove")
244}
245
246func TestCommandEstimate2(t *testing.T) {
247	var opts = struct {
248		Value bool `short:"v"`
249
250		Cmd1 struct {
251		} `command:"remove"`
252
253		Cmd2 struct {
254		} `command:"add"`
255	}{}
256
257	p := NewParser(&opts, None)
258	_, err := p.ParseArgs([]string{"rmive"})
259
260	assertError(t, err, ErrUnknownCommand, "Unknown command `rmive', did you mean `remove'?")
261}
262
263type testCommand struct {
264	G        bool `short:"g"`
265	Executed bool
266	EArgs    []string
267}
268
269func (c *testCommand) Execute(args []string) error {
270	c.Executed = true
271	c.EArgs = args
272
273	return nil
274}
275
276func TestCommandExecute(t *testing.T) {
277	var opts = struct {
278		Value bool `short:"v"`
279
280		Command testCommand `command:"cmd"`
281	}{}
282
283	assertParseSuccess(t, &opts, "-v", "cmd", "-g", "a", "b")
284
285	if !opts.Value {
286		t.Errorf("Expected Value to be true")
287	}
288
289	if !opts.Command.Executed {
290		t.Errorf("Did not execute command")
291	}
292
293	if !opts.Command.G {
294		t.Errorf("Expected Command.C to be true")
295	}
296
297	assertStringArray(t, opts.Command.EArgs, []string{"a", "b"})
298}
299
300func TestCommandClosest(t *testing.T) {
301	var opts = struct {
302		Value bool `short:"v"`
303
304		Cmd1 struct {
305		} `command:"remove"`
306
307		Cmd2 struct {
308		} `command:"add"`
309	}{}
310
311	args := assertParseFail(t, ErrUnknownCommand, "Unknown command `addd', did you mean `add'?", &opts, "-v", "addd")
312
313	assertStringArray(t, args, []string{"addd"})
314}
315
316func TestCommandAdd(t *testing.T) {
317	var opts = struct {
318		Value bool `short:"v"`
319	}{}
320
321	var cmd = struct {
322		G bool `short:"g"`
323	}{}
324
325	p := NewParser(&opts, Default)
326	c, err := p.AddCommand("cmd", "", "", &cmd)
327
328	if err != nil {
329		t.Fatalf("Unexpected error: %v", err)
330		return
331	}
332
333	ret, err := p.ParseArgs([]string{"-v", "cmd", "-g", "rest"})
334
335	if err != nil {
336		t.Fatalf("Unexpected error: %v", err)
337		return
338	}
339
340	assertStringArray(t, ret, []string{"rest"})
341
342	if !opts.Value {
343		t.Errorf("Expected Value to be true")
344	}
345
346	if !cmd.G {
347		t.Errorf("Expected Command.G to be true")
348	}
349
350	if p.Command.Find("cmd") != c {
351		t.Errorf("Expected to find command `cmd'")
352	}
353
354	if p.Commands()[0] != c {
355		t.Errorf("Expected command %#v, but got %#v", c, p.Commands()[0])
356	}
357
358	if c.Options()[0].ShortName != 'g' {
359		t.Errorf("Expected short name `g' but got %v", c.Options()[0].ShortName)
360	}
361}
362
363func TestCommandNestedInline(t *testing.T) {
364	var opts = struct {
365		Value bool `short:"v"`
366
367		Command struct {
368			G bool `short:"g"`
369
370			Nested struct {
371				N string `long:"n"`
372			} `command:"nested"`
373		} `command:"cmd"`
374	}{}
375
376	p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g", "nested", "--n", "n", "rest")
377
378	assertStringArray(t, ret, []string{"rest"})
379
380	if !opts.Value {
381		t.Errorf("Expected Value to be true")
382	}
383
384	if !opts.Command.G {
385		t.Errorf("Expected Command.G to be true")
386	}
387
388	assertString(t, opts.Command.Nested.N, "n")
389
390	if c := p.Command.Find("cmd"); c == nil {
391		t.Errorf("Expected to find command `cmd'")
392	} else {
393		if c != p.Active {
394			t.Errorf("Expected `cmd' to be the active parser command")
395		}
396
397		if nested := c.Find("nested"); nested == nil {
398			t.Errorf("Expected to find command `nested'")
399		} else if nested != c.Active {
400			t.Errorf("Expected to find command `nested' to be the active `cmd' command")
401		}
402	}
403}
404
405func TestRequiredOnCommand(t *testing.T) {
406	var opts = struct {
407		Value bool `short:"v" required:"true"`
408
409		Command struct {
410			G bool `short:"g"`
411		} `command:"cmd"`
412	}{}
413
414	assertParseFail(t, ErrRequired, fmt.Sprintf("the required flag `%cv' was not specified", defaultShortOptDelimiter), &opts, "cmd")
415}
416
417func TestRequiredAllOnCommand(t *testing.T) {
418	var opts = struct {
419		Value   bool `short:"v" required:"true"`
420		Missing bool `long:"missing" required:"true"`
421
422		Command struct {
423			G bool `short:"g"`
424		} `command:"cmd"`
425	}{}
426
427	assertParseFail(t, ErrRequired, fmt.Sprintf("the required flags `%smissing' and `%cv' were not specified", defaultLongOptDelimiter, defaultShortOptDelimiter), &opts, "cmd")
428}
429
430func TestDefaultOnCommand(t *testing.T) {
431	var opts = struct {
432		Command struct {
433			G string `short:"g" default:"value"`
434		} `command:"cmd"`
435	}{}
436
437	assertParseSuccess(t, &opts, "cmd")
438
439	if opts.Command.G != "value" {
440		t.Errorf("Expected G to be \"value\"")
441	}
442}
443
444func TestAfterNonCommand(t *testing.T) {
445	var opts = struct {
446		Value bool `short:"v"`
447
448		Cmd1 struct {
449		} `command:"remove"`
450
451		Cmd2 struct {
452		} `command:"add"`
453	}{}
454
455	assertParseFail(t, ErrUnknownCommand, "Unknown command `nocmd'. Please specify one command of: add or remove", &opts, "nocmd", "remove")
456}
457
458func TestSubcommandsOptional(t *testing.T) {
459	var opts = struct {
460		Value bool `short:"v"`
461
462		Cmd1 struct {
463		} `command:"remove"`
464
465		Cmd2 struct {
466		} `command:"add"`
467	}{}
468
469	p := NewParser(&opts, None)
470	p.SubcommandsOptional = true
471
472	_, err := p.ParseArgs([]string{"-v"})
473
474	if err != nil {
475		t.Fatalf("Unexpected error: %v", err)
476		return
477	}
478
479	if !opts.Value {
480		t.Errorf("Expected Value to be true")
481	}
482}
483
484func TestSubcommandsOptionalAfterNonCommand(t *testing.T) {
485	var opts = struct {
486		Value bool `short:"v"`
487
488		Cmd1 struct {
489		} `command:"remove"`
490
491		Cmd2 struct {
492		} `command:"add"`
493	}{}
494
495	p := NewParser(&opts, None)
496	p.SubcommandsOptional = true
497
498	retargs, err := p.ParseArgs([]string{"nocmd", "remove"})
499
500	if err != nil {
501		t.Fatalf("Unexpected error: %v", err)
502		return
503	}
504
505	assertStringArray(t, retargs, []string{"nocmd", "remove"})
506}
507
508func TestCommandAlias(t *testing.T) {
509	var opts = struct {
510		Command struct {
511			G string `short:"g" default:"value"`
512		} `command:"cmd" alias:"cm"`
513	}{}
514
515	assertParseSuccess(t, &opts, "cm")
516
517	if opts.Command.G != "value" {
518		t.Errorf("Expected G to be \"value\"")
519	}
520}
521
522func TestSubCommandFindOptionByLongFlag(t *testing.T) {
523	var opts struct {
524		Testing bool `long:"testing" description:"Testing"`
525	}
526
527	var cmd struct {
528		Other bool `long:"other" description:"Other"`
529	}
530
531	p := NewParser(&opts, Default)
532	c, _ := p.AddCommand("command", "Short", "Long", &cmd)
533
534	opt := c.FindOptionByLongName("other")
535
536	if opt == nil {
537		t.Errorf("Expected option, but found none")
538	}
539
540	assertString(t, opt.LongName, "other")
541
542	opt = c.FindOptionByLongName("testing")
543
544	if opt == nil {
545		t.Errorf("Expected option, but found none")
546	}
547
548	assertString(t, opt.LongName, "testing")
549}
550
551func TestSubCommandFindOptionByShortFlag(t *testing.T) {
552	var opts struct {
553		Testing bool `short:"t" description:"Testing"`
554	}
555
556	var cmd struct {
557		Other bool `short:"o" description:"Other"`
558	}
559
560	p := NewParser(&opts, Default)
561	c, _ := p.AddCommand("command", "Short", "Long", &cmd)
562
563	opt := c.FindOptionByShortName('o')
564
565	if opt == nil {
566		t.Errorf("Expected option, but found none")
567	}
568
569	if opt.ShortName != 'o' {
570		t.Errorf("Expected 'o', but got %v", opt.ShortName)
571	}
572
573	opt = c.FindOptionByShortName('t')
574
575	if opt == nil {
576		t.Errorf("Expected option, but found none")
577	}
578
579	if opt.ShortName != 't' {
580		t.Errorf("Expected 'o', but got %v", opt.ShortName)
581	}
582}
583