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