Skip to content

Commit

Permalink
improve the error messages when we're unable to parse something
Browse files Browse the repository at this point in the history
  • Loading branch information
vrischmann committed Feb 25, 2018
1 parent aa6abbc commit 98b0b9a
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 27 deletions.
44 changes: 24 additions & 20 deletions envconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,11 @@ func setField(value reflect.Value, ctx *context) (ok bool, err error) {
isSliceNotUnmarshaler := value.Kind() == reflect.Slice && !isUnmarshaler(value.Type())
switch {
case isSliceNotUnmarshaler && value.Type() == byteSliceType:
return true, parseBytesValue(value, str)
err := parseBytesValue(value, str)
if err != nil {
err = fmt.Errorf("envconfig: unable to parse value %q as bytes for possible keys %v. err=%v", str, makeAllPossibleKeys(ctx), err)
}
return true, err

case isSliceNotUnmarshaler:
return true, setSliceField(value, str, ctx)
Expand Down Expand Up @@ -285,37 +289,37 @@ func parseValue(v reflect.Value, str string, ctx *context) (err error) {
v.Set(reflect.MakeMap(vtype))
}

// Special case for Unmarshaler
if isUnmarshaler(vtype) {
return parseWithUnmarshaler(v, str)
}

// Special case for time.Duration
if isDurationField(vtype) {
return parseDuration(v, str)
}

kind := vtype.Kind()
switch kind {
case reflect.Bool:
switch {
case isUnmarshaler(vtype):
// Special case for Unmarshaler
err = parseWithUnmarshaler(v, str)
case isDurationField(vtype):
// Special case for time.Duration
err = parseDuration(v, str)
case kind == reflect.Bool:
err = parseBoolValue(v, str)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
case kind == reflect.Int, kind == reflect.Int8, kind == reflect.Int16, kind == reflect.Int32, kind == reflect.Int64:
err = parseIntValue(v, str)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
case kind == reflect.Uint, kind == reflect.Uint8, kind == reflect.Uint16, kind == reflect.Uint32, kind == reflect.Uint64:
err = parseUintValue(v, str)
case reflect.Float32, reflect.Float64:
case kind == reflect.Float32, kind == reflect.Float64:
err = parseFloatValue(v, str)
case reflect.Ptr:
case kind == reflect.Ptr:
v.Set(reflect.New(vtype.Elem()))
return parseValue(v.Elem(), str, ctx)
case reflect.String:
case kind == reflect.String:
v.SetString(str)
case reflect.Struct:
case kind == reflect.Struct:
err = parseStruct(v, str, ctx)
default:
return fmt.Errorf("envconfig: kind %v not supported", kind)
}

if err != nil {
return fmt.Errorf("envconfig: unable to parse value %q for possible keys %v. err=%v", str, makeAllPossibleKeys(ctx), err)
}

return
}

Expand All @@ -339,7 +343,7 @@ func parseDuration(v reflect.Value, str string) error {
func parseStruct(value reflect.Value, token string, ctx *context) error {
tokens := strings.Split(token[1:len(token)-1], ",")
if len(tokens) != value.NumField() {
return fmt.Errorf("envconfig: struct token has %d fields but struct has %d", len(tokens), value.NumField())
return fmt.Errorf("struct token has %d fields but struct has %d", len(tokens), value.NumField())
}

for i := 0; i < value.NumField(); i++ {
Expand Down
14 changes: 7 additions & 7 deletions envconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func TestParseStructSliceWrongData(t *testing.T) {
os.Setenv("SHARDS", "foobar")

err := envconfig.Init(&conf)
require.Equal(t, "envconfig: struct token has 1 fields but struct has 2", err.Error())
require.Equal(t, `envconfig: unable to parse value "foobar" for possible keys [SHARDS shards]. err=struct token has 1 fields but struct has 2`, err.Error())
}

func TestParseStructSliceWrongValue(t *testing.T) {
Expand All @@ -154,34 +154,34 @@ func TestParseStructSliceWrongValue(t *testing.T) {
os.Setenv("SHARDS", "{foobar,barbaz}")

err := envconfig.Init(&conf)
require.Equal(t, `strconv.ParseInt: parsing "barbaz": invalid syntax`, err.Error())
require.Equal(t, `envconfig: unable to parse value "{foobar,barbaz}" for possible keys [SHARDS shards]. err=envconfig: unable to parse value "barbaz" for possible keys [SHARDS shards]. err=strconv.ParseInt: parsing "barbaz": invalid syntax`, err.Error())
}

func TestParseWrongValues(t *testing.T) {
var conf struct{ OK bool }
os.Setenv("OK", "foobar")
err := envconfig.Init(&conf)
require.Equal(t, `strconv.ParseBool: parsing "foobar": invalid syntax`, err.Error())
require.Equal(t, `envconfig: unable to parse value "foobar" for possible keys [OK ok]. err=strconv.ParseBool: parsing "foobar": invalid syntax`, err.Error())

var conf2 struct{ Port int }
os.Setenv("PORT", "foobar")
err = envconfig.Init(&conf2)
require.Equal(t, `strconv.ParseInt: parsing "foobar": invalid syntax`, err.Error())
require.Equal(t, `envconfig: unable to parse value "foobar" for possible keys [PORT port]. err=strconv.ParseInt: parsing "foobar": invalid syntax`, err.Error())

var conf3 struct{ Port uint }
os.Setenv("PORT", "foobar")
err = envconfig.Init(&conf3)
require.Equal(t, `strconv.ParseUint: parsing "foobar": invalid syntax`, err.Error())
require.Equal(t, `envconfig: unable to parse value "foobar" for possible keys [PORT port]. err=strconv.ParseUint: parsing "foobar": invalid syntax`, err.Error())

var conf4 struct{ Port float32 }
os.Setenv("PORT", "foobar")
err = envconfig.Init(&conf4)
require.Equal(t, `strconv.ParseFloat: parsing "foobar": invalid syntax`, err.Error())
require.Equal(t, `envconfig: unable to parse value "foobar" for possible keys [PORT port]. err=strconv.ParseFloat: parsing "foobar": invalid syntax`, err.Error())

var conf5 struct{ Data []byte }
os.Setenv("DATA", "foobar")
err = envconfig.Init(&conf5)
require.Equal(t, "illegal base64 data at input byte 4", err.Error())
require.Equal(t, `envconfig: unable to parse value "foobar" as bytes for possible keys [DATA data]. err=illegal base64 data at input byte 4`, err.Error())
}

func TestDurationConfig(t *testing.T) {
Expand Down

0 comments on commit 98b0b9a

Please sign in to comment.