11 "github.com/spf13/pflag"
14 // test to ensure hidden commands run as intended
15 func TestHiddenCommandExecutes(t *testing.T) {
17 // ensure that outs does not already equal what the command will be setting it
18 // to, if it did this test would not actually be testing anything...
20 t.Errorf("outs should NOT EQUAL hidden")
25 // upon running the command, the value of outs should now be 'hidden'
27 t.Errorf("Hidden command failed to run!")
31 // test to ensure hidden commands do not show up in usage/help text
32 func TestHiddenCommandIsHidden(t *testing.T) {
33 if cmdHidden.IsAvailableCommand() {
34 t.Errorf("Hidden command found!")
38 func TestStripFlags(t *testing.T) {
44 []string{"foo", "bar"},
45 []string{"foo", "bar"},
48 []string{"foo", "--bar", "-b"},
52 []string{"-b", "foo", "--bar", "bar"},
56 []string{"-i10", "echo"},
60 []string{"-i=10", "echo"},
64 []string{"--int=100", "echo"},
68 []string{"-ib", "echo", "-bfoo", "baz"},
69 []string{"echo", "baz"},
72 []string{"-i=baz", "bar", "-i", "foo", "blah"},
73 []string{"bar", "blah"},
76 []string{"--int=baz", "-bbar", "-i", "foo", "blah"},
80 []string{"--cat", "bar", "-i", "foo", "blah"},
81 []string{"bar", "blah"},
84 []string{"-c", "bar", "-i", "foo", "blah"},
85 []string{"bar", "blah"},
88 []string{"--persist", "bar"},
92 []string{"-p", "bar"},
98 Use: "print [string to print]",
99 Short: "Print anything to the screen",
100 Long: `an utterly useless command for testing.`,
101 Run: func(cmd *Command, args []string) {
109 cmdPrint.PersistentFlags().BoolVarP(&flagbool, "persist", "p", false, "help for persistent one")
110 cmdPrint.Flags().IntVarP(&flagi, "int", "i", 345, "help message for flag int")
111 cmdPrint.Flags().StringVarP(&flagstr, "bar", "b", "bar", "help message for flag string")
112 cmdPrint.Flags().BoolVarP(&flagbool, "cat", "c", false, "help message for flag bool")
114 for _, test := range tests {
115 output := stripFlags(test.input, cmdPrint)
116 if !reflect.DeepEqual(test.output, output) {
117 t.Errorf("expected: %v, got: %v", test.output, output)
122 func TestDisableFlagParsing(t *testing.T) {
124 cmdPrint := &Command{
125 DisableFlagParsing: true,
126 Run: func(cmd *Command, args []string) {
130 args := []string{"cmd", "-v", "-race", "-file", "foo.go"}
131 cmdPrint.SetArgs(args)
132 err := cmdPrint.Execute()
136 if !reflect.DeepEqual(args, targs) {
137 t.Errorf("expected: %v, got: %v", args, targs)
141 func TestInitHelpFlagMergesFlags(t *testing.T) {
142 usage := "custom flag"
143 baseCmd := Command{Use: "testcmd"}
144 baseCmd.PersistentFlags().Bool("help", false, usage)
145 cmd := Command{Use: "do"}
146 baseCmd.AddCommand(&cmd)
148 cmd.InitDefaultHelpFlag()
149 actual := cmd.Flags().Lookup("help").Usage
151 t.Fatalf("Expected the help flag from the base command with usage '%s', but got the default with usage '%s'", usage, actual)
155 func TestCommandsAreSorted(t *testing.T) {
156 EnableCommandSorting = true
158 originalNames := []string{"middle", "zlast", "afirst"}
159 expectedNames := []string{"afirst", "middle", "zlast"}
161 var tmpCommand = &Command{Use: "tmp"}
163 for _, name := range originalNames {
164 tmpCommand.AddCommand(&Command{Use: name})
167 for i, c := range tmpCommand.Commands() {
168 if expectedNames[i] != c.Name() {
169 t.Errorf("expected: %s, got: %s", expectedNames[i], c.Name())
173 EnableCommandSorting = true
176 func TestEnableCommandSortingIsDisabled(t *testing.T) {
177 EnableCommandSorting = false
179 originalNames := []string{"middle", "zlast", "afirst"}
181 var tmpCommand = &Command{Use: "tmp"}
183 for _, name := range originalNames {
184 tmpCommand.AddCommand(&Command{Use: name})
187 for i, c := range tmpCommand.Commands() {
188 if originalNames[i] != c.Name() {
189 t.Errorf("expected: %s, got: %s", originalNames[i], c.Name())
193 EnableCommandSorting = true
196 func TestSetOutput(t *testing.T) {
199 if out := cmd.OutOrStdout(); out != os.Stdout {
200 t.Fatalf("expected setting output to nil to revert back to stdout, got %v", out)
204 func TestFlagErrorFunc(t *testing.T) {
207 RunE: func(cmd *Command, args []string) error {
211 expectedFmt := "This is expected: %s"
213 cmd.SetFlagErrorFunc(func(c *Command, err error) error {
214 return fmt.Errorf(expectedFmt, err)
216 cmd.SetArgs([]string{"--bogus-flag"})
217 cmd.SetOutput(new(bytes.Buffer))
221 expected := fmt.Sprintf(expectedFmt, "unknown flag: --bogus-flag")
222 if err.Error() != expected {
223 t.Errorf("expected %v, got %v", expected, err.Error())
227 // TestSortedFlags checks,
228 // if cmd.LocalFlags() is unsorted when cmd.Flags().SortFlags set to false.
229 // Related to https://github.com/spf13/cobra/issues/404.
230 func TestSortedFlags(t *testing.T) {
232 cmd.Flags().SortFlags = false
233 names := []string{"C", "B", "A", "D"}
234 for _, name := range names {
235 cmd.Flags().Bool(name, false, "")
239 cmd.LocalFlags().VisitAll(func(f *pflag.Flag) {
243 if isStringInStringSlice(f.Name, names) {
244 if names[i] != f.Name {
245 t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
252 // contains checks, if s is in ss.
253 func isStringInStringSlice(s string, ss []string) bool {
254 for _, v := range ss {
262 // TestHelpFlagInHelp checks,
263 // if '--help' flag is shown in help for child (executing `parent help child`),
264 // that has no other flags.
265 // Related to https://github.com/spf13/cobra/issues/302.
266 func TestHelpFlagInHelp(t *testing.T) {
267 output := new(bytes.Buffer)
268 parent := &Command{Use: "parent", Run: func(*Command, []string) {}}
269 parent.SetOutput(output)
271 child := &Command{Use: "child", Run: func(*Command, []string) {}}
272 parent.AddCommand(child)
274 parent.SetArgs([]string{"help", "child"})
275 err := parent.Execute()
280 if !strings.Contains(output.String(), "[flags]") {
281 t.Errorf("\nExpecting to contain: %v\nGot: %v", "[flags]", output.String())
285 // TestMergeCommandLineToFlags checks,
286 // if pflag.CommandLine is correctly merged to c.Flags() after first call
287 // of c.mergePersistentFlags.
288 // Related to https://github.com/spf13/cobra/issues/443.
289 func TestMergeCommandLineToFlags(t *testing.T) {
290 pflag.Bool("boolflag", false, "")
291 c := &Command{Use: "c", Run: func(*Command, []string) {}}
292 c.mergePersistentFlags()
293 if c.Flags().Lookup("boolflag") == nil {
294 t.Fatal("Expecting to have flag from CommandLine in c.Flags()")
297 // Reset pflag.CommandLine flagset.
298 pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
301 // TestUseDeprecatedFlags checks,
302 // if cobra.Execute() prints a message, if a deprecated flag is used.
303 // Related to https://github.com/spf13/cobra/issues/463.
304 func TestUseDeprecatedFlags(t *testing.T) {
305 c := &Command{Use: "c", Run: func(*Command, []string) {}}
306 output := new(bytes.Buffer)
308 c.Flags().BoolP("deprecated", "d", false, "deprecated flag")
309 c.Flags().MarkDeprecated("deprecated", "This flag is deprecated")
311 c.SetArgs([]string{"c", "-d"})
312 if err := c.Execute(); err != nil {
313 t.Error("Unexpected error:", err)
315 if !strings.Contains(output.String(), "This flag is deprecated") {
316 t.Errorf("Expected to contain deprecated message, but got %q", output.String())
320 // TestSetHelpCommand checks, if SetHelpCommand works correctly.
321 func TestSetHelpCommand(t *testing.T) {
322 c := &Command{Use: "c", Run: func(*Command, []string) {}}
323 output := new(bytes.Buffer)
325 c.SetArgs([]string{"help"})
327 // Help will not be shown, if c has no subcommands.
328 c.AddCommand(&Command{
330 Run: func(cmd *Command, args []string) {},
333 correctMessage := "WORKS"
334 c.SetHelpCommand(&Command{
335 Use: "help [command]",
336 Short: "Help about any command",
337 Long: `Help provides help for any command in the application.
338 Simply type ` + c.Name() + ` help [path to command] for full details.`,
339 Run: func(c *Command, args []string) { c.Print(correctMessage) },
342 if err := c.Execute(); err != nil {
343 t.Error("Unexpected error:", err)
346 if output.String() != correctMessage {
347 t.Errorf("Expected to contain %q message, but got %q", correctMessage, output.String())
351 func TestTraverseWithParentFlags(t *testing.T) {
354 TraverseChildren: true,
356 cmd.Flags().String("foo", "", "foo things")
357 cmd.Flags().BoolP("goo", "g", false, "foo things")
359 sub := &Command{Use: "next"}
360 sub.Flags().String("add", "", "add things")
363 c, args, err := cmd.Traverse([]string{"-g", "--foo", "ok", "next", "--add"})
365 t.Fatalf("Expected no error: %s", err)
367 if len(args) != 1 && args[0] != "--add" {
368 t.Fatalf("wrong args %s", args)
370 if c.Name() != sub.Name() {
371 t.Fatalf("wrong command %q expected %q", c.Name(), sub.Name())
375 func TestTraverseNoParentFlags(t *testing.T) {
378 TraverseChildren: true,
380 cmd.Flags().String("foo", "", "foo things")
382 sub := &Command{Use: "next"}
383 sub.Flags().String("add", "", "add things")
386 c, args, err := cmd.Traverse([]string{"next"})
388 t.Fatalf("Expected no error: %s", err)
391 t.Fatalf("wrong args %s", args)
393 if c.Name() != sub.Name() {
394 t.Fatalf("wrong command %q expected %q", c.Name(), sub.Name())
398 func TestTraverseWithBadParentFlags(t *testing.T) {
401 TraverseChildren: true,
403 sub := &Command{Use: "next"}
404 sub.Flags().String("add", "", "add things")
407 expected := "got unknown flag: --add"
409 c, _, err := cmd.Traverse([]string{"--add", "ok", "next"})
410 if err == nil || strings.Contains(err.Error(), expected) {
411 t.Fatalf("Expected error %s got %s", expected, err)
414 t.Fatalf("Expected nil command")
418 func TestTraverseWithBadChildFlag(t *testing.T) {
421 TraverseChildren: true,
423 cmd.Flags().String("foo", "", "foo things")
425 sub := &Command{Use: "next"}
428 // Expect no error because the last commands args shouldn't be parsed in
430 c, args, err := cmd.Traverse([]string{"next", "--add"})
432 t.Fatalf("Expected no error: %s", err)
434 if len(args) != 1 && args[0] != "--add" {
435 t.Fatalf("wrong args %s", args)
437 if c.Name() != sub.Name() {
438 t.Fatalf("wrong command %q expected %q", c.Name(), sub.Name())
442 func TestTraverseWithTwoSubcommands(t *testing.T) {
445 TraverseChildren: true,
450 TraverseChildren: true,
457 sub.AddCommand(subsub)
459 c, _, err := cmd.Traverse([]string{"sub", "subsub"})
461 t.Fatalf("Expected no error: %s", err)
463 if c.Name() != subsub.Name() {
464 t.Fatalf("wrong command %q expected %q", c.Name(), subsub.Name())
468 func TestRequiredFlags(t *testing.T) {
469 c := &Command{Use: "c", Run: func(*Command, []string) {}}
470 output := new(bytes.Buffer)
472 c.Flags().String("foo1", "", "required foo1")
473 c.MarkFlagRequired("foo1")
474 c.Flags().String("foo2", "", "required foo2")
475 c.MarkFlagRequired("foo2")
476 c.Flags().String("bar", "", "optional bar")
478 expected := fmt.Sprintf("Required flag(s) %q, %q have/has not been set", "foo1", "foo2")
480 if err := c.Execute(); err != nil {
481 if err.Error() != expected {
482 t.Errorf("expected %v, got %v", expected, err.Error())
487 func TestPersistentRequiredFlags(t *testing.T) {
488 parent := &Command{Use: "parent", Run: func(*Command, []string) {}}
489 output := new(bytes.Buffer)
490 parent.SetOutput(output)
491 parent.PersistentFlags().String("foo1", "", "required foo1")
492 parent.MarkPersistentFlagRequired("foo1")
493 parent.PersistentFlags().String("foo2", "", "required foo2")
494 parent.MarkPersistentFlagRequired("foo2")
495 parent.Flags().String("foo3", "", "optional foo3")
497 child := &Command{Use: "child", Run: func(*Command, []string) {}}
498 child.Flags().String("bar1", "", "required bar1")
499 child.MarkFlagRequired("bar1")
500 child.Flags().String("bar2", "", "required bar2")
501 child.MarkFlagRequired("bar2")
502 child.Flags().String("bar3", "", "optional bar3")
504 parent.AddCommand(child)
505 parent.SetArgs([]string{"child"})
507 expected := fmt.Sprintf("Required flag(s) %q, %q, %q, %q have/has not been set", "bar1", "bar2", "foo1", "foo2")
509 if err := parent.Execute(); err != nil {
510 if err.Error() != expected {
511 t.Errorf("expected %v, got %v", expected, err.Error())
516 // TestUpdateName checks if c.Name() updates on changed c.Use.
517 // Related to https://github.com/spf13/cobra/pull/422#discussion_r143918343.
518 func TestUpdateName(t *testing.T) {
519 c := &Command{Use: "name xyz"}
520 originalName := c.Name()
522 c.Use = "changedName abc"
523 if originalName == c.Name() || c.Name() != "changedName" {
524 t.Error("c.Name() should be updated on changed c.Use")