test combinations of args validators

This commit is contained in:
umarcor 2019-03-18 23:32:12 +01:00
parent 45b20e4ecd
commit ec474022ff
3 changed files with 227 additions and 24 deletions

View file

@ -32,7 +32,8 @@ func NoArgs(cmd *Command, args []string) error {
return nil return nil
} }
// OnlyValidArgs returns an error if any args are not in the list of ValidArgs. // OnlyValidArgs returns an error if there are any positional args that are not in
// the `ValidArgs` field of `Command`
func OnlyValidArgs(cmd *Command, args []string) error { func OnlyValidArgs(cmd *Command, args []string) error {
if len(cmd.ValidArgs) > 0 { if len(cmd.ValidArgs) > 0 {
// Remove any description that may be included in ValidArgs. // Remove any description that may be included in ValidArgs.
@ -41,7 +42,6 @@ func OnlyValidArgs(cmd *Command, args []string) error {
for _, v := range cmd.ValidArgs { for _, v := range cmd.ValidArgs {
validArgs = append(validArgs, strings.Split(v, "\t")[0]) validArgs = append(validArgs, strings.Split(v, "\t")[0])
} }
for _, v := range args { for _, v := range args {
if !stringInSlice(v, validArgs) { if !stringInSlice(v, validArgs) {
return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0])) return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0]))

View file

@ -27,7 +27,7 @@ func expectSuccess(output string, err error, t *testing.T) {
} }
} }
func validWithInvalidArgs(err error, t *testing.T) { func validOnlyWithInvalidArgs(err error, t *testing.T) {
if err == nil { if err == nil {
t.Fatal("Expected an error") t.Fatal("Expected an error")
} }
@ -43,7 +43,7 @@ func noArgsWithArgs(err error, t *testing.T) {
t.Fatal("Expected an error") t.Fatal("Expected an error")
} }
got := err.Error() got := err.Error()
expected := `unknown command "illegal" for "c"` expected := `unknown command "one" for "c"`
if got != expected { if got != expected {
t.Errorf("Expected: %q, got: %q", expected, got) t.Errorf("Expected: %q, got: %q", expected, got)
} }
@ -93,84 +93,280 @@ func rangeArgsWithInvalidCount(err error, t *testing.T) {
} }
} }
// NoArgs
func TestNoArgs(t *testing.T) { func TestNoArgs(t *testing.T) {
c := getCommand(NoArgs, false) c := getCommand(NoArgs, false)
output, err := executeCommand(c) output, err := executeCommand(c)
expectSuccess(output, err, t) expectSuccess(output, err, t)
} }
func TestNoArgsWithArgs(t *testing.T) { func TestNoArgs_WithArgs(t *testing.T) {
c := getCommand(NoArgs, false) c := getCommand(NoArgs, false)
_, err := executeCommand(c, "illegal") _, err := executeCommand(c, "one")
noArgsWithArgs(err, t) noArgsWithArgs(err, t)
} }
func TestNoArgs_WithValid_WithArgs(t *testing.T) {
c := getCommand(NoArgs, true)
_, err := executeCommand(c, "one")
noArgsWithArgs(err, t)
}
func TestNoArgs_WithValid_WithInvalidArgs(t *testing.T) {
c := getCommand(NoArgs, true)
_, err := executeCommand(c, "one")
noArgsWithArgs(err, t)
}
func TestNoArgs_WithValidOnly_WithInvalidArgs(t *testing.T) {
c := getCommand(MatchAll(OnlyValidArgs, NoArgs), true)
_, err := executeCommand(c, "a")
validOnlyWithInvalidArgs(err, t)
}
// OnlyValidArgs
func TestOnlyValidArgs(t *testing.T) { func TestOnlyValidArgs(t *testing.T) {
c := getCommand(OnlyValidArgs, true) c := getCommand(OnlyValidArgs, true)
output, err := executeCommand(c, "one", "two") output, err := executeCommand(c, "one", "two")
expectSuccess(output, err, t) expectSuccess(output, err, t)
} }
func TestOnlyValidArgsWithInvalidArgs(t *testing.T) { func TestOnlyValidArgs_WithInvalidArgs(t *testing.T) {
c := getCommand(OnlyValidArgs, true) c := getCommand(OnlyValidArgs, true)
_, err := executeCommand(c, "a") _, err := executeCommand(c, "a")
validWithInvalidArgs(err, t) validOnlyWithInvalidArgs(err, t)
} }
// ArbitraryArgs
func TestArbitraryArgs(t *testing.T) { func TestArbitraryArgs(t *testing.T) {
c := getCommand(ArbitraryArgs, false) c := getCommand(ArbitraryArgs, false)
output, err := executeCommand(c, "a", "b") output, err := executeCommand(c, "a", "b")
expectSuccess(output, err, t) expectSuccess(output, err, t)
} }
func TestArbitraryArgs_WithValid(t *testing.T) {
c := getCommand(ArbitraryArgs, true)
output, err := executeCommand(c, "one", "two")
expectSuccess(output, err, t)
}
func TestArbitraryArgs_WithValid_WithInvalidArgs(t *testing.T) {
c := getCommand(ArbitraryArgs, true)
output, err := executeCommand(c, "a")
expectSuccess(output, err, t)
}
func TestArbitraryArgs_WithValidOnly_WithInvalidArgs(t *testing.T) {
c := getCommand(MatchAll(OnlyValidArgs, ArbitraryArgs), true)
_, err := executeCommand(c, "a")
validOnlyWithInvalidArgs(err, t)
}
// MinimumNArgs
func TestMinimumNArgs(t *testing.T) { func TestMinimumNArgs(t *testing.T) {
c := getCommand(MinimumNArgs(2), false) c := getCommand(MinimumNArgs(2), false)
output, err := executeCommand(c, "a", "b", "c") output, err := executeCommand(c, "a", "b", "c")
expectSuccess(output, err, t) expectSuccess(output, err, t)
} }
func TestMinimumNArgsWithLessArgs(t *testing.T) { func TestMinimumNArgs_WithValid(t *testing.T) {
c := getCommand(MinimumNArgs(2), true)
output, err := executeCommand(c, "one", "three")
expectSuccess(output, err, t)
}
func TestMinimumNArgs_WithValid__WithInvalidArgs(t *testing.T) {
c := getCommand(MinimumNArgs(2), true)
output, err := executeCommand(c, "a", "b")
expectSuccess(output, err, t)
}
func TestMinimumNArgs_WithValidOnly_WithInvalidArgs(t *testing.T) {
c := getCommand(MatchAll(OnlyValidArgs, MinimumNArgs(2)), true)
_, err := executeCommand(c, "a", "b")
validOnlyWithInvalidArgs(err, t)
}
func TestMinimumNArgs_WithLessArgs(t *testing.T) {
c := getCommand(MinimumNArgs(2), false) c := getCommand(MinimumNArgs(2), false)
_, err := executeCommand(c, "a") _, err := executeCommand(c, "a")
minimumNArgsWithLessArgs(err, t) minimumNArgsWithLessArgs(err, t)
} }
func TestMinimumNArgs_WithLessArgs_WithValid(t *testing.T) {
c := getCommand(MinimumNArgs(2), true)
_, err := executeCommand(c, "one")
minimumNArgsWithLessArgs(err, t)
}
func TestMinimumNArgs_WithLessArgs_WithValid_WithInvalidArgs(t *testing.T) {
c := getCommand(MinimumNArgs(2), true)
_, err := executeCommand(c, "a")
minimumNArgsWithLessArgs(err, t)
}
func TestMinimumNArgs_WithLessArgs_WithValidOnly_WithInvalidArgs(t *testing.T) {
c := getCommand(MatchAll(OnlyValidArgs, MinimumNArgs(2)), true)
_, err := executeCommand(c, "a")
validOnlyWithInvalidArgs(err, t)
}
// MaximumNArgs
func TestMaximumNArgs(t *testing.T) { func TestMaximumNArgs(t *testing.T) {
c := getCommand(MaximumNArgs(3), false) c := getCommand(MaximumNArgs(3), false)
output, err := executeCommand(c, "a", "b") output, err := executeCommand(c, "a", "b")
expectSuccess(output, err, t) expectSuccess(output, err, t)
} }
func TestMaximumNArgsWithMoreArgs(t *testing.T) { func TestMaximumNArgs_WithValid(t *testing.T) {
c := getCommand(MaximumNArgs(2), true)
output, err := executeCommand(c, "one", "three")
expectSuccess(output, err, t)
}
func TestMaximumNArgs_WithValid_WithInvalidArgs(t *testing.T) {
c := getCommand(MaximumNArgs(2), true)
output, err := executeCommand(c, "a", "b")
expectSuccess(output, err, t)
}
func TestMaximumNArgs_WithValidOnly_WithInvalidArgs(t *testing.T) {
c := getCommand(MatchAll(OnlyValidArgs, MaximumNArgs(2)), true)
_, err := executeCommand(c, "a", "b")
validOnlyWithInvalidArgs(err, t)
}
func TestMaximumNArgs_WithMoreArgs(t *testing.T) {
c := getCommand(MaximumNArgs(2), false) c := getCommand(MaximumNArgs(2), false)
_, err := executeCommand(c, "a", "b", "c") _, err := executeCommand(c, "a", "b", "c")
maximumNArgsWithMoreArgs(err, t) maximumNArgsWithMoreArgs(err, t)
} }
func TestMaximumNArgs_WithMoreArgs_WithValid(t *testing.T) {
c := getCommand(MaximumNArgs(2), true)
_, err := executeCommand(c, "one", "three", "two")
maximumNArgsWithMoreArgs(err, t)
}
func TestMaximumNArgs_WithMoreArgs_WithValid_WithInvalidArgs(t *testing.T) {
c := getCommand(MaximumNArgs(2), true)
_, err := executeCommand(c, "a", "b", "c")
maximumNArgsWithMoreArgs(err, t)
}
func TestMaximumNArgs_WithMoreArgs_WithValidOnly_WithInvalidArgs(t *testing.T) {
c := getCommand(MatchAll(OnlyValidArgs, MaximumNArgs(2)), true)
_, err := executeCommand(c, "a", "b", "c")
validOnlyWithInvalidArgs(err, t)
}
// ExactArgs
func TestExactArgs(t *testing.T) { func TestExactArgs(t *testing.T) {
c := getCommand(ExactArgs(3), false) c := getCommand(ExactArgs(3), false)
output, err := executeCommand(c, "a", "b", "c") output, err := executeCommand(c, "a", "b", "c")
expectSuccess(output, err, t) expectSuccess(output, err, t)
} }
func TestExactArgsWithInvalidCount(t *testing.T) { func TestExactArgs_WithValid(t *testing.T) {
c := getCommand(ExactArgs(3), true)
output, err := executeCommand(c, "three", "one", "two")
expectSuccess(output, err, t)
}
func TestExactArgs_WithValid_WithInvalidArgs(t *testing.T) {
c := getCommand(ExactArgs(3), true)
output, err := executeCommand(c, "three", "a", "two")
expectSuccess(output, err, t)
}
func TestExactArgs_WithValidOnly_WithInvalidArgs(t *testing.T) {
c := getCommand(MatchAll(OnlyValidArgs, ExactArgs(3)), true)
_, err := executeCommand(c, "three", "a", "two")
validOnlyWithInvalidArgs(err, t)
}
func TestExactArgs_WithInvalidCount(t *testing.T) {
c := getCommand(ExactArgs(2), false) c := getCommand(ExactArgs(2), false)
_, err := executeCommand(c, "a", "b", "c") _, err := executeCommand(c, "a", "b", "c")
exactArgsWithInvalidCount(err, t) exactArgsWithInvalidCount(err, t)
} }
func TestExactArgs_WithInvalidCount_WithValid(t *testing.T) {
c := getCommand(ExactArgs(2), true)
_, err := executeCommand(c, "three", "one", "two")
exactArgsWithInvalidCount(err, t)
}
func TestExactArgs_WithInvalidCount_WithValid_WithInvalidArgs(t *testing.T) {
c := getCommand(ExactArgs(2), true)
_, err := executeCommand(c, "three", "a", "two")
exactArgsWithInvalidCount(err, t)
}
func TestExactArgs_WithInvalidCount_WithValidOnly_WithInvalidArgs(t *testing.T) {
c := getCommand(MatchAll(OnlyValidArgs, ExactArgs(2)), true)
_, err := executeCommand(c, "three", "a", "two")
validOnlyWithInvalidArgs(err, t)
}
// RangeArgs
func TestRangeArgs(t *testing.T) { func TestRangeArgs(t *testing.T) {
c := getCommand(RangeArgs(2, 4), false) c := getCommand(RangeArgs(2, 4), false)
output, err := executeCommand(c, "a", "b", "c") output, err := executeCommand(c, "a", "b", "c")
expectSuccess(output, err, t) expectSuccess(output, err, t)
} }
func TestRangeArgsWithInvalidCount(t *testing.T) { func TestRangeArgs_WithValid(t *testing.T) {
c := getCommand(RangeArgs(2, 4), true)
output, err := executeCommand(c, "three", "one", "two")
expectSuccess(output, err, t)
}
func TestRangeArgs_WithValid_WithInvalidArgs(t *testing.T) {
c := getCommand(RangeArgs(2, 4), true)
output, err := executeCommand(c, "three", "a", "two")
expectSuccess(output, err, t)
}
func TestRangeArgs_WithValidOnly_WithInvalidArgs(t *testing.T) {
c := getCommand(MatchAll(OnlyValidArgs, RangeArgs(2, 4)), true)
_, err := executeCommand(c, "three", "a", "two")
validOnlyWithInvalidArgs(err, t)
}
func TestRangeArgs_WithInvalidCount(t *testing.T) {
c := getCommand(RangeArgs(2, 4), false) c := getCommand(RangeArgs(2, 4), false)
_, err := executeCommand(c, "a") _, err := executeCommand(c, "a")
rangeArgsWithInvalidCount(err, t) rangeArgsWithInvalidCount(err, t)
} }
func TestRangeArgs_WithInvalidCount_WithValid(t *testing.T) {
c := getCommand(RangeArgs(2, 4), true)
_, err := executeCommand(c, "two")
rangeArgsWithInvalidCount(err, t)
}
func TestRangeArgs_WithInvalidCount_WithValid_WithInvalidArgs(t *testing.T) {
c := getCommand(RangeArgs(2, 4), true)
_, err := executeCommand(c, "a")
rangeArgsWithInvalidCount(err, t)
}
func TestRangeArgs_WithInvalidCount_WithValidOnly_WithInvalidArgs(t *testing.T) {
c := getCommand(MatchAll(OnlyValidArgs, RangeArgs(2, 4)), true)
_, err := executeCommand(c, "a")
validOnlyWithInvalidArgs(err, t)
}
// Takes(No)Args
func TestRootTakesNoArgs(t *testing.T) { func TestRootTakesNoArgs(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun} rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{Use: "child", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun}
@ -283,16 +479,22 @@ func TestExactValidArgs(t *testing.T) {
expectSuccess(output, err, t) expectSuccess(output, err, t)
} }
func TestExactValidArgsWithInvalidCount(t *testing.T) { func TestExactValidArgs_WithInvalidCount(t *testing.T) {
c := getCommand(ExactValidArgs(2), false) c := getCommand(ExactValidArgs(2), false)
_, err := executeCommand(c, "three", "one", "two") _, err := executeCommand(c, "three", "one", "two")
exactArgsWithInvalidCount(err, t) exactArgsWithInvalidCount(err, t)
} }
func TestExactValidArgsWithInvalidArgs(t *testing.T) { func TestExactValidArgs_WithInvalidCount_WithInvalidArgs(t *testing.T) {
c := getCommand(ExactValidArgs(3), true) c := getCommand(ExactValidArgs(3), true)
_, err := executeCommand(c, "three", "a", "two") _, err := executeCommand(c, "three", "a", "two")
validWithInvalidArgs(err, t) validOnlyWithInvalidArgs(err, t)
}
func TestExactValidArgs_WithInvalidArgs(t *testing.T) {
c := getCommand(ExactValidArgs(3), true)
_, err := executeCommand(c, "three", "a")
validOnlyWithInvalidArgs(err, t)
} }
// This test make sure we keep backwards-compatibility with respect // This test make sure we keep backwards-compatibility with respect

