diff --git a/README.md b/README.md index a5102eb..5e73ffe 100644 --- a/README.md +++ b/README.md @@ -389,6 +389,7 @@ The following validators are built in: - `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. +- `ExactValidArgs(int)` = the command will report and error if there are not exactly N positional args OR if there are any positional args that are not in the `ValidArgs` field of `Command` - `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args. An example of setting the custom validator: diff --git a/args.go b/args.go index a5d8a92..c4d820b 100644 --- a/args.go +++ b/args.go @@ -78,6 +78,18 @@ func ExactArgs(n int) PositionalArgs { } } +// ExactValidArgs returns an error if +// there are not exactly N positional args OR +// there are any positional args that are not in the `ValidArgs` field of `Command` +func ExactValidArgs(n int) PositionalArgs { + return func(cmd *Command, args []string) error { + if err := ExactArgs(n)(cmd, args); err != nil { + return err + } + return OnlyValidArgs(cmd, args) + } +} + // RangeArgs returns an error if the number of args is not within the expected range. func RangeArgs(min int, max int) PositionalArgs { return func(cmd *Command, args []string) error { diff --git a/args_test.go b/args_test.go index d797b6f..c81b212 100644 --- a/args_test.go +++ b/args_test.go @@ -158,6 +158,52 @@ func TestExactArgsWithInvalidCount(t *testing.T) { } } +func TestExactValidArgs(t *testing.T) { + c := &Command{Use: "c", Args: ExactValidArgs(3), ValidArgs: []string{"a", "b", "c"}, Run: emptyRun} + output, err := executeCommand(c, "a", "b", "c") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } +} + +func TestExactValidArgsWithInvalidCount(t *testing.T) { + c := &Command{Use: "c", Args: ExactValidArgs(2), Run: emptyRun} + _, err := executeCommand(c, "a", "b", "c") + + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := "accepts 2 arg(s), received 3" + if got != expected { + t.Fatalf("Expected %q, got %q", expected, got) + } +} + +func TestExactValidArgsWithInvalidArgs(t *testing.T) { + c := &Command{ + Use: "c", + Args: ExactValidArgs(1), + ValidArgs: []string{"one", "two"}, + Run: emptyRun, + } + + _, err := executeCommand(c, "three") + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := `invalid argument "three" for "c"` + if got != expected { + t.Errorf("Expected: %q, got: %q", expected, got) + } +} + func TestRangeArgs(t *testing.T) { c := &Command{Use: "c", Args: RangeArgs(2, 4), Run: emptyRun} output, err := executeCommand(c, "a", "b", "c")