|
@@ -306,30 +306,61 @@ func TestUnmarshalIntPtr(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func TestUnmarshalIntSliceOfPtr(t *testing.T) {
|
|
|
- type inner struct {
|
|
|
- Ints []*int `key:"ints"`
|
|
|
- Intps []**int `key:"intps"`
|
|
|
- }
|
|
|
- m := map[string]any{
|
|
|
- "ints": []int{1, 2, 3},
|
|
|
- "intps": []int{1, 2, 3, 4},
|
|
|
- }
|
|
|
+ t.Run("int slice", func(t *testing.T) {
|
|
|
+ type inner struct {
|
|
|
+ Ints []*int `key:"ints"`
|
|
|
+ Intps []**int `key:"intps"`
|
|
|
+ }
|
|
|
+ m := map[string]any{
|
|
|
+ "ints": []int{1, 2, 3},
|
|
|
+ "intps": []int{1, 2, 3, 4},
|
|
|
+ }
|
|
|
|
|
|
- var in inner
|
|
|
- if assert.NoError(t, UnmarshalKey(m, &in)) {
|
|
|
- assert.NotEmpty(t, in.Ints)
|
|
|
- var ints []int
|
|
|
- for _, i := range in.Ints {
|
|
|
- ints = append(ints, *i)
|
|
|
+ var in inner
|
|
|
+ if assert.NoError(t, UnmarshalKey(m, &in)) {
|
|
|
+ assert.NotEmpty(t, in.Ints)
|
|
|
+ var ints []int
|
|
|
+ for _, i := range in.Ints {
|
|
|
+ ints = append(ints, *i)
|
|
|
+ }
|
|
|
+ assert.EqualValues(t, []int{1, 2, 3}, ints)
|
|
|
+
|
|
|
+ var intps []int
|
|
|
+ for _, i := range in.Intps {
|
|
|
+ intps = append(intps, **i)
|
|
|
+ }
|
|
|
+ assert.EqualValues(t, []int{1, 2, 3, 4}, intps)
|
|
|
}
|
|
|
- assert.EqualValues(t, []int{1, 2, 3}, ints)
|
|
|
+ })
|
|
|
|
|
|
- var intps []int
|
|
|
- for _, i := range in.Intps {
|
|
|
- intps = append(intps, **i)
|
|
|
+ t.Run("int slice with error", func(t *testing.T) {
|
|
|
+ type inner struct {
|
|
|
+ Ints []*int `key:"ints"`
|
|
|
+ Intps []**int `key:"intps"`
|
|
|
}
|
|
|
- assert.EqualValues(t, []int{1, 2, 3, 4}, 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) {
|
|
@@ -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) {
|
|
|
type inner struct {
|
|
|
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) {
|
|
|
type inner struct {
|
|
|
Int **int64 `key:"int"`
|
|
@@ -491,14 +606,25 @@ func TestUnmarshalBoolSliceEmpty(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func TestUnmarshalBoolSliceWithDefault(t *testing.T) {
|
|
|
- type inner struct {
|
|
|
- Bools []bool `key:"bools,default=[true,false]"`
|
|
|
- }
|
|
|
+ t.Run("slice with default", func(t *testing.T) {
|
|
|
+ type inner struct {
|
|
|
+ Bools []bool `key:"bools,default=[true,false]"`
|
|
|
+ }
|
|
|
|
|
|
- var in inner
|
|
|
- if assert.NoError(t, UnmarshalKey(nil, &in)) {
|
|
|
- assert.ElementsMatch(t, []bool{true, false}, in.Bools)
|
|
|
- }
|
|
|
+ var in inner
|
|
|
+ if assert.NoError(t, UnmarshalKey(nil, &in)) {
|
|
|
+ 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) {
|
|
@@ -726,19 +852,45 @@ func TestUnmarshalStringWithMissing(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func TestUnmarshalStringSliceFromString(t *testing.T) {
|
|
|
- var v struct {
|
|
|
- Names []string `key:"names"`
|
|
|
- }
|
|
|
- m := map[string]any{
|
|
|
- "names": `["first", "second"]`,
|
|
|
- }
|
|
|
+ t.Run("slice from string", func(t *testing.T) {
|
|
|
+ var v struct {
|
|
|
+ Names []string `key:"names"`
|
|
|
+ }
|
|
|
+ m := map[string]any{
|
|
|
+ "names": `["first", "second"]`,
|
|
|
+ }
|
|
|
|
|
|
- ast := assert.New(t)
|
|
|
- if ast.NoError(UnmarshalKey(m, &v)) {
|
|
|
- ast.Equal(2, len(v.Names))
|
|
|
- ast.Equal("first", v.Names[0])
|
|
|
- ast.Equal("second", v.Names[1])
|
|
|
- }
|
|
|
+ ast := assert.New(t)
|
|
|
+ if ast.NoError(UnmarshalKey(m, &v)) {
|
|
|
+ ast.Equal(2, len(v.Names))
|
|
|
+ ast.Equal("first", v.Names[0])
|
|
|
+ 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) {
|
|
@@ -800,19 +952,32 @@ func (c CustomStringer) String() string {
|
|
|
}
|
|
|
|
|
|
func TestUnmarshalStringMapFromStringer(t *testing.T) {
|
|
|
- var v struct {
|
|
|
- Sort map[string]string `key:"sort"`
|
|
|
- }
|
|
|
- m := map[string]any{
|
|
|
- "sort": CustomStringer(`"value":"ascend","emptyStr":""`),
|
|
|
- }
|
|
|
+ t.Run("CustomStringer", func(t *testing.T) {
|
|
|
+ var v struct {
|
|
|
+ Sort map[string]string `key:"sort"`
|
|
|
+ }
|
|
|
+ m := map[string]any{
|
|
|
+ "sort": CustomStringer(`"value":"ascend","emptyStr":""`),
|
|
|
+ }
|
|
|
|
|
|
- ast := assert.New(t)
|
|
|
- if ast.NoError(UnmarshalKey(m, &v)) {
|
|
|
- ast.Equal(2, len(v.Sort))
|
|
|
- ast.Equal("ascend", v.Sort["value"])
|
|
|
- ast.Equal("", v.Sort["emptyStr"])
|
|
|
- }
|
|
|
+ ast := assert.New(t)
|
|
|
+ if ast.NoError(UnmarshalKey(m, &v)) {
|
|
|
+ ast.Equal(2, len(v.Sort))
|
|
|
+ ast.Equal("ascend", v.Sort["value"])
|
|
|
+ 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) {
|
|
@@ -906,48 +1071,83 @@ func TestUnmarshalStringSliceMapFromString(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func TestUnmarshalStruct(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": "400000",
|
|
|
- },
|
|
|
- }
|
|
|
+ t.Run("struct", 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": "400000",
|
|
|
+ },
|
|
|
+ }
|
|
|
|
|
|
- var in inner
|
|
|
- ast := assert.New(t)
|
|
|
- if ast.NoError(UnmarshalKey(m, &in)) {
|
|
|
- ast.Equal("kevin", in.Name)
|
|
|
- ast.Equal("shanghai", in.Address.City)
|
|
|
- ast.Equal(200000, in.Address.ZipCode)
|
|
|
- ast.Equal("hello", in.AddressP.DefaultString)
|
|
|
- ast.Equal("beijing", in.AddressP.City)
|
|
|
- ast.Equal(300000, in.AddressP.ZipCode)
|
|
|
- ast.Equal("hello", in.AddressP.DefaultString)
|
|
|
- ast.Equal("guangzhou", (*in.AddressPP).City)
|
|
|
- ast.Equal(400000, (*in.AddressPP).ZipCode)
|
|
|
- ast.Equal("hello", (*in.AddressPP).DefaultString)
|
|
|
- }
|
|
|
+ var in inner
|
|
|
+ ast := assert.New(t)
|
|
|
+ if ast.NoError(UnmarshalKey(m, &in)) {
|
|
|
+ ast.Equal("kevin", in.Name)
|
|
|
+ ast.Equal("shanghai", in.Address.City)
|
|
|
+ ast.Equal(200000, in.Address.ZipCode)
|
|
|
+ ast.Equal("hello", in.AddressP.DefaultString)
|
|
|
+ ast.Equal("beijing", in.AddressP.City)
|
|
|
+ ast.Equal(300000, in.AddressP.ZipCode)
|
|
|
+ ast.Equal("hello", in.AddressP.DefaultString)
|
|
|
+ ast.Equal("guangzhou", (*in.AddressPP).City)
|
|
|
+ ast.Equal(400000, (*in.AddressPP).ZipCode)
|
|
|
+ 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) {
|
|
@@ -1086,21 +1286,44 @@ func TestUnmarshalStructOptionalDependsNot(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func TestUnmarshalStructOptionalDependsNotErrorDetails(t *testing.T) {
|
|
|
- type address struct {
|
|
|
- Optional string `key:",optional"`
|
|
|
- OptionalDepends string `key:",optional=!Optional"`
|
|
|
- }
|
|
|
- type inner struct {
|
|
|
- Name string `key:"name"`
|
|
|
- Address address `key:"address"`
|
|
|
- }
|
|
|
+ t.Run("mutal optionals", func(t *testing.T) {
|
|
|
+ type address struct {
|
|
|
+ Optional string `key:",optional"`
|
|
|
+ OptionalDepends string `key:",optional=!Optional"`
|
|
|
+ }
|
|
|
+ type inner struct {
|
|
|
+ Name string `key:"name"`
|
|
|
+ Address address `key:"address"`
|
|
|
+ }
|
|
|
|
|
|
- m := map[string]any{
|
|
|
- "name": "kevin",
|
|
|
- }
|
|
|
+ m := map[string]any{
|
|
|
+ "name": "kevin",
|
|
|
+ }
|
|
|
|
|
|
- var in inner
|
|
|
- assert.Error(t, UnmarshalKey(m, &in))
|
|
|
+ var in inner
|
|
|
+ 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) {
|
|
@@ -1440,16 +1663,48 @@ func TestUnmarshalMapOfInt(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func TestUnmarshalMapOfStructError(t *testing.T) {
|
|
|
- m := map[string]any{
|
|
|
- "Ids": map[string]any{"first": "second"},
|
|
|
- }
|
|
|
- var v struct {
|
|
|
- Ids map[string]struct {
|
|
|
- Name string
|
|
|
+func TestUnmarshalMapOfStruct(t *testing.T) {
|
|
|
+ t.Run("map of struct with error", func(t *testing.T) {
|
|
|
+ m := map[string]any{
|
|
|
+ "Ids": map[string]any{"first": "second"},
|
|
|
}
|
|
|
- }
|
|
|
- assert.Error(t, UnmarshalKey(m, &v))
|
|
|
+ var v struct {
|
|
|
+ Ids map[string]struct {
|
|
|
+ Name string
|
|
|
+ }
|
|
|
+ }
|
|
|
+ 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) {
|
|
@@ -1492,26 +1747,46 @@ func TestUnmarshalSlice(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func TestUnmarshalSliceOfStruct(t *testing.T) {
|
|
|
- m := map[string]any{
|
|
|
- "Ids": []map[string]any{
|
|
|
- {
|
|
|
- "First": 1,
|
|
|
- "Second": 2,
|
|
|
+ t.Run("slice of struct", func(t *testing.T) {
|
|
|
+ m := map[string]any{
|
|
|
+ "Ids": []map[string]any{
|
|
|
+ {
|
|
|
+ "First": 1,
|
|
|
+ "Second": 2,
|
|
|
+ },
|
|
|
},
|
|
|
- },
|
|
|
- }
|
|
|
- var v struct {
|
|
|
- Ids []struct {
|
|
|
- First int
|
|
|
- Second int
|
|
|
}
|
|
|
- }
|
|
|
- ast := assert.New(t)
|
|
|
- if ast.NoError(UnmarshalKey(m, &v)) {
|
|
|
- ast.Equal(1, len(v.Ids))
|
|
|
- ast.Equal(1, v.Ids[0].First)
|
|
|
- ast.Equal(2, v.Ids[0].Second)
|
|
|
- }
|
|
|
+ var v struct {
|
|
|
+ Ids []struct {
|
|
|
+ First int
|
|
|
+ Second int
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ast := assert.New(t)
|
|
|
+ if ast.NoError(UnmarshalKey(m, &v)) {
|
|
|
+ ast.Equal(1, len(v.Ids))
|
|
|
+ ast.Equal(1, v.Ids[0].First)
|
|
|
+ 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) {
|
|
@@ -3122,21 +3397,57 @@ func TestUnmarshalRangeError(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func TestUnmarshalNestedMap(t *testing.T) {
|
|
|
- var c struct {
|
|
|
- Anything map[string]map[string]string `json:"anything"`
|
|
|
- }
|
|
|
- m := map[string]any{
|
|
|
- "anything": map[string]map[string]any{
|
|
|
- "inner": {
|
|
|
- "id": "1",
|
|
|
- "name": "any",
|
|
|
+ t.Run("nested map", func(t *testing.T) {
|
|
|
+ var c struct {
|
|
|
+ Anything map[string]map[string]string `json:"anything"`
|
|
|
+ }
|
|
|
+ m := map[string]any{
|
|
|
+ "anything": map[string]map[string]any{
|
|
|
+ "inner": {
|
|
|
+ "id": "1",
|
|
|
+ "name": "any",
|
|
|
+ },
|
|
|
},
|
|
|
- },
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- if assert.NoError(t, NewUnmarshaler("json").Unmarshal(m, &c)) {
|
|
|
- assert.Equal(t, "1", c.Anything["inner"]["id"])
|
|
|
- }
|
|
|
+ if assert.NoError(t, NewUnmarshaler("json").Unmarshal(m, &c)) {
|
|
|
+ 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) {
|
|
@@ -3810,15 +4121,27 @@ func TestUnmarshal_EnvWithOptionsWrongValueString(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func TestUnmarshalJsonReaderMultiArray(t *testing.T) {
|
|
|
- var res struct {
|
|
|
- A string `json:"a"`
|
|
|
- B [][]string `json:"b"`
|
|
|
- }
|
|
|
- payload := `{"a": "133", "b": [["add", "cccd"], ["eeee"]]}`
|
|
|
- reader := strings.NewReader(payload)
|
|
|
- if assert.NoError(t, UnmarshalJsonReader(reader, &res)) {
|
|
|
- assert.Equal(t, 2, len(res.B))
|
|
|
- }
|
|
|
+ t.Run("reader multi array", func(t *testing.T) {
|
|
|
+ var res struct {
|
|
|
+ A string `json:"a"`
|
|
|
+ B [][]string `json:"b"`
|
|
|
+ }
|
|
|
+ payload := `{"a": "133", "b": [["add", "cccd"], ["eeee"]]}`
|
|
|
+ reader := strings.NewReader(payload)
|
|
|
+ if assert.NoError(t, UnmarshalJsonReader(reader, &res)) {
|
|
|
+ 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) {
|
|
@@ -4059,12 +4382,24 @@ func TestUnmarshalJsonReaderWithTypeMismatchBool(t *testing.T) {
|
|
|
assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(body), &req))
|
|
|
}
|
|
|
|
|
|
-func TestUnmarshalJsonReaderWithTypeMismatchString(t *testing.T) {
|
|
|
- var req struct {
|
|
|
- Params map[string]string `json:"params"`
|
|
|
- }
|
|
|
- body := `{"params":{"a":{"a":123}}}`
|
|
|
- assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(body), &req))
|
|
|
+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 {
|
|
|
+ Params map[string]string `json:"params"`
|
|
|
+ }
|
|
|
+ body := `{"params":{"a":{"a":123}}}`
|
|
|
+ assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(body), &req))
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
func TestUnmarshalJsonReaderWithMismatchType(t *testing.T) {
|
|
@@ -4077,43 +4412,95 @@ func TestUnmarshalJsonReaderWithMismatchType(t *testing.T) {
|
|
|
assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(body), &req))
|
|
|
}
|
|
|
|
|
|
-func TestUnmarshalJsonReaderWithMismatchTypeBool(t *testing.T) {
|
|
|
- type Req struct {
|
|
|
- Params map[string]bool `json:"params"`
|
|
|
- }
|
|
|
+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
|
|
|
- }{
|
|
|
- {
|
|
|
- name: "int",
|
|
|
- input: `{"params":{"a":123}}`,
|
|
|
- },
|
|
|
- {
|
|
|
- name: "int",
|
|
|
- input: `{"params":{"a":"123"}}`,
|
|
|
- },
|
|
|
- }
|
|
|
+ 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
|
|
|
- assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(test.input), &req))
|
|
|
- })
|
|
|
- }
|
|
|
+ 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 {
|
|
|
+ Params map[string]bool `json:"params"`
|
|
|
+ }
|
|
|
+
|
|
|
+ tests := []struct {
|
|
|
+ name string
|
|
|
+ input string
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "int",
|
|
|
+ input: `{"params":{"a":123}}`,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "int",
|
|
|
+ input: `{"params":{"a":"123"}}`,
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, test := range tests {
|
|
|
+ test := test
|
|
|
+ t.Run(test.name, func(t *testing.T) {
|
|
|
+ var req Req
|
|
|
+ assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(strings.NewReader(test.input), &req))
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
-func TestUnmarshalJsonReaderWithMismatchTypeBoolMap(t *testing.T) {
|
|
|
- var req struct {
|
|
|
- Params map[string]string `json:"params"`
|
|
|
- }
|
|
|
- assert.Equal(t, errTypeMismatch, UnmarshalJsonMap(map[string]any{
|
|
|
- "params": map[string]any{
|
|
|
- "a": true,
|
|
|
- },
|
|
|
- }, &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)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ t.Run("bool map with error", func(t *testing.T) {
|
|
|
+ var req struct {
|
|
|
+ Params map[string]string `json:"params"`
|
|
|
+ }
|
|
|
+ assert.Equal(t, errTypeMismatch, UnmarshalJsonMap(map[string]any{
|
|
|
+ "params": map[string]any{
|
|
|
+ "a": true,
|
|
|
+ },
|
|
|
+ }, &req))
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
func TestUnmarshalJsonBytesSliceOfMaps(t *testing.T) {
|
|
@@ -4446,6 +4833,55 @@ func Test_UnmarshalMap(t *testing.T) {
|
|
|
var customer Customer
|
|
|
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) {
|