|
@@ -0,0 +1,1733 @@
|
|
|
+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")
|
|
|
+}
|