Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions args.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ func OnlyValidArgs(cmd *Command, args []string) error {
return nil
}

// NoDuplicateArgs returns an error if there are any duplicate positional args.
func NoDuplicateArgs(cmd *Command, args []string) error {
seen := make(map[string]struct{}, len(args))
for _, arg := range args {
if _, ok := seen[arg]; ok {
return fmt.Errorf("duplicate argument %q for %q", arg, cmd.CommandPath())
}
seen[arg] = struct{}{}
}

return nil
}

// ArbitraryArgs never returns an error.
func ArbitraryArgs(cmd *Command, args []string) error {
return nil
Expand Down
37 changes: 37 additions & 0 deletions args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,17 @@ func rangeArgsWithInvalidCount(err error, t *testing.T) {
}
}

func noDuplicateArgsWithDuplicate(err error, t *testing.T, arg string) {
if err == nil {
t.Fatal("Expected an error")
}
got := err.Error()
expected := `duplicate argument "` + arg + `" for "c"`
if got != expected {
t.Errorf("Expected: %q, got: %q", expected, got)
}
}

// NoArgs

func TestNoArgs(t *testing.T) {
Expand Down Expand Up @@ -153,6 +164,32 @@ func TestOnlyValidArgs_WithInvalidArgs(t *testing.T) {
validOnlyWithInvalidArgs(err, t)
}

// NoDuplicateArgs

func TestNoDuplicateArgs(t *testing.T) {
c := getCommand(NoDuplicateArgs, false)
output, err := executeCommand(c, "one", "two")
expectSuccess(output, err, t)
}

func TestNoDuplicateArgs_WithDuplicateArgs(t *testing.T) {
c := getCommand(NoDuplicateArgs, false)
_, err := executeCommand(c, "one", "one")
noDuplicateArgsWithDuplicate(err, t, "one")
}

func TestNoDuplicateArgs_WithValid_WithDuplicateArgs(t *testing.T) {
c := getCommand(NoDuplicateArgs, true)
_, err := executeCommand(c, "one", "one")
noDuplicateArgsWithDuplicate(err, t, "one")
}

func TestNoDuplicateArgs_WithValidOnly_WithInvalidArgs(t *testing.T) {
c := getCommand(MatchAll(OnlyValidArgs, NoDuplicateArgs), true)
_, err := executeCommand(c, "a", "a")
validOnlyWithInvalidArgs(err, t)
}

// ArbitraryArgs

func TestArbitraryArgs(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions site/content/user_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ The following validators are built in:
- `RangeArgs(min, max)` - report an error if the number of args is not between `min` and `max`.
- Content of the arguments:
- `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.
- `NoDuplicateArgs` - report an error if any positional argument value is provided more than once.

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

Expand Down
Loading