diff --git a/core/mapping/unmarshaler.go b/core/mapping/unmarshaler.go index 1f5da75b..5d315085 100644 --- a/core/mapping/unmarshaler.go +++ b/core/mapping/unmarshaler.go @@ -148,14 +148,17 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map return errValueNotSettable } - baseType := fieldType.Elem() - dereffedBaseType := Deref(baseType) - dereffedBaseKind := dereffedBaseType.Kind() refValue := reflect.ValueOf(mapValue) + if refValue.Kind() != reflect.Slice { + return errTypeMismatch + } if refValue.IsNil() { return nil } + baseType := fieldType.Elem() + dereffedBaseType := Deref(baseType) + dereffedBaseKind := dereffedBaseType.Kind() conv := reflect.MakeSlice(reflect.SliceOf(baseType), refValue.Len(), refValue.Cap()) if refValue.Len() == 0 { value.Set(conv) diff --git a/core/mapping/unmarshaler_test.go b/core/mapping/unmarshaler_test.go index ed21f32f..425dc80c 100644 --- a/core/mapping/unmarshaler_test.go +++ b/core/mapping/unmarshaler_test.go @@ -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) {