From 34a9eba03a2b0809e3226f93b8d2ca11c833afe3 Mon Sep 17 00:00:00 2001 From: NiseVoid Date: Tue, 8 Oct 2019 11:09:07 +0200 Subject: [PATCH] Return parse errors --- forms.go | 62 ++++++++++++++++++++++++++++++++++++++------------- forms_test.go | 18 ++++++++++++++- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/forms.go b/forms.go index bcf3b48..7a555c0 100644 --- a/forms.go +++ b/forms.go @@ -8,18 +8,28 @@ import ( "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 -func Decode(form Values, v interface{}) { +func Decode(form Values, v interface{}) error { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr { 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++ { 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() } - decode(form, fv, getPrefix(ft, prefix)) + err := decode(form, fv, getPrefix(ft, prefix)) + if err != nil { + return err + } continue } - v, ok := form[getName(ft, prefix)] + fieldName := getName(ft, prefix) + v, ok := form[fieldName] if !ok || len(v) == 0 { continue } @@ -75,37 +89,55 @@ func decode(form Values, rv reflect.Value, prefix string) { 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 { - parse(values[0], fv) - return + return parse(fieldName, values[0], fv) } slice := reflect.MakeSlice(fv.Elem().Type(), len(values), len(values)) val := reflect.New(slice.Type().Elem()) for i, v := range values { - parse(v, val) + err := parse(fieldName, v, val) + if err != nil { + return err + } slice.Index(i).Set(val.Elem()) } 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) { case *string: *f = v case *int: - *f, _ = strconv.Atoi(v) + *f, err = strconv.Atoi(v) case *float32: - v, _ := strconv.ParseFloat(v, 32) - *f = float32(v) + var f64 float64 + f64, err = strconv.ParseFloat(v, 32) + *f = float32(f64) 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 { diff --git a/forms_test.go b/forms_test.go index c33ed33..b8cb3dc 100644 --- a/forms_test.go +++ b/forms_test.go @@ -73,7 +73,7 @@ var expectedPD = nested{`test5`, 30, 3.75} func TestDecode(t *testing.T) { data := testStruct{} - Decode(input, &data) + _ = Decode(input, &data) if *data.PA != expectedPA { 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) } } + +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) +}