Skip to content

Commit

Permalink
Merge pull request #45 from EVODelavega/add-custom-parser-for-non-struct
Browse files Browse the repository at this point in the history
Expand support for custom parsers to non-struct types
  • Loading branch information
caarlos0 authored May 1, 2018
2 parents 9b2b307 + 1696c10 commit 1cddc31
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 1 deletion.
10 changes: 9 additions & 1 deletion env.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,15 @@ func set(field reflect.Value, refType reflect.StructField, value string, funcMap
case reflect.Struct:
return handleStruct(field, refType, value, funcMap)
default:
return ErrUnsupportedType
parserFunc, ok := funcMap[refType.Type]
if !ok {
return ErrUnsupportedType
}
val, err := parserFunc(value)
if err != nil {
return err
}
field.Set(reflect.ValueOf(val))
}
return nil
}
Expand Down
72 changes: 72 additions & 0 deletions env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http"
"os"
"reflect"
"strconv"
"testing"
"time"

Expand Down Expand Up @@ -400,6 +401,76 @@ func TestCustomParserError(t *testing.T) {
assert.Equal(t, err.Error(), "Custom parser error: something broke")
}

func TestCustomParserBasicType(t *testing.T) {
type ConstT int32

type config struct {
Const ConstT `env:"CONST_VAL"`
}

exp := ConstT(123)
os.Setenv("CONST_VAL", fmt.Sprintf("%d", exp))

customParserFunc := func(v string) (interface{}, error) {
i, err := strconv.Atoi(v)
if err != nil {
return nil, err
}
r := ConstT(i)
return r, nil
}

cfg := &config{}
err := env.ParseWithFuncs(cfg, map[reflect.Type]env.ParserFunc{
reflect.TypeOf(ConstT(0)): customParserFunc,
})

assert.NoError(t, err)
assert.Equal(t, exp, cfg.Const)
}

func TypeCustomParserBasicInvalid(t *testing.T) {
type ConstT int32

type config struct {
Const ConstT `env:"CONST_VAL"`
}

os.Setenv("CONST_VAL", "foobar")

expErr := errors.New("Random error")
customParserFunc := func(_ string) (interface{}, error) {
return nil, expErr
}

cfg := &config{}
err := env.ParseWithFuncs(cfg, map[reflect.Type]env.ParserFunc{
reflect.TypeOf(ConstT(0)): customParserFunc,
})

assert.Empty(t, cfg.Const)
assert.Error(t, err)
assert.Equal(t, expErr, err)
}

func TestCustomParserBasicUnsupported(t *testing.T) {
type ConstT int32

type config struct {
Const ConstT `env:"CONST_VAL"`
}

exp := ConstT(123)
os.Setenv("CONST_VAL", fmt.Sprintf("%d", exp))

cfg := &config{}
err := env.Parse(cfg)

assert.Zero(t, cfg.Const)
assert.Error(t, err)
assert.Equal(t, env.ErrUnsupportedType, err)
}

func TestUnsupportedStructType(t *testing.T) {
type config struct {
Foo http.Client `env:"FOO"`
Expand All @@ -413,6 +484,7 @@ func TestUnsupportedStructType(t *testing.T) {
assert.Error(t, err)
assert.Equal(t, env.ErrUnsupportedType, err)
}

func TestEmptyOption(t *testing.T) {
type config struct {
Var string `env:"VAR,"`
Expand Down

0 comments on commit 1cddc31

Please sign in to comment.