From d8dc27c896429a7cddb9c2789e26aacc6cbb5bba Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 30 Nov 2021 10:20:29 -0300 Subject: [PATCH] fix: prefixes on pointers (#203) closes #202 Signed-off-by: Carlos A Becker --- env.go | 28 ++++++++++++++++++---------- env_test.go | 30 +++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/env.go b/env.go index 53e36c4..6279555 100644 --- a/env.go +++ b/env.go @@ -204,15 +204,19 @@ func doParse(ref reflect.Value, funcMap map[reflect.Type]ParserFunc, opts []Opti continue } if reflect.Ptr == refField.Kind() && !refField.IsNil() { - err := ParseWithFuncs(refField.Interface(), funcMap, opts...) - if err != nil { + if refField.Elem().Kind() == reflect.Struct { + if err := ParseWithFuncs(refField.Interface(), funcMap, optsWithPrefix(refType.Field(i), opts)...); err != nil { + return err + } + continue + } + if err := ParseWithFuncs(refField.Interface(), funcMap, opts...); err != nil { return err } continue } if reflect.Struct == refField.Kind() && refField.CanAddr() && refField.Type().Name() == "" { - err := Parse(refField.Addr().Interface(), opts...) - if err != nil { + if err := Parse(refField.Addr().Interface(), opts...); err != nil { return err } continue @@ -224,12 +228,7 @@ func doParse(ref reflect.Value, funcMap map[reflect.Type]ParserFunc, opts []Opti } if value == "" { if reflect.Struct == refField.Kind() { - subOpts := make([]Options, len(opts)) - copy(subOpts, opts) - if prefix := refType.Field(i).Tag.Get("envPrefix"); prefix != "" { - subOpts[0].Prefix += prefix - } - if err := doParse(refField, funcMap, subOpts); err != nil { + if err := doParse(refField, funcMap, optsWithPrefix(refType.Field(i), opts)); err != nil { return err } } @@ -475,3 +474,12 @@ func (e parseError) Error() string { func newNoParserError(sf reflect.StructField) error { return fmt.Errorf(`env: no parser found for field "%s" of type "%s"`, sf.Name, sf.Type) } + +func optsWithPrefix(field reflect.StructField, opts []Options) []Options { + subOpts := make([]Options, len(opts)) + copy(subOpts, opts) + if prefix := field.Tag.Get("envPrefix"); prefix != "" { + subOpts[0].Prefix += prefix + } + return subOpts +} diff --git a/env_test.go b/env_test.go index 3e04dd3..8f9036c 100644 --- a/env_test.go +++ b/env_test.go @@ -1433,13 +1433,34 @@ func TestPrefix(t *testing.T) { Clean Config } cfg := ComplexConfig{} - err := Parse(&cfg, Options{Environment: map[string]string{"FOO_HOME": "/foo", "BAR_HOME": "/bar", "HOME": "/clean"}}) - is.NoErr(err) + is.NoErr(Parse(&cfg, Options{Environment: map[string]string{"FOO_HOME": "/foo", "BAR_HOME": "/bar", "HOME": "/clean"}})) is.Equal("/foo", cfg.Foo.Home) is.Equal("/bar", cfg.Bar.Home) is.Equal("/clean", cfg.Clean.Home) } +func TestPrefixPointers(t *testing.T) { + is := is.New(t) + type Test struct { + Str string `env:"TEST"` + } + type ComplexConfig struct { + Foo *Test `envPrefix:"FOO_"` + Bar *Test `envPrefix:"BAR_"` + Clean *Test + } + + cfg := ComplexConfig{ + Foo: &Test{}, + Bar: &Test{}, + Clean: &Test{}, + } + is.NoErr(Parse(&cfg, Options{Environment: map[string]string{"FOO_TEST": "kek", "BAR_TEST": "lel", "TEST": "clean"}})) + is.Equal("kek", cfg.Foo.Str) + is.Equal("lel", cfg.Bar.Str) + is.Equal("clean", cfg.Clean.Str) +} + func TestComplePrefix(t *testing.T) { is := is.New(t) type Config struct { @@ -1452,7 +1473,7 @@ func TestComplePrefix(t *testing.T) { Blah string `env:"BLAH"` } cfg := ComplexConfig{} - err := Parse(&cfg, Options{ + is.NoErr(Parse(&cfg, Options{ Prefix: "T_", Environment: map[string]string{ "T_FOO_HOME": "/foo", @@ -1460,8 +1481,7 @@ func TestComplePrefix(t *testing.T) { "T_BLAH": "blahhh", "T_HOME": "/clean", }, - }) - is.NoErr(err) + })) is.Equal("/foo", cfg.Foo.Home) is.Equal("/bar", cfg.Bar.Home) is.Equal("/clean", cfg.Clean.Home)