1package cobra
2
3import (
4	"bytes"
5	"fmt"
6	"os"
7	"reflect"
8	"runtime"
9	"strings"
10	"testing"
11	"text/template"
12
13	"github.com/spf13/pflag"
14)
15
16var tp, te, tt, t1, tr []string
17var rootPersPre, echoPre, echoPersPre, timesPersPre []string
18var flagb1, flagb2, flagb3, flagbr, flagbp bool
19var flags1, flags2a, flags2b, flags3, outs string
20var flagi1, flagi2, flagi3, flagi4, flagir int
21var globalFlag1 bool
22var flagEcho, rootcalled bool
23var versionUsed int
24
25const strtwoParentHelp = "help message for parent flag strtwo"
26const strtwoChildHelp = "help message for child flag strtwo"
27
28var cmdHidden = &Command{
29	Use:   "hide [secret string to print]",
30	Short: "Print anything to screen (if command is known)",
31	Long:  `an absolutely utterly useless command for testing.`,
32	Run: func(cmd *Command, args []string) {
33		outs = "hidden"
34	},
35	Hidden: true,
36}
37
38var cmdPrint = &Command{
39	Use:   "print [string to print]",
40	Short: "Print anything to the screen",
41	Long:  `an absolutely utterly useless command for testing.`,
42	Run: func(cmd *Command, args []string) {
43		tp = args
44	},
45}
46
47var cmdEcho = &Command{
48	Use:     "echo [string to echo]",
49	Aliases: []string{"say"},
50	Short:   "Echo anything to the screen",
51	Long:    `an utterly useless command for testing.`,
52	Example: "Just run cobra-test echo",
53	PersistentPreRun: func(cmd *Command, args []string) {
54		echoPersPre = args
55	},
56	PreRun: func(cmd *Command, args []string) {
57		echoPre = args
58	},
59	Run: func(cmd *Command, args []string) {
60		te = args
61	},
62}
63
64var cmdEchoSub = &Command{
65	Use:   "echosub [string to print]",
66	Short: "second sub command for echo",
67	Long:  `an absolutely utterly useless command for testing gendocs!.`,
68	Run: func(cmd *Command, args []string) {
69	},
70}
71
72var cmdDeprecated = &Command{
73	Use:        "deprecated [can't do anything here]",
74	Short:      "A command which is deprecated",
75	Long:       `an absolutely utterly useless command for testing deprecation!.`,
76	Deprecated: "Please use echo instead",
77	Run: func(cmd *Command, args []string) {
78	},
79}
80
81var cmdTimes = &Command{
82	Use:        "times [# times] [string to echo]",
83	SuggestFor: []string{"counts"},
84	Short:      "Echo anything to the screen more times",
85	Long:       `a slightly useless command for testing.`,
86	PersistentPreRun: func(cmd *Command, args []string) {
87		timesPersPre = args
88	},
89	Run: func(cmd *Command, args []string) {
90		tt = args
91	},
92}
93
94var cmdRootNoRun = &Command{
95	Use:   "cobra-test",
96	Short: "The root can run its own function",
97	Long:  "The root description for help",
98	PersistentPreRun: func(cmd *Command, args []string) {
99		rootPersPre = args
100	},
101}
102
103var cmdRootSameName = &Command{
104	Use:   "print",
105	Short: "Root with the same name as a subcommand",
106	Long:  "The root description for help",
107}
108
109var cmdRootWithRun = &Command{
110	Use:   "cobra-test",
111	Short: "The root can run its own function",
112	Long:  "The root description for help",
113	Run: func(cmd *Command, args []string) {
114		tr = args
115		rootcalled = true
116	},
117}
118
119var cmdSubNoRun = &Command{
120	Use:   "subnorun",
121	Short: "A subcommand without a Run function",
122	Long:  "A long output about a subcommand without a Run function",
123}
124
125var cmdCustomFlags = &Command{
126	Use:   "customflags [flags] -- REMOTE_COMMAND",
127	Short: "A command that expects flags in a custom location",
128	Long:  "A long output about a command that expects flags in a custom location",
129	Run: func(cmd *Command, args []string) {
130	},
131}
132
133var cmdVersion1 = &Command{
134	Use:   "version",
135	Short: "Print the version number",
136	Long:  `First version of the version command`,
137	Run: func(cmd *Command, args []string) {
138		versionUsed = 1
139	},
140}
141
142var cmdVersion2 = &Command{
143	Use:   "version",
144	Short: "Print the version number",
145	Long:  `Second version of the version command`,
146	Run: func(cmd *Command, args []string) {
147		versionUsed = 2
148	},
149}
150
151var cmdColon = &Command{
152	Use: "cmd:colon",
153	Run: func(cmd *Command, args []string) {
154	},
155}
156
157func flagInit() {
158	cmdEcho.ResetFlags()
159	cmdPrint.ResetFlags()
160	cmdTimes.ResetFlags()
161	cmdRootNoRun.ResetFlags()
162	cmdRootSameName.ResetFlags()
163	cmdRootWithRun.ResetFlags()
164	cmdSubNoRun.ResetFlags()
165	cmdCustomFlags.ResetFlags()
166	cmdVersion1.ResetFlags()
167	cmdVersion2.ResetFlags()
168
169	cmdRootNoRun.PersistentFlags().StringVarP(&flags2a, "strtwo", "t", "two", strtwoParentHelp)
170	cmdCustomFlags.Flags().IntVar(&flagi4, "intfour", 456, "help message for flag intfour")
171	cmdEcho.Flags().BoolVarP(&flagb1, "boolone", "b", true, "help message for flag boolone")
172	cmdEcho.Flags().IntVarP(&flagi1, "intone", "i", 123, "help message for flag intone")
173	cmdEcho.PersistentFlags().BoolVarP(&flagbp, "persistentbool", "p", false, "help message for flag persistentbool")
174	cmdEcho.PersistentFlags().StringVarP(&flags1, "strone", "s", "one", "help message for flag strone")
175	cmdPrint.Flags().IntVarP(&flagi3, "intthree", "i", 345, "help message for flag intthree")
176	cmdTimes.Flags().BoolVarP(&flagb2, "booltwo", "c", false, "help message for flag booltwo")
177	cmdTimes.Flags().IntVarP(&flagi2, "inttwo", "j", 234, "help message for flag inttwo")
178	cmdTimes.Flags().StringVarP(&flags2b, "strtwo", "t", "2", strtwoChildHelp)
179	cmdTimes.PersistentFlags().StringVarP(&flags2b, "strtwo", "t", "2", strtwoChildHelp)
180	cmdPrint.Flags().BoolVarP(&flagb3, "boolthree", "b", true, "help message for flag boolthree")
181	cmdPrint.PersistentFlags().StringVarP(&flags3, "strthree", "s", "three", "help message for flag strthree")
182}
183
184func commandInit() {
185	cmdEcho.ResetCommands()
186	cmdPrint.ResetCommands()
187	cmdTimes.ResetCommands()
188	cmdRootNoRun.ResetCommands()
189	cmdRootSameName.ResetCommands()
190	cmdRootWithRun.ResetCommands()
191	cmdSubNoRun.ResetCommands()
192	cmdCustomFlags.ResetCommands()
193}
194
195func initialize() *Command {
196	tt, tp, te = nil, nil, nil
197	rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil
198
199	var c = cmdRootNoRun
200	flagInit()
201	commandInit()
202	return c
203}
204
205func initializeWithSameName() *Command {
206	tt, tp, te = nil, nil, nil
207	rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil
208	var c = cmdRootSameName
209	flagInit()
210	commandInit()
211	return c
212}
213
214func initializeWithRootCmd() *Command {
215	cmdRootWithRun.ResetCommands()
216	tt, tp, te, tr, rootcalled = nil, nil, nil, nil, false
217	flagInit()
218	cmdRootWithRun.Flags().BoolVarP(&flagbr, "boolroot", "b", false, "help message for flag boolroot")
219	cmdRootWithRun.Flags().IntVarP(&flagir, "introot", "i", 321, "help message for flag introot")
220	commandInit()
221	return cmdRootWithRun
222}
223
224type resulter struct {
225	Error   error
226	Output  string
227	Command *Command
228}
229
230func fullSetupTest(input string) resulter {
231	c := initializeWithRootCmd()
232
233	return fullTester(c, input)
234}
235
236func noRRSetupTestSilenced(input string) resulter {
237	c := initialize()
238	c.SilenceErrors = true
239	c.SilenceUsage = true
240	return fullTester(c, input)
241}
242
243func noRRSetupTest(input string) resulter {
244	c := initialize()
245
246	return fullTester(c, input)
247}
248
249func rootOnlySetupTest(input string) resulter {
250	c := initializeWithRootCmd()
251
252	return simpleTester(c, input)
253}
254
255func simpleTester(c *Command, input string) resulter {
256	buf := new(bytes.Buffer)
257	// Testing flag with invalid input
258	c.SetOutput(buf)
259	c.SetArgs(strings.Split(input, " "))
260
261	err := c.Execute()
262	output := buf.String()
263
264	return resulter{err, output, c}
265}
266
267func simpleTesterC(c *Command, input string) resulter {
268	buf := new(bytes.Buffer)
269	// Testing flag with invalid input
270	c.SetOutput(buf)
271	c.SetArgs(strings.Split(input, " "))
272
273	cmd, err := c.ExecuteC()
274	output := buf.String()
275
276	return resulter{err, output, cmd}
277}
278
279func fullTester(c *Command, input string) resulter {
280	buf := new(bytes.Buffer)
281	// Testing flag with invalid input
282	c.SetOutput(buf)
283	cmdEcho.AddCommand(cmdTimes)
284	c.AddCommand(cmdPrint, cmdEcho, cmdSubNoRun, cmdCustomFlags, cmdDeprecated)
285	c.SetArgs(strings.Split(input, " "))
286
287	err := c.Execute()
288	output := buf.String()
289
290	return resulter{err, output, c}
291}
292
293func logErr(t *testing.T, found, expected string) {
294	out := new(bytes.Buffer)
295
296	_, _, line, ok := runtime.Caller(2)
297	if ok {
298		fmt.Fprintf(out, "Line: %d ", line)
299	}
300	fmt.Fprintf(out, "Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
301	t.Errorf(out.String())
302}
303
304func checkStringContains(t *testing.T, found, expected string) {
305	if !strings.Contains(found, expected) {
306		logErr(t, found, expected)
307	}
308}
309
310func checkResultContains(t *testing.T, x resulter, check string) {
311	checkStringContains(t, x.Output, check)
312}
313
314func checkStringOmits(t *testing.T, found, expected string) {
315	if strings.Contains(found, expected) {
316		logErr(t, found, expected)
317	}
318}
319
320func checkResultOmits(t *testing.T, x resulter, check string) {
321	checkStringOmits(t, x.Output, check)
322}
323
324func checkOutputContains(t *testing.T, c *Command, check string) {
325	buf := new(bytes.Buffer)
326	c.SetOutput(buf)
327	c.Execute()
328
329	if !strings.Contains(buf.String(), check) {
330		logErr(t, buf.String(), check)
331	}
332}
333
334func TestSingleCommand(t *testing.T) {
335	noRRSetupTest("print one two")
336
337	if te != nil || tt != nil {
338		t.Error("Wrong command called")
339	}
340	if tp == nil {
341		t.Error("Wrong command called")
342	}
343	if strings.Join(tp, " ") != "one two" {
344		t.Error("Command didn't parse correctly")
345	}
346}
347
348func TestChildCommand(t *testing.T) {
349	noRRSetupTest("echo times one two")
350
351	if te != nil || tp != nil {
352		t.Error("Wrong command called")
353	}
354	if tt == nil {
355		t.Error("Wrong command called")
356	}
357	if strings.Join(tt, " ") != "one two" {
358		t.Error("Command didn't parse correctly")
359	}
360}
361
362func TestCommandAlias(t *testing.T) {
363	noRRSetupTest("say times one two")
364
365	if te != nil || tp != nil {
366		t.Error("Wrong command called")
367	}
368	if tt == nil {
369		t.Error("Wrong command called")
370	}
371	if strings.Join(tt, " ") != "one two" {
372		t.Error("Command didn't parse correctly")
373	}
374}
375
376func TestPrefixMatching(t *testing.T) {
377	EnablePrefixMatching = true
378	noRRSetupTest("ech times one two")
379
380	if te != nil || tp != nil {
381		t.Error("Wrong command called")
382	}
383	if tt == nil {
384		t.Error("Wrong command called")
385	}
386	if strings.Join(tt, " ") != "one two" {
387		t.Error("Command didn't parse correctly")
388	}
389
390	EnablePrefixMatching = false
391}
392
393func TestNoPrefixMatching(t *testing.T) {
394	EnablePrefixMatching = false
395
396	noRRSetupTest("ech times one two")
397
398	if !(tt == nil && te == nil && tp == nil) {
399		t.Error("Wrong command called")
400	}
401}
402
403func TestAliasPrefixMatching(t *testing.T) {
404	EnablePrefixMatching = true
405	noRRSetupTest("sa times one two")
406
407	if te != nil || tp != nil {
408		t.Error("Wrong command called")
409	}
410	if tt == nil {
411		t.Error("Wrong command called")
412	}
413	if strings.Join(tt, " ") != "one two" {
414		t.Error("Command didn't parse correctly")
415	}
416	EnablePrefixMatching = false
417}
418
419func TestChildSameName(t *testing.T) {
420	c := initializeWithSameName()
421	c.AddCommand(cmdPrint, cmdEcho)
422	c.SetArgs(strings.Split("print one two", " "))
423	c.Execute()
424
425	if te != nil || tt != nil {
426		t.Error("Wrong command called")
427	}
428	if tp == nil {
429		t.Error("Wrong command called")
430	}
431	if strings.Join(tp, " ") != "one two" {
432		t.Error("Command didn't parse correctly")
433	}
434}
435
436func TestGrandChildSameName(t *testing.T) {
437	c := initializeWithSameName()
438	cmdTimes.AddCommand(cmdPrint)
439	c.AddCommand(cmdTimes)
440	c.SetArgs(strings.Split("times print one two", " "))
441	c.Execute()
442
443	if te != nil || tt != nil {
444		t.Error("Wrong command called")
445	}
446	if tp == nil {
447		t.Error("Wrong command called")
448	}
449	if strings.Join(tp, " ") != "one two" {
450		t.Error("Command didn't parse correctly")
451	}
452}
453
454func TestUsage(t *testing.T) {
455	x := fullSetupTest("help")
456	checkResultContains(t, x, cmdRootWithRun.Use+" [flags]")
457	x = fullSetupTest("help customflags")
458	checkResultContains(t, x, cmdCustomFlags.Use)
459	checkResultOmits(t, x, cmdCustomFlags.Use+" [flags]")
460}
461
462func TestFlagLong(t *testing.T) {
463	noRRSetupTest("echo --intone=13 something -- here")
464
465	if cmdEcho.ArgsLenAtDash() != 1 {
466		t.Errorf("expected argsLenAtDash: %d but got %d", 1, cmdRootNoRun.ArgsLenAtDash())
467	}
468	if strings.Join(te, " ") != "something here" {
469		t.Errorf("flags didn't leave proper args remaining..%s given", te)
470	}
471	if flagi1 != 13 {
472		t.Errorf("int flag didn't get correct value, had %d", flagi1)
473	}
474	if flagi2 != 234 {
475		t.Errorf("default flag value changed, 234 expected, %d given", flagi2)
476	}
477}
478
479func TestFlagShort(t *testing.T) {
480	noRRSetupTest("echo -i13 -- something here")
481
482	if cmdEcho.ArgsLenAtDash() != 0 {
483		t.Errorf("expected argsLenAtDash: %d but got %d", 0, cmdRootNoRun.ArgsLenAtDash())
484	}
485	if strings.Join(te, " ") != "something here" {
486		t.Errorf("flags didn't leave proper args remaining..%s given", te)
487	}
488	if flagi1 != 13 {
489		t.Errorf("int flag didn't get correct value, had %d", flagi1)
490	}
491	if flagi2 != 234 {
492		t.Errorf("default flag value changed, 234 expected, %d given", flagi2)
493	}
494
495	noRRSetupTest("echo -i 13 something here")
496
497	if strings.Join(te, " ") != "something here" {
498		t.Errorf("flags didn't leave proper args remaining..%s given", te)
499	}
500	if flagi1 != 13 {
501		t.Errorf("int flag didn't get correct value, had %d", flagi1)
502	}
503	if flagi2 != 234 {
504		t.Errorf("default flag value changed, 234 expected, %d given", flagi2)
505	}
506
507	noRRSetupTest("print -i99 one two")
508
509	if strings.Join(tp, " ") != "one two" {
510		t.Errorf("flags didn't leave proper args remaining..%s given", tp)
511	}
512	if flagi3 != 99 {
513		t.Errorf("int flag didn't get correct value, had %d", flagi3)
514	}
515	if flagi1 != 123 {
516		t.Errorf("default flag value changed on different command with same shortname, 234 expected, %d given", flagi2)
517	}
518}
519
520func TestChildCommandFlags(t *testing.T) {
521	noRRSetupTest("echo times -j 99 one two")
522
523	if strings.Join(tt, " ") != "one two" {
524		t.Errorf("flags didn't leave proper args remaining..%s given", tt)
525	}
526
527	// Testing with flag that shouldn't be persistent
528	r := noRRSetupTest("echo times -j 99 -i77 one two")
529
530	if r.Error == nil {
531		t.Errorf("invalid flag should generate error")
532	}
533
534	if !strings.Contains(r.Error.Error(), "unknown shorthand") {
535		t.Errorf("Wrong error message displayed, \n %s", r.Error)
536	}
537
538	if flagi2 != 99 {
539		t.Errorf("flag value should be 99, %d given", flagi2)
540	}
541
542	if flagi1 != 123 {
543		t.Errorf("unset flag should have default value, expecting 123, given %d", flagi1)
544	}
545
546	// Testing with flag only existing on child
547	r = noRRSetupTest("echo -j 99 -i77 one two")
548
549	if r.Error == nil {
550		t.Errorf("invalid flag should generate error")
551	}
552	if !strings.Contains(r.Error.Error(), "unknown shorthand flag") {
553		t.Errorf("Wrong error message displayed, \n %s", r.Error)
554	}
555
556	// Testing with persistent flag overwritten by child
557	noRRSetupTest("echo times --strtwo=child one two")
558
559	if flags2b != "child" {
560		t.Errorf("flag value should be child, %s given", flags2b)
561	}
562
563	if flags2a != "two" {
564		t.Errorf("unset flag should have default value, expecting two, given %s", flags2a)
565	}
566
567	// Testing flag with invalid input
568	r = noRRSetupTest("echo -i10E")
569
570	if r.Error == nil {
571		t.Errorf("invalid input should generate error")
572	}
573	if !strings.Contains(r.Error.Error(), "invalid syntax") {
574		t.Errorf("Wrong error message displayed, \n %s", r.Error)
575	}
576}
577
578func TestTrailingCommandFlags(t *testing.T) {
579	x := fullSetupTest("echo two -x")
580
581	if x.Error == nil {
582		t.Errorf("invalid flag should generate error")
583	}
584}
585
586func TestInvalidSubcommandFlags(t *testing.T) {
587	cmd := initializeWithRootCmd()
588	cmd.AddCommand(cmdTimes)
589
590	result := simpleTester(cmd, "times --inttwo=2 --badflag=bar")
591	// given that we are not checking here result.Error we check for
592	// stock usage message
593	checkResultContains(t, result, "cobra-test times [# times]")
594	if strings.Contains(result.Error.Error(), "unknown flag: --inttwo") {
595		t.Errorf("invalid --badflag flag shouldn't fail on 'unknown' --inttwo flag")
596	}
597
598}
599
600func TestSubcommandExecuteC(t *testing.T) {
601	cmd := initializeWithRootCmd()
602	double := &Command{
603		Use: "double message",
604		Run: func(c *Command, args []string) {
605			msg := strings.Join(args, " ")
606			c.Println(msg, msg)
607		},
608	}
609
610	echo := &Command{
611		Use: "echo message",
612		Run: func(c *Command, args []string) {
613			msg := strings.Join(args, " ")
614			c.Println(msg)
615		},
616	}
617
618	cmd.AddCommand(double, echo)
619
620	result := simpleTesterC(cmd, "double hello world")
621	checkResultContains(t, result, "hello world hello world")
622
623	if result.Command.Name() != "double" {
624		t.Errorf("invalid cmd returned from ExecuteC: should be 'double' but got %s", result.Command.Name())
625	}
626
627	result = simpleTesterC(cmd, "echo msg to be echoed")
628	checkResultContains(t, result, "msg to be echoed")
629
630	if result.Command.Name() != "echo" {
631		t.Errorf("invalid cmd returned from ExecuteC: should be 'echo' but got %s", result.Command.Name())
632	}
633}
634
635func TestSubcommandArgEvaluation(t *testing.T) {
636	cmd := initializeWithRootCmd()
637
638	first := &Command{
639		Use: "first",
640		Run: func(cmd *Command, args []string) {
641		},
642	}
643	cmd.AddCommand(first)
644
645	second := &Command{
646		Use: "second",
647		Run: func(cmd *Command, args []string) {
648			fmt.Fprintf(cmd.OutOrStdout(), "%v", args)
649		},
650	}
651	first.AddCommand(second)
652
653	result := simpleTester(cmd, "first second first third")
654
655	expectedOutput := fmt.Sprintf("%v", []string{"first third"})
656	if result.Output != expectedOutput {
657		t.Errorf("exptected %v, got %v", expectedOutput, result.Output)
658	}
659}
660
661func TestPersistentFlags(t *testing.T) {
662	fullSetupTest("echo -s something -p more here")
663
664	// persistentFlag should act like normal flag on its own command
665	if strings.Join(te, " ") != "more here" {
666		t.Errorf("flags didn't leave proper args remaining..%s given", te)
667	}
668	if flags1 != "something" {
669		t.Errorf("string flag didn't get correct value, had %v", flags1)
670	}
671	if !flagbp {
672		t.Errorf("persistent bool flag not parsed correctly. Expected true, had %v", flagbp)
673	}
674
675	// persistentFlag should act like normal flag on its own command
676	fullSetupTest("echo times -s again -c -p test here")
677
678	if strings.Join(tt, " ") != "test here" {
679		t.Errorf("flags didn't leave proper args remaining. %s given", tt)
680	}
681
682	if flags1 != "again" {
683		t.Errorf("string flag didn't get correct value, had %v", flags1)
684	}
685
686	if !flagb2 {
687		t.Errorf("local flag not parsed correctly. Expected true, had %v", flagb2)
688	}
689	if !flagbp {
690		t.Errorf("persistent bool flag not parsed correctly. Expected true, had %v", flagbp)
691	}
692}
693
694func TestHelpCommand(t *testing.T) {
695	x := fullSetupTest("help")
696	checkResultContains(t, x, cmdRootWithRun.Long)
697
698	x = fullSetupTest("help echo")
699	checkResultContains(t, x, cmdEcho.Long)
700
701	x = fullSetupTest("help echo times")
702	checkResultContains(t, x, cmdTimes.Long)
703}
704
705func TestChildCommandHelp(t *testing.T) {
706	c := noRRSetupTest("print --help")
707	checkResultContains(t, c, strtwoParentHelp)
708	r := noRRSetupTest("echo times --help")
709	checkResultContains(t, r, strtwoChildHelp)
710}
711
712func TestNonRunChildHelp(t *testing.T) {
713	x := noRRSetupTest("subnorun")
714	checkResultContains(t, x, cmdSubNoRun.Long)
715}
716
717func TestRunnableRootCommand(t *testing.T) {
718	x := fullSetupTest("")
719
720	if rootcalled != true {
721		t.Errorf("Root Function was not called\n out:%v", x.Error)
722	}
723}
724
725func TestVisitParents(t *testing.T) {
726	c := &Command{Use: "app"}
727	sub := &Command{Use: "sub"}
728	dsub := &Command{Use: "dsub"}
729	sub.AddCommand(dsub)
730	c.AddCommand(sub)
731	total := 0
732	add := func(x *Command) {
733		total++
734	}
735	sub.VisitParents(add)
736	if total != 1 {
737		t.Errorf("Should have visited 1 parent but visited %d", total)
738	}
739
740	total = 0
741	dsub.VisitParents(add)
742	if total != 2 {
743		t.Errorf("Should have visited 2 parent but visited %d", total)
744	}
745
746	total = 0
747	c.VisitParents(add)
748	if total != 0 {
749		t.Errorf("Should have not visited any parent but visited %d", total)
750	}
751}
752
753func TestRunnableRootCommandNilInput(t *testing.T) {
754	var emptyArg []string
755	c := initializeWithRootCmd()
756
757	buf := new(bytes.Buffer)
758	// Testing flag with invalid input
759	c.SetOutput(buf)
760	cmdEcho.AddCommand(cmdTimes)
761	c.AddCommand(cmdPrint, cmdEcho)
762	c.SetArgs(emptyArg)
763
764	err := c.Execute()
765	if err != nil {
766		t.Errorf("Execute() failed with %v", err)
767	}
768
769	if rootcalled != true {
770		t.Errorf("Root Function was not called")
771	}
772}
773
774func TestRunnableRootCommandEmptyInput(t *testing.T) {
775	args := make([]string, 3)
776	args[0] = ""
777	args[1] = "--introot=12"
778	args[2] = ""
779	c := initializeWithRootCmd()
780
781	buf := new(bytes.Buffer)
782	// Testing flag with invalid input
783	c.SetOutput(buf)
784	cmdEcho.AddCommand(cmdTimes)
785	c.AddCommand(cmdPrint, cmdEcho)
786	c.SetArgs(args)
787
788	c.Execute()
789
790	if rootcalled != true {
791		t.Errorf("Root Function was not called.\n\nOutput was:\n\n%s\n", buf)
792	}
793}
794
795func TestInvalidSubcommandWhenArgsAllowed(t *testing.T) {
796	fullSetupTest("echo invalid-sub")
797
798	if te[0] != "invalid-sub" {
799		t.Errorf("Subcommand didn't work...")
800	}
801}
802
803func TestRootFlags(t *testing.T) {
804	fullSetupTest("-i 17 -b")
805
806	if flagbr != true {
807		t.Errorf("flag value should be true, %v given", flagbr)
808	}
809
810	if flagir != 17 {
811		t.Errorf("flag value should be 17, %d given", flagir)
812	}
813}
814
815func TestRootHelp(t *testing.T) {
816	x := fullSetupTest("--help")
817
818	checkResultContains(t, x, "Available Commands:")
819	checkResultContains(t, x, "for more information about a command")
820
821	if strings.Contains(x.Output, "unknown flag: --help") {
822		t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output)
823	}
824
825	if strings.Contains(x.Output, cmdEcho.Use) {
826		t.Errorf("--help shouldn't display subcommand's usage, Got: \n %s", x.Output)
827	}
828
829	x = fullSetupTest("echo --help")
830
831	if strings.Contains(x.Output, cmdTimes.Use) {
832		t.Errorf("--help shouldn't display subsubcommand's usage, Got: \n %s", x.Output)
833	}
834
835	checkResultContains(t, x, "Available Commands:")
836	checkResultContains(t, x, "for more information about a command")
837
838	if strings.Contains(x.Output, "unknown flag: --help") {
839		t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output)
840	}
841
842}
843
844func TestFlagAccess(t *testing.T) {
845	initialize()
846
847	local := cmdTimes.LocalFlags()
848	inherited := cmdTimes.InheritedFlags()
849
850	for _, f := range []string{"inttwo", "strtwo", "booltwo"} {
851		if local.Lookup(f) == nil {
852			t.Errorf("LocalFlags expected to contain %s, Got: nil", f)
853		}
854	}
855	if inherited.Lookup("strone") == nil {
856		t.Errorf("InheritedFlags expected to contain strone, Got: nil")
857	}
858	if inherited.Lookup("strtwo") != nil {
859		t.Errorf("InheritedFlags shouldn not contain overwritten flag strtwo")
860	}
861}
862
863func TestNoNRunnableRootCommandNilInput(t *testing.T) {
864	var args []string
865	c := initialize()
866
867	buf := new(bytes.Buffer)
868	// Testing flag with invalid input
869	c.SetOutput(buf)
870	cmdEcho.AddCommand(cmdTimes)
871	c.AddCommand(cmdPrint, cmdEcho)
872	c.SetArgs(args)
873
874	c.Execute()
875
876	if !strings.Contains(buf.String(), cmdRootNoRun.Long) {
877		t.Errorf("Expected to get help output, Got: \n %s", buf)
878	}
879}
880
881func TestRootNoCommandHelp(t *testing.T) {
882	x := rootOnlySetupTest("--help")
883
884	checkResultOmits(t, x, "Available Commands:")
885	checkResultOmits(t, x, "for more information about a command")
886
887	if strings.Contains(x.Output, "unknown flag: --help") {
888		t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output)
889	}
890
891	x = rootOnlySetupTest("echo --help")
892
893	checkResultOmits(t, x, "Available Commands:")
894	checkResultOmits(t, x, "for more information about a command")
895
896	if strings.Contains(x.Output, "unknown flag: --help") {
897		t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output)
898	}
899}
900
901func TestRootUnknownCommand(t *testing.T) {
902	r := noRRSetupTest("bogus")
903	s := "Error: unknown command \"bogus\" for \"cobra-test\"\nRun 'cobra-test --help' for usage.\n"
904
905	if r.Output != s {
906		t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", s, r.Output)
907	}
908
909	r = noRRSetupTest("--strtwo=a bogus")
910	if r.Output != s {
911		t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", s, r.Output)
912	}
913}
914
915func TestRootUnknownCommandSilenced(t *testing.T) {
916	r := noRRSetupTestSilenced("bogus")
917
918	if r.Output != "" {
919		t.Errorf("Unexpected response.\nExpecting to be: \n\"\"\n Got:\n %q\n", r.Output)
920	}
921
922	r = noRRSetupTestSilenced("--strtwo=a bogus")
923	if r.Output != "" {
924		t.Errorf("Unexpected response.\nExpecting to be:\n\"\"\nGot:\n %q\n", r.Output)
925	}
926}
927
928func TestRootSuggestions(t *testing.T) {
929	outputWithSuggestions := "Error: unknown command \"%s\" for \"cobra-test\"\n\nDid you mean this?\n\t%s\n\nRun 'cobra-test --help' for usage.\n"
930	outputWithoutSuggestions := "Error: unknown command \"%s\" for \"cobra-test\"\nRun 'cobra-test --help' for usage.\n"
931
932	cmd := initializeWithRootCmd()
933	cmd.AddCommand(cmdTimes)
934
935	tests := map[string]string{
936		"time":     "times",
937		"tiems":    "times",
938		"tims":     "times",
939		"timeS":    "times",
940		"rimes":    "times",
941		"ti":       "times",
942		"t":        "times",
943		"timely":   "times",
944		"ri":       "",
945		"timezone": "",
946		"foo":      "",
947		"counts":   "times",
948	}
949
950	for typo, suggestion := range tests {
951		for _, suggestionsDisabled := range []bool{false, true} {
952			cmd.DisableSuggestions = suggestionsDisabled
953			result := simpleTester(cmd, typo)
954			expected := ""
955			if len(suggestion) == 0 || suggestionsDisabled {
956				expected = fmt.Sprintf(outputWithoutSuggestions, typo)
957			} else {
958				expected = fmt.Sprintf(outputWithSuggestions, typo, suggestion)
959			}
960			if result.Output != expected {
961				t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", expected, result.Output)
962			}
963		}
964	}
965}
966
967func TestFlagsBeforeCommand(t *testing.T) {
968	// short without space
969	x := fullSetupTest("-i10 echo")
970	if x.Error != nil {
971		t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error)
972	}
973
974	// short (int) with equals
975	// It appears that pflags doesn't support this...
976	// Commenting out until support can be added
977
978	//x = noRRSetupTest("echo -i=10")
979	//if x.Error != nil {
980	//t.Errorf("Valid Input shouldn't have errors, got:\n %s", x.Error)
981	//}
982
983	// long with equals
984	x = noRRSetupTest("--intone=123 echo one two")
985	if x.Error != nil {
986		t.Errorf("Valid Input shouldn't have errors, got:\n %s", x.Error)
987	}
988
989	// With parsing error properly reported
990	x = fullSetupTest("-i10E echo")
991	if !strings.Contains(x.Error.Error(), "invalid syntax") {
992		t.Errorf("Wrong error message displayed, \n %s", x.Error)
993	}
994
995	//With quotes
996	x = fullSetupTest("-s=\"walking\" echo")
997	if x.Error != nil {
998		t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error)
999	}
1000
1001	//With quotes and space
1002	x = fullSetupTest("-s=\"walking fast\" echo")
1003	if x.Error != nil {
1004		t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error)
1005	}
1006
1007	//With inner quote
1008	x = fullSetupTest("-s=\"walking \\\"Inner Quote\\\" fast\" echo")
1009	if x.Error != nil {
1010		t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error)
1011	}
1012
1013	//With quotes and space
1014	x = fullSetupTest("-s=\"walking \\\"Inner Quote\\\" fast\" echo")
1015	if x.Error != nil {
1016		t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error)
1017	}
1018
1019}
1020
1021func TestRemoveCommand(t *testing.T) {
1022	versionUsed = 0
1023	c := initializeWithRootCmd()
1024	c.AddCommand(cmdVersion1)
1025	c.RemoveCommand(cmdVersion1)
1026	x := fullTester(c, "version")
1027	if x.Error == nil {
1028		t.Errorf("Removed command should not have been called\n")
1029		return
1030	}
1031}
1032
1033func TestCommandWithoutSubcommands(t *testing.T) {
1034	c := initializeWithRootCmd()
1035
1036	x := simpleTester(c, "")
1037	if x.Error != nil {
1038		t.Errorf("Calling command without subcommands should not have error: %v", x.Error)
1039		return
1040	}
1041}
1042
1043func TestCommandWithoutSubcommandsWithArg(t *testing.T) {
1044	c := initializeWithRootCmd()
1045	expectedArgs := []string{"arg"}
1046
1047	x := simpleTester(c, "arg")
1048	if x.Error != nil {
1049		t.Errorf("Calling command without subcommands but with arg should not have error: %v", x.Error)
1050		return
1051	}
1052	if !reflect.DeepEqual(expectedArgs, tr) {
1053		t.Errorf("Calling command without subcommands but with arg has wrong args: expected: %v, actual: %v", expectedArgs, tr)
1054		return
1055	}
1056}
1057
1058func TestReplaceCommandWithRemove(t *testing.T) {
1059	versionUsed = 0
1060	c := initializeWithRootCmd()
1061	c.AddCommand(cmdVersion1)
1062	c.RemoveCommand(cmdVersion1)
1063	c.AddCommand(cmdVersion2)
1064	x := fullTester(c, "version")
1065	if x.Error != nil {
1066		t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error)
1067		return
1068	}
1069	if versionUsed == 1 {
1070		t.Errorf("Removed command shouldn't be called\n")
1071	}
1072	if versionUsed != 2 {
1073		t.Errorf("Replacing command should have been called but didn't\n")
1074	}
1075}
1076
1077func TestDeprecatedSub(t *testing.T) {
1078	c := fullSetupTest("deprecated")
1079
1080	checkResultContains(t, c, cmdDeprecated.Deprecated)
1081}
1082
1083func TestPreRun(t *testing.T) {
1084	noRRSetupTest("echo one two")
1085	if echoPre == nil || echoPersPre == nil {
1086		t.Error("PreRun or PersistentPreRun not called")
1087	}
1088	if rootPersPre != nil || timesPersPre != nil {
1089		t.Error("Wrong *Pre functions called!")
1090	}
1091
1092	noRRSetupTest("echo times one two")
1093	if timesPersPre == nil {
1094		t.Error("PreRun or PersistentPreRun not called")
1095	}
1096	if echoPre != nil || echoPersPre != nil || rootPersPre != nil {
1097		t.Error("Wrong *Pre functions called!")
1098	}
1099
1100	noRRSetupTest("print one two")
1101	if rootPersPre == nil {
1102		t.Error("Parent PersistentPreRun not called but should not have been")
1103	}
1104	if echoPre != nil || echoPersPre != nil || timesPersPre != nil {
1105		t.Error("Wrong *Pre functions called!")
1106	}
1107}
1108
1109// Check if cmdEchoSub gets PersistentPreRun from rootCmd even if is added last
1110func TestPeristentPreRunPropagation(t *testing.T) {
1111	rootCmd := initialize()
1112
1113	// First add the cmdEchoSub to cmdPrint
1114	cmdPrint.AddCommand(cmdEchoSub)
1115	// Now add cmdPrint to rootCmd
1116	rootCmd.AddCommand(cmdPrint)
1117
1118	rootCmd.SetArgs(strings.Split("print echosub lala", " "))
1119	rootCmd.Execute()
1120
1121	if rootPersPre == nil || len(rootPersPre) == 0 || rootPersPre[0] != "lala" {
1122		t.Error("RootCmd PersistentPreRun not called but should have been")
1123	}
1124}
1125
1126func TestGlobalNormFuncPropagation(t *testing.T) {
1127	normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
1128		return pflag.NormalizedName(name)
1129	}
1130
1131	rootCmd := initialize()
1132	rootCmd.SetGlobalNormalizationFunc(normFunc)
1133	if reflect.ValueOf(normFunc) != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()) {
1134		t.Error("rootCmd seems to have a wrong normalization function")
1135	}
1136
1137	// First add the cmdEchoSub to cmdPrint
1138	cmdPrint.AddCommand(cmdEchoSub)
1139	if cmdPrint.GlobalNormalizationFunc() != nil && cmdEchoSub.GlobalNormalizationFunc() != nil {
1140		t.Error("cmdPrint and cmdEchoSub should had no normalization functions")
1141	}
1142
1143	// Now add cmdPrint to rootCmd
1144	rootCmd.AddCommand(cmdPrint)
1145	if reflect.ValueOf(cmdPrint.GlobalNormalizationFunc()).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() ||
1146		reflect.ValueOf(cmdEchoSub.GlobalNormalizationFunc()).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() {
1147		t.Error("cmdPrint and cmdEchoSub should had the normalization function of rootCmd")
1148	}
1149}
1150
1151func TestFlagOnPflagCommandLine(t *testing.T) {
1152	flagName := "flagOnCommandLine"
1153	pflag.CommandLine.String(flagName, "", "about my flag")
1154	r := fullSetupTest("--help")
1155
1156	checkResultContains(t, r, flagName)
1157
1158	// reset CommandLine flagset
1159	pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
1160}
1161
1162func TestAddTemplateFunctions(t *testing.T) {
1163	AddTemplateFunc("t", func() bool { return true })
1164	AddTemplateFuncs(template.FuncMap{
1165		"f": func() bool { return false },
1166		"h": func() string { return "Hello," },
1167		"w": func() string { return "world." }})
1168
1169	const usage = "Hello, world."
1170
1171	c := &Command{}
1172	c.SetUsageTemplate(`{{if t}}{{h}}{{end}}{{if f}}{{h}}{{end}} {{w}}`)
1173
1174	if us := c.UsageString(); us != usage {
1175		t.Errorf("c.UsageString() != \"%s\", is \"%s\"", usage, us)
1176	}
1177}
1178
1179func TestUsageIsNotPrintedTwice(t *testing.T) {
1180	var cmd = &Command{Use: "root"}
1181	var sub = &Command{Use: "sub"}
1182	cmd.AddCommand(sub)
1183
1184	r := simpleTester(cmd, "")
1185	if strings.Count(r.Output, "Usage:") != 1 {
1186		t.Error("Usage output is not printed exactly once")
1187	}
1188}
1189
1190func BenchmarkInheritedFlags(b *testing.B) {
1191	initialize()
1192	cmdEcho.AddCommand(cmdTimes)
1193	b.ResetTimer()
1194
1195	for i := 0; i < b.N; i++ {
1196		cmdTimes.InheritedFlags()
1197	}
1198}
1199
1200func BenchmarkLocalFlags(b *testing.B) {
1201	initialize()
1202	cmdEcho.AddCommand(cmdTimes)
1203	b.ResetTimer()
1204
1205	for i := 0; i < b.N; i++ {
1206		cmdTimes.LocalFlags()
1207	}
1208}
1209