Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: if a different type in slice, raise error #212

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ func (d *Decoder) Decode(dst interface{}, src map[string][]string) error {
return nil
}

//setDefaults sets the default values when the `default` tag is specified,
//default is supported on basic/primitive types and their pointers,
//nested structs can also have default tags
// setDefaults sets the default values when the `default` tag is specified,
// default is supported on basic/primitive types and their pointers,
// nested structs can also have default tags
func (d *Decoder) setDefaults(t reflect.Type, v reflect.Value) MultiError {
struc := d.cache.get(t)
if struc == nil {
Expand Down Expand Up @@ -130,9 +130,12 @@ func (d *Decoder) setDefaults(t reflect.Type, v reflect.Value) MultiError {
defaultSlice := reflect.MakeSlice(f.typ, 0, cap(vals))
for _, val := range vals {
//this check is to handle if the wrong value is provided
if convertedVal := builtinConverters[f.typ.Elem().Kind()](val); convertedVal.IsValid() {
defaultSlice = reflect.Append(defaultSlice, convertedVal)
convertedVal := builtinConverters[f.typ.Elem().Kind()](val)
if !convertedVal.IsValid() {
errs.merge(MultiError{"default-" + f.name: fmt.Errorf("failed setting default: %s is not compatible with field %s type", val, f.name)})
break
}
defaultSlice = reflect.Append(defaultSlice, convertedVal)
}
vCurrent.Set(defaultSlice)
} else if f.typ.Kind() == reflect.Ptr {
Expand Down
71 changes: 69 additions & 2 deletions decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package schema
import (
"encoding/hex"
"errors"
"fmt"
"reflect"
"strings"
"testing"
Expand Down Expand Up @@ -2214,9 +2215,75 @@ func TestRequiredFieldsCannotHaveDefaults(t *testing.T) {

}

func TestInvalidDefaultElementInSliceRaiseError(t *testing.T) {
type D struct {
A []int `schema:"a,default:0|notInt"`
B []bool `schema:"b,default:true|notInt"`
C []*float32 `schema:"c,default:1.1|notInt"`
AlexVulaj marked this conversation as resolved.
Show resolved Hide resolved
// //uint types
D []uint `schema:"d,default:1|notInt"`
E []uint8 `schema:"e,default:2|notInt"`
F []uint16 `schema:"f,default:3|notInt"`
G []uint32 `schema:"g,default:4|notInt"`
H []uint64 `schema:"h,default:5|notInt"`
// // uint types pointers
I []*uint `schema:"i,default:6|notInt"`
J []*uint8 `schema:"j,default:7|notInt"`
K []*uint16 `schema:"k,default:12|notInt"`
L []*uint32 `schema:"l,default:129|notInt"`
M []*uint64 `schema:"m,default:11111|notInt"`
// // int types
N []int `schema:"n,default:11|notInt"`
O []int8 `schema:"o,default:12|notInt"`
P []int16 `schema:"p,default:13|notInt"`
Q []int32 `schema:"q,default:14|notInt"`
R []int64 `schema:"r,default:15|notInt"`
// // int types pointers
S []*int `schema:"s,default:1000|notInt"`
T []*int8 `schema:"t,default:1000|notInt"`
U []*int16 `schema:"u,default:1000|notInt"`
V []*int32 `schema:"v,default:22222|notInt"`
W []*int64 `schema:"w,default:11111|notInt"`
// // float
X []float32 `schema:"c,default:2.2|notInt"`
Y []float64 `schema:"c,default:3.3|notInt"`
Z []*float64 `schema:"c,default:4.4|notInt"`
}
d := D{}

data := map[string][]string{}
pErrMsg := "default option is supported only on: bool, float variants, string, unit variants types or their corresponding pointers or slices"
eng := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

decoder := NewDecoder()

err := decoder.Decode(&d, data)

if err == nil {
t.Error("if a different type exists, error should be raised")
}

e, ok := err.(MultiError)
AlexVulaj marked this conversation as resolved.
Show resolved Hide resolved
if !ok || len(e) != 26 {
t.Errorf("Expected 26 errors, got %#v", err)
}
for _, v := range eng {
fieldKey := "default-" + string(v)
errMsg := fmt.Sprintf("failed setting default: notInt is not compatible with field %s type", string(v))
if ferr, ok := e[fieldKey]; ok {
// check pointer type field
if ferr.Error() == pErrMsg {
continue
}
if strings.Compare(ferr.Error(), errMsg) != 0 {
t.Errorf("%s: expected %s, got %#v", fieldKey, ferr.Error(), errMsg)
}
}
}
AlexVulaj marked this conversation as resolved.
Show resolved Hide resolved
}

func TestInvalidDefaultsValuesHaveNoEffect(t *testing.T) {
type D struct {
A []int `schema:"a,default:wrong1|wrong2"`
B bool `schema:"b,default:invalid"`
C *float32 `schema:"c,default:notAFloat"`
//uint types
Expand Down Expand Up @@ -2251,7 +2318,7 @@ func TestInvalidDefaultsValuesHaveNoEffect(t *testing.T) {

d := D{}

expected := D{A: []int{}}
expected := D{}

data := map[string][]string{}

Expand Down