From ee1273206c2d8a5c3b613ffc25a24ebb5b4cb8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Soul=C3=A9?= Date: Thu, 13 Jan 2022 23:40:38 +0100 Subject: [PATCH] feat: introduce binding.FieldError type to tell the erroneous field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maxime Soulé --- binding/form_mapping.go | 29 ++++++++++++++++++++++++++++- binding/form_mapping_test.go | 20 +++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/binding/form_mapping.go b/binding/form_mapping.go index c24dd553..4334f702 100644 --- a/binding/form_mapping.go +++ b/binding/form_mapping.go @@ -26,6 +26,29 @@ var ( ErrConvertToMapString = errors.New("can not convert to map of strings") ) +type FieldError struct { + Field string + Err error +} + +func NewFieldError(field string, err error) error { + if err == nil { + return nil + } + return &FieldError{ + Field: field, + Err: err, + } +} + +func (e *FieldError) Error() string { + return fmt.Sprintf("field %q error: %s", e.Field, e.Err) +} + +func (e *FieldError) Unwrap() error { + return e.Err +} + func mapURI(ptr any, m map[string][]string) error { return mapFormByTag(ptr, m, "uri") } @@ -161,7 +184,11 @@ func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter } } - return setter.TrySet(value, field, tagValue, setOpt) + ok, err := setter.TrySet(value, field, tagValue, setOpt) + if err != nil { + return ok, NewFieldError(tagValue, err) + } + return ok, nil } func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSet bool, err error) { diff --git a/binding/form_mapping_test.go b/binding/form_mapping_test.go index 78f4df0e..b2a87873 100644 --- a/binding/form_mapping_test.go +++ b/binding/form_mapping_test.go @@ -5,6 +5,7 @@ package binding import ( + "errors" "reflect" "testing" "time" @@ -124,7 +125,7 @@ func TestMappingUnknownFieldType(t *testing.T) { err := mappingByPtr(&s, formSource{"U": {"unknown"}}, "form") assert.Error(t, err) - assert.Equal(t, errUnknownType, err) + assert.Equal(t, &FieldError{"U", errUnknownType}, err) } func TestMappingURI(t *testing.T) { @@ -288,3 +289,20 @@ func TestMappingIgnoredCircularRef(t *testing.T) { err := mappingByPtr(&s, formSource{}, "form") assert.NoError(t, err) } + +func TestNewField(t *testing.T) { + assert.NoError(t, NewFieldError("foo", nil)) + + orig := errors.New("bad value") + err := NewFieldError("foo", orig) + if assert.Error(t, err) { + assert.Equal(t, `field "foo" error: bad value`, err.Error()) + + if fieldErr, ok := err.(*FieldError); assert.True(t, ok) { //nolint: errorlint + assert.Equal(t, fieldErr.Field, "foo") + assert.Equal(t, fieldErr.Err, orig) + } + + assert.Equal(t, orig, errors.Unwrap(err)) + } +}