From f9bc630ef87b06a14cc0115cc4d3188aa5b79e3b Mon Sep 17 00:00:00 2001 From: Michal Kralik Date: Sun, 17 Jul 2022 11:31:21 +0200 Subject: [PATCH] Panic on duplicate command names (#317) --- build.go | 22 ++++++++++++++++++++++ kong_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/build.go b/build.go index 4be5f24..32c83e1 100644 --- a/build.go +++ b/build.go @@ -158,6 +158,11 @@ MAIN: } } + // Validate if there are no duplicate names + if err := checkDuplicateNames(node, v); err != nil { + return nil, err + } + // "Unsee" flags. for _, flag := range node.Flags { delete(seenFlags, "--"+flag.Name) @@ -311,3 +316,20 @@ func buildGroupForKey(k *Kong, key string) *Group { Title: key, } } + +func checkDuplicateNames(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 = "" + } + return fmt.Errorf("duplicate command name %q in command %q", node.Name, name) + } + + seenNames[node.Name] = struct{}{} + } + + return nil +} diff --git a/kong_test.go b/kong_test.go index 8dff864..d66cbd6 100644 --- a/kong_test.go +++ b/kong_test.go @@ -1662,3 +1662,35 @@ func TestMapDecoderHelpfulErrorMsg(t *testing.T) { }) } } + +func TestDuplicateName(t *testing.T) { + var cli struct { + DupA struct{} `cmd:"" name:"duplicate"` + DupB struct{} `cmd:"" name:"duplicate"` + } + _, err := kong.New(&cli) + assert.Error(t, err) +} + +func TestDuplicateChildName(t *testing.T) { + var cli struct { + A struct { + DupA struct{} `cmd:"" name:"duplicate"` + DupB struct{} `cmd:"" name:"duplicate"` + } `cmd:""` + B struct{} `cmd:""` + } + _, err := kong.New(&cli) + assert.Error(t, err) +} + +func TestChildNameCanBeDuplicated(t *testing.T) { + var cli struct { + A struct { + A struct{} `cmd:"" name:"duplicateA"` + B struct{} `cmd:"" name:"duplicateB"` + } `cmd:"" name:"duplicateA"` + B struct{} `cmd:"" name:"duplicateB"` + } + mustNew(t, &cli) +}