Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panic on duplicate command aliases #318

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 19 additions & 7 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ MAIN:
}

// Validate if there are no duplicate names
if err := checkDuplicateNames(node, v); err != nil {
if err := checkDuplicateNamesAndAliases(node, v); err != nil {
return nil, err
}

Expand Down Expand Up @@ -342,19 +342,31 @@ func buildGroupForKey(k *Kong, key string) *Group {
}
}

func checkDuplicateNames(node *Node, v reflect.Value) error {
func checkDuplicateNamesAndAliases(node *Node, v reflect.Value) error {
seenNames := make(map[string]struct{})
for _, node := range node.Children {
if _, ok := seenNames[node.Name]; ok {
name := v.Type().Name()
if name == "" {
name = "<anonymous struct>"
}
return fmt.Errorf("duplicate command name %q in command %q", node.Name, name)
return fmt.Errorf("duplicate command name %q in command %q", node.Name, getStructName(v))
}

seenNames[node.Name] = struct{}{}

for _, alias := range node.Aliases {
if _, ok := seenNames[alias]; ok {
return fmt.Errorf("duplicate alias %q in command %q with parent %q", alias, node.Name, getStructName(v))
}

seenNames[alias] = struct{}{}
}
}

return nil
}

func getStructName(v reflect.Value) string {
name := v.Type().Name()
if name == "" {
name = "<anonymous struct>"
}
return name
}
41 changes: 41 additions & 0 deletions kong_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,7 @@
assert.EqualError(t, err, "<anonymous struct>.Flag2: duplicate short flag -t")
}

func TestDuplicateAliases(t *testing.T) {

Check failure on line 1334 in kong_test.go

View workflow job for this annotation

GitHub Actions / Test / Windows / Go 1.20.x

other declaration of TestDuplicateAliases
cli1 := struct {
Flag1 string `aliases:"flag"`
Flag2 string `aliases:"flag"`
Expand Down Expand Up @@ -1766,6 +1766,47 @@
mustNew(t, &cli)
}

func TestDuplicateAliases(t *testing.T) {

Check failure on line 1769 in kong_test.go

View workflow job for this annotation

GitHub Actions / Test / Windows / Go 1.20.x

TestDuplicateAliases redeclared in this block
var cli struct {
DupA struct{} `cmd:"" aliases:"alias"`
DupB struct{} `cmd:"" aliases:"alias"`
}

_, err := kong.New(&cli)
assert.Error(t, err)
}

func TestDuplicateAliasesInCommand(t *testing.T) {
var cli struct {
DupA struct{} `cmd:"" aliases:"alias,alias"`
DupB struct{} `cmd:""`
}
_, err := kong.New(&cli)
assert.Error(t, err)
}

func TestDuplicateChildAliases(t *testing.T) {
var cli struct {
A struct {
DupA struct{} `cmd:"" aliases:"alias"`
DupB struct{} `cmd:"" aliases:"alias"`
} `cmd:""`
B struct{} `cmd:""`
}
_, err := kong.New(&cli)
assert.Error(t, err)
}

func TestChildAliasesCanBeDuplicated(t *testing.T) {
var cli struct {
A struct {
A struct{} `cmd:"" aliases:"alias"`
} `cmd:"" aliases:"alias"`
B struct{} `cmd:""`
}
mustNew(t, &cli)
}

func TestCumulativeArgumentLast(t *testing.T) {
var cli struct {
Arg1 string `arg:""`
Expand Down
14 changes: 0 additions & 14 deletions tag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,20 +175,6 @@ func TestTagAliases(t *testing.T) {
assert.Equal(t, "arg", cli.Cmd.Arg)
}

func TestTagAliasesConflict(t *testing.T) {
type Command struct {
Arg string `arg help:"Some arg"`
}
var cli struct {
Cmd Command `cmd hidden aliases:"other-cmd"`
OtherCmd Command `cmd`
}
p := mustNew(t, &cli)
_, err := p.Parse([]string{"other-cmd", "arg"})
assert.NoError(t, err)
assert.Equal(t, "arg", cli.OtherCmd.Arg)
}

func TestTagAliasesSub(t *testing.T) {
type SubCommand struct {
Arg string `arg help:"Some arg"`
Expand Down