View file

@ -327,8 +327,6 @@ In both of these cases:
## Positional and Custom Arguments ## Positional and Custom Arguments
Validation of positional arguments can be specified using the `Args` field of `Command`. Validation of positional arguments can be specified using the `Args` field of `Command`.
If `Args` is undefined or `nil`, it defaults to `ArbitraryArgs`.
The following validators are built in: The following validators are built in:
- Number of arguments: - Number of arguments:
@ -339,8 +337,9 @@ The following validators are built in:
- `ExactArgs(int)` - report an error if there are not exactly N positional args. - `ExactArgs(int)` - report an error if there are not exactly N positional args.
- `RangeArgs(min, max)` - report an error if the number of args is not between `min` and `max`. - `RangeArgs(min, max)` - report an error if the number of args is not between `min` and `max`.
- Content of the arguments: - Content of the arguments:
- `OnlyValidArgs` - report an error if there are any positional args that are not in the `ValidArgs` field of type - `OnlyValidArgs` - report an error if there are any positional args not specified in the `ValidArgs` field of `Command`, which can optionally be set to a list of valid values for positional args.
`[]string` defined in `Command`.
If `Args` is undefined or `nil`, it defaults to `ArbitraryArgs`.
Moreover, `MatchAll(pargs ...PositionalArgs)` enables combining existing checks with arbitrary other checks. Moreover, `MatchAll(pargs ...PositionalArgs)` enables combining existing checks with arbitrary other checks.
For instance, if you want to report an error if there are not exactly N positional args OR if there are any positional For instance, if you want to report an error if there are not exactly N positional args OR if there are any positional
@ -364,9 +363,11 @@ For example:
var cmd = &cobra.Command{ var cmd = &cobra.Command{
Short: "hello", Short: "hello",
Args: func(cmd *cobra.Command, args []string) error { Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 { // Optionally run one of the validators provided by cobra
return errors.New("requires a color argument") if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {
return err
} }
// Run the custom validation logic
if myapp.IsValidColor(args[0]) { if myapp.IsValidColor(args[0]) {
return nil return nil
} }