Return parse errors

This commit is contained in:
Nise Void 2019-10-08 11:09:07 +02:00
parent 0efb52d29e
commit 34a9eba03a
Signed by untrusted user: NiseVoid
GPG Key ID: FBA14AC83EA602F3
2 changed files with 64 additions and 16 deletions

View File

@ -8,18 +8,28 @@ import (
"unicode" "unicode"
) )
type DecodeError struct {
Field string
Type string
Value string
}
func (de DecodeError) Error() string {
return `Failed to decode "` + de.Value + `" into field ` + de.Field + ` of type ` + de.Type + `.`
}
type Values = map[string][]string type Values = map[string][]string
func Decode(form Values, v interface{}) { func Decode(form Values, v interface{}) error {
rv := reflect.ValueOf(v) rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr { if rv.Kind() != reflect.Ptr {
panic(`Input is not a pointer`) panic(`Input is not a pointer`)
} }
decode(form, rv.Elem(), ``) return decode(form, rv.Elem(), ``)
} }
func decode(form Values, rv reflect.Value, prefix string) { func decode(form Values, rv reflect.Value, prefix string) error {
for i := 0; i < rv.NumField(); i++ { for i := 0; i < rv.NumField(); i++ {
ft, fv := rv.Type().Field(i), rv.Field(i) ft, fv := rv.Type().Field(i), rv.Field(i)
@ -60,11 +70,15 @@ func decode(form Values, rv reflect.Value, prefix string) {
fv = fv.Elem() fv = fv.Elem()
} }
decode(form, fv, getPrefix(ft, prefix)) err := decode(form, fv, getPrefix(ft, prefix))
if err != nil {
return err
}
continue continue
} }
v, ok := form[getName(ft, prefix)] fieldName := getName(ft, prefix)
v, ok := form[fieldName]
if !ok || len(v) == 0 { if !ok || len(v) == 0 {
continue continue
} }
@ -75,37 +89,55 @@ func decode(form Values, rv reflect.Value, prefix string) {
fv.Set(reflect.New(ft.Type.Elem())) fv.Set(reflect.New(ft.Type.Elem()))
} }
setValue(v, fv) err := setValue(fieldName, v, fv)
if err != nil {
return err
} }
}
return nil
} }
func setValue(values []string, fv reflect.Value) { func setValue(fieldName string, values []string, fv reflect.Value) error {
if fv.Elem().Type().Kind() != reflect.Slice { if fv.Elem().Type().Kind() != reflect.Slice {
parse(values[0], fv) return parse(fieldName, values[0], fv)
return
} }
slice := reflect.MakeSlice(fv.Elem().Type(), len(values), len(values)) slice := reflect.MakeSlice(fv.Elem().Type(), len(values), len(values))
val := reflect.New(slice.Type().Elem()) val := reflect.New(slice.Type().Elem())
for i, v := range values { for i, v := range values {
parse(v, val) err := parse(fieldName, v, val)
if err != nil {
return err
}
slice.Index(i).Set(val.Elem()) slice.Index(i).Set(val.Elem())
} }
fv.Elem().Set(slice) fv.Elem().Set(slice)
return nil
} }
func parse(v string, fv reflect.Value) { func parse(fieldName, v string, fv reflect.Value) error {
var err error
switch f := fv.Interface().(type) { switch f := fv.Interface().(type) {
case *string: case *string:
*f = v *f = v
case *int: case *int:
*f, _ = strconv.Atoi(v) *f, err = strconv.Atoi(v)
case *float32: case *float32:
v, _ := strconv.ParseFloat(v, 32) var f64 float64
*f = float32(v) f64, err = strconv.ParseFloat(v, 32)
*f = float32(f64)
case *float64: case *float64:
*f, _ = strconv.ParseFloat(v, 64) *f, err = strconv.ParseFloat(v, 64)
} }
if err != nil {
return DecodeError{fieldName, fv.Elem().Type().Kind().String(), v}
}
return nil
} }
func getPrefix(ft reflect.StructField, prefix string) string { func getPrefix(ft reflect.StructField, prefix string) string {

View File

@ -73,7 +73,7 @@ var expectedPD = nested{`test5`, 30, 3.75}
func TestDecode(t *testing.T) { func TestDecode(t *testing.T) {
data := testStruct{} data := testStruct{}
Decode(input, &data) _ = Decode(input, &data)
if *data.PA != expectedPA { if *data.PA != expectedPA {
t.Errorf(`PA was incorrect. Expected %v but got %v`, expectedPA, *data.PA) t.Errorf(`PA was incorrect. Expected %v but got %v`, expectedPA, *data.PA)
@ -87,3 +87,19 @@ func TestDecode(t *testing.T) {
t.Errorf("Data dit not match expected output. Expected \n%v\nbut got\n%v", expected, data) t.Errorf("Data dit not match expected output. Expected \n%v\nbut got\n%v", expected, data)
} }
} }
func TestDecodeError(t *testing.T) {
var data struct {
A struct {
B float64
}
}
err := Decode(Values{`A.B`: {`a`}}, &data)
if err == nil {
t.Error(`Expected error but got nil`)
}
t.Log(err)
}