From f449f3d6ecce2d7351821537a5b41810c654aca5 Mon Sep 17 00:00:00 2001 From: Markus Sommer Date: Mon, 20 May 2024 17:31:47 +0200 Subject: [PATCH 1/4] feat: added regex and net types: ip, ipnet, cidr --- mapper.go | 104 +++++++++++++++++++++++++++++++ mapper_test.go | 164 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+) diff --git a/mapper.go b/mapper.go index 584bb00..22013ad 100644 --- a/mapper.go +++ b/mapper.go @@ -7,9 +7,12 @@ import ( "fmt" "io" "math/bits" + "net" + "net/netip" "net/url" "os" "reflect" + "regexp" "strconv" "strings" "time" @@ -285,6 +288,11 @@ func (r *Registry) RegisterDefaults() *Registry { RegisterType(reflect.TypeOf(time.Duration(0)), durationDecoder()). RegisterType(reflect.TypeOf(&url.URL{}), urlMapper()). RegisterType(reflect.TypeOf(&os.File{}), fileMapper(r)). + RegisterType(reflect.TypeOf(®exp.Regexp{}), regexMapper()). + RegisterType(reflect.TypeOf(&net.IP{}), netIPMapper()). + RegisterType(reflect.TypeOf(&net.IPNet{}), netIPNetMapper()). + RegisterType(reflect.TypeOf(netip.Addr{}), netipAddrMapper()). + RegisterType(reflect.TypeOf(netip.Prefix{}), netipPrefixMapper()). RegisterName("path", pathMapper(r)). RegisterName("existingfile", existingFileMapper(r)). RegisterName("existingdir", existingDirMapper(r)). @@ -733,6 +741,102 @@ func fileContentMapper(r *Registry) MapperFunc { } } +func regexMapper() MapperFunc { + return func(ctx *DecodeContext, target reflect.Value) error { + t, err := ctx.Scan.PopValue("regex") + if err != nil { + return err + } + + var f *regexp.Regexp + switch v := t.Value.(type) { + case string: + f, err = regexp.Compile(v) + if err != nil { + return fmt.Errorf("expected regular expression but got %q: %w", v, err) + } + default: + return fmt.Errorf("expected string but got %q", v) + } + + target.Set(reflect.ValueOf(f)) + + return nil + } +} + +func netIPMapper() MapperFunc { + return func(ctx *DecodeContext, target reflect.Value) error { + var value string + if err := ctx.Scan.PopValueInto("ip", &value); err != nil { + return err + } + + ip := net.ParseIP(value) + if ip == nil { + return fmt.Errorf("expected ip addresss but got %q", value) + } + + target.Set(reflect.ValueOf(ip)) + + return nil + } +} + +func netIPNetMapper() MapperFunc { + return func(ctx *DecodeContext, target reflect.Value) error { + var value string + if err := ctx.Scan.PopValueInto("cidr", &value); err != nil { + return err + } + + _, ipnet, err := net.ParseCIDR(value) + if err != nil { + return fmt.Errorf("expected cidr but got %q: %w", value, err) + } + + target.Set(reflect.ValueOf(ipnet)) + + return nil + } +} + +func netipAddrMapper() MapperFunc { + return func(ctx *DecodeContext, target reflect.Value) error { + var value string + if err := ctx.Scan.PopValueInto("ip", &value); err != nil { + return err + } + + ip, err := netip.ParseAddr(value) + if err != nil { + return fmt.Errorf("expected ip addresss but got %q: %w", value, err) + } + + target.Set(reflect.ValueOf(ip)) + + return nil + } +} + +func netipPrefixMapper() MapperFunc { + return func(ctx *DecodeContext, target reflect.Value) error { + var value string + if err := ctx.Scan.PopValueInto("cidr", &value); err != nil { + return err + } + + prefix, err := netip.ParsePrefix(value) + if err != nil { + return fmt.Errorf("expected ipnet but got %q: %w", value, err) + } + + target.Set(reflect.ValueOf(prefix)) + + return nil + } +} + type ptrMapper struct { r *Registry } diff --git a/mapper_test.go b/mapper_test.go index 113e9f5..d919455 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -5,10 +5,13 @@ import ( "encoding/json" "fmt" "math" + "net" + "net/netip" "net/url" "os" "path/filepath" "reflect" + "regexp" "strings" "testing" "time" @@ -138,6 +141,167 @@ func TestDurationMapperJSONResolver(t *testing.T) { assert.Equal(t, time.Second*5, cli.Flag) } +func TestNetIP(t *testing.T) { + var cli struct { + Flag net.IP + } + k := mustNew(t, &cli) + _, err := k.Parse([]string{"--flag", "127.0.0.1"}) + assert.NoError(t, err) + assert.Equal(t, "127.0.0.1", cli.Flag.String()) + + _, err = k.Parse([]string{"--flag", "2001:db8:abcd:0012::1"}) + assert.NoError(t, err) + assert.Equal(t, "2001:db8:abcd:12::1", cli.Flag.String()) +} + +func TestNetIPSplice(t *testing.T) { + var cli struct { + Flag []net.IP + } + k := mustNew(t, &cli) + _, err := k.Parse([]string{ + "--flag", "127.0.0.1", + "--flag", "192.168.0.1", + "--flag", "2001:db8:abcd:0012::1", + }) + assert.NoError(t, err) + + assert.Equal(t, 3, len(cli.Flag)) + assert.Equal(t, "127.0.0.1", cli.Flag[0].String()) + assert.Equal(t, "192.168.0.1", cli.Flag[1].String()) + assert.Equal(t, "2001:db8:abcd:12::1", cli.Flag[2].String()) +} + +func TestIPNet(t *testing.T) { + var cli struct { + Flag *net.IPNet + } + k := mustNew(t, &cli) + _, err := k.Parse([]string{"--flag", "127.0.0.0/24"}) + assert.NoError(t, err) + assert.Equal(t, "127.0.0.0/24", cli.Flag.String()) + + _, err = k.Parse([]string{"--flag", "2001:db8:abcd:0012::0/64"}) + assert.NoError(t, err) + assert.Equal(t, "2001:db8:abcd:12::/64", cli.Flag.String()) +} + +func TestIPNetSlice(t *testing.T) { + var cli struct { + Test []*net.IPNet + } + + k := mustNew(t, &cli) + _, err := k.Parse([]string{ + "--test", "127.0.0.0/24", + "--test", "123.0.0.0/23", + "--test", "2001:db8:abcd:0012::0/64", + }) + assert.NoError(t, err) + + assert.Equal(t, 3, len(cli.Test)) + assert.Equal(t, "127.0.0.0/24", cli.Test[0].String()) + assert.Equal(t, "123.0.0.0/23", cli.Test[1].String()) + assert.Equal(t, "2001:db8:abcd:12::/64", cli.Test[2].String()) +} + +func TestNetipAddr(t *testing.T) { + var cli struct { + Flag netip.Addr + } + k := mustNew(t, &cli) + _, err := k.Parse([]string{"--flag", "127.0.0.1"}) + assert.NoError(t, err) + assert.Equal(t, "127.0.0.1", cli.Flag.String()) + + _, err = k.Parse([]string{"--flag", "2001:db8:abcd:0012::1"}) + assert.NoError(t, err) + assert.Equal(t, "2001:db8:abcd:12::1", cli.Flag.String()) +} + +func TestNetipAddrSplice(t *testing.T) { + var cli struct { + Flag []net.IP + } + k := mustNew(t, &cli) + _, err := k.Parse([]string{ + "--flag", "127.0.0.1", + "--flag", "192.168.0.1", + "--flag", "2001:db8:abcd:0012::1", + }) + assert.NoError(t, err) + + assert.Equal(t, 3, len(cli.Flag)) + assert.Equal(t, "127.0.0.1", cli.Flag[0].String()) + assert.Equal(t, "192.168.0.1", cli.Flag[1].String()) + assert.Equal(t, "2001:db8:abcd:12::1", cli.Flag[2].String()) +} + +func TestNetipPrefix(t *testing.T) { + var cli struct { + Flag netip.Prefix + } + k := mustNew(t, &cli) + + _, err := k.Parse([]string{"--flag", "127.0.0.0/24"}) + assert.NoError(t, err) + assert.Equal(t, "127.0.0.0/24", cli.Flag.String()) + assert.Equal(t, 24, cli.Flag.Bits()) + + _, err = k.Parse([]string{"--flag", "2001:db8:abcd:0012::0/64"}) + assert.NoError(t, err) + assert.Equal(t, "2001:db8:abcd:12::/64", cli.Flag.String()) +} + +func TestNetipPrefixSlice(t *testing.T) { + var cli struct { + Test []*net.IPNet `kong:"sep=','"` + } + + k := mustNew(t, &cli) + _, err := k.Parse([]string{ + "--test", "127.0.0.0/24", + "--test", "123.0.0.0/23", + "--test", "2001:db8:abcd:0012::0/64", + }) + assert.NoError(t, err) + + assert.Equal(t, 3, len(cli.Test)) + assert.Equal(t, "127.0.0.0/24", cli.Test[0].String()) + assert.Equal(t, "123.0.0.0/23", cli.Test[1].String()) + assert.Equal(t, "2001:db8:abcd:12::/64", cli.Test[2].String()) +} + +func TestRegex(t *testing.T) { + var cli struct { + Test *regexp.Regexp + } + + k := mustNew(t, &cli) + _, err := k.Parse([]string{"--test", "a.+[a-b]{2,4}"}) + assert.NoError(t, err) + assert.Equal(t, "a.+[a-b]{2,4}", cli.Test.String()) +} + +func TestRegexSlice(t *testing.T) { + var cli struct { + Test []*regexp.Regexp `kong:"sep='none'"` + } + + k := mustNew(t, &cli) + _, err := k.Parse([]string{ + "--test", "foo.+[b-r]{2,4}", + "--test", "foo=bar", + }) + assert.NoError(t, err) + + assert.Equal(t, 2, len(cli.Test)) + assert.Equal(t, "foo.+[b-r]{2,4}", cli.Test[0].String()) + assert.Equal(t, "foo=bar", cli.Test[1].String()) + +} + func TestSplitEscaped(t *testing.T) { assert.Equal(t, []string{"a", "b"}, kong.SplitEscaped("a,b", ',')) assert.Equal(t, []string{"a,b", "c"}, kong.SplitEscaped(`a\,b,c`, ',')) From 8727b631da05d6c1860be59ad4823ea7a05a6a71 Mon Sep 17 00:00:00 2001 From: Markus Sommer Date: Tue, 21 May 2024 22:51:47 +0200 Subject: [PATCH 2/4] fix: removed netip mappers because they are supported out of the box --- mapper.go | 39 -------- mapper_test.go | 245 +++++++++++++++++++++++++++---------------------- 2 files changed, 136 insertions(+), 148 deletions(-) diff --git a/mapper.go b/mapper.go index 22013ad..9b88d4e 100644 --- a/mapper.go +++ b/mapper.go @@ -8,7 +8,6 @@ import ( "io" "math/bits" "net" - "net/netip" "net/url" "os" "reflect" @@ -291,8 +290,6 @@ func (r *Registry) RegisterDefaults() *Registry { RegisterType(reflect.TypeOf(®exp.Regexp{}), regexMapper()). RegisterType(reflect.TypeOf(&net.IP{}), netIPMapper()). RegisterType(reflect.TypeOf(&net.IPNet{}), netIPNetMapper()). - RegisterType(reflect.TypeOf(netip.Addr{}), netipAddrMapper()). - RegisterType(reflect.TypeOf(netip.Prefix{}), netipPrefixMapper()). RegisterName("path", pathMapper(r)). RegisterName("existingfile", existingFileMapper(r)). RegisterName("existingdir", existingDirMapper(r)). @@ -801,42 +798,6 @@ func netIPNetMapper() MapperFunc { } } -func netipAddrMapper() MapperFunc { - return func(ctx *DecodeContext, target reflect.Value) error { - var value string - if err := ctx.Scan.PopValueInto("ip", &value); err != nil { - return err - } - - ip, err := netip.ParseAddr(value) - if err != nil { - return fmt.Errorf("expected ip addresss but got %q: %w", value, err) - } - - target.Set(reflect.ValueOf(ip)) - - return nil - } -} - -func netipPrefixMapper() MapperFunc { - return func(ctx *DecodeContext, target reflect.Value) error { - var value string - if err := ctx.Scan.PopValueInto("cidr", &value); err != nil { - return err - } - - prefix, err := netip.ParsePrefix(value) - if err != nil { - return fmt.Errorf("expected ipnet but got %q: %w", value, err) - } - - target.Set(reflect.ValueOf(prefix)) - - return nil - } -} - type ptrMapper struct { r *Registry } diff --git a/mapper_test.go b/mapper_test.go index d919455..b67ae4f 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -141,136 +141,164 @@ func TestDurationMapperJSONResolver(t *testing.T) { assert.Equal(t, time.Second*5, cli.Flag) } -func TestNetIP(t *testing.T) { - var cli struct { - Flag net.IP - } - k := mustNew(t, &cli) - _, err := k.Parse([]string{"--flag", "127.0.0.1"}) - assert.NoError(t, err) - assert.Equal(t, "127.0.0.1", cli.Flag.String()) - - _, err = k.Parse([]string{"--flag", "2001:db8:abcd:0012::1"}) - assert.NoError(t, err) - assert.Equal(t, "2001:db8:abcd:12::1", cli.Flag.String()) -} +func TestIPAddress(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"127.0.0.1", "127.0.0.1"}, + {"2001:db8:abcd:0012::1", "2001:db8:abcd:12::1"}, + } + + t.Run("TestNetPackage", func(t *testing.T) { + var cli1 struct { + Flag net.IP + } + k1 := mustNew(t, &cli1) -func TestNetIPSplice(t *testing.T) { - var cli struct { - Flag []net.IP - } - k := mustNew(t, &cli) - _, err := k.Parse([]string{ - "--flag", "127.0.0.1", - "--flag", "192.168.0.1", - "--flag", "2001:db8:abcd:0012::1", + for _, tt := range tests { + _, err := k1.Parse([]string{"--flag", tt.input}) + assert.NoError(t, err) + assert.Equal(t, tt.expected, cli1.Flag.String()) + } }) - assert.NoError(t, err) - assert.Equal(t, 3, len(cli.Flag)) - assert.Equal(t, "127.0.0.1", cli.Flag[0].String()) - assert.Equal(t, "192.168.0.1", cli.Flag[1].String()) - assert.Equal(t, "2001:db8:abcd:12::1", cli.Flag[2].String()) -} - -func TestIPNet(t *testing.T) { - var cli struct { - Flag *net.IPNet - } - k := mustNew(t, &cli) - _, err := k.Parse([]string{"--flag", "127.0.0.0/24"}) - assert.NoError(t, err) - assert.Equal(t, "127.0.0.0/24", cli.Flag.String()) + t.Run("TestNetipPackage", func(t *testing.T) { + var cli1 struct { + Flag netip.Addr + } + k1 := mustNew(t, &cli1) - _, err = k.Parse([]string{"--flag", "2001:db8:abcd:0012::0/64"}) - assert.NoError(t, err) - assert.Equal(t, "2001:db8:abcd:12::/64", cli.Flag.String()) + for _, tt := range tests { + _, err := k1.Parse([]string{"--flag", tt.input}) + assert.NoError(t, err) + assert.Equal(t, tt.expected, cli1.Flag.String()) + } + }) } -func TestIPNetSlice(t *testing.T) { - var cli struct { - Test []*net.IPNet +func TestIPAddressSlice(t *testing.T) { + tests := []struct { + input []string + expected []string + }{ + {input: []string{"127.0.0.1", "192.168.0.1"}, expected: []string{"127.0.0.1", "192.168.0.1"}}, + {input: []string{"2001:db8:abcd:0012::1", "::1"}, expected: []string{"2001:db8:abcd:12::1", "::1"}}, } - k := mustNew(t, &cli) - _, err := k.Parse([]string{ - "--test", "127.0.0.0/24", - "--test", "123.0.0.0/23", - "--test", "2001:db8:abcd:0012::0/64", - }) - assert.NoError(t, err) + t.Run("TestNetPackage", func(t *testing.T) { + var cli struct { + Flag []net.IP + } + k := mustNew(t, &cli) - assert.Equal(t, 3, len(cli.Test)) - assert.Equal(t, "127.0.0.0/24", cli.Test[0].String()) - assert.Equal(t, "123.0.0.0/23", cli.Test[1].String()) - assert.Equal(t, "2001:db8:abcd:12::/64", cli.Test[2].String()) -} + for _, tt := range tests { + _, err := k.Parse([]string{"--flag", strings.Join(tt.input, ",")}) + assert.NoError(t, err) + assert.Equal(t, len(tt.input), len(cli.Flag)) + } + }) -func TestNetipAddr(t *testing.T) { - var cli struct { - Flag netip.Addr - } - k := mustNew(t, &cli) - _, err := k.Parse([]string{"--flag", "127.0.0.1"}) - assert.NoError(t, err) - assert.Equal(t, "127.0.0.1", cli.Flag.String()) + t.Run("TestNetipPackage", func(t *testing.T) { + var cli struct { + Flag []netip.Addr + } + k := mustNew(t, &cli) - _, err = k.Parse([]string{"--flag", "2001:db8:abcd:0012::1"}) - assert.NoError(t, err) - assert.Equal(t, "2001:db8:abcd:12::1", cli.Flag.String()) + for _, tt := range tests { + _, err := k.Parse([]string{"--flag", strings.Join(tt.input, ",")}) + assert.NoError(t, err) + assert.Equal(t, len(tt.input), len(cli.Flag)) + } + }) } -func TestNetipAddrSplice(t *testing.T) { - var cli struct { - Flag []net.IP +func TestCIDR(t *testing.T) { + tests := []struct { + input string + expectedNet string + expectedNetip string + }{ + {"127.0.0.1/16", "127.0.0.0/16", "127.0.0.1/16"}, + {"2001:db8:abcd:0012::0/64", "2001:db8:abcd:12::/64", "2001:db8:abcd:12::/64"}, } - k := mustNew(t, &cli) - _, err := k.Parse([]string{ - "--flag", "127.0.0.1", - "--flag", "192.168.0.1", - "--flag", "2001:db8:abcd:0012::1", - }) - assert.NoError(t, err) - assert.Equal(t, 3, len(cli.Flag)) - assert.Equal(t, "127.0.0.1", cli.Flag[0].String()) - assert.Equal(t, "192.168.0.1", cli.Flag[1].String()) - assert.Equal(t, "2001:db8:abcd:12::1", cli.Flag[2].String()) -} + t.Run("TestNetPackage", func(t *testing.T) { + var cli1 struct { + Flag *net.IPNet + } + k1 := mustNew(t, &cli1) -func TestNetipPrefix(t *testing.T) { - var cli struct { - Flag netip.Prefix - } - k := mustNew(t, &cli) + for _, tt := range tests { + _, err := k1.Parse([]string{"--flag", tt.input}) + assert.NoError(t, err) + assert.Equal(t, tt.expectedNet, cli1.Flag.String()) + } + }) - _, err := k.Parse([]string{"--flag", "127.0.0.0/24"}) - assert.NoError(t, err) - assert.Equal(t, "127.0.0.0/24", cli.Flag.String()) - assert.Equal(t, 24, cli.Flag.Bits()) + t.Run("TestNetipPackage", func(t *testing.T) { + var cli1 struct { + Flag netip.Prefix + } + k1 := mustNew(t, &cli1) - _, err = k.Parse([]string{"--flag", "2001:db8:abcd:0012::0/64"}) - assert.NoError(t, err) - assert.Equal(t, "2001:db8:abcd:12::/64", cli.Flag.String()) + for _, tt := range tests { + _, err := k1.Parse([]string{"--flag", tt.input}) + assert.NoError(t, err) + assert.Equal(t, tt.expectedNetip, cli1.Flag.String()) + } + }) } -func TestNetipPrefixSlice(t *testing.T) { - var cli struct { - Test []*net.IPNet `kong:"sep=','"` - } - - k := mustNew(t, &cli) - _, err := k.Parse([]string{ - "--test", "127.0.0.0/24", - "--test", "123.0.0.0/23", - "--test", "2001:db8:abcd:0012::0/64", +func TestCIDRSlice(t *testing.T) { + tests := []struct { + input []string + expectedNet []string + expectedNetip []string + }{ + { + []string{"127.0.0.1/16", "192.168.1.0/20"}, + []string{"127.0.0.0/16", "192.168.0.0/20"}, + []string{"127.0.0.1/16", "192.168.1.0/20"}, + }, + { + []string{"2001:db8:abcd:0012::0/64", "2001:db8:abcd:0012::0/128"}, + []string{"2001:db8:abcd:12::/64", "2001:db8:abcd:12::/128"}, + []string{"2001:db8:abcd:12::/64", "2001:db8:abcd:12::/128"}, + }, + } + + t.Run("TestNetPackage", func(t *testing.T) { + var cli struct { + Flag []*net.IPNet + } + k := mustNew(t, &cli) + + for _, tt := range tests { + _, err := k.Parse([]string{"--flag", strings.Join(tt.input, ",")}) + assert.NoError(t, err) + assert.Equal(t, len(tt.input), len(cli.Flag)) + for i := 0; i < len(cli.Flag); i++ { + assert.Equal(t, tt.expectedNet[i], cli.Flag[i].String()) + } + } }) - assert.NoError(t, err) - assert.Equal(t, 3, len(cli.Test)) - assert.Equal(t, "127.0.0.0/24", cli.Test[0].String()) - assert.Equal(t, "123.0.0.0/23", cli.Test[1].String()) - assert.Equal(t, "2001:db8:abcd:12::/64", cli.Test[2].String()) + t.Run("TestNetipPackage", func(t *testing.T) { + var cli struct { + Flag []netip.Prefix + } + k := mustNew(t, &cli) + + for _, tt := range tests { + _, err := k.Parse([]string{"--flag", strings.Join(tt.input, ",")}) + assert.NoError(t, err) + assert.Equal(t, len(tt.input), len(cli.Flag)) + for i := 0; i < len(cli.Flag); i++ { + assert.Equal(t, tt.expectedNetip[i], cli.Flag[i].String()) + } + } + }) } func TestRegex(t *testing.T) { @@ -299,7 +327,6 @@ func TestRegexSlice(t *testing.T) { assert.Equal(t, 2, len(cli.Test)) assert.Equal(t, "foo.+[b-r]{2,4}", cli.Test[0].String()) assert.Equal(t, "foo=bar", cli.Test[1].String()) - } func TestSplitEscaped(t *testing.T) { From f068e3a4fabab09ce0c73b5b02179e93edd82eb7 Mon Sep 17 00:00:00 2001 From: Markus Sommer Date: Thu, 23 May 2024 21:53:47 +0200 Subject: [PATCH 3/4] fix: remove all new mappers except the regex mapper --- mapper.go | 39 ---------------------- mapper_test.go | 89 +++++++++++++++----------------------------------- 2 files changed, 26 insertions(+), 102 deletions(-) diff --git a/mapper.go b/mapper.go index 9b88d4e..a182706 100644 --- a/mapper.go +++ b/mapper.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "math/bits" - "net" "net/url" "os" "reflect" @@ -288,8 +287,6 @@ func (r *Registry) RegisterDefaults() *Registry { RegisterType(reflect.TypeOf(&url.URL{}), urlMapper()). RegisterType(reflect.TypeOf(&os.File{}), fileMapper(r)). RegisterType(reflect.TypeOf(®exp.Regexp{}), regexMapper()). - RegisterType(reflect.TypeOf(&net.IP{}), netIPMapper()). - RegisterType(reflect.TypeOf(&net.IPNet{}), netIPNetMapper()). RegisterName("path", pathMapper(r)). RegisterName("existingfile", existingFileMapper(r)). RegisterName("existingdir", existingDirMapper(r)). @@ -762,42 +759,6 @@ func regexMapper() MapperFunc { } } -func netIPMapper() MapperFunc { - return func(ctx *DecodeContext, target reflect.Value) error { - var value string - if err := ctx.Scan.PopValueInto("ip", &value); err != nil { - return err - } - - ip := net.ParseIP(value) - if ip == nil { - return fmt.Errorf("expected ip addresss but got %q", value) - } - - target.Set(reflect.ValueOf(ip)) - - return nil - } -} - -func netIPNetMapper() MapperFunc { - return func(ctx *DecodeContext, target reflect.Value) error { - var value string - if err := ctx.Scan.PopValueInto("cidr", &value); err != nil { - return err - } - - _, ipnet, err := net.ParseCIDR(value) - if err != nil { - return fmt.Errorf("expected cidr but got %q: %w", value, err) - } - - target.Set(reflect.ValueOf(ipnet)) - - return nil - } -} - type ptrMapper struct { r *Registry } diff --git a/mapper_test.go b/mapper_test.go index b67ae4f..ca1b079 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -215,90 +215,53 @@ func TestIPAddressSlice(t *testing.T) { func TestCIDR(t *testing.T) { tests := []struct { - input string - expectedNet string - expectedNetip string + input string + expected string }{ - {"127.0.0.1/16", "127.0.0.0/16", "127.0.0.1/16"}, - {"2001:db8:abcd:0012::0/64", "2001:db8:abcd:12::/64", "2001:db8:abcd:12::/64"}, + {"127.0.0.1/16", "127.0.0.1/16"}, + {"2001:db8:abcd:0012::0/64", "2001:db8:abcd:12::/64"}, } - t.Run("TestNetPackage", func(t *testing.T) { - var cli1 struct { - Flag *net.IPNet - } - k1 := mustNew(t, &cli1) - - for _, tt := range tests { - _, err := k1.Parse([]string{"--flag", tt.input}) - assert.NoError(t, err) - assert.Equal(t, tt.expectedNet, cli1.Flag.String()) - } - }) - - t.Run("TestNetipPackage", func(t *testing.T) { - var cli1 struct { - Flag netip.Prefix - } - k1 := mustNew(t, &cli1) + var cli1 struct { + Flag netip.Prefix + } + k1 := mustNew(t, &cli1) - for _, tt := range tests { - _, err := k1.Parse([]string{"--flag", tt.input}) - assert.NoError(t, err) - assert.Equal(t, tt.expectedNetip, cli1.Flag.String()) - } - }) + for _, tt := range tests { + _, err := k1.Parse([]string{"--flag", tt.input}) + assert.NoError(t, err) + assert.Equal(t, tt.expected, cli1.Flag.String()) + } } func TestCIDRSlice(t *testing.T) { tests := []struct { - input []string - expectedNet []string - expectedNetip []string + input []string + expected []string }{ { []string{"127.0.0.1/16", "192.168.1.0/20"}, - []string{"127.0.0.0/16", "192.168.0.0/20"}, []string{"127.0.0.1/16", "192.168.1.0/20"}, }, { []string{"2001:db8:abcd:0012::0/64", "2001:db8:abcd:0012::0/128"}, []string{"2001:db8:abcd:12::/64", "2001:db8:abcd:12::/128"}, - []string{"2001:db8:abcd:12::/64", "2001:db8:abcd:12::/128"}, }, } - t.Run("TestNetPackage", func(t *testing.T) { - var cli struct { - Flag []*net.IPNet - } - k := mustNew(t, &cli) - - for _, tt := range tests { - _, err := k.Parse([]string{"--flag", strings.Join(tt.input, ",")}) - assert.NoError(t, err) - assert.Equal(t, len(tt.input), len(cli.Flag)) - for i := 0; i < len(cli.Flag); i++ { - assert.Equal(t, tt.expectedNet[i], cli.Flag[i].String()) - } - } - }) - - t.Run("TestNetipPackage", func(t *testing.T) { - var cli struct { - Flag []netip.Prefix - } - k := mustNew(t, &cli) + var cli struct { + Flag []netip.Prefix + } + k := mustNew(t, &cli) - for _, tt := range tests { - _, err := k.Parse([]string{"--flag", strings.Join(tt.input, ",")}) - assert.NoError(t, err) - assert.Equal(t, len(tt.input), len(cli.Flag)) - for i := 0; i < len(cli.Flag); i++ { - assert.Equal(t, tt.expectedNetip[i], cli.Flag[i].String()) - } + for _, tt := range tests { + _, err := k.Parse([]string{"--flag", strings.Join(tt.input, ",")}) + assert.NoError(t, err) + assert.Equal(t, len(tt.input), len(cli.Flag)) + for i := 0; i < len(cli.Flag); i++ { + assert.Equal(t, tt.expected[i], cli.Flag[i].String()) } - }) + } } func TestRegex(t *testing.T) { From 4f796492d6078a09b7eb075c90f7332f82ef9c1c Mon Sep 17 00:00:00 2001 From: Markus Sommer Date: Sat, 25 May 2024 22:42:18 +0200 Subject: [PATCH 4/4] fix: removed all mappers, added failing test for questioning --- mapper.go | 26 -------------------------- mapper_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/mapper.go b/mapper.go index a182706..584bb00 100644 --- a/mapper.go +++ b/mapper.go @@ -10,7 +10,6 @@ import ( "net/url" "os" "reflect" - "regexp" "strconv" "strings" "time" @@ -286,7 +285,6 @@ func (r *Registry) RegisterDefaults() *Registry { RegisterType(reflect.TypeOf(time.Duration(0)), durationDecoder()). RegisterType(reflect.TypeOf(&url.URL{}), urlMapper()). RegisterType(reflect.TypeOf(&os.File{}), fileMapper(r)). - RegisterType(reflect.TypeOf(®exp.Regexp{}), regexMapper()). RegisterName("path", pathMapper(r)). RegisterName("existingfile", existingFileMapper(r)). RegisterName("existingdir", existingDirMapper(r)). @@ -735,30 +733,6 @@ func fileContentMapper(r *Registry) MapperFunc { } } -func regexMapper() MapperFunc { - return func(ctx *DecodeContext, target reflect.Value) error { - t, err := ctx.Scan.PopValue("regex") - if err != nil { - return err - } - - var f *regexp.Regexp - switch v := t.Value.(type) { - case string: - f, err = regexp.Compile(v) - if err != nil { - return fmt.Errorf("expected regular expression but got %q: %w", v, err) - } - default: - return fmt.Errorf("expected string but got %q", v) - } - - target.Set(reflect.ValueOf(f)) - - return nil - } -} - type ptrMapper struct { r *Registry } diff --git a/mapper_test.go b/mapper_test.go index ca1b079..cf5b804 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -265,6 +265,17 @@ func TestCIDRSlice(t *testing.T) { } func TestRegex(t *testing.T) { + var cli struct { + Test regexp.Regexp + } + + k := mustNew(t, &cli) + _, err := k.Parse([]string{"--test", "a.+[a-b]{2,4}"}) + assert.NoError(t, err) + assert.Equal(t, "a.+[a-b]{2,4}", cli.Test.String()) +} + +func TestRegexPointer(t *testing.T) { var cli struct { Test *regexp.Regexp } @@ -276,6 +287,23 @@ func TestRegex(t *testing.T) { } func TestRegexSlice(t *testing.T) { + var cli struct { + Test []regexp.Regexp `kong:"sep='none'"` + } + + k := mustNew(t, &cli) + _, err := k.Parse([]string{ + "--test", "foo.+[b-r]{2,4}", + "--test", "foo=bar", + }) + assert.NoError(t, err) + + assert.Equal(t, 2, len(cli.Test)) + assert.Equal(t, "foo.+[b-r]{2,4}", cli.Test[0].String()) + assert.Equal(t, "foo=bar", cli.Test[1].String()) +} + +func TestRegexPointerSlice(t *testing.T) { var cli struct { Test []*regexp.Regexp `kong:"sep='none'"` }