Skip to content

Commit a03136b

Browse files
nelz9999umarcor
authored andcommitted
add MatchAll: enable composing PositionalArgs (spf13#896)
1 parent 4f7a2c9 commit a03136b

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ of `Command`. The following validators are built in:
421421
- `MaximumNArgs(int)` - report an error if more than N positional args are provided.
422422
- `ExactArgs(int)` - report an error if there are not exactly N positional args.
423423
- `RangeArgs(min, max)` - report an error if the number of args is not between `min` and `max`.
424+
- `MatchAll(pargs ...PositionalArgs)` - enables combining existing checks with arbitrary other checks (e.g. you want to check the ExactArgs length along with other qualities).
424425

425426
If `Args` is undefined or `nil`, it defaults to `ArbitraryArgs`.
426427

args.go

+12
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,18 @@ func RangeArgs(min int, max int) PositionalArgs {
8989
}
9090
}
9191

92+
// MatchAll allows combining several PositionalArgs to work in concert.
93+
func MatchAll(pargs ...PositionalArgs) PositionalArgs {
94+
return func(cmd *Command, args []string) error {
95+
for _, parg := range pargs {
96+
if err := parg(cmd, args); err != nil {
97+
return err
98+
}
99+
}
100+
return nil
101+
}
102+
}
103+
92104
// ExactValidArgs returns an error if there are not exactly N positional args OR
93105
// there are any positional args that are not in the `ValidArgs` field of `Command`
94106
//

args_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cobra
22

33
import (
4+
"fmt"
45
"strings"
56
"testing"
67
)
@@ -184,3 +185,51 @@ func TestChildTakesArgs(t *testing.T) {
184185
t.Fatalf("Unexpected error: %v", err)
185186
}
186187
}
188+
189+
func TestMatchAll(t *testing.T) {
190+
// Somewhat contrived example check that ensures there are exactly 3
191+
// arguments, and each argument is exactly 2 bytes long.
192+
pargs := MatchAll(
193+
ExactArgs(3),
194+
func(cmd *Command, args []string) error {
195+
for _, arg := range args {
196+
if len([]byte(arg)) != 2 {
197+
return fmt.Errorf("expected to be exactly 2 bytes long")
198+
}
199+
}
200+
return nil
201+
},
202+
)
203+
204+
testCases := map[string]struct {
205+
args []string
206+
fail bool
207+
}{
208+
"happy path": {
209+
[]string{"aa", "bb", "cc"},
210+
false,
211+
},
212+
"incorrect number of args": {
213+
[]string{"aa", "bb", "cc", "dd"},
214+
true,
215+
},
216+
"incorrect number of bytes in one arg": {
217+
[]string{"aa", "bb", "abc"},
218+
true,
219+
},
220+
}
221+
222+
rootCmd := &Command{Use: "root", Args: pargs, Run: emptyRun}
223+
224+
for name, tc := range testCases {
225+
t.Run(name, func(t *testing.T) {
226+
_, err := executeCommand(rootCmd, tc.args...)
227+
if err != nil && !tc.fail {
228+
t.Errorf("unexpected: %v\n", err)
229+
}
230+
if err == nil && tc.fail {
231+
t.Errorf("expected error")
232+
}
233+
})
234+
}
235+
}

0 commit comments

Comments
 (0)