diff --git a/README.md b/README.md index 851fcc08..8f10e778 100644 --- a/README.md +++ b/README.md @@ -392,6 +392,7 @@ The following validators are built in: - `NoArgs` - the command will report an error if there are any positional args. - `ArbitraryArgs` - the command will accept any args. - `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`. +- `OnlySubCommands` - the command will report an error if if any args are included except for subcommands. - `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args. - `MaximumNArgs(int)` - the command will report an error if there are more than N positional args. - `ExactArgs(int)` - the command will report an error if there are not exactly N positional args. diff --git a/args.go b/args.go index a5d8a927..423d1f90 100644 --- a/args.go +++ b/args.go @@ -43,6 +43,17 @@ func OnlyValidArgs(cmd *Command, args []string) error { return nil } +// OnlySubCommands returns an error if any args are included except for subcommands. +func OnlySubCommands(cmd *Command, args []string) error { + if !cmd.HasSubCommands() { + return nil + } + if len(args) > 0 { + return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])) + } + return nil +} + // ArbitraryArgs never returns an error. func ArbitraryArgs(cmd *Command, args []string) error { return nil diff --git a/args_test.go b/args_test.go index d797b6f5..92a6482f 100644 --- a/args_test.go +++ b/args_test.go @@ -69,6 +69,46 @@ func TestOnlyValidArgsWithInvalidArgs(t *testing.T) { } } +func TestOnlySubCommandsArgs(t *testing.T) { + rootCmd := &Command{ + Use: "root", + Args: OnlySubCommands, + Run: emptyRun, + } + subCmd := &Command{Use: "sub", Run: emptyRun} + rootCmd.AddCommand(subCmd) + + output, err := executeCommand(rootCmd, "sub") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } +} + +func TestOnlySubCommandsArgsWithInvalidArgs(t *testing.T) { + rootCmd := &Command{ + Use: "root", + Args: OnlySubCommands, + Run: emptyRun, + } + subCmd := &Command{Use: "sub", Run: emptyRun} + rootCmd.AddCommand(subCmd) + + _, err := executeCommand(rootCmd, "notsub") + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := `unknown command "notsub" for "root"` + if got != expected { + t.Errorf("Expected: %q, got: %q", expected, got) + } +} + func TestArbitraryArgs(t *testing.T) { c := &Command{Use: "c", Args: ArbitraryArgs, Run: emptyRun} output, err := executeCommand(c, "a", "b")