| package cobra |
| |
| import ( |
| "bytes" |
| "fmt" |
| "os" |
| "reflect" |
| "strings" |
| "testing" |
| |
| "github.com/spf13/pflag" |
| ) |
| |
| func emptyRun(*Command, []string) {} |
| |
| func executeCommand(root *Command, args ...string) (output string, err error) { |
| _, output, err = executeCommandC(root, args...) |
| return output, err |
| } |
| |
| func executeCommandC(root *Command, args ...string) (c *Command, output string, err error) { |
| buf := new(bytes.Buffer) |
| root.SetOutput(buf) |
| root.SetArgs(args) |
| |
| c, err = root.ExecuteC() |
| |
| return c, buf.String(), err |
| } |
| |
| func resetCommandLineFlagSet() { |
| pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError) |
| } |
| |
| func checkStringContains(t *testing.T, got, expected string) { |
| if !strings.Contains(got, expected) { |
| t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got) |
| } |
| } |
| |
| func checkStringOmits(t *testing.T, got, expected string) { |
| if strings.Contains(got, expected) { |
| t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got) |
| } |
| } |
| |
| func TestSingleCommand(t *testing.T) { |
| var rootCmdArgs []string |
| rootCmd := &Command{ |
| Use: "root", |
| Args: ExactArgs(2), |
| Run: func(_ *Command, args []string) { rootCmdArgs = args }, |
| } |
| aCmd := &Command{Use: "a", Args: NoArgs, Run: emptyRun} |
| bCmd := &Command{Use: "b", Args: NoArgs, Run: emptyRun} |
| rootCmd.AddCommand(aCmd, bCmd) |
| |
| output, err := executeCommand(rootCmd, "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| got := strings.Join(rootCmdArgs, " ") |
| expected := "one two" |
| if got != expected { |
| t.Errorf("rootCmdArgs expected: %q, got: %q", expected, got) |
| } |
| } |
| |
| func TestChildCommand(t *testing.T) { |
| var child1CmdArgs []string |
| rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} |
| child1Cmd := &Command{ |
| Use: "child1", |
| Args: ExactArgs(2), |
| Run: func(_ *Command, args []string) { child1CmdArgs = args }, |
| } |
| child2Cmd := &Command{Use: "child2", Args: NoArgs, Run: emptyRun} |
| rootCmd.AddCommand(child1Cmd, child2Cmd) |
| |
| output, err := executeCommand(rootCmd, "child1", "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| got := strings.Join(child1CmdArgs, " ") |
| expected := "one two" |
| if got != expected { |
| t.Errorf("child1CmdArgs expected: %q, got: %q", expected, got) |
| } |
| } |
| |
| func TestCallCommandWithoutSubcommands(t *testing.T) { |
| rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} |
| _, err := executeCommand(rootCmd) |
| if err != nil { |
| t.Errorf("Calling command without subcommands should not have error: %v", err) |
| } |
| } |
| |
| func TestRootExecuteUnknownCommand(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) |
| |
| output, _ := executeCommand(rootCmd, "unknown") |
| |
| expected := "Error: unknown command \"unknown\" for \"root\"\nRun 'root --help' for usage.\n" |
| |
| if output != expected { |
| t.Errorf("Expected:\n %q\nGot:\n %q\n", expected, output) |
| } |
| } |
| |
| func TestSubcommandExecuteC(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| childCmd := &Command{Use: "child", Run: emptyRun} |
| rootCmd.AddCommand(childCmd) |
| |
| c, output, err := executeCommandC(rootCmd, "child") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| if c.Name() != "child" { |
| t.Errorf(`invalid command returned from ExecuteC: expected "child"', got %q`, c.Name()) |
| } |
| } |
| |
| func TestRootUnknownCommandSilenced(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| rootCmd.SilenceErrors = true |
| rootCmd.SilenceUsage = true |
| rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) |
| |
| output, _ := executeCommand(rootCmd, "unknown") |
| if output != "" { |
| t.Errorf("Expected blank output, because of silenced usage.\nGot:\n %q\n", output) |
| } |
| } |
| |
| func TestCommandAlias(t *testing.T) { |
| var timesCmdArgs []string |
| rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} |
| echoCmd := &Command{ |
| Use: "echo", |
| Aliases: []string{"say", "tell"}, |
| Args: NoArgs, |
| Run: emptyRun, |
| } |
| timesCmd := &Command{ |
| Use: "times", |
| Args: ExactArgs(2), |
| Run: func(_ *Command, args []string) { timesCmdArgs = args }, |
| } |
| echoCmd.AddCommand(timesCmd) |
| rootCmd.AddCommand(echoCmd) |
| |
| output, err := executeCommand(rootCmd, "tell", "times", "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| got := strings.Join(timesCmdArgs, " ") |
| expected := "one two" |
| if got != expected { |
| t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got) |
| } |
| } |
| |
| func TestEnablePrefixMatching(t *testing.T) { |
| EnablePrefixMatching = true |
| |
| var aCmdArgs []string |
| rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} |
| aCmd := &Command{ |
| Use: "aCmd", |
| Args: ExactArgs(2), |
| Run: func(_ *Command, args []string) { aCmdArgs = args }, |
| } |
| bCmd := &Command{Use: "bCmd", Args: NoArgs, Run: emptyRun} |
| rootCmd.AddCommand(aCmd, bCmd) |
| |
| output, err := executeCommand(rootCmd, "a", "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| got := strings.Join(aCmdArgs, " ") |
| expected := "one two" |
| if got != expected { |
| t.Errorf("aCmdArgs expected: %q, got: %q", expected, got) |
| } |
| |
| EnablePrefixMatching = false |
| } |
| |
| func TestAliasPrefixMatching(t *testing.T) { |
| EnablePrefixMatching = true |
| |
| var timesCmdArgs []string |
| rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} |
| echoCmd := &Command{ |
| Use: "echo", |
| Aliases: []string{"say", "tell"}, |
| Args: NoArgs, |
| Run: emptyRun, |
| } |
| timesCmd := &Command{ |
| Use: "times", |
| Args: ExactArgs(2), |
| Run: func(_ *Command, args []string) { timesCmdArgs = args }, |
| } |
| echoCmd.AddCommand(timesCmd) |
| rootCmd.AddCommand(echoCmd) |
| |
| output, err := executeCommand(rootCmd, "sa", "times", "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| got := strings.Join(timesCmdArgs, " ") |
| expected := "one two" |
| if got != expected { |
| t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got) |
| } |
| |
| EnablePrefixMatching = false |
| } |
| |
| // TestChildSameName checks the correct behaviour of cobra in cases, |
| // when an application with name "foo" and with subcommand "foo" |
| // is executed with args "foo foo". |
| func TestChildSameName(t *testing.T) { |
| var fooCmdArgs []string |
| rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun} |
| fooCmd := &Command{ |
| Use: "foo", |
| Args: ExactArgs(2), |
| Run: func(_ *Command, args []string) { fooCmdArgs = args }, |
| } |
| barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun} |
| rootCmd.AddCommand(fooCmd, barCmd) |
| |
| output, err := executeCommand(rootCmd, "foo", "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| got := strings.Join(fooCmdArgs, " ") |
| expected := "one two" |
| if got != expected { |
| t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got) |
| } |
| } |
| |
| // TestGrandChildSameName checks the correct behaviour of cobra in cases, |
| // when user has a root command and a grand child |
| // with the same name. |
| func TestGrandChildSameName(t *testing.T) { |
| var fooCmdArgs []string |
| rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun} |
| barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun} |
| fooCmd := &Command{ |
| Use: "foo", |
| Args: ExactArgs(2), |
| Run: func(_ *Command, args []string) { fooCmdArgs = args }, |
| } |
| barCmd.AddCommand(fooCmd) |
| rootCmd.AddCommand(barCmd) |
| |
| output, err := executeCommand(rootCmd, "bar", "foo", "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| got := strings.Join(fooCmdArgs, " ") |
| expected := "one two" |
| if got != expected { |
| t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got) |
| } |
| } |
| |
| func TestFlagLong(t *testing.T) { |
| var cArgs []string |
| c := &Command{ |
| Use: "c", |
| Args: ArbitraryArgs, |
| Run: func(_ *Command, args []string) { cArgs = args }, |
| } |
| |
| var intFlagValue int |
| var stringFlagValue string |
| c.Flags().IntVar(&intFlagValue, "intf", -1, "") |
| c.Flags().StringVar(&stringFlagValue, "sf", "", "") |
| |
| output, err := executeCommand(c, "--intf=7", "--sf=abc", "one", "--", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", err) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| if c.ArgsLenAtDash() != 1 { |
| t.Errorf("Expected ArgsLenAtDash: %v but got %v", 1, c.ArgsLenAtDash()) |
| } |
| if intFlagValue != 7 { |
| t.Errorf("Expected intFlagValue: %v, got %v", 7, intFlagValue) |
| } |
| if stringFlagValue != "abc" { |
| t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue) |
| } |
| |
| got := strings.Join(cArgs, " ") |
| expected := "one two" |
| if got != expected { |
| t.Errorf("Expected arguments: %q, got %q", expected, got) |
| } |
| } |
| |
| func TestFlagShort(t *testing.T) { |
| var cArgs []string |
| c := &Command{ |
| Use: "c", |
| Args: ArbitraryArgs, |
| Run: func(_ *Command, args []string) { cArgs = args }, |
| } |
| |
| var intFlagValue int |
| var stringFlagValue string |
| c.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") |
| c.Flags().StringVarP(&stringFlagValue, "sf", "s", "", "") |
| |
| output, err := executeCommand(c, "-i", "7", "-sabc", "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", err) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| if intFlagValue != 7 { |
| t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) |
| } |
| if stringFlagValue != "abc" { |
| t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue) |
| } |
| |
| got := strings.Join(cArgs, " ") |
| expected := "one two" |
| if got != expected { |
| t.Errorf("Expected arguments: %q, got %q", expected, got) |
| } |
| } |
| |
| func TestChildFlag(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| childCmd := &Command{Use: "child", Run: emptyRun} |
| rootCmd.AddCommand(childCmd) |
| |
| var intFlagValue int |
| childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") |
| |
| output, err := executeCommand(rootCmd, "child", "-i7") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", err) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| if intFlagValue != 7 { |
| t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) |
| } |
| } |
| |
| func TestChildFlagWithParentLocalFlag(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| childCmd := &Command{Use: "child", Run: emptyRun} |
| rootCmd.AddCommand(childCmd) |
| |
| var intFlagValue int |
| rootCmd.Flags().StringP("sf", "s", "", "") |
| childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") |
| |
| _, err := executeCommand(rootCmd, "child", "-i7", "-sabc") |
| if err == nil { |
| t.Errorf("Invalid flag should generate error") |
| } |
| |
| checkStringContains(t, err.Error(), "unknown shorthand") |
| |
| if intFlagValue != 7 { |
| t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) |
| } |
| } |
| |
| func TestFlagInvalidInput(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| rootCmd.Flags().IntP("intf", "i", -1, "") |
| |
| _, err := executeCommand(rootCmd, "-iabc") |
| if err == nil { |
| t.Errorf("Invalid flag value should generate error") |
| } |
| |
| checkStringContains(t, err.Error(), "invalid syntax") |
| } |
| |
| func TestFlagBeforeCommand(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| childCmd := &Command{Use: "child", Run: emptyRun} |
| rootCmd.AddCommand(childCmd) |
| |
| var flagValue int |
| childCmd.Flags().IntVarP(&flagValue, "intf", "i", -1, "") |
| |
| // With short flag. |
| _, err := executeCommand(rootCmd, "-i7", "child") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| if flagValue != 7 { |
| t.Errorf("Expected flag value: %v, got %v", 7, flagValue) |
| } |
| |
| // With long flag. |
| _, err = executeCommand(rootCmd, "--intf=8", "child") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| if flagValue != 8 { |
| t.Errorf("Expected flag value: %v, got %v", 9, flagValue) |
| } |
| } |
| |
| func TestStripFlags(t *testing.T) { |
| tests := []struct { |
| input []string |
| output []string |
| }{ |
| { |
| []string{"foo", "bar"}, |
| []string{"foo", "bar"}, |
| }, |
| { |
| []string{"foo", "--str", "-s"}, |
| []string{"foo"}, |
| }, |
| { |
| []string{"-s", "foo", "--str", "bar"}, |
| []string{}, |
| }, |
| { |
| []string{"-i10", "echo"}, |
| []string{"echo"}, |
| }, |
| { |
| []string{"-i=10", "echo"}, |
| []string{"echo"}, |
| }, |
| { |
| []string{"--int=100", "echo"}, |
| []string{"echo"}, |
| }, |
| { |
| []string{"-ib", "echo", "-sfoo", "baz"}, |
| []string{"echo", "baz"}, |
| }, |
| { |
| []string{"-i=baz", "bar", "-i", "foo", "blah"}, |
| []string{"bar", "blah"}, |
| }, |
| { |
| []string{"--int=baz", "-sbar", "-i", "foo", "blah"}, |
| []string{"blah"}, |
| }, |
| { |
| []string{"--bool", "bar", "-i", "foo", "blah"}, |
| []string{"bar", "blah"}, |
| }, |
| { |
| []string{"-b", "bar", "-i", "foo", "blah"}, |
| []string{"bar", "blah"}, |
| }, |
| { |
| []string{"--persist", "bar"}, |
| []string{"bar"}, |
| }, |
| { |
| []string{"-p", "bar"}, |
| []string{"bar"}, |
| }, |
| } |
| |
| c := &Command{Use: "c", Run: emptyRun} |
| c.PersistentFlags().BoolP("persist", "p", false, "") |
| c.Flags().IntP("int", "i", -1, "") |
| c.Flags().StringP("str", "s", "", "") |
| c.Flags().BoolP("bool", "b", false, "") |
| |
| for i, test := range tests { |
| got := stripFlags(test.input, c) |
| if !reflect.DeepEqual(test.output, got) { |
| t.Errorf("(%v) Expected: %v, got: %v", i, test.output, got) |
| } |
| } |
| } |
| |
| func TestDisableFlagParsing(t *testing.T) { |
| var cArgs []string |
| c := &Command{ |
| Use: "c", |
| DisableFlagParsing: true, |
| Run: func(_ *Command, args []string) { |
| cArgs = args |
| }, |
| } |
| |
| args := []string{"cmd", "-v", "-race", "-file", "foo.go"} |
| output, err := executeCommand(c, args...) |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| if !reflect.DeepEqual(args, cArgs) { |
| t.Errorf("Expected: %v, got: %v", args, cArgs) |
| } |
| } |
| |
| func TestPersistentFlagsOnSameCommand(t *testing.T) { |
| var rootCmdArgs []string |
| rootCmd := &Command{ |
| Use: "root", |
| Args: ArbitraryArgs, |
| Run: func(_ *Command, args []string) { rootCmdArgs = args }, |
| } |
| |
| var flagValue int |
| rootCmd.PersistentFlags().IntVarP(&flagValue, "intf", "i", -1, "") |
| |
| output, err := executeCommand(rootCmd, "-i7", "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| got := strings.Join(rootCmdArgs, " ") |
| expected := "one two" |
| if got != expected { |
| t.Errorf("rootCmdArgs expected: %q, got %q", expected, got) |
| } |
| if flagValue != 7 { |
| t.Errorf("flagValue expected: %v, got %v", 7, flagValue) |
| } |
| } |
| |
| // TestEmptyInputs checks, |
| // if flags correctly parsed with blank strings in args. |
| func TestEmptyInputs(t *testing.T) { |
| c := &Command{Use: "c", Run: emptyRun} |
| |
| var flagValue int |
| c.Flags().IntVarP(&flagValue, "intf", "i", -1, "") |
| |
| output, err := executeCommand(c, "", "-i7", "") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| if flagValue != 7 { |
| t.Errorf("flagValue expected: %v, got %v", 7, flagValue) |
| } |
| } |
| |
| func TestOverwrittenFlag(t *testing.T) { |
| // TODO: This test fails, but should work. |
| t.Skip() |
| |
| parent := &Command{Use: "parent", Run: emptyRun} |
| child := &Command{Use: "child", Run: emptyRun} |
| |
| parent.PersistentFlags().Bool("boolf", false, "") |
| parent.PersistentFlags().Int("intf", -1, "") |
| child.Flags().String("strf", "", "") |
| child.Flags().Int("intf", -1, "") |
| |
| parent.AddCommand(child) |
| |
| childInherited := child.InheritedFlags() |
| childLocal := child.LocalFlags() |
| |
| if childLocal.Lookup("strf") == nil { |
| t.Error(`LocalFlags expected to contain "strf", got "nil"`) |
| } |
| if childInherited.Lookup("boolf") == nil { |
| t.Error(`InheritedFlags expected to contain "boolf", got "nil"`) |
| } |
| |
| if childInherited.Lookup("intf") != nil { |
| t.Errorf(`InheritedFlags should not contain overwritten flag "intf"`) |
| } |
| if childLocal.Lookup("intf") == nil { |
| t.Error(`LocalFlags expected to contain "intf", got "nil"`) |
| } |
| } |
| |
| func TestPersistentFlagsOnChild(t *testing.T) { |
| var childCmdArgs []string |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| childCmd := &Command{ |
| Use: "child", |
| Args: ArbitraryArgs, |
| Run: func(_ *Command, args []string) { childCmdArgs = args }, |
| } |
| rootCmd.AddCommand(childCmd) |
| |
| var parentFlagValue int |
| var childFlagValue int |
| rootCmd.PersistentFlags().IntVarP(&parentFlagValue, "parentf", "p", -1, "") |
| childCmd.Flags().IntVarP(&childFlagValue, "childf", "c", -1, "") |
| |
| output, err := executeCommand(rootCmd, "child", "-c7", "-p8", "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| got := strings.Join(childCmdArgs, " ") |
| expected := "one two" |
| if got != expected { |
| t.Errorf("childCmdArgs expected: %q, got %q", expected, got) |
| } |
| if parentFlagValue != 8 { |
| t.Errorf("parentFlagValue expected: %v, got %v", 8, parentFlagValue) |
| } |
| if childFlagValue != 7 { |
| t.Errorf("childFlagValue expected: %v, got %v", 7, childFlagValue) |
| } |
| } |
| |
| func TestRequiredFlags(t *testing.T) { |
| c := &Command{Use: "c", Run: emptyRun} |
| c.Flags().String("foo1", "", "") |
| c.MarkFlagRequired("foo1") |
| c.Flags().String("foo2", "", "") |
| c.MarkFlagRequired("foo2") |
| c.Flags().String("bar", "", "") |
| |
| expected := fmt.Sprintf("required flag(s) %q, %q not set", "foo1", "foo2") |
| |
| _, err := executeCommand(c) |
| got := err.Error() |
| |
| if got != expected { |
| t.Errorf("Expected error: %q, got: %q", expected, got) |
| } |
| } |
| |
| func TestPersistentRequiredFlags(t *testing.T) { |
| parent := &Command{Use: "parent", Run: emptyRun} |
| parent.PersistentFlags().String("foo1", "", "") |
| parent.MarkPersistentFlagRequired("foo1") |
| parent.PersistentFlags().String("foo2", "", "") |
| parent.MarkPersistentFlagRequired("foo2") |
| parent.Flags().String("foo3", "", "") |
| |
| child := &Command{Use: "child", Run: emptyRun} |
| child.Flags().String("bar1", "", "") |
| child.MarkFlagRequired("bar1") |
| child.Flags().String("bar2", "", "") |
| child.MarkFlagRequired("bar2") |
| child.Flags().String("bar3", "", "") |
| |
| parent.AddCommand(child) |
| |
| expected := fmt.Sprintf("required flag(s) %q, %q, %q, %q not set", "bar1", "bar2", "foo1", "foo2") |
| |
| _, err := executeCommand(parent, "child") |
| if err.Error() != expected { |
| t.Errorf("Expected %q, got %q", expected, err.Error()) |
| } |
| } |
| |
| func TestInitHelpFlagMergesFlags(t *testing.T) { |
| usage := "custom flag" |
| rootCmd := &Command{Use: "root"} |
| rootCmd.PersistentFlags().Bool("help", false, "custom flag") |
| childCmd := &Command{Use: "child"} |
| rootCmd.AddCommand(childCmd) |
| |
| childCmd.InitDefaultHelpFlag() |
| got := childCmd.Flags().Lookup("help").Usage |
| if got != usage { |
| t.Errorf("Expected the help flag from the root command with usage: %v\nGot the default with usage: %v", usage, got) |
| } |
| } |
| |
| func TestHelpCommandExecuted(t *testing.T) { |
| rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun} |
| rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) |
| |
| output, err := executeCommand(rootCmd, "help") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| checkStringContains(t, output, rootCmd.Long) |
| } |
| |
| func TestHelpCommandExecutedOnChild(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun} |
| rootCmd.AddCommand(childCmd) |
| |
| output, err := executeCommand(rootCmd, "help", "child") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| checkStringContains(t, output, childCmd.Long) |
| } |
| |
| func TestSetHelpCommand(t *testing.T) { |
| c := &Command{Use: "c", Run: emptyRun} |
| c.AddCommand(&Command{Use: "empty", Run: emptyRun}) |
| |
| expected := "WORKS" |
| c.SetHelpCommand(&Command{ |
| Use: "help [command]", |
| Short: "Help about any command", |
| Long: `Help provides help for any command in the application. |
| Simply type ` + c.Name() + ` help [path to command] for full details.`, |
| Run: func(c *Command, _ []string) { c.Print(expected) }, |
| }) |
| |
| got, err := executeCommand(c, "help") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| if got != expected { |
| t.Errorf("Expected to contain %q, got %q", expected, got) |
| } |
| } |
| |
| func TestHelpFlagExecuted(t *testing.T) { |
| rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun} |
| |
| output, err := executeCommand(rootCmd, "--help") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| checkStringContains(t, output, rootCmd.Long) |
| } |
| |
| func TestHelpFlagExecutedOnChild(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun} |
| rootCmd.AddCommand(childCmd) |
| |
| output, err := executeCommand(rootCmd, "child", "--help") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| checkStringContains(t, output, childCmd.Long) |
| } |
| |
| // TestHelpFlagInHelp checks, |
| // if '--help' flag is shown in help for child (executing `parent help child`), |
| // that has no other flags. |
| // Related to https://github.com/spf13/cobra/issues/302. |
| func TestHelpFlagInHelp(t *testing.T) { |
| parentCmd := &Command{Use: "parent", Run: func(*Command, []string) {}} |
| |
| childCmd := &Command{Use: "child", Run: func(*Command, []string) {}} |
| parentCmd.AddCommand(childCmd) |
| |
| output, err := executeCommand(parentCmd, "help", "child") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| checkStringContains(t, output, "[flags]") |
| } |
| |
| func TestFlagsInUsage(t *testing.T) { |
| rootCmd := &Command{Use: "root", Args: NoArgs, Run: func(*Command, []string) {}} |
| output, err := executeCommand(rootCmd, "--help") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| checkStringContains(t, output, "[flags]") |
| } |
| |
| func TestHelpExecutedOnNonRunnableChild(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| childCmd := &Command{Use: "child", Long: "Long description"} |
| rootCmd.AddCommand(childCmd) |
| |
| output, err := executeCommand(rootCmd, "child") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| checkStringContains(t, output, childCmd.Long) |
| } |
| |
| func TestVersionFlagExecuted(t *testing.T) { |
| rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} |
| |
| output, err := executeCommand(rootCmd, "--version", "arg1") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| checkStringContains(t, output, "root version 1.0.0") |
| } |
| |
| func TestVersionTemplate(t *testing.T) { |
| rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} |
| rootCmd.SetVersionTemplate(`customized version: {{.Version}}`) |
| |
| output, err := executeCommand(rootCmd, "--version", "arg1") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| checkStringContains(t, output, "customized version: 1.0.0") |
| } |
| |
| func TestVersionFlagExecutedOnSubcommand(t *testing.T) { |
| rootCmd := &Command{Use: "root", Version: "1.0.0"} |
| rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) |
| |
| output, err := executeCommand(rootCmd, "--version", "sub") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| checkStringContains(t, output, "root version 1.0.0") |
| } |
| |
| func TestVersionFlagOnlyAddedToRoot(t *testing.T) { |
| rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} |
| rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) |
| |
| _, err := executeCommand(rootCmd, "sub", "--version") |
| if err == nil { |
| t.Errorf("Expected error") |
| } |
| |
| checkStringContains(t, err.Error(), "unknown flag: --version") |
| } |
| |
| func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| |
| _, err := executeCommand(rootCmd, "--version") |
| if err == nil { |
| t.Errorf("Expected error") |
| } |
| checkStringContains(t, err.Error(), "unknown flag: --version") |
| } |
| |
| func TestUsageIsNotPrintedTwice(t *testing.T) { |
| var cmd = &Command{Use: "root"} |
| var sub = &Command{Use: "sub"} |
| cmd.AddCommand(sub) |
| |
| output, _ := executeCommand(cmd, "") |
| if strings.Count(output, "Usage:") != 1 { |
| t.Error("Usage output is not printed exactly once") |
| } |
| } |
| |
| func TestVisitParents(t *testing.T) { |
| c := &Command{Use: "app"} |
| sub := &Command{Use: "sub"} |
| dsub := &Command{Use: "dsub"} |
| sub.AddCommand(dsub) |
| c.AddCommand(sub) |
| |
| total := 0 |
| add := func(x *Command) { |
| total++ |
| } |
| sub.VisitParents(add) |
| if total != 1 { |
| t.Errorf("Should have visited 1 parent but visited %d", total) |
| } |
| |
| total = 0 |
| dsub.VisitParents(add) |
| if total != 2 { |
| t.Errorf("Should have visited 2 parents but visited %d", total) |
| } |
| |
| total = 0 |
| c.VisitParents(add) |
| if total != 0 { |
| t.Errorf("Should have visited no parents but visited %d", total) |
| } |
| } |
| |
| func TestSuggestions(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| timesCmd := &Command{ |
| Use: "times", |
| SuggestFor: []string{"counts"}, |
| Run: emptyRun, |
| } |
| rootCmd.AddCommand(timesCmd) |
| |
| templateWithSuggestions := "Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n" |
| templateWithoutSuggestions := "Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n" |
| |
| tests := map[string]string{ |
| "time": "times", |
| "tiems": "times", |
| "tims": "times", |
| "timeS": "times", |
| "rimes": "times", |
| "ti": "times", |
| "t": "times", |
| "timely": "times", |
| "ri": "", |
| "timezone": "", |
| "foo": "", |
| "counts": "times", |
| } |
| |
| for typo, suggestion := range tests { |
| for _, suggestionsDisabled := range []bool{true, false} { |
| rootCmd.DisableSuggestions = suggestionsDisabled |
| |
| var expected string |
| output, _ := executeCommand(rootCmd, typo) |
| |
| if suggestion == "" || suggestionsDisabled { |
| expected = fmt.Sprintf(templateWithoutSuggestions, typo) |
| } else { |
| expected = fmt.Sprintf(templateWithSuggestions, typo, suggestion) |
| } |
| |
| if output != expected { |
| t.Errorf("Unexpected response.\nExpected:\n %q\nGot:\n %q\n", expected, output) |
| } |
| } |
| } |
| } |
| |
| func TestRemoveCommand(t *testing.T) { |
| rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} |
| childCmd := &Command{Use: "child", Run: emptyRun} |
| rootCmd.AddCommand(childCmd) |
| rootCmd.RemoveCommand(childCmd) |
| |
| _, err := executeCommand(rootCmd, "child") |
| if err == nil { |
| t.Error("Expected error on calling removed command. Got nil.") |
| } |
| } |
| |
| func TestReplaceCommandWithRemove(t *testing.T) { |
| childUsed := 0 |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| child1Cmd := &Command{ |
| Use: "child", |
| Run: func(*Command, []string) { childUsed = 1 }, |
| } |
| child2Cmd := &Command{ |
| Use: "child", |
| Run: func(*Command, []string) { childUsed = 2 }, |
| } |
| rootCmd.AddCommand(child1Cmd) |
| rootCmd.RemoveCommand(child1Cmd) |
| rootCmd.AddCommand(child2Cmd) |
| |
| output, err := executeCommand(rootCmd, "child") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| if childUsed == 1 { |
| t.Error("Removed command shouldn't be called") |
| } |
| if childUsed != 2 { |
| t.Error("Replacing command should have been called but didn't") |
| } |
| } |
| |
| func TestDeprecatedCommand(t *testing.T) { |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| deprecatedCmd := &Command{ |
| Use: "deprecated", |
| Deprecated: "This command is deprecated", |
| Run: emptyRun, |
| } |
| rootCmd.AddCommand(deprecatedCmd) |
| |
| output, err := executeCommand(rootCmd, "deprecated") |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| checkStringContains(t, output, deprecatedCmd.Deprecated) |
| } |
| |
| func TestHooks(t *testing.T) { |
| var ( |
| persPreArgs string |
| preArgs string |
| runArgs string |
| postArgs string |
| persPostArgs string |
| ) |
| |
| c := &Command{ |
| Use: "c", |
| PersistentPreRun: func(_ *Command, args []string) { |
| persPreArgs = strings.Join(args, " ") |
| }, |
| PreRun: func(_ *Command, args []string) { |
| preArgs = strings.Join(args, " ") |
| }, |
| Run: func(_ *Command, args []string) { |
| runArgs = strings.Join(args, " ") |
| }, |
| PostRun: func(_ *Command, args []string) { |
| postArgs = strings.Join(args, " ") |
| }, |
| PersistentPostRun: func(_ *Command, args []string) { |
| persPostArgs = strings.Join(args, " ") |
| }, |
| } |
| |
| output, err := executeCommand(c, "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| if persPreArgs != "one two" { |
| t.Errorf("Expected persPreArgs %q, got %q", "one two", persPreArgs) |
| } |
| if preArgs != "one two" { |
| t.Errorf("Expected preArgs %q, got %q", "one two", preArgs) |
| } |
| if runArgs != "one two" { |
| t.Errorf("Expected runArgs %q, got %q", "one two", runArgs) |
| } |
| if postArgs != "one two" { |
| t.Errorf("Expected postArgs %q, got %q", "one two", postArgs) |
| } |
| if persPostArgs != "one two" { |
| t.Errorf("Expected persPostArgs %q, got %q", "one two", persPostArgs) |
| } |
| } |
| |
| func TestPersistentHooks(t *testing.T) { |
| var ( |
| parentPersPreArgs string |
| parentPreArgs string |
| parentRunArgs string |
| parentPostArgs string |
| parentPersPostArgs string |
| ) |
| |
| var ( |
| childPersPreArgs string |
| childPreArgs string |
| childRunArgs string |
| childPostArgs string |
| childPersPostArgs string |
| ) |
| |
| parentCmd := &Command{ |
| Use: "parent", |
| PersistentPreRun: func(_ *Command, args []string) { |
| parentPersPreArgs = strings.Join(args, " ") |
| }, |
| PreRun: func(_ *Command, args []string) { |
| parentPreArgs = strings.Join(args, " ") |
| }, |
| Run: func(_ *Command, args []string) { |
| parentRunArgs = strings.Join(args, " ") |
| }, |
| PostRun: func(_ *Command, args []string) { |
| parentPostArgs = strings.Join(args, " ") |
| }, |
| PersistentPostRun: func(_ *Command, args []string) { |
| parentPersPostArgs = strings.Join(args, " ") |
| }, |
| } |
| |
| childCmd := &Command{ |
| Use: "child", |
| PersistentPreRun: func(_ *Command, args []string) { |
| childPersPreArgs = strings.Join(args, " ") |
| }, |
| PreRun: func(_ *Command, args []string) { |
| childPreArgs = strings.Join(args, " ") |
| }, |
| Run: func(_ *Command, args []string) { |
| childRunArgs = strings.Join(args, " ") |
| }, |
| PostRun: func(_ *Command, args []string) { |
| childPostArgs = strings.Join(args, " ") |
| }, |
| PersistentPostRun: func(_ *Command, args []string) { |
| childPersPostArgs = strings.Join(args, " ") |
| }, |
| } |
| parentCmd.AddCommand(childCmd) |
| |
| output, err := executeCommand(parentCmd, "child", "one", "two") |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| // TODO: This test fails, but should not. |
| // Related to https://github.com/spf13/cobra/issues/252. |
| // |
| // if parentPersPreArgs != "one two" { |
| // t.Errorf("Expected parentPersPreArgs %q, got %q", "one two", parentPersPreArgs) |
| // } |
| if parentPreArgs != "" { |
| t.Errorf("Expected blank parentPreArgs, got %q", parentPreArgs) |
| } |
| if parentRunArgs != "" { |
| t.Errorf("Expected blank parentRunArgs, got %q", parentRunArgs) |
| } |
| if parentPostArgs != "" { |
| t.Errorf("Expected blank parentPostArgs, got %q", parentPostArgs) |
| } |
| // TODO: This test fails, but should not. |
| // Related to https://github.com/spf13/cobra/issues/252. |
| // |
| // if parentPersPostArgs != "one two" { |
| // t.Errorf("Expected parentPersPostArgs %q, got %q", "one two", parentPersPostArgs) |
| // } |
| |
| if childPersPreArgs != "one two" { |
| t.Errorf("Expected childPersPreArgs %q, got %q", "one two", childPersPreArgs) |
| } |
| if childPreArgs != "one two" { |
| t.Errorf("Expected childPreArgs %q, got %q", "one two", childPreArgs) |
| } |
| if childRunArgs != "one two" { |
| t.Errorf("Expected childRunArgs %q, got %q", "one two", childRunArgs) |
| } |
| if childPostArgs != "one two" { |
| t.Errorf("Expected childPostArgs %q, got %q", "one two", childPostArgs) |
| } |
| if childPersPostArgs != "one two" { |
| t.Errorf("Expected childPersPostArgs %q, got %q", "one two", childPersPostArgs) |
| } |
| } |
| |
| // Related to https://github.com/spf13/cobra/issues/521. |
| func TestGlobalNormFuncPropagation(t *testing.T) { |
| normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName { |
| return pflag.NormalizedName(name) |
| } |
| |
| rootCmd := &Command{Use: "root", Run: emptyRun} |
| childCmd := &Command{Use: "child", Run: emptyRun} |
| rootCmd.AddCommand(childCmd) |
| |
| rootCmd.SetGlobalNormalizationFunc(normFunc) |
| if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() { |
| t.Error("rootCmd seems to have a wrong normalization function") |
| } |
| |
| if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(childCmd.GlobalNormalizationFunc()).Pointer() { |
| t.Error("childCmd should have had the normalization function of rootCmd") |
| } |
| } |
| |
| // Related to https://github.com/spf13/cobra/issues/521. |
| func TestNormPassedOnLocal(t *testing.T) { |
| toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { |
| return pflag.NormalizedName(strings.ToUpper(name)) |
| } |
| |
| c := &Command{} |
| c.Flags().Bool("flagname", true, "this is a dummy flag") |
| c.SetGlobalNormalizationFunc(toUpper) |
| if c.LocalFlags().Lookup("flagname") != c.LocalFlags().Lookup("FLAGNAME") { |
| t.Error("Normalization function should be passed on to Local flag set") |
| } |
| } |
| |
| // Related to https://github.com/spf13/cobra/issues/521. |
| func TestNormPassedOnInherited(t *testing.T) { |
| toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { |
| return pflag.NormalizedName(strings.ToUpper(name)) |
| } |
| |
| c := &Command{} |
| c.SetGlobalNormalizationFunc(toUpper) |
| |
| child1 := &Command{} |
| c.AddCommand(child1) |
| |
| c.PersistentFlags().Bool("flagname", true, "") |
| |
| child2 := &Command{} |
| c.AddCommand(child2) |
| |
| inherited := child1.InheritedFlags() |
| if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") { |
| t.Error("Normalization function should be passed on to inherited flag set in command added before flag") |
| } |
| |
| inherited = child2.InheritedFlags() |
| if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") { |
| t.Error("Normalization function should be passed on to inherited flag set in command added after flag") |
| } |
| } |
| |
| // Related to https://github.com/spf13/cobra/issues/521. |
| func TestConsistentNormalizedName(t *testing.T) { |
| toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { |
| return pflag.NormalizedName(strings.ToUpper(name)) |
| } |
| n := func(f *pflag.FlagSet, name string) pflag.NormalizedName { |
| return pflag.NormalizedName(name) |
| } |
| |
| c := &Command{} |
| c.Flags().Bool("flagname", true, "") |
| c.SetGlobalNormalizationFunc(toUpper) |
| c.SetGlobalNormalizationFunc(n) |
| |
| if c.LocalFlags().Lookup("flagname") == c.LocalFlags().Lookup("FLAGNAME") { |
| t.Error("Normalizing flag names should not result in duplicate flags") |
| } |
| } |
| |
| func TestFlagOnPflagCommandLine(t *testing.T) { |
| flagName := "flagOnCommandLine" |
| pflag.String(flagName, "", "about my flag") |
| |
| c := &Command{Use: "c", Run: emptyRun} |
| c.AddCommand(&Command{Use: "child", Run: emptyRun}) |
| |
| output, _ := executeCommand(c, "--help") |
| checkStringContains(t, output, flagName) |
| |
| resetCommandLineFlagSet() |
| } |
| |
| // TestHiddenCommandExecutes checks, |
| // if hidden commands run as intended. |
| func TestHiddenCommandExecutes(t *testing.T) { |
| executed := false |
| c := &Command{ |
| Use: "c", |
| Hidden: true, |
| Run: func(*Command, []string) { executed = true }, |
| } |
| |
| output, err := executeCommand(c) |
| if output != "" { |
| t.Errorf("Unexpected output: %v", output) |
| } |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| |
| if !executed { |
| t.Error("Hidden command should have been executed") |
| } |
| } |
| |
| // test to ensure hidden commands do not show up in usage/help text |
| func TestHiddenCommandIsHidden(t *testing.T) { |
| c := &Command{Use: "c", Hidden: true, Run: emptyRun} |
| if c.IsAvailableCommand() { |
| t.Errorf("Hidden command should be unavailable") |
| } |
| } |
| |
| func TestCommandsAreSorted(t *testing.T) { |
| EnableCommandSorting = true |
| |
| originalNames := []string{"middle", "zlast", "afirst"} |
| expectedNames := []string{"afirst", "middle", "zlast"} |
| |
| var rootCmd = &Command{Use: "root"} |
| |
| for _, name := range originalNames { |
| rootCmd.AddCommand(&Command{Use: name}) |
| } |
| |
| for i, c := range rootCmd.Commands() { |
| got := c.Name() |
| if expectedNames[i] != got { |
| t.Errorf("Expected: %s, got: %s", expectedNames[i], got) |
| } |
| } |
| |
| EnableCommandSorting = true |
| } |
| |
| func TestEnableCommandSortingIsDisabled(t *testing.T) { |
| EnableCommandSorting = false |
| |
| originalNames := []string{"middle", "zlast", "afirst"} |
| |
| var rootCmd = &Command{Use: "root"} |
| |
| for _, name := range originalNames { |
| rootCmd.AddCommand(&Command{Use: name}) |
| } |
| |
| for i, c := range rootCmd.Commands() { |
| got := c.Name() |
| if originalNames[i] != got { |
| t.Errorf("expected: %s, got: %s", originalNames[i], got) |
| } |
| } |
| |
| EnableCommandSorting = true |
| } |
| |
| func TestSetOutput(t *testing.T) { |
| c := &Command{} |
| c.SetOutput(nil) |
| if out := c.OutOrStdout(); out != os.Stdout { |
| t.Errorf("Expected setting output to nil to revert back to stdout") |
| } |
| } |
| |
| func TestFlagErrorFunc(t *testing.T) { |
| c := &Command{Use: "c", Run: emptyRun} |
| |
| expectedFmt := "This is expected: %v" |
| c.SetFlagErrorFunc(func(_ *Command, err error) error { |
| return fmt.Errorf(expectedFmt, err) |
| }) |
| |
| _, err := executeCommand(c, "--unknown-flag") |
| |
| got := err.Error() |
| expected := fmt.Sprintf(expectedFmt, "unknown flag: --unknown-flag") |
| if got != expected { |
| t.Errorf("Expected %v, got %v", expected, got) |
| } |
| } |
| |
| // TestSortedFlags checks, |
| // if cmd.LocalFlags() is unsorted when cmd.Flags().SortFlags set to false. |
| // Related to https://github.com/spf13/cobra/issues/404. |
| func TestSortedFlags(t *testing.T) { |
| c := &Command{} |
| c.Flags().SortFlags = false |
| names := []string{"C", "B", "A", "D"} |
| for _, name := range names { |
| c.Flags().Bool(name, false, "") |
| } |
| |
| i := 0 |
| c.LocalFlags().VisitAll(func(f *pflag.Flag) { |
| if i == len(names) { |
| return |
| } |
| if stringInSlice(f.Name, names) { |
| if names[i] != f.Name { |
| t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name) |
| } |
| i++ |
| } |
| }) |
| } |
| |
| // TestMergeCommandLineToFlags checks, |
| // if pflag.CommandLine is correctly merged to c.Flags() after first call |
| // of c.mergePersistentFlags. |
| // Related to https://github.com/spf13/cobra/issues/443. |
| func TestMergeCommandLineToFlags(t *testing.T) { |
| pflag.Bool("boolflag", false, "") |
| c := &Command{Use: "c", Run: emptyRun} |
| c.mergePersistentFlags() |
| if c.Flags().Lookup("boolflag") == nil { |
| t.Fatal("Expecting to have flag from CommandLine in c.Flags()") |
| } |
| |
| resetCommandLineFlagSet() |
| } |
| |
| // TestUseDeprecatedFlags checks, |
| // if cobra.Execute() prints a message, if a deprecated flag is used. |
| // Related to https://github.com/spf13/cobra/issues/463. |
| func TestUseDeprecatedFlags(t *testing.T) { |
| c := &Command{Use: "c", Run: emptyRun} |
| c.Flags().BoolP("deprecated", "d", false, "deprecated flag") |
| c.Flags().MarkDeprecated("deprecated", "This flag is deprecated") |
| |
| output, err := executeCommand(c, "c", "-d") |
| if err != nil { |
| t.Error("Unexpected error:", err) |
| } |
| checkStringContains(t, output, "This flag is deprecated") |
| } |
| |
| func TestTraverseWithParentFlags(t *testing.T) { |
| rootCmd := &Command{Use: "root", TraverseChildren: true} |
| rootCmd.Flags().String("str", "", "") |
| rootCmd.Flags().BoolP("bool", "b", false, "") |
| |
| childCmd := &Command{Use: "child"} |
| childCmd.Flags().Int("int", -1, "") |
| |
| rootCmd.AddCommand(childCmd) |
| |
| c, args, err := rootCmd.Traverse([]string{"-b", "--str", "ok", "child", "--int"}) |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| if len(args) != 1 && args[0] != "--add" { |
| t.Errorf("Wrong args: %v", args) |
| } |
| if c.Name() != childCmd.Name() { |
| t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name()) |
| } |
| } |
| |
| func TestTraverseNoParentFlags(t *testing.T) { |
| rootCmd := &Command{Use: "root", TraverseChildren: true} |
| rootCmd.Flags().String("foo", "", "foo things") |
| |
| childCmd := &Command{Use: "child"} |
| childCmd.Flags().String("str", "", "") |
| rootCmd.AddCommand(childCmd) |
| |
| c, args, err := rootCmd.Traverse([]string{"child"}) |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| if len(args) != 0 { |
| t.Errorf("Wrong args %v", args) |
| } |
| if c.Name() != childCmd.Name() { |
| t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name()) |
| } |
| } |
| |
| func TestTraverseWithBadParentFlags(t *testing.T) { |
| rootCmd := &Command{Use: "root", TraverseChildren: true} |
| |
| childCmd := &Command{Use: "child"} |
| childCmd.Flags().String("str", "", "") |
| rootCmd.AddCommand(childCmd) |
| |
| expected := "unknown flag: --str" |
| |
| c, _, err := rootCmd.Traverse([]string{"--str", "ok", "child"}) |
| if err == nil || !strings.Contains(err.Error(), expected) { |
| t.Errorf("Expected error, %q, got %q", expected, err) |
| } |
| if c != nil { |
| t.Errorf("Expected nil command") |
| } |
| } |
| |
| func TestTraverseWithBadChildFlag(t *testing.T) { |
| rootCmd := &Command{Use: "root", TraverseChildren: true} |
| rootCmd.Flags().String("str", "", "") |
| |
| childCmd := &Command{Use: "child"} |
| rootCmd.AddCommand(childCmd) |
| |
| // Expect no error because the last commands args shouldn't be parsed in |
| // Traverse. |
| c, args, err := rootCmd.Traverse([]string{"child", "--str"}) |
| if err != nil { |
| t.Errorf("Unexpected error: %v", err) |
| } |
| if len(args) != 1 && args[0] != "--str" { |
| t.Errorf("Wrong args: %v", args) |
| } |
| if c.Name() != childCmd.Name() { |
| t.Errorf("Expected command %q, got: %q", childCmd.Name(), c.Name()) |
| } |
| } |
| |
| func TestTraverseWithTwoSubcommands(t *testing.T) { |
| rootCmd := &Command{Use: "root", TraverseChildren: true} |
| |
| subCmd := &Command{Use: "sub", TraverseChildren: true} |
| rootCmd.AddCommand(subCmd) |
| |
| subsubCmd := &Command{ |
| Use: "subsub", |
| } |
| subCmd.AddCommand(subsubCmd) |
| |
| c, _, err := rootCmd.Traverse([]string{"sub", "subsub"}) |
| if err != nil { |
| t.Fatalf("Unexpected error: %v", err) |
| } |
| if c.Name() != subsubCmd.Name() { |
| t.Fatalf("Expected command: %q, got %q", subsubCmd.Name(), c.Name()) |
| } |
| } |
| |
| // TestUpdateName checks if c.Name() updates on changed c.Use. |
| // Related to https://github.com/spf13/cobra/pull/422#discussion_r143918343. |
| func TestUpdateName(t *testing.T) { |
| c := &Command{Use: "name xyz"} |
| originalName := c.Name() |
| |
| c.Use = "changedName abc" |
| if originalName == c.Name() || c.Name() != "changedName" { |
| t.Error("c.Name() should be updated on changed c.Use") |
| } |
| } |
| |
| type calledAsTestcase struct { |
| args []string |
| call string |
| want string |
| epm bool |
| tc bool |
| } |
| |
| func (tc *calledAsTestcase) test(t *testing.T) { |
| defer func(ov bool) { EnablePrefixMatching = ov }(EnablePrefixMatching) |
| EnablePrefixMatching = tc.epm |
| |
| var called *Command |
| run := func(c *Command, _ []string) { t.Logf("called: %q", c.Name()); called = c } |
| |
| parent := &Command{Use: "parent", Run: run} |
| child1 := &Command{Use: "child1", Run: run, Aliases: []string{"this"}} |
| child2 := &Command{Use: "child2", Run: run, Aliases: []string{"that"}} |
| |
| parent.AddCommand(child1) |
| parent.AddCommand(child2) |
| parent.SetArgs(tc.args) |
| |
| output := new(bytes.Buffer) |
| parent.SetOutput(output) |
| |
| parent.Execute() |
| |
| if called == nil { |
| if tc.call != "" { |
| t.Errorf("missing expected call to command: %s", tc.call) |
| } |
| return |
| } |
| |
| if called.Name() != tc.call { |
| t.Errorf("called command == %q; Wanted %q", called.Name(), tc.call) |
| } else if got := called.CalledAs(); got != tc.want { |
| t.Errorf("%s.CalledAs() == %q; Wanted: %q", tc.call, got, tc.want) |
| } |
| } |
| |
| func TestCalledAs(t *testing.T) { |
| tests := map[string]calledAsTestcase{ |
| "find/no-args": {nil, "parent", "parent", false, false}, |
| "find/real-name": {[]string{"child1"}, "child1", "child1", false, false}, |
| "find/full-alias": {[]string{"that"}, "child2", "that", false, false}, |
| "find/part-no-prefix": {[]string{"thi"}, "", "", false, false}, |
| "find/part-alias": {[]string{"thi"}, "child1", "this", true, false}, |
| "find/conflict": {[]string{"th"}, "", "", true, false}, |
| "traverse/no-args": {nil, "parent", "parent", false, true}, |
| "traverse/real-name": {[]string{"child1"}, "child1", "child1", false, true}, |
| "traverse/full-alias": {[]string{"that"}, "child2", "that", false, true}, |
| "traverse/part-no-prefix": {[]string{"thi"}, "", "", false, true}, |
| "traverse/part-alias": {[]string{"thi"}, "child1", "this", true, true}, |
| "traverse/conflict": {[]string{"th"}, "", "", true, true}, |
| } |
| |
| for name, tc := range tests { |
| t.Run(name, tc.test) |
| } |
| } |
| |
| func TestFParseErrWhitelistBackwardCompatibility(t *testing.T) { |
| c := &Command{Use: "c", Run: emptyRun} |
| c.Flags().BoolP("boola", "a", false, "a boolean flag") |
| |
| output, err := executeCommand(c, "c", "-a", "--unknown", "flag") |
| if err == nil { |
| t.Error("expected unknown flag error") |
| } |
| checkStringContains(t, output, "unknown flag: --unknown") |
| } |
| |
| func TestFParseErrWhitelistSameCommand(t *testing.T) { |
| c := &Command{ |
| Use: "c", |
| Run: emptyRun, |
| FParseErrWhitelist: FParseErrWhitelist{ |
| UnknownFlags: true, |
| }, |
| } |
| c.Flags().BoolP("boola", "a", false, "a boolean flag") |
| |
| _, err := executeCommand(c, "c", "-a", "--unknown", "flag") |
| if err != nil { |
| t.Error("unexpected error: ", err) |
| } |
| } |
| |
| func TestFParseErrWhitelistParentCommand(t *testing.T) { |
| root := &Command{ |
| Use: "root", |
| Run: emptyRun, |
| FParseErrWhitelist: FParseErrWhitelist{ |
| UnknownFlags: true, |
| }, |
| } |
| |
| c := &Command{ |
| Use: "child", |
| Run: emptyRun, |
| } |
| c.Flags().BoolP("boola", "a", false, "a boolean flag") |
| |
| root.AddCommand(c) |
| |
| output, err := executeCommand(root, "child", "-a", "--unknown", "flag") |
| if err == nil { |
| t.Error("expected unknown flag error") |
| } |
| checkStringContains(t, output, "unknown flag: --unknown") |
| } |
| |
| func TestFParseErrWhitelistChildCommand(t *testing.T) { |
| root := &Command{ |
| Use: "root", |
| Run: emptyRun, |
| } |
| |
| c := &Command{ |
| Use: "child", |
| Run: emptyRun, |
| FParseErrWhitelist: FParseErrWhitelist{ |
| UnknownFlags: true, |
| }, |
| } |
| c.Flags().BoolP("boola", "a", false, "a boolean flag") |
| |
| root.AddCommand(c) |
| |
| _, err := executeCommand(root, "child", "-a", "--unknown", "flag") |
| if err != nil { |
| t.Error("unexpected error: ", err.Error()) |
| } |
| } |
| |
| func TestFParseErrWhitelistSiblingCommand(t *testing.T) { |
| root := &Command{ |
| Use: "root", |
| Run: emptyRun, |
| } |
| |
| c := &Command{ |
| Use: "child", |
| Run: emptyRun, |
| FParseErrWhitelist: FParseErrWhitelist{ |
| UnknownFlags: true, |
| }, |
| } |
| c.Flags().BoolP("boola", "a", false, "a boolean flag") |
| |
| s := &Command{ |
| Use: "sibling", |
| Run: emptyRun, |
| } |
| s.Flags().BoolP("boolb", "b", false, "a boolean flag") |
| |
| root.AddCommand(c) |
| root.AddCommand(s) |
| |
| output, err := executeCommand(root, "sibling", "-b", "--unknown", "flag") |
| if err == nil { |
| t.Error("expected unknown flag error") |
| } |
| checkStringContains(t, output, "unknown flag: --unknown") |
| } |