diff --git a/command_run.go b/command_run.go index 578683da4a..9166ffbd5e 100644 --- a/command_run.go +++ b/command_run.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "io" - "reflect" "slices" "unicode" ) @@ -252,6 +251,7 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context if cmd.SuggestCommandFunc != nil && name != "--" { name = cmd.SuggestCommandFunc(cmd.Commands, name) + tracef("suggested command name=%1[q] (cmd=%[2]q)", name, cmd.Name) } subCmd = cmd.Command(name) if subCmd == nil { @@ -263,14 +263,13 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context } if isFlagName || hasDefault { - argsWithDefault := cmd.argsWithDefaultCommand(args) + argsWithDefault := cmd.argsWithDefaultCommand(cmd.parsedArgs) tracef("using default command args=%[1]q (cmd=%[2]q)", argsWithDefault, cmd.Name) - if !reflect.DeepEqual(args, argsWithDefault) { - subCmd = cmd.Command(argsWithDefault.First()) - } + subCmd = cmd.Command(argsWithDefault.First()) + cmd.parsedArgs = argsWithDefault } } - } else if cmd.parent == nil && cmd.DefaultCommand != "" { + } else if cmd.DefaultCommand != "" { tracef("no positional args present; checking default command %[1]q (cmd=%[2]q)", cmd.DefaultCommand, cmd.Name) if dc := cmd.Command(cmd.DefaultCommand); dc != cmd { diff --git a/command_test.go b/command_test.go index 424e8c0eda..efc64e9b56 100644 --- a/command_test.go +++ b/command_test.go @@ -814,37 +814,79 @@ func TestCommand_Command(t *testing.T) { var defaultCommandTests = []struct { cmdName string defaultCmd string + args []string errNotExpected bool }{ - {"foobar", "foobar", true}, - {"batbaz", "foobar", true}, - {"b", "", true}, - {"f", "", true}, - {"", "foobar", true}, - // TBD - //{"", "", true}, - //{" ", "", false}, - {"bat", "batbaz", true}, - {"nothing", "batbaz", true}, - {"nothing", "", false}, + {"foobar", "foobar", nil, true}, + {"batbaz", "foobar", nil, true}, + {"b", "", nil, true}, + {"f", "", nil, true}, + {"", "foobar", nil, true}, + {"", "", nil, true}, + {" ", "", nil, true}, + {"bat", "batbaz", nil, true}, + {"nothing", "batbaz", nil, true}, + {"nothing", "", nil, false}, + {"foobar", "foobar", []string{"xy", "zdf"}, true}, + {"", "foobar", []string{"xy", "zdf"}, true}, } func TestCommand_RunDefaultCommand(t *testing.T) { for _, test := range defaultCommandTests { - testTitle := fmt.Sprintf("command=%[1]s-default=%[2]s", test.cmdName, test.defaultCmd) + testTitle := fmt.Sprintf("command=%[1]s-default=%[2]s-args=%[3]v", test.cmdName, test.defaultCmd, test.args) t.Run(testTitle, func(t *testing.T) { + fooCount := 0 + var fooArgs Args + barCount := 0 cmd := &Command{ DefaultCommand: test.defaultCmd, Commands: []*Command{ - {Name: "foobar", Aliases: []string{"f"}}, - {Name: "batbaz", Aliases: []string{"b"}}, + { + Name: "foobar", + Aliases: []string{"f"}, + Action: func(ctx context.Context, c *Command) error { + fooCount++ + fooArgs = c.Args() + return nil + }, + }, + { + Name: "batbaz", + Aliases: []string{"b"}, + Action: func(ctx context.Context, c *Command) error { + barCount++ + return nil + }, + }, }, } - err := cmd.Run(buildTestContext(t), []string{"c", test.cmdName}) + runArgs := []string{"c"} + if test.cmdName != "" { + runArgs = append(runArgs, test.cmdName) + } + if test.args != nil { + runArgs = append(runArgs, test.args...) + } + err := cmd.Run(buildTestContext(t), runArgs) if test.errNotExpected { assert.NoError(t, err) + if fooCount == 0 && barCount == 0 && test.defaultCmd != "" { + t.Errorf("expected one of the commands to run") + } + if fooCount > 0 { + expectedArgs := &stringSliceArgs{v: []string{}} + if len(test.args) > 0 && (test.args[0] == "foobar" || test.args[0] == "f") { + expectedArgs = &stringSliceArgs{v: test.args[1:]} + } else if test.args != nil { + expectedArgs = &stringSliceArgs{v: test.args} + } + assert.Equal(t, expectedArgs, fooArgs) + } } else { + if fooCount > 0 || barCount > 0 { + t.Errorf("expected no commands to run") + } assert.Error(t, err) } }) @@ -867,14 +909,14 @@ var defaultCommandSubCommandTests = []struct { {"", "jimbob", "foobar", true}, {"", "j", "foobar", true}, {"", "carly", "foobar", true}, - {"", "jimmers", "foobar", true}, - {"", "jimmers", "", true}, + {"", "jimmers", "foobar", false}, + {"", "jimmers", "", false}, {" ", "jimmers", "foobar", true}, - /*{"", "", "", true}, - {" ", "", "", false}, - {" ", "j", "", false},*/ - {"bat", "", "batbaz", true}, - {"nothing", "", "batbaz", true}, + {"", "", "", true}, + {" ", "", "", true}, + {" ", "j", "", true}, + {"bat", "", "batbaz", false}, + {"nothing", "", "batbaz", false}, {"nothing", "", "", false}, {"nothing", "j", "batbaz", false}, {"nothing", "carly", "", false}, @@ -899,7 +941,14 @@ func TestCommand_RunDefaultCommandWithSubCommand(t *testing.T) { }, } - err := cmd.Run(buildTestContext(t), []string{"c", test.cmdName, test.subCmd}) + runArgs := []string{"c"} + if test.cmdName != "" { + runArgs = append(runArgs, test.cmdName) + } + if test.subCmd != "" { + runArgs = append(runArgs, test.subCmd) + } + err := cmd.Run(buildTestContext(t), runArgs) if test.errNotExpected { assert.NoError(t, err) } else { @@ -932,10 +981,10 @@ var defaultCommandFlagTests = []struct { {"", "", "", true}, {" ", "", "", true}, {" ", "-j", "", true}, - {"bat", "", "batbaz", true}, - {"nothing", "", "batbaz", true}, + {"bat", "", "batbaz", false}, + {"nothing", "", "batbaz", false}, {"nothing", "", "", false}, - {"nothing", "--jimbob", "batbaz", true}, + {"nothing", "--jimbob", "batbaz", false}, {"nothing", "--carly", "", false}, }