chore: add more tests (#3282)

master
Kevin Wan 2 years ago committed by GitHub
parent d76a39ac26
commit fa33329a44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -148,14 +148,17 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
return errValueNotSettable return errValueNotSettable
} }
baseType := fieldType.Elem()
dereffedBaseType := Deref(baseType)
dereffedBaseKind := dereffedBaseType.Kind()
refValue := reflect.ValueOf(mapValue) refValue := reflect.ValueOf(mapValue)
if refValue.Kind() != reflect.Slice {
return errTypeMismatch
}
if refValue.IsNil() { if refValue.IsNil() {
return nil return nil
} }
baseType := fieldType.Elem()
dereffedBaseType := Deref(baseType)
dereffedBaseKind := dereffedBaseType.Kind()
conv := reflect.MakeSlice(reflect.SliceOf(baseType), refValue.Len(), refValue.Cap()) conv := reflect.MakeSlice(reflect.SliceOf(baseType), refValue.Len(), refValue.Cap())
if refValue.Len() == 0 { if refValue.Len() == 0 {
value.Set(conv) value.Set(conv)

@ -306,6 +306,7 @@ func TestUnmarshalIntPtr(t *testing.T) {
} }
func TestUnmarshalIntSliceOfPtr(t *testing.T) { func TestUnmarshalIntSliceOfPtr(t *testing.T) {
t.Run("int slice", func(t *testing.T) {
type inner struct { type inner struct {
Ints []*int `key:"ints"` Ints []*int `key:"ints"`
Intps []**int `key:"intps"` Intps []**int `key:"intps"`
@ -330,6 +331,36 @@ func TestUnmarshalIntSliceOfPtr(t *testing.T) {
} }
assert.EqualValues(t, []int{1, 2, 3, 4}, intps) assert.EqualValues(t, []int{1, 2, 3, 4}, intps)
} }
})
t.Run("int slice with error", func(t *testing.T) {
type inner struct {
Ints []*int `key:"ints"`
Intps []**int `key:"intps"`
}
m := map[string]any{
"ints": []any{1, 2, "a"},
"intps": []int{1, 2, 3, 4},
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int slice with nil", func(t *testing.T) {
type inner struct {
Ints []int `key:"ints"`
}
m := map[string]any{
"ints": []any{nil},
}
var in inner
if assert.NoError(t, UnmarshalKey(m, &in)) {
assert.Empty(t, in.Ints)
}
})
} }
func TestUnmarshalIntWithDefault(t *testing.T) { func TestUnmarshalIntWithDefault(t *testing.T) {
@ -373,6 +404,42 @@ func TestUnmarshalIntWithString(t *testing.T) {
} }
}) })
t.Run("int wrong range", func(t *testing.T) {
type inner struct {
Int int64 `key:"int,string,range=[2:3]"`
Intp *int64 `key:"intp,range=[2:3]"`
Intpp **int64 `key:"intpp,range=[2:3]"`
}
m := map[string]any{
"int": json.Number("1"),
"intp": json.Number("2"),
"intpp": json.Number("3"),
}
var in inner
assert.ErrorIs(t, UnmarshalKey(m, &in), errNumberRange)
})
t.Run("int with wrong type", func(t *testing.T) {
type (
myString string
inner struct {
Int int64 `key:"int,string"`
Intp *int64 `key:"intp,string"`
Intpp **int64 `key:"intpp,string"`
}
)
m := map[string]any{
"int": myString("1"),
"intp": myString("2"),
"intpp": myString("3"),
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int with ptr", func(t *testing.T) { t.Run("int with ptr", func(t *testing.T) {
type inner struct { type inner struct {
Int *int64 `key:"int"` Int *int64 `key:"int"`
@ -387,6 +454,54 @@ func TestUnmarshalIntWithString(t *testing.T) {
} }
}) })
t.Run("int with invalid value", func(t *testing.T) {
type inner struct {
Int int64 `key:"int"`
}
m := map[string]any{
"int": json.Number("a"),
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("uint with invalid value", func(t *testing.T) {
type inner struct {
Int uint64 `key:"int"`
}
m := map[string]any{
"int": json.Number("a"),
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("float with invalid value", func(t *testing.T) {
type inner struct {
Value float64 `key:"float"`
}
m := map[string]any{
"float": json.Number("a"),
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("float with invalid value", func(t *testing.T) {
type inner struct {
Value string `key:"value"`
}
m := map[string]any{
"value": json.Number("a"),
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int with ptr of ptr", func(t *testing.T) { t.Run("int with ptr of ptr", func(t *testing.T) {
type inner struct { type inner struct {
Int **int64 `key:"int"` Int **int64 `key:"int"`
@ -491,6 +606,7 @@ func TestUnmarshalBoolSliceEmpty(t *testing.T) {
} }
func TestUnmarshalBoolSliceWithDefault(t *testing.T) { func TestUnmarshalBoolSliceWithDefault(t *testing.T) {
t.Run("slice with default", func(t *testing.T) {
type inner struct { type inner struct {
Bools []bool `key:"bools,default=[true,false]"` Bools []bool `key:"bools,default=[true,false]"`
} }
@ -499,6 +615,16 @@ func TestUnmarshalBoolSliceWithDefault(t *testing.T) {
if assert.NoError(t, UnmarshalKey(nil, &in)) { if assert.NoError(t, UnmarshalKey(nil, &in)) {
assert.ElementsMatch(t, []bool{true, false}, in.Bools) assert.ElementsMatch(t, []bool{true, false}, in.Bools)
} }
})
t.Run("slice with default error", func(t *testing.T) {
type inner struct {
Bools []bool `key:"bools,default=[true,fal]"`
}
var in inner
assert.Error(t, UnmarshalKey(nil, &in))
})
} }
func TestUnmarshalIntSliceWithDefault(t *testing.T) { func TestUnmarshalIntSliceWithDefault(t *testing.T) {
@ -726,6 +852,7 @@ func TestUnmarshalStringWithMissing(t *testing.T) {
} }
func TestUnmarshalStringSliceFromString(t *testing.T) { func TestUnmarshalStringSliceFromString(t *testing.T) {
t.Run("slice from string", func(t *testing.T) {
var v struct { var v struct {
Names []string `key:"names"` Names []string `key:"names"`
} }
@ -739,6 +866,31 @@ func TestUnmarshalStringSliceFromString(t *testing.T) {
ast.Equal("first", v.Names[0]) ast.Equal("first", v.Names[0])
ast.Equal("second", v.Names[1]) ast.Equal("second", v.Names[1])
} }
})
t.Run("slice from string with slice error", func(t *testing.T) {
var v struct {
Names []int `key:"names"`
}
m := map[string]any{
"names": `["first", 1]`,
}
assert.Error(t, UnmarshalKey(m, &v))
})
t.Run("slice from string with error", func(t *testing.T) {
type myString string
var v struct {
Names []string `key:"names"`
}
m := map[string]any{
"names": myString("not a slice"),
}
assert.Error(t, UnmarshalKey(m, &v))
})
} }
func TestUnmarshalIntSliceFromString(t *testing.T) { func TestUnmarshalIntSliceFromString(t *testing.T) {
@ -800,6 +952,7 @@ func (c CustomStringer) String() string {
} }
func TestUnmarshalStringMapFromStringer(t *testing.T) { func TestUnmarshalStringMapFromStringer(t *testing.T) {
t.Run("CustomStringer", func(t *testing.T) {
var v struct { var v struct {
Sort map[string]string `key:"sort"` Sort map[string]string `key:"sort"`
} }
@ -813,6 +966,18 @@ func TestUnmarshalStringMapFromStringer(t *testing.T) {
ast.Equal("ascend", v.Sort["value"]) ast.Equal("ascend", v.Sort["value"])
ast.Equal("", v.Sort["emptyStr"]) ast.Equal("", v.Sort["emptyStr"])
} }
})
t.Run("CustomStringer incorrect", func(t *testing.T) {
var v struct {
Sort map[string]string `key:"sort"`
}
m := map[string]any{
"sort": CustomStringer(`"value"`),
}
assert.Error(t, UnmarshalKey(m, &v))
})
} }
func TestUnmarshalStringMapFromUnsupportedType(t *testing.T) { func TestUnmarshalStringMapFromUnsupportedType(t *testing.T) {
@ -906,6 +1071,7 @@ func TestUnmarshalStringSliceMapFromString(t *testing.T) {
} }
func TestUnmarshalStruct(t *testing.T) { func TestUnmarshalStruct(t *testing.T) {
t.Run("struct", func(t *testing.T) {
type address struct { type address struct {
City string `key:"city"` City string `key:"city"`
ZipCode int `key:"zipcode,string"` ZipCode int `key:"zipcode,string"`
@ -948,6 +1114,40 @@ func TestUnmarshalStruct(t *testing.T) {
ast.Equal(400000, (*in.AddressPP).ZipCode) ast.Equal(400000, (*in.AddressPP).ZipCode)
ast.Equal("hello", (*in.AddressPP).DefaultString) ast.Equal("hello", (*in.AddressPP).DefaultString)
} }
})
t.Run("struct with error", func(t *testing.T) {
type address struct {
City string `key:"city"`
ZipCode int `key:"zipcode,string"`
DefaultString string `key:"defaultstring,default=hello"`
Optional string `key:",optional"`
}
type inner struct {
Name string `key:"name"`
Address address `key:"address"`
AddressP *address `key:"addressp"`
AddressPP **address `key:"addresspp"`
}
m := map[string]any{
"name": "kevin",
"address": map[string]any{
"city": "shanghai",
"zipcode": "200000",
},
"addressp": map[string]any{
"city": "beijing",
"zipcode": "300000",
},
"addresspp": map[string]any{
"city": "guangzhou",
"zipcode": "a",
},
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
} }
func TestUnmarshalStructOptionalDepends(t *testing.T) { func TestUnmarshalStructOptionalDepends(t *testing.T) {
@ -1086,6 +1286,7 @@ func TestUnmarshalStructOptionalDependsNot(t *testing.T) {
} }
func TestUnmarshalStructOptionalDependsNotErrorDetails(t *testing.T) { func TestUnmarshalStructOptionalDependsNotErrorDetails(t *testing.T) {
t.Run("mutal optionals", func(t *testing.T) {
type address struct { type address struct {
Optional string `key:",optional"` Optional string `key:",optional"`
OptionalDepends string `key:",optional=!Optional"` OptionalDepends string `key:",optional=!Optional"`
@ -1101,6 +1302,28 @@ func TestUnmarshalStructOptionalDependsNotErrorDetails(t *testing.T) {
var in inner var in inner
assert.Error(t, UnmarshalKey(m, &in)) assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("with default", func(t *testing.T) {
type address struct {
Optional string `key:",optional"`
OptionalDepends string `key:",default=value,optional"`
}
type inner struct {
Name string `key:"name"`
Address address `key:"address"`
}
m := map[string]any{
"name": "kevin",
}
var in inner
if assert.NoError(t, UnmarshalKey(m, &in)) {
assert.Equal(t, "kevin", in.Name)
assert.Equal(t, "value", in.Address.OptionalDepends)
}
})
} }
func TestUnmarshalStructOptionalDependsNotNested(t *testing.T) { func TestUnmarshalStructOptionalDependsNotNested(t *testing.T) {
@ -1440,7 +1663,8 @@ func TestUnmarshalMapOfInt(t *testing.T) {
} }
} }
func TestUnmarshalMapOfStructError(t *testing.T) { func TestUnmarshalMapOfStruct(t *testing.T) {
t.Run("map of struct with error", func(t *testing.T) {
m := map[string]any{ m := map[string]any{
"Ids": map[string]any{"first": "second"}, "Ids": map[string]any{"first": "second"},
} }
@ -1450,6 +1674,37 @@ func TestUnmarshalMapOfStructError(t *testing.T) {
} }
} }
assert.Error(t, UnmarshalKey(m, &v)) assert.Error(t, UnmarshalKey(m, &v))
})
t.Run("map of struct", func(t *testing.T) {
m := map[string]any{
"Ids": map[string]any{
"foo": map[string]any{"Name": "foo"},
},
}
var v struct {
Ids map[string]struct {
Name string
}
}
if assert.NoError(t, UnmarshalKey(m, &v)) {
assert.Equal(t, "foo", v.Ids["foo"].Name)
}
})
t.Run("map of struct error", func(t *testing.T) {
m := map[string]any{
"Ids": map[string]any{
"foo": map[string]any{"name": "foo"},
},
}
var v struct {
Ids map[string]struct {
Name string
}
}
assert.Error(t, UnmarshalKey(m, &v))
})
} }
func TestUnmarshalSlice(t *testing.T) { func TestUnmarshalSlice(t *testing.T) {
@ -1492,6 +1747,7 @@ func TestUnmarshalSlice(t *testing.T) {
} }
func TestUnmarshalSliceOfStruct(t *testing.T) { func TestUnmarshalSliceOfStruct(t *testing.T) {
t.Run("slice of struct", func(t *testing.T) {
m := map[string]any{ m := map[string]any{
"Ids": []map[string]any{ "Ids": []map[string]any{
{ {
@ -1512,6 +1768,25 @@ func TestUnmarshalSliceOfStruct(t *testing.T) {
ast.Equal(1, v.Ids[0].First) ast.Equal(1, v.Ids[0].First)
ast.Equal(2, v.Ids[0].Second) ast.Equal(2, v.Ids[0].Second)
} }
})
t.Run("slice of struct", func(t *testing.T) {
m := map[string]any{
"Ids": []map[string]any{
{
"First": "a",
"Second": 2,
},
},
}
var v struct {
Ids []struct {
First int
Second int
}
}
assert.Error(t, UnmarshalKey(m, &v))
})
} }
func TestUnmarshalWithStringOptionsCorrect(t *testing.T) { func TestUnmarshalWithStringOptionsCorrect(t *testing.T) {
@ -3122,6 +3397,7 @@ func TestUnmarshalRangeError(t *testing.T) {
} }
func TestUnmarshalNestedMap(t *testing.T) { func TestUnmarshalNestedMap(t *testing.T) {
t.Run("nested map", func(t *testing.T) {
var c struct { var c struct {
Anything map[string]map[string]string `json:"anything"` Anything map[string]map[string]string `json:"anything"`
} }
@ -3137,6 +3413,41 @@ func TestUnmarshalNestedMap(t *testing.T) {
if assert.NoError(t, NewUnmarshaler("json").Unmarshal(m, &c)) { if assert.NoError(t, NewUnmarshaler("json").Unmarshal(m, &c)) {
assert.Equal(t, "1", c.Anything["inner"]["id"]) assert.Equal(t, "1", c.Anything["inner"]["id"])
} }
})
t.Run("nested map with slice element", func(t *testing.T) {
var c struct {
Anything map[string][]string `json:"anything"`
}
m := map[string]any{
"anything": map[string][]any{
"inner": {
"id",
"name",
},
},
}
if assert.NoError(t, NewUnmarshaler("json").Unmarshal(m, &c)) {
assert.Equal(t, []string{"id", "name"}, c.Anything["inner"])
}
})
t.Run("nested map with slice element error", func(t *testing.T) {
var c struct {
Anything map[string][]string `json:"anything"`
}
m := map[string]any{
"anything": map[string][]any{
"inner": {
"id",
1,
},
},
}
assert.Error(t, NewUnmarshaler("json").Unmarshal(m, &c))
})
} }
func TestUnmarshalNestedMapMismatch(t *testing.T) { func TestUnmarshalNestedMapMismatch(t *testing.T) {
@ -3810,6 +4121,7 @@ func TestUnmarshal_EnvWithOptionsWrongValueString(t *testing.T) {
} }
func TestUnmarshalJsonReaderMultiArray(t *testing.T) { func TestUnmarshalJsonReaderMultiArray(t *testing.T) {
t.Run("reader multi array", func(t *testing.T) {
var res struct { var res struct {
A string `json:"a"` A string `json:"a"`
B [][]string `json:"b"` B [][]string `json:"b"`
@ -3819,6 +4131,17 @@ func TestUnmarshalJsonReaderMultiArray(t *testing.T) {
if assert.NoError(t, UnmarshalJsonReader(reader, &res)) { if assert.NoError(t, UnmarshalJsonReader(reader, &res)) {
assert.Equal(t, 2, len(res.B)) assert.Equal(t, 2, len(res.B))
} }
})
t.Run("reader multi array with error", func(t *testing.T) {
var res struct {
A string `json:"a"`
B [][]string `json:"b"`
}
payload := `{"a": "133", "b": ["eeee"]}`
reader := strings.NewReader(payload)
assert.Error(t, UnmarshalJsonReader(reader, &res))
})
} }
func TestUnmarshalJsonReaderPtrMultiArrayString(t *testing.T) { func TestUnmarshalJsonReaderPtrMultiArrayString(t *testing.T) {
@ -4059,12 +4382,24 @@ func TestUnmarshalJsonReaderWithTypeMismatchBool(t *testing.T) {
assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(body), &req)) assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(body), &req))
} }
func TestUnmarshalJsonReaderWithTypeMismatchString(t *testing.T) { func TestUnmarshalJsonReaderWithTypeString(t *testing.T) {
t.Run("string type", func(t *testing.T) {
var req struct {
Params map[string]string `json:"params"`
}
body := `{"params":{"a":"b"}}`
if assert.NoError(t, UnmarshalJsonReader(strings.NewReader(body), &req)) {
assert.Equal(t, "b", req.Params["a"])
}
})
t.Run("string type mismatch", func(t *testing.T) {
var req struct { var req struct {
Params map[string]string `json:"params"` Params map[string]string `json:"params"`
} }
body := `{"params":{"a":{"a":123}}}` body := `{"params":{"a":{"a":123}}}`
assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(body), &req)) assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(body), &req))
})
} }
func TestUnmarshalJsonReaderWithMismatchType(t *testing.T) { func TestUnmarshalJsonReaderWithMismatchType(t *testing.T) {
@ -4077,7 +4412,41 @@ func TestUnmarshalJsonReaderWithMismatchType(t *testing.T) {
assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(body), &req)) assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(body), &req))
} }
func TestUnmarshalJsonReaderWithMismatchTypeBool(t *testing.T) { func TestUnmarshalJsonReaderWithTypeBool(t *testing.T) {
t.Run("bool type", func(t *testing.T) {
type Req struct {
Params map[string]bool `json:"params"`
}
tests := []struct {
name string
input string
expect bool
}{
{
name: "int",
input: `{"params":{"a":1}}`,
expect: true,
},
{
name: "int",
input: `{"params":{"a":0}}`,
expect: false,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
var req Req
if assert.NoError(t, UnmarshalJsonReader(strings.NewReader(test.input), &req)) {
assert.Equal(t, test.expect, req.Params["a"])
}
})
}
})
t.Run("bool type mismatch", func(t *testing.T) {
type Req struct { type Req struct {
Params map[string]bool `json:"params"` Params map[string]bool `json:"params"`
} }
@ -4103,9 +4472,26 @@ func TestUnmarshalJsonReaderWithMismatchTypeBool(t *testing.T) {
assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(test.input), &req)) assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(test.input), &req))
}) })
} }
})
}
func TestUnmarshalJsonReaderWithTypeBoolMap(t *testing.T) {
t.Run("bool map", func(t *testing.T) {
var req struct {
Params map[string]bool `json:"params"`
}
if assert.NoError(t, UnmarshalJsonMap(map[string]any{
"params": map[string]any{
"a": true,
},
}, &req)) {
assert.Equal(t, map[string]bool{
"a": true,
}, req.Params)
} }
})
func TestUnmarshalJsonReaderWithMismatchTypeBoolMap(t *testing.T) { t.Run("bool map with error", func(t *testing.T) {
var req struct { var req struct {
Params map[string]string `json:"params"` Params map[string]string `json:"params"`
} }
@ -4114,6 +4500,7 @@ func TestUnmarshalJsonReaderWithMismatchTypeBoolMap(t *testing.T) {
"a": true, "a": true,
}, },
}, &req)) }, &req))
})
} }
func TestUnmarshalJsonBytesSliceOfMaps(t *testing.T) { func TestUnmarshalJsonBytesSliceOfMaps(t *testing.T) {
@ -4446,6 +4833,55 @@ func Test_UnmarshalMap(t *testing.T) {
var customer Customer var customer Customer
assert.ErrorIs(t, UnmarshalKey(input, &customer), errTypeMismatch) assert.ErrorIs(t, UnmarshalKey(input, &customer), errTypeMismatch)
}) })
t.Run("map from string", func(t *testing.T) {
type Customer struct {
Names map[string]string `key:"names,string"`
}
input := map[string]any{
"names": `{"name": "Tom"}`,
}
var customer Customer
assert.NoError(t, UnmarshalKey(input, &customer))
assert.Equal(t, "Tom", customer.Names["name"])
})
t.Run("map from string with error", func(t *testing.T) {
type Customer struct {
Names map[string]any `key:"names,string"`
}
input := map[string]any{
"names": `"name"`,
}
var customer Customer
assert.Error(t, UnmarshalKey(input, &customer))
})
}
// func TestUnmarshalWithFillPrimitives(t *testing.T) {
// t.Run("fill primitives", func(t *testing.T) {
// type St struct {
// A int `key:"a,string,range=[5,10]"`
// }
// var st St
// err := UnmarshalKey(map[string]any{
// "a": "1",
// }, &st)
// assert.ErrorIs(t, err, errNumberRange)
// })
// }
func TestUnmarshaler_Unmarshal(t *testing.T) {
t.Run("not struct", func(t *testing.T) {
var i int
unmarshaler := NewUnmarshaler(jsonTagKey)
err := unmarshaler.UnmarshalValuer(nil, &i)
assert.Error(t, err)
})
} }
func TestGetValueWithChainedKeys(t *testing.T) { func TestGetValueWithChainedKeys(t *testing.T) {

Loading…
Cancel
Save