1package cobra
2
3import (
4	"bytes"
5	"context"
6	"fmt"
7	"os"
8	"reflect"
9	"strings"
10	"testing"
11
12	"github.com/spf13/pflag"
13)
14
15func emptyRun(*Command, []string) {}
16
17func executeCommand(root *Command, args ...string) (output string, err error) {
18	_, output, err = executeCommandC(root, args...)
19	return output, err
20}
21
22func executeCommandWithContext(ctx context.Context, root *Command, args ...string) (output string, err error) {
23	buf := new(bytes.Buffer)
24	root.SetOut(buf)
25	root.SetErr(buf)
26	root.SetArgs(args)
27
28	err = root.ExecuteContext(ctx)
29
30	return buf.String(), err
31}
32
33func executeCommandC(root *Command, args ...string) (c *Command, output string, err error) {
34	buf := new(bytes.Buffer)
35	root.SetOut(buf)
36	root.SetErr(buf)
37	root.SetArgs(args)
38
39	c, err = root.ExecuteC()
40
41	return c, buf.String(), err
42}
43
44func resetCommandLineFlagSet() {
45	pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
46}
47
48func checkStringContains(t *testing.T, got, expected string) {
49	if !strings.Contains(got, expected) {
50		t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got)
51	}
52}
53
54func checkStringOmits(t *testing.T, got, expected string) {
55	if strings.Contains(got, expected) {
56		t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got)
57	}
58}
59
60func TestSingleCommand(t *testing.T) {
61	var rootCmdArgs []string
62	rootCmd := &Command{
63		Use:  "root",
64		Args: ExactArgs(2),
65		Run:  func(_ *Command, args []string) { rootCmdArgs = args },
66	}
67	aCmd := &Command{Use: "a", Args: NoArgs, Run: emptyRun}
68	bCmd := &Command{Use: "b", Args: NoArgs, Run: emptyRun}
69	rootCmd.AddCommand(aCmd, bCmd)
70
71	output, err := executeCommand(rootCmd, "one", "two")
72	if output != "" {
73		t.Errorf("Unexpected output: %v", output)
74	}
75	if err != nil {
76		t.Errorf("Unexpected error: %v", err)
77	}
78
79	got := strings.Join(rootCmdArgs, " ")
80	expected := "one two"
81	if got != expected {
82		t.Errorf("rootCmdArgs expected: %q, got: %q", expected, got)
83	}
84}
85
86func TestChildCommand(t *testing.T) {
87	var child1CmdArgs []string
88	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
89	child1Cmd := &Command{
90		Use:  "child1",
91		Args: ExactArgs(2),
92		Run:  func(_ *Command, args []string) { child1CmdArgs = args },
93	}
94	child2Cmd := &Command{Use: "child2", Args: NoArgs, Run: emptyRun}
95	rootCmd.AddCommand(child1Cmd, child2Cmd)
96
97	output, err := executeCommand(rootCmd, "child1", "one", "two")
98	if output != "" {
99		t.Errorf("Unexpected output: %v", output)
100	}
101	if err != nil {
102		t.Errorf("Unexpected error: %v", err)
103	}
104
105	got := strings.Join(child1CmdArgs, " ")
106	expected := "one two"
107	if got != expected {
108		t.Errorf("child1CmdArgs expected: %q, got: %q", expected, got)
109	}
110}
111
112func TestCallCommandWithoutSubcommands(t *testing.T) {
113	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
114	_, err := executeCommand(rootCmd)
115	if err != nil {
116		t.Errorf("Calling command without subcommands should not have error: %v", err)
117	}
118}
119
120func TestRootExecuteUnknownCommand(t *testing.T) {
121	rootCmd := &Command{Use: "root", Run: emptyRun}
122	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
123
124	output, _ := executeCommand(rootCmd, "unknown")
125
126	expected := "Error: unknown command \"unknown\" for \"root\"\nRun 'root --help' for usage.\n"
127
128	if output != expected {
129		t.Errorf("Expected:\n %q\nGot:\n %q\n", expected, output)
130	}
131}
132
133func TestSubcommandExecuteC(t *testing.T) {
134	rootCmd := &Command{Use: "root", Run: emptyRun}
135	childCmd := &Command{Use: "child", Run: emptyRun}
136	rootCmd.AddCommand(childCmd)
137
138	c, output, err := executeCommandC(rootCmd, "child")
139	if output != "" {
140		t.Errorf("Unexpected output: %v", output)
141	}
142	if err != nil {
143		t.Errorf("Unexpected error: %v", err)
144	}
145
146	if c.Name() != "child" {
147		t.Errorf(`invalid command returned from ExecuteC: expected "child"', got %q`, c.Name())
148	}
149}
150
151func TestExecuteContext(t *testing.T) {
152	ctx := context.TODO()
153
154	ctxRun := func(cmd *Command, args []string) {
155		if cmd.Context() != ctx {
156			t.Errorf("Command %q must have context when called with ExecuteContext", cmd.Use)
157		}
158	}
159
160	rootCmd := &Command{Use: "root", Run: ctxRun, PreRun: ctxRun}
161	childCmd := &Command{Use: "child", Run: ctxRun, PreRun: ctxRun}
162	granchildCmd := &Command{Use: "grandchild", Run: ctxRun, PreRun: ctxRun}
163
164	childCmd.AddCommand(granchildCmd)
165	rootCmd.AddCommand(childCmd)
166
167	if _, err := executeCommandWithContext(ctx, rootCmd, ""); err != nil {
168		t.Errorf("Root command must not fail: %+v", err)
169	}
170
171	if _, err := executeCommandWithContext(ctx, rootCmd, "child"); err != nil {
172		t.Errorf("Subcommand must not fail: %+v", err)
173	}
174
175	if _, err := executeCommandWithContext(ctx, rootCmd, "child", "grandchild"); err != nil {
176		t.Errorf("Command child must not fail: %+v", err)
177	}
178}
179
180func TestExecute_NoContext(t *testing.T) {
181	run := func(cmd *Command, args []string) {
182		if cmd.Context() != context.Background() {
183			t.Errorf("Command %s must have background context", cmd.Use)
184		}
185	}
186
187	rootCmd := &Command{Use: "root", Run: run, PreRun: run}
188	childCmd := &Command{Use: "child", Run: run, PreRun: run}
189	granchildCmd := &Command{Use: "grandchild", Run: run, PreRun: run}
190
191	childCmd.AddCommand(granchildCmd)
192	rootCmd.AddCommand(childCmd)
193
194	if _, err := executeCommand(rootCmd, ""); err != nil {
195		t.Errorf("Root command must not fail: %+v", err)
196	}
197
198	if _, err := executeCommand(rootCmd, "child"); err != nil {
199		t.Errorf("Subcommand must not fail: %+v", err)
200	}
201
202	if _, err := executeCommand(rootCmd, "child", "grandchild"); err != nil {
203		t.Errorf("Command child must not fail: %+v", err)
204	}
205}
206
207func TestRootUnknownCommandSilenced(t *testing.T) {
208	rootCmd := &Command{Use: "root", Run: emptyRun}
209	rootCmd.SilenceErrors = true
210	rootCmd.SilenceUsage = true
211	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
212
213	output, _ := executeCommand(rootCmd, "unknown")
214	if output != "" {
215		t.Errorf("Expected blank output, because of silenced usage.\nGot:\n %q\n", output)
216	}
217}
218
219func TestCommandAlias(t *testing.T) {
220	var timesCmdArgs []string
221	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
222	echoCmd := &Command{
223		Use:     "echo",
224		Aliases: []string{"say", "tell"},
225		Args:    NoArgs,
226		Run:     emptyRun,
227	}
228	timesCmd := &Command{
229		Use:  "times",
230		Args: ExactArgs(2),
231		Run:  func(_ *Command, args []string) { timesCmdArgs = args },
232	}
233	echoCmd.AddCommand(timesCmd)
234	rootCmd.AddCommand(echoCmd)
235
236	output, err := executeCommand(rootCmd, "tell", "times", "one", "two")
237	if output != "" {
238		t.Errorf("Unexpected output: %v", output)
239	}
240	if err != nil {
241		t.Errorf("Unexpected error: %v", err)
242	}
243
244	got := strings.Join(timesCmdArgs, " ")
245	expected := "one two"
246	if got != expected {
247		t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got)
248	}
249}
250
251func TestEnablePrefixMatching(t *testing.T) {
252	EnablePrefixMatching = true
253
254	var aCmdArgs []string
255	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
256	aCmd := &Command{
257		Use:  "aCmd",
258		Args: ExactArgs(2),
259		Run:  func(_ *Command, args []string) { aCmdArgs = args },
260	}
261	bCmd := &Command{Use: "bCmd", Args: NoArgs, Run: emptyRun}
262	rootCmd.AddCommand(aCmd, bCmd)
263
264	output, err := executeCommand(rootCmd, "a", "one", "two")
265	if output != "" {
266		t.Errorf("Unexpected output: %v", output)
267	}
268	if err != nil {
269		t.Errorf("Unexpected error: %v", err)
270	}
271
272	got := strings.Join(aCmdArgs, " ")
273	expected := "one two"
274	if got != expected {
275		t.Errorf("aCmdArgs expected: %q, got: %q", expected, got)
276	}
277
278	EnablePrefixMatching = false
279}
280
281func TestAliasPrefixMatching(t *testing.T) {
282	EnablePrefixMatching = true
283
284	var timesCmdArgs []string
285	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
286	echoCmd := &Command{
287		Use:     "echo",
288		Aliases: []string{"say", "tell"},
289		Args:    NoArgs,
290		Run:     emptyRun,
291	}
292	timesCmd := &Command{
293		Use:  "times",
294		Args: ExactArgs(2),
295		Run:  func(_ *Command, args []string) { timesCmdArgs = args },
296	}
297	echoCmd.AddCommand(timesCmd)
298	rootCmd.AddCommand(echoCmd)
299
300	output, err := executeCommand(rootCmd, "sa", "times", "one", "two")
301	if output != "" {
302		t.Errorf("Unexpected output: %v", output)
303	}
304	if err != nil {
305		t.Errorf("Unexpected error: %v", err)
306	}
307
308	got := strings.Join(timesCmdArgs, " ")
309	expected := "one two"
310	if got != expected {
311		t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got)
312	}
313
314	EnablePrefixMatching = false
315}
316
317// TestChildSameName checks the correct behaviour of cobra in cases,
318// when an application with name "foo" and with subcommand "foo"
319// is executed with args "foo foo".
320func TestChildSameName(t *testing.T) {
321	var fooCmdArgs []string
322	rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun}
323	fooCmd := &Command{
324		Use:  "foo",
325		Args: ExactArgs(2),
326		Run:  func(_ *Command, args []string) { fooCmdArgs = args },
327	}
328	barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun}
329	rootCmd.AddCommand(fooCmd, barCmd)
330
331	output, err := executeCommand(rootCmd, "foo", "one", "two")
332	if output != "" {
333		t.Errorf("Unexpected output: %v", output)
334	}
335	if err != nil {
336		t.Errorf("Unexpected error: %v", err)
337	}
338
339	got := strings.Join(fooCmdArgs, " ")
340	expected := "one two"
341	if got != expected {
342		t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got)
343	}
344}
345
346// TestGrandChildSameName checks the correct behaviour of cobra in cases,
347// when user has a root command and a grand child
348// with the same name.
349func TestGrandChildSameName(t *testing.T) {
350	var fooCmdArgs []string
351	rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun}
352	barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun}
353	fooCmd := &Command{
354		Use:  "foo",
355		Args: ExactArgs(2),
356		Run:  func(_ *Command, args []string) { fooCmdArgs = args },
357	}
358	barCmd.AddCommand(fooCmd)
359	rootCmd.AddCommand(barCmd)
360
361	output, err := executeCommand(rootCmd, "bar", "foo", "one", "two")
362	if output != "" {
363		t.Errorf("Unexpected output: %v", output)
364	}
365	if err != nil {
366		t.Errorf("Unexpected error: %v", err)
367	}
368
369	got := strings.Join(fooCmdArgs, " ")
370	expected := "one two"
371	if got != expected {
372		t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got)
373	}
374}
375
376func TestFlagLong(t *testing.T) {
377	var cArgs []string
378	c := &Command{
379		Use:  "c",
380		Args: ArbitraryArgs,
381		Run:  func(_ *Command, args []string) { cArgs = args },
382	}
383
384	var intFlagValue int
385	var stringFlagValue string
386	c.Flags().IntVar(&intFlagValue, "intf", -1, "")
387	c.Flags().StringVar(&stringFlagValue, "sf", "", "")
388
389	output, err := executeCommand(c, "--intf=7", "--sf=abc", "one", "--", "two")
390	if output != "" {
391		t.Errorf("Unexpected output: %v", err)
392	}
393	if err != nil {
394		t.Errorf("Unexpected error: %v", err)
395	}
396
397	if c.ArgsLenAtDash() != 1 {
398		t.Errorf("Expected ArgsLenAtDash: %v but got %v", 1, c.ArgsLenAtDash())
399	}
400	if intFlagValue != 7 {
401		t.Errorf("Expected intFlagValue: %v, got %v", 7, intFlagValue)
402	}
403	if stringFlagValue != "abc" {
404		t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue)
405	}
406
407	got := strings.Join(cArgs, " ")
408	expected := "one two"
409	if got != expected {
410		t.Errorf("Expected arguments: %q, got %q", expected, got)
411	}
412}
413
414func TestFlagShort(t *testing.T) {
415	var cArgs []string
416	c := &Command{
417		Use:  "c",
418		Args: ArbitraryArgs,
419		Run:  func(_ *Command, args []string) { cArgs = args },
420	}
421
422	var intFlagValue int
423	var stringFlagValue string
424	c.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
425	c.Flags().StringVarP(&stringFlagValue, "sf", "s", "", "")
426
427	output, err := executeCommand(c, "-i", "7", "-sabc", "one", "two")
428	if output != "" {
429		t.Errorf("Unexpected output: %v", err)
430	}
431	if err != nil {
432		t.Errorf("Unexpected error: %v", err)
433	}
434
435	if intFlagValue != 7 {
436		t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
437	}
438	if stringFlagValue != "abc" {
439		t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue)
440	}
441
442	got := strings.Join(cArgs, " ")
443	expected := "one two"
444	if got != expected {
445		t.Errorf("Expected arguments: %q, got %q", expected, got)
446	}
447}
448
449func TestChildFlag(t *testing.T) {
450	rootCmd := &Command{Use: "root", Run: emptyRun}
451	childCmd := &Command{Use: "child", Run: emptyRun}
452	rootCmd.AddCommand(childCmd)
453
454	var intFlagValue int
455	childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
456
457	output, err := executeCommand(rootCmd, "child", "-i7")
458	if output != "" {
459		t.Errorf("Unexpected output: %v", err)
460	}
461	if err != nil {
462		t.Errorf("Unexpected error: %v", err)
463	}
464
465	if intFlagValue != 7 {
466		t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
467	}
468}
469
470func TestChildFlagWithParentLocalFlag(t *testing.T) {
471	rootCmd := &Command{Use: "root", Run: emptyRun}
472	childCmd := &Command{Use: "child", Run: emptyRun}
473	rootCmd.AddCommand(childCmd)
474
475	var intFlagValue int
476	rootCmd.Flags().StringP("sf", "s", "", "")
477	childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
478
479	_, err := executeCommand(rootCmd, "child", "-i7", "-sabc")
480	if err == nil {
481		t.Errorf("Invalid flag should generate error")
482	}
483
484	checkStringContains(t, err.Error(), "unknown shorthand")
485
486	if intFlagValue != 7 {
487		t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
488	}
489}
490
491func TestFlagInvalidInput(t *testing.T) {
492	rootCmd := &Command{Use: "root", Run: emptyRun}
493	rootCmd.Flags().IntP("intf", "i", -1, "")
494
495	_, err := executeCommand(rootCmd, "-iabc")
496	if err == nil {
497		t.Errorf("Invalid flag value should generate error")
498	}
499
500	checkStringContains(t, err.Error(), "invalid syntax")
501}
502
503func TestFlagBeforeCommand(t *testing.T) {
504	rootCmd := &Command{Use: "root", Run: emptyRun}
505	childCmd := &Command{Use: "child", Run: emptyRun}
506	rootCmd.AddCommand(childCmd)
507
508	var flagValue int
509	childCmd.Flags().IntVarP(&flagValue, "intf", "i", -1, "")
510
511	// With short flag.
512	_, err := executeCommand(rootCmd, "-i7", "child")
513	if err != nil {
514		t.Errorf("Unexpected error: %v", err)
515	}
516	if flagValue != 7 {
517		t.Errorf("Expected flag value: %v, got %v", 7, flagValue)
518	}
519
520	// With long flag.
521	_, err = executeCommand(rootCmd, "--intf=8", "child")
522	if err != nil {
523		t.Errorf("Unexpected error: %v", err)
524	}
525	if flagValue != 8 {
526		t.Errorf("Expected flag value: %v, got %v", 9, flagValue)
527	}
528}
529
530func TestStripFlags(t *testing.T) {
531	tests := []struct {
532		input  []string
533		output []string
534	}{
535		{
536			[]string{"foo", "bar"},
537			[]string{"foo", "bar"},
538		},
539		{
540			[]string{"foo", "--str", "-s"},
541			[]string{"foo"},
542		},
543		{
544			[]string{"-s", "foo", "--str", "bar"},
545			[]string{},
546		},
547		{
548			[]string{"-i10", "echo"},
549			[]string{"echo"},
550		},
551		{
552			[]string{"-i=10", "echo"},
553			[]string{"echo"},
554		},
555		{
556			[]string{"--int=100", "echo"},
557			[]string{"echo"},
558		},
559		{
560			[]string{"-ib", "echo", "-sfoo", "baz"},
561			[]string{"echo", "baz"},
562		},
563		{
564			[]string{"-i=baz", "bar", "-i", "foo", "blah"},
565			[]string{"bar", "blah"},
566		},
567		{
568			[]string{"--int=baz", "-sbar", "-i", "foo", "blah"},
569			[]string{"blah"},
570		},
571		{
572			[]string{"--bool", "bar", "-i", "foo", "blah"},
573			[]string{"bar", "blah"},
574		},
575		{
576			[]string{"-b", "bar", "-i", "foo", "blah"},
577			[]string{"bar", "blah"},
578		},
579		{
580			[]string{"--persist", "bar"},
581			[]string{"bar"},
582		},
583		{
584			[]string{"-p", "bar"},
585			[]string{"bar"},
586		},
587	}
588
589	c := &Command{Use: "c", Run: emptyRun}
590	c.PersistentFlags().BoolP("persist", "p", false, "")
591	c.Flags().IntP("int", "i", -1, "")
592	c.Flags().StringP("str", "s", "", "")
593	c.Flags().BoolP("bool", "b", false, "")
594
595	for i, test := range tests {
596		got := stripFlags(test.input, c)
597		if !reflect.DeepEqual(test.output, got) {
598			t.Errorf("(%v) Expected: %v, got: %v", i, test.output, got)
599		}
600	}
601}
602
603func TestDisableFlagParsing(t *testing.T) {
604	var cArgs []string
605	c := &Command{
606		Use:                "c",
607		DisableFlagParsing: true,
608		Run: func(_ *Command, args []string) {
609			cArgs = args
610		},
611	}
612
613	args := []string{"cmd", "-v", "-race", "-file", "foo.go"}
614	output, err := executeCommand(c, args...)
615	if output != "" {
616		t.Errorf("Unexpected output: %v", output)
617	}
618	if err != nil {
619		t.Errorf("Unexpected error: %v", err)
620	}
621
622	if !reflect.DeepEqual(args, cArgs) {
623		t.Errorf("Expected: %v, got: %v", args, cArgs)
624	}
625}
626
627func TestPersistentFlagsOnSameCommand(t *testing.T) {
628	var rootCmdArgs []string
629	rootCmd := &Command{
630		Use:  "root",
631		Args: ArbitraryArgs,
632		Run:  func(_ *Command, args []string) { rootCmdArgs = args },
633	}
634
635	var flagValue int
636	rootCmd.PersistentFlags().IntVarP(&flagValue, "intf", "i", -1, "")
637
638	output, err := executeCommand(rootCmd, "-i7", "one", "two")
639	if output != "" {
640		t.Errorf("Unexpected output: %v", output)
641	}
642	if err != nil {
643		t.Errorf("Unexpected error: %v", err)
644	}
645
646	got := strings.Join(rootCmdArgs, " ")
647	expected := "one two"
648	if got != expected {
649		t.Errorf("rootCmdArgs expected: %q, got %q", expected, got)
650	}
651	if flagValue != 7 {
652		t.Errorf("flagValue expected: %v, got %v", 7, flagValue)
653	}
654}
655
656// TestEmptyInputs checks,
657// if flags correctly parsed with blank strings in args.
658func TestEmptyInputs(t *testing.T) {
659	c := &Command{Use: "c", Run: emptyRun}
660
661	var flagValue int
662	c.Flags().IntVarP(&flagValue, "intf", "i", -1, "")
663
664	output, err := executeCommand(c, "", "-i7", "")
665	if output != "" {
666		t.Errorf("Unexpected output: %v", output)
667	}
668	if err != nil {
669		t.Errorf("Unexpected error: %v", err)
670	}
671
672	if flagValue != 7 {
673		t.Errorf("flagValue expected: %v, got %v", 7, flagValue)
674	}
675}
676
677func TestOverwrittenFlag(t *testing.T) {
678	// TODO: This test fails, but should work.
679	t.Skip()
680
681	parent := &Command{Use: "parent", Run: emptyRun}
682	child := &Command{Use: "child", Run: emptyRun}
683
684	parent.PersistentFlags().Bool("boolf", false, "")
685	parent.PersistentFlags().Int("intf", -1, "")
686	child.Flags().String("strf", "", "")
687	child.Flags().Int("intf", -1, "")
688
689	parent.AddCommand(child)
690
691	childInherited := child.InheritedFlags()
692	childLocal := child.LocalFlags()
693
694	if childLocal.Lookup("strf") == nil {
695		t.Error(`LocalFlags expected to contain "strf", got "nil"`)
696	}
697	if childInherited.Lookup("boolf") == nil {
698		t.Error(`InheritedFlags expected to contain "boolf", got "nil"`)
699	}
700
701	if childInherited.Lookup("intf") != nil {
702		t.Errorf(`InheritedFlags should not contain overwritten flag "intf"`)
703	}
704	if childLocal.Lookup("intf") == nil {
705		t.Error(`LocalFlags expected to contain "intf", got "nil"`)
706	}
707}
708
709func TestPersistentFlagsOnChild(t *testing.T) {
710	var childCmdArgs []string
711	rootCmd := &Command{Use: "root", Run: emptyRun}
712	childCmd := &Command{
713		Use:  "child",
714		Args: ArbitraryArgs,
715		Run:  func(_ *Command, args []string) { childCmdArgs = args },
716	}
717	rootCmd.AddCommand(childCmd)
718
719	var parentFlagValue int
720	var childFlagValue int
721	rootCmd.PersistentFlags().IntVarP(&parentFlagValue, "parentf", "p", -1, "")
722	childCmd.Flags().IntVarP(&childFlagValue, "childf", "c", -1, "")
723
724	output, err := executeCommand(rootCmd, "child", "-c7", "-p8", "one", "two")
725	if output != "" {
726		t.Errorf("Unexpected output: %v", output)
727	}
728	if err != nil {
729		t.Errorf("Unexpected error: %v", err)
730	}
731
732	got := strings.Join(childCmdArgs, " ")
733	expected := "one two"
734	if got != expected {
735		t.Errorf("childCmdArgs expected: %q, got %q", expected, got)
736	}
737	if parentFlagValue != 8 {
738		t.Errorf("parentFlagValue expected: %v, got %v", 8, parentFlagValue)
739	}
740	if childFlagValue != 7 {
741		t.Errorf("childFlagValue expected: %v, got %v", 7, childFlagValue)
742	}
743}
744
745func TestRequiredFlags(t *testing.T) {
746	c := &Command{Use: "c", Run: emptyRun}
747	c.Flags().String("foo1", "", "")
748	c.MarkFlagRequired("foo1")
749	c.Flags().String("foo2", "", "")
750	c.MarkFlagRequired("foo2")
751	c.Flags().String("bar", "", "")
752
753	expected := fmt.Sprintf("required flag(s) %q, %q not set", "foo1", "foo2")
754
755	_, err := executeCommand(c)
756	got := err.Error()
757
758	if got != expected {
759		t.Errorf("Expected error: %q, got: %q", expected, got)
760	}
761}
762
763func TestPersistentRequiredFlags(t *testing.T) {
764	parent := &Command{Use: "parent", Run: emptyRun}
765	parent.PersistentFlags().String("foo1", "", "")
766	parent.MarkPersistentFlagRequired("foo1")
767	parent.PersistentFlags().String("foo2", "", "")
768	parent.MarkPersistentFlagRequired("foo2")
769	parent.Flags().String("foo3", "", "")
770
771	child := &Command{Use: "child", Run: emptyRun}
772	child.Flags().String("bar1", "", "")
773	child.MarkFlagRequired("bar1")
774	child.Flags().String("bar2", "", "")
775	child.MarkFlagRequired("bar2")
776	child.Flags().String("bar3", "", "")
777
778	parent.AddCommand(child)
779
780	expected := fmt.Sprintf("required flag(s) %q, %q, %q, %q not set", "bar1", "bar2", "foo1", "foo2")
781
782	_, err := executeCommand(parent, "child")
783	if err.Error() != expected {
784		t.Errorf("Expected %q, got %q", expected, err.Error())
785	}
786}
787
788func TestInitHelpFlagMergesFlags(t *testing.T) {
789	usage := "custom flag"
790	rootCmd := &Command{Use: "root"}
791	rootCmd.PersistentFlags().Bool("help", false, "custom flag")
792	childCmd := &Command{Use: "child"}
793	rootCmd.AddCommand(childCmd)
794
795	childCmd.InitDefaultHelpFlag()
796	got := childCmd.Flags().Lookup("help").Usage
797	if got != usage {
798		t.Errorf("Expected the help flag from the root command with usage: %v\nGot the default with usage: %v", usage, got)
799	}
800}
801
802func TestHelpCommandExecuted(t *testing.T) {
803	rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun}
804	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
805
806	output, err := executeCommand(rootCmd, "help")
807	if err != nil {
808		t.Errorf("Unexpected error: %v", err)
809	}
810
811	checkStringContains(t, output, rootCmd.Long)
812}
813
814func TestHelpCommandExecutedOnChild(t *testing.T) {
815	rootCmd := &Command{Use: "root", Run: emptyRun}
816	childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun}
817	rootCmd.AddCommand(childCmd)
818
819	output, err := executeCommand(rootCmd, "help", "child")
820	if err != nil {
821		t.Errorf("Unexpected error: %v", err)
822	}
823
824	checkStringContains(t, output, childCmd.Long)
825}
826
827func TestSetHelpCommand(t *testing.T) {
828	c := &Command{Use: "c", Run: emptyRun}
829	c.AddCommand(&Command{Use: "empty", Run: emptyRun})
830
831	expected := "WORKS"
832	c.SetHelpCommand(&Command{
833		Use:   "help [command]",
834		Short: "Help about any command",
835		Long: `Help provides help for any command in the application.
836	Simply type ` + c.Name() + ` help [path to command] for full details.`,
837		Run: func(c *Command, _ []string) { c.Print(expected) },
838	})
839
840	got, err := executeCommand(c, "help")
841	if err != nil {
842		t.Errorf("Unexpected error: %v", err)
843	}
844
845	if got != expected {
846		t.Errorf("Expected to contain %q, got %q", expected, got)
847	}
848}
849
850func TestHelpFlagExecuted(t *testing.T) {
851	rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun}
852
853	output, err := executeCommand(rootCmd, "--help")
854	if err != nil {
855		t.Errorf("Unexpected error: %v", err)
856	}
857
858	checkStringContains(t, output, rootCmd.Long)
859}
860
861func TestHelpFlagExecutedOnChild(t *testing.T) {
862	rootCmd := &Command{Use: "root", Run: emptyRun}
863	childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun}
864	rootCmd.AddCommand(childCmd)
865
866	output, err := executeCommand(rootCmd, "child", "--help")
867	if err != nil {
868		t.Errorf("Unexpected error: %v", err)
869	}
870
871	checkStringContains(t, output, childCmd.Long)
872}
873
874// TestHelpFlagInHelp checks,
875// if '--help' flag is shown in help for child (executing `parent help child`),
876// that has no other flags.
877// Related to https://github.com/spf13/cobra/issues/302.
878func TestHelpFlagInHelp(t *testing.T) {
879	parentCmd := &Command{Use: "parent", Run: func(*Command, []string) {}}
880
881	childCmd := &Command{Use: "child", Run: func(*Command, []string) {}}
882	parentCmd.AddCommand(childCmd)
883
884	output, err := executeCommand(parentCmd, "help", "child")
885	if err != nil {
886		t.Errorf("Unexpected error: %v", err)
887	}
888
889	checkStringContains(t, output, "[flags]")
890}
891
892func TestFlagsInUsage(t *testing.T) {
893	rootCmd := &Command{Use: "root", Args: NoArgs, Run: func(*Command, []string) {}}
894	output, err := executeCommand(rootCmd, "--help")
895	if err != nil {
896		t.Errorf("Unexpected error: %v", err)
897	}
898
899	checkStringContains(t, output, "[flags]")
900}
901
902func TestHelpExecutedOnNonRunnableChild(t *testing.T) {
903	rootCmd := &Command{Use: "root", Run: emptyRun}
904	childCmd := &Command{Use: "child", Long: "Long description"}
905	rootCmd.AddCommand(childCmd)
906
907	output, err := executeCommand(rootCmd, "child")
908	if err != nil {
909		t.Errorf("Unexpected error: %v", err)
910	}
911
912	checkStringContains(t, output, childCmd.Long)
913}
914
915func TestVersionFlagExecuted(t *testing.T) {
916	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
917
918	output, err := executeCommand(rootCmd, "--version", "arg1")
919	if err != nil {
920		t.Errorf("Unexpected error: %v", err)
921	}
922
923	checkStringContains(t, output, "root version 1.0.0")
924}
925
926func TestVersionFlagExecutedWithNoName(t *testing.T) {
927	rootCmd := &Command{Version: "1.0.0", Run: emptyRun}
928
929	output, err := executeCommand(rootCmd, "--version", "arg1")
930	if err != nil {
931		t.Errorf("Unexpected error: %v", err)
932	}
933
934	checkStringContains(t, output, "version 1.0.0")
935}
936
937func TestShortAndLongVersionFlagInHelp(t *testing.T) {
938	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
939
940	output, err := executeCommand(rootCmd, "--help")
941	if err != nil {
942		t.Errorf("Unexpected error: %v", err)
943	}
944
945	checkStringContains(t, output, "-v, --version")
946}
947
948func TestLongVersionFlagOnlyInHelpWhenShortPredefined(t *testing.T) {
949	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
950	rootCmd.Flags().StringP("foo", "v", "", "not a version flag")
951
952	output, err := executeCommand(rootCmd, "--help")
953	if err != nil {
954		t.Errorf("Unexpected error: %v", err)
955	}
956
957	checkStringOmits(t, output, "-v, --version")
958	checkStringContains(t, output, "--version")
959}
960
961func TestShorthandVersionFlagExecuted(t *testing.T) {
962	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
963
964	output, err := executeCommand(rootCmd, "-v", "arg1")
965	if err != nil {
966		t.Errorf("Unexpected error: %v", err)
967	}
968
969	checkStringContains(t, output, "root version 1.0.0")
970}
971
972func TestVersionTemplate(t *testing.T) {
973	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
974	rootCmd.SetVersionTemplate(`customized version: {{.Version}}`)
975
976	output, err := executeCommand(rootCmd, "--version", "arg1")
977	if err != nil {
978		t.Errorf("Unexpected error: %v", err)
979	}
980
981	checkStringContains(t, output, "customized version: 1.0.0")
982}
983
984func TestShorthandVersionTemplate(t *testing.T) {
985	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
986	rootCmd.SetVersionTemplate(`customized version: {{.Version}}`)
987
988	output, err := executeCommand(rootCmd, "-v", "arg1")
989	if err != nil {
990		t.Errorf("Unexpected error: %v", err)
991	}
992
993	checkStringContains(t, output, "customized version: 1.0.0")
994}
995
996func TestVersionFlagExecutedOnSubcommand(t *testing.T) {
997	rootCmd := &Command{Use: "root", Version: "1.0.0"}
998	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
999
1000	output, err := executeCommand(rootCmd, "--version", "sub")
1001	if err != nil {
1002		t.Errorf("Unexpected error: %v", err)
1003	}
1004
1005	checkStringContains(t, output, "root version 1.0.0")
1006}
1007
1008func TestShorthandVersionFlagExecutedOnSubcommand(t *testing.T) {
1009	rootCmd := &Command{Use: "root", Version: "1.0.0"}
1010	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
1011
1012	output, err := executeCommand(rootCmd, "-v", "sub")
1013	if err != nil {
1014		t.Errorf("Unexpected error: %v", err)
1015	}
1016
1017	checkStringContains(t, output, "root version 1.0.0")
1018}
1019
1020func TestVersionFlagOnlyAddedToRoot(t *testing.T) {
1021	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
1022	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
1023
1024	_, err := executeCommand(rootCmd, "sub", "--version")
1025	if err == nil {
1026		t.Errorf("Expected error")
1027	}
1028
1029	checkStringContains(t, err.Error(), "unknown flag: --version")
1030}
1031
1032func TestShortVersionFlagOnlyAddedToRoot(t *testing.T) {
1033	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
1034	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
1035
1036	_, err := executeCommand(rootCmd, "sub", "-v")
1037	if err == nil {
1038		t.Errorf("Expected error")
1039	}
1040
1041	checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v")
1042}
1043
1044func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) {
1045	rootCmd := &Command{Use: "root", Run: emptyRun}
1046
1047	_, err := executeCommand(rootCmd, "--version")
1048	if err == nil {
1049		t.Errorf("Expected error")
1050	}
1051	checkStringContains(t, err.Error(), "unknown flag: --version")
1052}
1053
1054func TestShorthandVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) {
1055	rootCmd := &Command{Use: "root", Run: emptyRun}
1056
1057	_, err := executeCommand(rootCmd, "-v")
1058	if err == nil {
1059		t.Errorf("Expected error")
1060	}
1061	checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v")
1062}
1063
1064func TestShorthandVersionFlagOnlyAddedIfShorthandNotDefined(t *testing.T) {
1065	rootCmd := &Command{Use: "root", Run: emptyRun, Version: "1.2.3"}
1066	rootCmd.Flags().StringP("notversion", "v", "", "not a version flag")
1067
1068	_, err := executeCommand(rootCmd, "-v")
1069	if err == nil {
1070		t.Errorf("Expected error")
1071	}
1072	check(t, rootCmd.Flags().ShorthandLookup("v").Name, "notversion")
1073	checkStringContains(t, err.Error(), "flag needs an argument: 'v' in -v")
1074}
1075
1076func TestShorthandVersionFlagOnlyAddedIfVersionNotDefined(t *testing.T) {
1077	rootCmd := &Command{Use: "root", Run: emptyRun, Version: "1.2.3"}
1078	rootCmd.Flags().Bool("version", false, "a different kind of version flag")
1079
1080	_, err := executeCommand(rootCmd, "-v")
1081	if err == nil {
1082		t.Errorf("Expected error")
1083	}
1084	checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v")
1085}
1086
1087func TestUsageIsNotPrintedTwice(t *testing.T) {
1088	var cmd = &Command{Use: "root"}
1089	var sub = &Command{Use: "sub"}
1090	cmd.AddCommand(sub)
1091
1092	output, _ := executeCommand(cmd, "")
1093	if strings.Count(output, "Usage:") != 1 {
1094		t.Error("Usage output is not printed exactly once")
1095	}
1096}
1097
1098func TestVisitParents(t *testing.T) {
1099	c := &Command{Use: "app"}
1100	sub := &Command{Use: "sub"}
1101	dsub := &Command{Use: "dsub"}
1102	sub.AddCommand(dsub)
1103	c.AddCommand(sub)
1104
1105	total := 0
1106	add := func(x *Command) {
1107		total++
1108	}
1109	sub.VisitParents(add)
1110	if total != 1 {
1111		t.Errorf("Should have visited 1 parent but visited %d", total)
1112	}
1113
1114	total = 0
1115	dsub.VisitParents(add)
1116	if total != 2 {
1117		t.Errorf("Should have visited 2 parents but visited %d", total)
1118	}
1119
1120	total = 0
1121	c.VisitParents(add)
1122	if total != 0 {
1123		t.Errorf("Should have visited no parents but visited %d", total)
1124	}
1125}
1126
1127func TestSuggestions(t *testing.T) {
1128	rootCmd := &Command{Use: "root", Run: emptyRun}
1129	timesCmd := &Command{
1130		Use:        "times",
1131		SuggestFor: []string{"counts"},
1132		Run:        emptyRun,
1133	}
1134	rootCmd.AddCommand(timesCmd)
1135
1136	templateWithSuggestions := "Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n"
1137	templateWithoutSuggestions := "Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n"
1138
1139	tests := map[string]string{
1140		"time":     "times",
1141		"tiems":    "times",
1142		"tims":     "times",
1143		"timeS":    "times",
1144		"rimes":    "times",
1145		"ti":       "times",
1146		"t":        "times",
1147		"timely":   "times",
1148		"ri":       "",
1149		"timezone": "",
1150		"foo":      "",
1151		"counts":   "times",
1152	}
1153
1154	for typo, suggestion := range tests {
1155		for _, suggestionsDisabled := range []bool{true, false} {
1156			rootCmd.DisableSuggestions = suggestionsDisabled
1157
1158			var expected string
1159			output, _ := executeCommand(rootCmd, typo)
1160
1161			if suggestion == "" || suggestionsDisabled {
1162				expected = fmt.Sprintf(templateWithoutSuggestions, typo)
1163			} else {
1164				expected = fmt.Sprintf(templateWithSuggestions, typo, suggestion)
1165			}
1166
1167			if output != expected {
1168				t.Errorf("Unexpected response.\nExpected:\n %q\nGot:\n %q\n", expected, output)
1169			}
1170		}
1171	}
1172}
1173
1174func TestRemoveCommand(t *testing.T) {
1175	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
1176	childCmd := &Command{Use: "child", Run: emptyRun}
1177	rootCmd.AddCommand(childCmd)
1178	rootCmd.RemoveCommand(childCmd)
1179
1180	_, err := executeCommand(rootCmd, "child")
1181	if err == nil {
1182		t.Error("Expected error on calling removed command. Got nil.")
1183	}
1184}
1185
1186func TestReplaceCommandWithRemove(t *testing.T) {
1187	childUsed := 0
1188	rootCmd := &Command{Use: "root", Run: emptyRun}
1189	child1Cmd := &Command{
1190		Use: "child",
1191		Run: func(*Command, []string) { childUsed = 1 },
1192	}
1193	child2Cmd := &Command{
1194		Use: "child",
1195		Run: func(*Command, []string) { childUsed = 2 },
1196	}
1197	rootCmd.AddCommand(child1Cmd)
1198	rootCmd.RemoveCommand(child1Cmd)
1199	rootCmd.AddCommand(child2Cmd)
1200
1201	output, err := executeCommand(rootCmd, "child")
1202	if output != "" {
1203		t.Errorf("Unexpected output: %v", output)
1204	}
1205	if err != nil {
1206		t.Errorf("Unexpected error: %v", err)
1207	}
1208
1209	if childUsed == 1 {
1210		t.Error("Removed command shouldn't be called")
1211	}
1212	if childUsed != 2 {
1213		t.Error("Replacing command should have been called but didn't")
1214	}
1215}
1216
1217func TestDeprecatedCommand(t *testing.T) {
1218	rootCmd := &Command{Use: "root", Run: emptyRun}
1219	deprecatedCmd := &Command{
1220		Use:        "deprecated",
1221		Deprecated: "This command is deprecated",
1222		Run:        emptyRun,
1223	}
1224	rootCmd.AddCommand(deprecatedCmd)
1225
1226	output, err := executeCommand(rootCmd, "deprecated")
1227	if err != nil {
1228		t.Errorf("Unexpected error: %v", err)
1229	}
1230
1231	checkStringContains(t, output, deprecatedCmd.Deprecated)
1232}
1233
1234func TestHooks(t *testing.T) {
1235	var (
1236		persPreArgs  string
1237		preArgs      string
1238		runArgs      string
1239		postArgs     string
1240		persPostArgs string
1241	)
1242
1243	c := &Command{
1244		Use: "c",
1245		PersistentPreRun: func(_ *Command, args []string) {
1246			persPreArgs = strings.Join(args, " ")
1247		},
1248		PreRun: func(_ *Command, args []string) {
1249			preArgs = strings.Join(args, " ")
1250		},
1251		Run: func(_ *Command, args []string) {
1252			runArgs = strings.Join(args, " ")
1253		},
1254		PostRun: func(_ *Command, args []string) {
1255			postArgs = strings.Join(args, " ")
1256		},
1257		PersistentPostRun: func(_ *Command, args []string) {
1258			persPostArgs = strings.Join(args, " ")
1259		},
1260	}
1261
1262	output, err := executeCommand(c, "one", "two")
1263	if output != "" {
1264		t.Errorf("Unexpected output: %v", output)
1265	}
1266	if err != nil {
1267		t.Errorf("Unexpected error: %v", err)
1268	}
1269
1270	if persPreArgs != "one two" {
1271		t.Errorf("Expected persPreArgs %q, got %q", "one two", persPreArgs)
1272	}
1273	if preArgs != "one two" {
1274		t.Errorf("Expected preArgs %q, got %q", "one two", preArgs)
1275	}
1276	if runArgs != "one two" {
1277		t.Errorf("Expected runArgs %q, got %q", "one two", runArgs)
1278	}
1279	if postArgs != "one two" {
1280		t.Errorf("Expected postArgs %q, got %q", "one two", postArgs)
1281	}
1282	if persPostArgs != "one two" {
1283		t.Errorf("Expected persPostArgs %q, got %q", "one two", persPostArgs)
1284	}
1285}
1286
1287func TestPersistentHooks(t *testing.T) {
1288	var (
1289		parentPersPreArgs  string
1290		parentPreArgs      string
1291		parentRunArgs      string
1292		parentPostArgs     string
1293		parentPersPostArgs string
1294	)
1295
1296	var (
1297		childPersPreArgs  string
1298		childPreArgs      string
1299		childRunArgs      string
1300		childPostArgs     string
1301		childPersPostArgs string
1302	)
1303
1304	parentCmd := &Command{
1305		Use: "parent",
1306		PersistentPreRun: func(_ *Command, args []string) {
1307			parentPersPreArgs = strings.Join(args, " ")
1308		},
1309		PreRun: func(_ *Command, args []string) {
1310			parentPreArgs = strings.Join(args, " ")
1311		},
1312		Run: func(_ *Command, args []string) {
1313			parentRunArgs = strings.Join(args, " ")
1314		},
1315		PostRun: func(_ *Command, args []string) {
1316			parentPostArgs = strings.Join(args, " ")
1317		},
1318		PersistentPostRun: func(_ *Command, args []string) {
1319			parentPersPostArgs = strings.Join(args, " ")
1320		},
1321	}
1322
1323	childCmd := &Command{
1324		Use: "child",
1325		PersistentPreRun: func(_ *Command, args []string) {
1326			childPersPreArgs = strings.Join(args, " ")
1327		},
1328		PreRun: func(_ *Command, args []string) {
1329			childPreArgs = strings.Join(args, " ")
1330		},
1331		Run: func(_ *Command, args []string) {
1332			childRunArgs = strings.Join(args, " ")
1333		},
1334		PostRun: func(_ *Command, args []string) {
1335			childPostArgs = strings.Join(args, " ")
1336		},
1337		PersistentPostRun: func(_ *Command, args []string) {
1338			childPersPostArgs = strings.Join(args, " ")
1339		},
1340	}
1341	parentCmd.AddCommand(childCmd)
1342
1343	output, err := executeCommand(parentCmd, "child", "one", "two")
1344	if output != "" {
1345		t.Errorf("Unexpected output: %v", output)
1346	}
1347	if err != nil {
1348		t.Errorf("Unexpected error: %v", err)
1349	}
1350
1351	// TODO: currently PersistenPreRun* defined in parent does not
1352	// run if the matchin child subcommand has PersistenPreRun.
1353	// If the behavior changes (https://github.com/spf13/cobra/issues/252)
1354	// this test must be fixed.
1355	if parentPersPreArgs != "" {
1356		t.Errorf("Expected blank parentPersPreArgs, got %q", parentPersPreArgs)
1357	}
1358	if parentPreArgs != "" {
1359		t.Errorf("Expected blank parentPreArgs, got %q", parentPreArgs)
1360	}
1361	if parentRunArgs != "" {
1362		t.Errorf("Expected blank parentRunArgs, got %q", parentRunArgs)
1363	}
1364	if parentPostArgs != "" {
1365		t.Errorf("Expected blank parentPostArgs, got %q", parentPostArgs)
1366	}
1367	// TODO: currently PersistenPostRun* defined in parent does not
1368	// run if the matchin child subcommand has PersistenPostRun.
1369	// If the behavior changes (https://github.com/spf13/cobra/issues/252)
1370	// this test must be fixed.
1371	if parentPersPostArgs != "" {
1372		t.Errorf("Expected blank parentPersPostArgs, got %q", parentPersPostArgs)
1373	}
1374
1375	if childPersPreArgs != "one two" {
1376		t.Errorf("Expected childPersPreArgs %q, got %q", "one two", childPersPreArgs)
1377	}
1378	if childPreArgs != "one two" {
1379		t.Errorf("Expected childPreArgs %q, got %q", "one two", childPreArgs)
1380	}
1381	if childRunArgs != "one two" {
1382		t.Errorf("Expected childRunArgs %q, got %q", "one two", childRunArgs)
1383	}
1384	if childPostArgs != "one two" {
1385		t.Errorf("Expected childPostArgs %q, got %q", "one two", childPostArgs)
1386	}
1387	if childPersPostArgs != "one two" {
1388		t.Errorf("Expected childPersPostArgs %q, got %q", "one two", childPersPostArgs)
1389	}
1390}
1391
1392// Related to https://github.com/spf13/cobra/issues/521.
1393func TestGlobalNormFuncPropagation(t *testing.T) {
1394	normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
1395		return pflag.NormalizedName(name)
1396	}
1397
1398	rootCmd := &Command{Use: "root", Run: emptyRun}
1399	childCmd := &Command{Use: "child", Run: emptyRun}
1400	rootCmd.AddCommand(childCmd)
1401
1402	rootCmd.SetGlobalNormalizationFunc(normFunc)
1403	if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() {
1404		t.Error("rootCmd seems to have a wrong normalization function")
1405	}
1406
1407	if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(childCmd.GlobalNormalizationFunc()).Pointer() {
1408		t.Error("childCmd should have had the normalization function of rootCmd")
1409	}
1410}
1411
1412// Related to https://github.com/spf13/cobra/issues/521.
1413func TestNormPassedOnLocal(t *testing.T) {
1414	toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
1415		return pflag.NormalizedName(strings.ToUpper(name))
1416	}
1417
1418	c := &Command{}
1419	c.Flags().Bool("flagname", true, "this is a dummy flag")
1420	c.SetGlobalNormalizationFunc(toUpper)
1421	if c.LocalFlags().Lookup("flagname") != c.LocalFlags().Lookup("FLAGNAME") {
1422		t.Error("Normalization function should be passed on to Local flag set")
1423	}
1424}
1425
1426// Related to https://github.com/spf13/cobra/issues/521.
1427func TestNormPassedOnInherited(t *testing.T) {
1428	toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
1429		return pflag.NormalizedName(strings.ToUpper(name))
1430	}
1431
1432	c := &Command{}
1433	c.SetGlobalNormalizationFunc(toUpper)
1434
1435	child1 := &Command{}
1436	c.AddCommand(child1)
1437
1438	c.PersistentFlags().Bool("flagname", true, "")
1439
1440	child2 := &Command{}
1441	c.AddCommand(child2)
1442
1443	inherited := child1.InheritedFlags()
1444	if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") {
1445		t.Error("Normalization function should be passed on to inherited flag set in command added before flag")
1446	}
1447
1448	inherited = child2.InheritedFlags()
1449	if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") {
1450		t.Error("Normalization function should be passed on to inherited flag set in command added after flag")
1451	}
1452}
1453
1454// Related to https://github.com/spf13/cobra/issues/521.
1455func TestConsistentNormalizedName(t *testing.T) {
1456	toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
1457		return pflag.NormalizedName(strings.ToUpper(name))
1458	}
1459	n := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
1460		return pflag.NormalizedName(name)
1461	}
1462
1463	c := &Command{}
1464	c.Flags().Bool("flagname", true, "")
1465	c.SetGlobalNormalizationFunc(toUpper)
1466	c.SetGlobalNormalizationFunc(n)
1467
1468	if c.LocalFlags().Lookup("flagname") == c.LocalFlags().Lookup("FLAGNAME") {
1469		t.Error("Normalizing flag names should not result in duplicate flags")
1470	}
1471}
1472
1473func TestFlagOnPflagCommandLine(t *testing.T) {
1474	flagName := "flagOnCommandLine"
1475	pflag.String(flagName, "", "about my flag")
1476
1477	c := &Command{Use: "c", Run: emptyRun}
1478	c.AddCommand(&Command{Use: "child", Run: emptyRun})
1479
1480	output, _ := executeCommand(c, "--help")
1481	checkStringContains(t, output, flagName)
1482
1483	resetCommandLineFlagSet()
1484}
1485
1486// TestHiddenCommandExecutes checks,
1487// if hidden commands run as intended.
1488func TestHiddenCommandExecutes(t *testing.T) {
1489	executed := false
1490	c := &Command{
1491		Use:    "c",
1492		Hidden: true,
1493		Run:    func(*Command, []string) { executed = true },
1494	}
1495
1496	output, err := executeCommand(c)
1497	if output != "" {
1498		t.Errorf("Unexpected output: %v", output)
1499	}
1500	if err != nil {
1501		t.Errorf("Unexpected error: %v", err)
1502	}
1503
1504	if !executed {
1505		t.Error("Hidden command should have been executed")
1506	}
1507}
1508
1509// test to ensure hidden commands do not show up in usage/help text
1510func TestHiddenCommandIsHidden(t *testing.T) {
1511	c := &Command{Use: "c", Hidden: true, Run: emptyRun}
1512	if c.IsAvailableCommand() {
1513		t.Errorf("Hidden command should be unavailable")
1514	}
1515}
1516
1517func TestCommandsAreSorted(t *testing.T) {
1518	EnableCommandSorting = true
1519
1520	originalNames := []string{"middle", "zlast", "afirst"}
1521	expectedNames := []string{"afirst", "middle", "zlast"}
1522
1523	var rootCmd = &Command{Use: "root"}
1524
1525	for _, name := range originalNames {
1526		rootCmd.AddCommand(&Command{Use: name})
1527	}
1528
1529	for i, c := range rootCmd.Commands() {
1530		got := c.Name()
1531		if expectedNames[i] != got {
1532			t.Errorf("Expected: %s, got: %s", expectedNames[i], got)
1533		}
1534	}
1535
1536	EnableCommandSorting = true
1537}
1538
1539func TestEnableCommandSortingIsDisabled(t *testing.T) {
1540	EnableCommandSorting = false
1541
1542	originalNames := []string{"middle", "zlast", "afirst"}
1543
1544	var rootCmd = &Command{Use: "root"}
1545
1546	for _, name := range originalNames {
1547		rootCmd.AddCommand(&Command{Use: name})
1548	}
1549
1550	for i, c := range rootCmd.Commands() {
1551		got := c.Name()
1552		if originalNames[i] != got {
1553			t.Errorf("expected: %s, got: %s", originalNames[i], got)
1554		}
1555	}
1556
1557	EnableCommandSorting = true
1558}
1559
1560func TestSetOutput(t *testing.T) {
1561	c := &Command{}
1562	c.SetOutput(nil)
1563	if out := c.OutOrStdout(); out != os.Stdout {
1564		t.Errorf("Expected setting output to nil to revert back to stdout")
1565	}
1566}
1567
1568func TestSetOut(t *testing.T) {
1569	c := &Command{}
1570	c.SetOut(nil)
1571	if out := c.OutOrStdout(); out != os.Stdout {
1572		t.Errorf("Expected setting output to nil to revert back to stdout")
1573	}
1574}
1575
1576func TestSetErr(t *testing.T) {
1577	c := &Command{}
1578	c.SetErr(nil)
1579	if out := c.ErrOrStderr(); out != os.Stderr {
1580		t.Errorf("Expected setting error to nil to revert back to stderr")
1581	}
1582}
1583
1584func TestSetIn(t *testing.T) {
1585	c := &Command{}
1586	c.SetIn(nil)
1587	if out := c.InOrStdin(); out != os.Stdin {
1588		t.Errorf("Expected setting input to nil to revert back to stdin")
1589	}
1590}
1591
1592func TestUsageStringRedirected(t *testing.T) {
1593	c := &Command{}
1594
1595	c.usageFunc = func(cmd *Command) error {
1596		cmd.Print("[stdout1]")
1597		cmd.PrintErr("[stderr2]")
1598		cmd.Print("[stdout3]")
1599		return nil
1600	}
1601
1602	expected := "[stdout1][stderr2][stdout3]"
1603	if got := c.UsageString(); got != expected {
1604		t.Errorf("Expected usage string to consider both stdout and stderr")
1605	}
1606}
1607
1608func TestFlagErrorFunc(t *testing.T) {
1609	c := &Command{Use: "c", Run: emptyRun}
1610
1611	expectedFmt := "This is expected: %v"
1612	c.SetFlagErrorFunc(func(_ *Command, err error) error {
1613		return fmt.Errorf(expectedFmt, err)
1614	})
1615
1616	_, err := executeCommand(c, "--unknown-flag")
1617
1618	got := err.Error()
1619	expected := fmt.Sprintf(expectedFmt, "unknown flag: --unknown-flag")
1620	if got != expected {
1621		t.Errorf("Expected %v, got %v", expected, got)
1622	}
1623}
1624
1625// TestSortedFlags checks,
1626// if cmd.LocalFlags() is unsorted when cmd.Flags().SortFlags set to false.
1627// Related to https://github.com/spf13/cobra/issues/404.
1628func TestSortedFlags(t *testing.T) {
1629	c := &Command{}
1630	c.Flags().SortFlags = false
1631	names := []string{"C", "B", "A", "D"}
1632	for _, name := range names {
1633		c.Flags().Bool(name, false, "")
1634	}
1635
1636	i := 0
1637	c.LocalFlags().VisitAll(func(f *pflag.Flag) {
1638		if i == len(names) {
1639			return
1640		}
1641		if stringInSlice(f.Name, names) {
1642			if names[i] != f.Name {
1643				t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
1644			}
1645			i++
1646		}
1647	})
1648}
1649
1650// TestMergeCommandLineToFlags checks,
1651// if pflag.CommandLine is correctly merged to c.Flags() after first call
1652// of c.mergePersistentFlags.
1653// Related to https://github.com/spf13/cobra/issues/443.
1654func TestMergeCommandLineToFlags(t *testing.T) {
1655	pflag.Bool("boolflag", false, "")
1656	c := &Command{Use: "c", Run: emptyRun}
1657	c.mergePersistentFlags()
1658	if c.Flags().Lookup("boolflag") == nil {
1659		t.Fatal("Expecting to have flag from CommandLine in c.Flags()")
1660	}
1661
1662	resetCommandLineFlagSet()
1663}
1664
1665// TestUseDeprecatedFlags checks,
1666// if cobra.Execute() prints a message, if a deprecated flag is used.
1667// Related to https://github.com/spf13/cobra/issues/463.
1668func TestUseDeprecatedFlags(t *testing.T) {
1669	c := &Command{Use: "c", Run: emptyRun}
1670	c.Flags().BoolP("deprecated", "d", false, "deprecated flag")
1671	c.Flags().MarkDeprecated("deprecated", "This flag is deprecated")
1672
1673	output, err := executeCommand(c, "c", "-d")
1674	if err != nil {
1675		t.Error("Unexpected error:", err)
1676	}
1677	checkStringContains(t, output, "This flag is deprecated")
1678}
1679
1680func TestTraverseWithParentFlags(t *testing.T) {
1681	rootCmd := &Command{Use: "root", TraverseChildren: true}
1682	rootCmd.Flags().String("str", "", "")
1683	rootCmd.Flags().BoolP("bool", "b", false, "")
1684
1685	childCmd := &Command{Use: "child"}
1686	childCmd.Flags().Int("int", -1, "")
1687
1688	rootCmd.AddCommand(childCmd)
1689
1690	c, args, err := rootCmd.Traverse([]string{"-b", "--str", "ok", "child", "--int"})
1691	if err != nil {
1692		t.Errorf("Unexpected error: %v", err)
1693	}
1694	if len(args) != 1 && args[0] != "--add" {
1695		t.Errorf("Wrong args: %v", args)
1696	}
1697	if c.Name() != childCmd.Name() {
1698		t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name())
1699	}
1700}
1701
1702func TestTraverseNoParentFlags(t *testing.T) {
1703	rootCmd := &Command{Use: "root", TraverseChildren: true}
1704	rootCmd.Flags().String("foo", "", "foo things")
1705
1706	childCmd := &Command{Use: "child"}
1707	childCmd.Flags().String("str", "", "")
1708	rootCmd.AddCommand(childCmd)
1709
1710	c, args, err := rootCmd.Traverse([]string{"child"})
1711	if err != nil {
1712		t.Errorf("Unexpected error: %v", err)
1713	}
1714	if len(args) != 0 {
1715		t.Errorf("Wrong args %v", args)
1716	}
1717	if c.Name() != childCmd.Name() {
1718		t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name())
1719	}
1720}
1721
1722func TestTraverseWithBadParentFlags(t *testing.T) {
1723	rootCmd := &Command{Use: "root", TraverseChildren: true}
1724
1725	childCmd := &Command{Use: "child"}
1726	childCmd.Flags().String("str", "", "")
1727	rootCmd.AddCommand(childCmd)
1728
1729	expected := "unknown flag: --str"
1730
1731	c, _, err := rootCmd.Traverse([]string{"--str", "ok", "child"})
1732	if err == nil || !strings.Contains(err.Error(), expected) {
1733		t.Errorf("Expected error, %q, got %q", expected, err)
1734	}
1735	if c != nil {
1736		t.Errorf("Expected nil command")
1737	}
1738}
1739
1740func TestTraverseWithBadChildFlag(t *testing.T) {
1741	rootCmd := &Command{Use: "root", TraverseChildren: true}
1742	rootCmd.Flags().String("str", "", "")
1743
1744	childCmd := &Command{Use: "child"}
1745	rootCmd.AddCommand(childCmd)
1746
1747	// Expect no error because the last commands args shouldn't be parsed in
1748	// Traverse.
1749	c, args, err := rootCmd.Traverse([]string{"child", "--str"})
1750	if err != nil {
1751		t.Errorf("Unexpected error: %v", err)
1752	}
1753	if len(args) != 1 && args[0] != "--str" {
1754		t.Errorf("Wrong args: %v", args)
1755	}
1756	if c.Name() != childCmd.Name() {
1757		t.Errorf("Expected command %q, got: %q", childCmd.Name(), c.Name())
1758	}
1759}
1760
1761func TestTraverseWithTwoSubcommands(t *testing.T) {
1762	rootCmd := &Command{Use: "root", TraverseChildren: true}
1763
1764	subCmd := &Command{Use: "sub", TraverseChildren: true}
1765	rootCmd.AddCommand(subCmd)
1766
1767	subsubCmd := &Command{
1768		Use: "subsub",
1769	}
1770	subCmd.AddCommand(subsubCmd)
1771
1772	c, _, err := rootCmd.Traverse([]string{"sub", "subsub"})
1773	if err != nil {
1774		t.Fatalf("Unexpected error: %v", err)
1775	}
1776	if c.Name() != subsubCmd.Name() {
1777		t.Fatalf("Expected command: %q, got %q", subsubCmd.Name(), c.Name())
1778	}
1779}
1780
1781// TestUpdateName checks if c.Name() updates on changed c.Use.
1782// Related to https://github.com/spf13/cobra/pull/422#discussion_r143918343.
1783func TestUpdateName(t *testing.T) {
1784	c := &Command{Use: "name xyz"}
1785	originalName := c.Name()
1786
1787	c.Use = "changedName abc"
1788	if originalName == c.Name() || c.Name() != "changedName" {
1789		t.Error("c.Name() should be updated on changed c.Use")
1790	}
1791}
1792
1793type calledAsTestcase struct {
1794	args []string
1795	call string
1796	want string
1797	epm  bool
1798	tc   bool
1799}
1800
1801func (tc *calledAsTestcase) test(t *testing.T) {
1802	defer func(ov bool) { EnablePrefixMatching = ov }(EnablePrefixMatching)
1803	EnablePrefixMatching = tc.epm
1804
1805	var called *Command
1806	run := func(c *Command, _ []string) { t.Logf("called: %q", c.Name()); called = c }
1807
1808	parent := &Command{Use: "parent", Run: run}
1809	child1 := &Command{Use: "child1", Run: run, Aliases: []string{"this"}}
1810	child2 := &Command{Use: "child2", Run: run, Aliases: []string{"that"}}
1811
1812	parent.AddCommand(child1)
1813	parent.AddCommand(child2)
1814	parent.SetArgs(tc.args)
1815
1816	output := new(bytes.Buffer)
1817	parent.SetOut(output)
1818	parent.SetErr(output)
1819
1820	parent.Execute()
1821
1822	if called == nil {
1823		if tc.call != "" {
1824			t.Errorf("missing expected call to command: %s", tc.call)
1825		}
1826		return
1827	}
1828
1829	if called.Name() != tc.call {
1830		t.Errorf("called command == %q; Wanted %q", called.Name(), tc.call)
1831	} else if got := called.CalledAs(); got != tc.want {
1832		t.Errorf("%s.CalledAs() == %q; Wanted: %q", tc.call, got, tc.want)
1833	}
1834}
1835
1836func TestCalledAs(t *testing.T) {
1837	tests := map[string]calledAsTestcase{
1838		"find/no-args":            {nil, "parent", "parent", false, false},
1839		"find/real-name":          {[]string{"child1"}, "child1", "child1", false, false},
1840		"find/full-alias":         {[]string{"that"}, "child2", "that", false, false},
1841		"find/part-no-prefix":     {[]string{"thi"}, "", "", false, false},
1842		"find/part-alias":         {[]string{"thi"}, "child1", "this", true, false},
1843		"find/conflict":           {[]string{"th"}, "", "", true, false},
1844		"traverse/no-args":        {nil, "parent", "parent", false, true},
1845		"traverse/real-name":      {[]string{"child1"}, "child1", "child1", false, true},
1846		"traverse/full-alias":     {[]string{"that"}, "child2", "that", false, true},
1847		"traverse/part-no-prefix": {[]string{"thi"}, "", "", false, true},
1848		"traverse/part-alias":     {[]string{"thi"}, "child1", "this", true, true},
1849		"traverse/conflict":       {[]string{"th"}, "", "", true, true},
1850	}
1851
1852	for name, tc := range tests {
1853		t.Run(name, tc.test)
1854	}
1855}
1856
1857func TestFParseErrWhitelistBackwardCompatibility(t *testing.T) {
1858	c := &Command{Use: "c", Run: emptyRun}
1859	c.Flags().BoolP("boola", "a", false, "a boolean flag")
1860
1861	output, err := executeCommand(c, "c", "-a", "--unknown", "flag")
1862	if err == nil {
1863		t.Error("expected unknown flag error")
1864	}
1865	checkStringContains(t, output, "unknown flag: --unknown")
1866}
1867
1868func TestFParseErrWhitelistSameCommand(t *testing.T) {
1869	c := &Command{
1870		Use: "c",
1871		Run: emptyRun,
1872		FParseErrWhitelist: FParseErrWhitelist{
1873			UnknownFlags: true,
1874		},
1875	}
1876	c.Flags().BoolP("boola", "a", false, "a boolean flag")
1877
1878	_, err := executeCommand(c, "c", "-a", "--unknown", "flag")
1879	if err != nil {
1880		t.Error("unexpected error: ", err)
1881	}
1882}
1883
1884func TestFParseErrWhitelistParentCommand(t *testing.T) {
1885	root := &Command{
1886		Use: "root",
1887		Run: emptyRun,
1888		FParseErrWhitelist: FParseErrWhitelist{
1889			UnknownFlags: true,
1890		},
1891	}
1892
1893	c := &Command{
1894		Use: "child",
1895		Run: emptyRun,
1896	}
1897	c.Flags().BoolP("boola", "a", false, "a boolean flag")
1898
1899	root.AddCommand(c)
1900
1901	output, err := executeCommand(root, "child", "-a", "--unknown", "flag")
1902	if err == nil {
1903		t.Error("expected unknown flag error")
1904	}
1905	checkStringContains(t, output, "unknown flag: --unknown")
1906}
1907
1908func TestFParseErrWhitelistChildCommand(t *testing.T) {
1909	root := &Command{
1910		Use: "root",
1911		Run: emptyRun,
1912	}
1913
1914	c := &Command{
1915		Use: "child",
1916		Run: emptyRun,
1917		FParseErrWhitelist: FParseErrWhitelist{
1918			UnknownFlags: true,
1919		},
1920	}
1921	c.Flags().BoolP("boola", "a", false, "a boolean flag")
1922
1923	root.AddCommand(c)
1924
1925	_, err := executeCommand(root, "child", "-a", "--unknown", "flag")
1926	if err != nil {
1927		t.Error("unexpected error: ", err.Error())
1928	}
1929}
1930
1931func TestFParseErrWhitelistSiblingCommand(t *testing.T) {
1932	root := &Command{
1933		Use: "root",
1934		Run: emptyRun,
1935	}
1936
1937	c := &Command{
1938		Use: "child",
1939		Run: emptyRun,
1940		FParseErrWhitelist: FParseErrWhitelist{
1941			UnknownFlags: true,
1942		},
1943	}
1944	c.Flags().BoolP("boola", "a", false, "a boolean flag")
1945
1946	s := &Command{
1947		Use: "sibling",
1948		Run: emptyRun,
1949	}
1950	s.Flags().BoolP("boolb", "b", false, "a boolean flag")
1951
1952	root.AddCommand(c)
1953	root.AddCommand(s)
1954
1955	output, err := executeCommand(root, "sibling", "-b", "--unknown", "flag")
1956	if err == nil {
1957		t.Error("expected unknown flag error")
1958	}
1959	checkStringContains(t, output, "unknown flag: --unknown")
1960}
1961