package mapping import ( "encoding/json" "strconv" "testing" "time" "github.com/stretchr/testify/assert" "github.com/tal-tech/go-zero/core/stringx" ) // because json.Number doesn't support strconv.ParseUint(...), // so we only can test to 62 bits. const maxUintBitsToTest = 62 func TestUnmarshalWithFullNameNotStruct(t *testing.T) { var s map[string]interface{} content := []byte(`{"name":"xiaoming"}`) err := UnmarshalJsonBytes(content, &s) assert.Equal(t, errValueNotStruct, err) } func TestUnmarshalWithoutTagName(t *testing.T) { type inner struct { Optional bool `key:",optional"` } m := map[string]interface{}{ "Optional": true, } var in inner assert.Nil(t, UnmarshalKey(m, &in)) assert.True(t, in.Optional) } func TestUnmarshalBool(t *testing.T) { type inner struct { True bool `key:"yes"` False bool `key:"no"` TrueFromOne bool `key:"yesone,string"` FalseFromZero bool `key:"nozero,string"` TrueFromTrue bool `key:"yestrue,string"` FalseFromFalse bool `key:"nofalse,string"` DefaultTrue bool `key:"defaulttrue,default=1"` Optional bool `key:"optional,optional"` } m := map[string]interface{}{ "yes": true, "no": false, "yesone": "1", "nozero": "0", "yestrue": "true", "nofalse": "false", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.True(in.True) ast.False(in.False) ast.True(in.TrueFromOne) ast.False(in.FalseFromZero) ast.True(in.TrueFromTrue) ast.False(in.FalseFromFalse) ast.True(in.DefaultTrue) } func TestUnmarshalDuration(t *testing.T) { type inner struct { Duration time.Duration `key:"duration"` LessDuration time.Duration `key:"less"` MoreDuration time.Duration `key:"more"` } m := map[string]interface{}{ "duration": "5s", "less": "100ms", "more": "24h", } var in inner assert.Nil(t, UnmarshalKey(m, &in)) assert.Equal(t, time.Second*5, in.Duration) assert.Equal(t, time.Millisecond*100, in.LessDuration) assert.Equal(t, time.Hour*24, in.MoreDuration) } func TestUnmarshalDurationDefault(t *testing.T) { type inner struct { Int int `key:"int"` Duration time.Duration `key:"duration,default=5s"` } m := map[string]interface{}{ "int": 5, } var in inner assert.Nil(t, UnmarshalKey(m, &in)) assert.Equal(t, 5, in.Int) assert.Equal(t, time.Second*5, in.Duration) } func TestUnmarshalDurationPtr(t *testing.T) { type inner struct { Duration *time.Duration `key:"duration"` } m := map[string]interface{}{ "duration": "5s", } var in inner assert.Nil(t, UnmarshalKey(m, &in)) assert.Equal(t, time.Second*5, *in.Duration) } func TestUnmarshalDurationPtrDefault(t *testing.T) { type inner struct { Int int `key:"int"` Value *int `key:",default=5"` Duration *time.Duration `key:"duration,default=5s"` } m := map[string]interface{}{ "int": 5, } var in inner assert.Nil(t, UnmarshalKey(m, &in)) assert.Equal(t, 5, in.Int) assert.Equal(t, 5, *in.Value) assert.Equal(t, time.Second*5, *in.Duration) } func TestUnmarshalInt(t *testing.T) { type inner struct { Int int `key:"int"` IntFromStr int `key:"intstr,string"` Int8 int8 `key:"int8"` Int8FromStr int8 `key:"int8str,string"` Int16 int16 `key:"int16"` Int16FromStr int16 `key:"int16str,string"` Int32 int32 `key:"int32"` Int32FromStr int32 `key:"int32str,string"` Int64 int64 `key:"int64"` Int64FromStr int64 `key:"int64str,string"` DefaultInt int64 `key:"defaultint,default=11"` Optional int `key:"optional,optional"` } m := map[string]interface{}{ "int": 1, "intstr": "2", "int8": int8(3), "int8str": "4", "int16": int16(5), "int16str": "6", "int32": int32(7), "int32str": "8", "int64": int64(9), "int64str": "10", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(1, in.Int) ast.Equal(2, in.IntFromStr) ast.Equal(int8(3), in.Int8) ast.Equal(int8(4), in.Int8FromStr) ast.Equal(int16(5), in.Int16) ast.Equal(int16(6), in.Int16FromStr) ast.Equal(int32(7), in.Int32) ast.Equal(int32(8), in.Int32FromStr) ast.Equal(int64(9), in.Int64) ast.Equal(int64(10), in.Int64FromStr) ast.Equal(int64(11), in.DefaultInt) } func TestUnmarshalIntPtr(t *testing.T) { type inner struct { Int *int `key:"int"` } m := map[string]interface{}{ "int": 1, } var in inner assert.Nil(t, UnmarshalKey(m, &in)) assert.NotNil(t, in.Int) assert.Equal(t, 1, *in.Int) } func TestUnmarshalIntWithDefault(t *testing.T) { type inner struct { Int int `key:"int,default=5"` } m := map[string]interface{}{ "int": 1, } var in inner assert.Nil(t, UnmarshalKey(m, &in)) assert.Equal(t, 1, in.Int) } func TestUnmarshalUint(t *testing.T) { type inner struct { Uint uint `key:"uint"` UintFromStr uint `key:"uintstr,string"` Uint8 uint8 `key:"uint8"` Uint8FromStr uint8 `key:"uint8str,string"` Uint16 uint16 `key:"uint16"` Uint16FromStr uint16 `key:"uint16str,string"` Uint32 uint32 `key:"uint32"` Uint32FromStr uint32 `key:"uint32str,string"` Uint64 uint64 `key:"uint64"` Uint64FromStr uint64 `key:"uint64str,string"` DefaultUint uint `key:"defaultuint,default=11"` Optional uint `key:"optional,optional"` } m := map[string]interface{}{ "uint": uint(1), "uintstr": "2", "uint8": uint8(3), "uint8str": "4", "uint16": uint16(5), "uint16str": "6", "uint32": uint32(7), "uint32str": "8", "uint64": uint64(9), "uint64str": "10", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(uint(1), in.Uint) ast.Equal(uint(2), in.UintFromStr) ast.Equal(uint8(3), in.Uint8) ast.Equal(uint8(4), in.Uint8FromStr) ast.Equal(uint16(5), in.Uint16) ast.Equal(uint16(6), in.Uint16FromStr) ast.Equal(uint32(7), in.Uint32) ast.Equal(uint32(8), in.Uint32FromStr) ast.Equal(uint64(9), in.Uint64) ast.Equal(uint64(10), in.Uint64FromStr) ast.Equal(uint(11), in.DefaultUint) } func TestUnmarshalFloat(t *testing.T) { type inner struct { Float32 float32 `key:"float32"` Float32Str float32 `key:"float32str,string"` Float64 float64 `key:"float64"` Float64Str float64 `key:"float64str,string"` DefaultFloat float32 `key:"defaultfloat,default=5.5"` Optional float32 `key:",optional"` } m := map[string]interface{}{ "float32": float32(1.5), "float32str": "2.5", "float64": float64(3.5), "float64str": "4.5", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(float32(1.5), in.Float32) ast.Equal(float32(2.5), in.Float32Str) ast.Equal(3.5, in.Float64) ast.Equal(4.5, in.Float64Str) ast.Equal(float32(5.5), in.DefaultFloat) } func TestUnmarshalInt64Slice(t *testing.T) { var v struct { Ages []int64 `key:"ages"` } m := map[string]interface{}{ "ages": []int64{1, 2}, } ast := assert.New(t) ast.Nil(UnmarshalKey(m, &v)) ast.ElementsMatch([]int64{1, 2}, v.Ages) } func TestUnmarshalIntSlice(t *testing.T) { var v struct { Ages []int `key:"ages"` } m := map[string]interface{}{ "ages": []int{1, 2}, } ast := assert.New(t) ast.Nil(UnmarshalKey(m, &v)) ast.ElementsMatch([]int{1, 2}, v.Ages) } func TestUnmarshalString(t *testing.T) { type inner struct { Name string `key:"name"` NameStr string `key:"namestr,string"` NotPresent string `key:",optional"` NotPresentWithTag string `key:"notpresent,optional"` DefaultString string `key:"defaultstring,default=hello"` Optional string `key:",optional"` } m := map[string]interface{}{ "name": "kevin", "namestr": "namewithstring", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal("kevin", in.Name) ast.Equal("namewithstring", in.NameStr) ast.Empty(in.NotPresent) ast.Empty(in.NotPresentWithTag) ast.Equal("hello", in.DefaultString) } func TestUnmarshalStringWithMissing(t *testing.T) { type inner struct { Name string `key:"name"` } m := map[string]interface{}{} var in inner assert.NotNil(t, UnmarshalKey(m, &in)) } func TestUnmarshalStringSliceFromString(t *testing.T) { var v struct { Names []string `key:"names"` } m := map[string]interface{}{ "names": `["first", "second"]`, } ast := assert.New(t) ast.Nil(UnmarshalKey(m, &v)) ast.Equal(2, len(v.Names)) ast.Equal("first", v.Names[0]) ast.Equal("second", v.Names[1]) } func TestUnmarshalIntSliceFromString(t *testing.T) { var v struct { Values []int `key:"values"` } m := map[string]interface{}{ "values": `[1, 2]`, } ast := assert.New(t) ast.Nil(UnmarshalKey(m, &v)) ast.Equal(2, len(v.Values)) ast.Equal(1, v.Values[0]) ast.Equal(2, v.Values[1]) } 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"` } m := map[string]interface{}{ "name": "kevin", "address": map[string]interface{}{ "city": "shanghai", "zipcode": "200000", }, } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal("kevin", in.Name) ast.Equal("shanghai", in.Address.City) ast.Equal(200000, in.Address.ZipCode) ast.Equal("hello", in.Address.DefaultString) } func TestUnmarshalStructOptionalDepends(t *testing.T) { type address struct { City string `key:"city"` Optional string `key:",optional"` OptionalDepends string `key:",optional=Optional"` } type inner struct { Name string `key:"name"` Address address `key:"address"` } tests := []struct { input map[string]string pass bool }{ { pass: true, }, { input: map[string]string{ "OptionalDepends": "b", }, pass: false, }, { input: map[string]string{ "Optional": "a", }, pass: false, }, { input: map[string]string{ "Optional": "a", "OptionalDepends": "b", }, pass: true, }, } for _, test := range tests { t.Run(stringx.Rand(), func(t *testing.T) { m := map[string]interface{}{ "name": "kevin", "address": map[string]interface{}{ "city": "shanghai", }, } for k, v := range test.input { m["address"].(map[string]interface{})[k] = v } var in inner ast := assert.New(t) if test.pass { ast.Nil(UnmarshalKey(m, &in)) ast.Equal("kevin", in.Name) ast.Equal("shanghai", in.Address.City) ast.Equal(test.input["Optional"], in.Address.Optional) ast.Equal(test.input["OptionalDepends"], in.Address.OptionalDepends) } else { ast.NotNil(UnmarshalKey(m, &in)) } }) } } func TestUnmarshalStructOptionalDependsNot(t *testing.T) { type address struct { City string `key:"city"` Optional string `key:",optional"` OptionalDepends string `key:",optional=!Optional"` } type inner struct { Name string `key:"name"` Address address `key:"address"` } tests := []struct { input map[string]string pass bool }{ { input: map[string]string{}, pass: false, }, { input: map[string]string{ "Optional": "a", "OptionalDepends": "b", }, pass: false, }, { input: map[string]string{ "Optional": "a", }, pass: true, }, { input: map[string]string{ "OptionalDepends": "b", }, pass: true, }, } for _, test := range tests { t.Run(stringx.Rand(), func(t *testing.T) { m := map[string]interface{}{ "name": "kevin", "address": map[string]interface{}{ "city": "shanghai", }, } for k, v := range test.input { m["address"].(map[string]interface{})[k] = v } var in inner ast := assert.New(t) if test.pass { ast.Nil(UnmarshalKey(m, &in)) ast.Equal("kevin", in.Name) ast.Equal("shanghai", in.Address.City) ast.Equal(test.input["Optional"], in.Address.Optional) ast.Equal(test.input["OptionalDepends"], in.Address.OptionalDepends) } else { ast.NotNil(UnmarshalKey(m, &in)) } }) } } 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"` } m := map[string]interface{}{ "name": "kevin", } var in inner err := UnmarshalKey(m, &in) assert.NotNil(t, err) } func TestUnmarshalStructOptionalDependsNotNested(t *testing.T) { type address struct { Optional string `key:",optional"` OptionalDepends string `key:",optional=!Optional"` } type combo struct { Name string `key:"name,optional"` Address address `key:"address"` } type inner struct { Name string `key:"name"` Combo combo `key:"combo"` } m := map[string]interface{}{ "name": "kevin", } var in inner err := UnmarshalKey(m, &in) assert.NotNil(t, err) } func TestUnmarshalStructOptionalNestedDifferentKey(t *testing.T) { type address struct { Optional string `dkey:",optional"` OptionalDepends string `key:",optional"` } type combo struct { Name string `key:"name,optional"` Address address `key:"address"` } type inner struct { Name string `key:"name"` Combo combo `key:"combo"` } m := map[string]interface{}{ "name": "kevin", } var in inner assert.NotNil(t, UnmarshalKey(m, &in)) } func TestUnmarshalStructOptionalDependsNotEnoughValue(t *testing.T) { type address struct { Optional string `key:",optional"` OptionalDepends string `key:",optional=!"` } type inner struct { Name string `key:"name"` Address address `key:"address"` } m := map[string]interface{}{ "name": "kevin", "address": map[string]interface{}{}, } var in inner err := UnmarshalKey(m, &in) assert.NotNil(t, err) } func TestUnmarshalAnonymousStructOptionalDepends(t *testing.T) { type AnonAddress struct { City string `key:"city"` Optional string `key:",optional"` OptionalDepends string `key:",optional=Optional"` } type inner struct { Name string `key:"name"` AnonAddress } tests := []struct { input map[string]string pass bool }{ { pass: true, }, { input: map[string]string{ "OptionalDepends": "b", }, pass: false, }, { input: map[string]string{ "Optional": "a", }, pass: false, }, { input: map[string]string{ "Optional": "a", "OptionalDepends": "b", }, pass: true, }, } for _, test := range tests { t.Run(stringx.Rand(), func(t *testing.T) { m := map[string]interface{}{ "name": "kevin", "city": "shanghai", } for k, v := range test.input { m[k] = v } var in inner ast := assert.New(t) if test.pass { ast.Nil(UnmarshalKey(m, &in)) ast.Equal("kevin", in.Name) ast.Equal("shanghai", in.City) ast.Equal(test.input["Optional"], in.Optional) ast.Equal(test.input["OptionalDepends"], in.OptionalDepends) } else { ast.NotNil(UnmarshalKey(m, &in)) } }) } } func TestUnmarshalStructPtr(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"` } m := map[string]interface{}{ "name": "kevin", "address": map[string]interface{}{ "city": "shanghai", "zipcode": "200000", }, } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal("kevin", in.Name) ast.Equal("shanghai", in.Address.City) ast.Equal(200000, in.Address.ZipCode) ast.Equal("hello", in.Address.DefaultString) } func TestUnmarshalWithStringIgnored(t *testing.T) { type inner struct { True bool `key:"yes"` False bool `key:"no"` Int int `key:"int"` Int8 int8 `key:"int8"` Int16 int16 `key:"int16"` Int32 int32 `key:"int32"` Int64 int64 `key:"int64"` Uint uint `key:"uint"` Uint8 uint8 `key:"uint8"` Uint16 uint16 `key:"uint16"` Uint32 uint32 `key:"uint32"` Uint64 uint64 `key:"uint64"` Float32 float32 `key:"float32"` Float64 float64 `key:"float64"` } m := map[string]interface{}{ "yes": "1", "no": "0", "int": "1", "int8": "3", "int16": "5", "int32": "7", "int64": "9", "uint": "1", "uint8": "3", "uint16": "5", "uint32": "7", "uint64": "9", "float32": "1.5", "float64": "3.5", } var in inner um := NewUnmarshaler("key", WithStringValues()) ast := assert.New(t) ast.Nil(um.Unmarshal(m, &in)) ast.True(in.True) ast.False(in.False) ast.Equal(1, in.Int) ast.Equal(int8(3), in.Int8) ast.Equal(int16(5), in.Int16) ast.Equal(int32(7), in.Int32) ast.Equal(int64(9), in.Int64) ast.Equal(uint(1), in.Uint) ast.Equal(uint8(3), in.Uint8) ast.Equal(uint16(5), in.Uint16) ast.Equal(uint32(7), in.Uint32) ast.Equal(uint64(9), in.Uint64) ast.Equal(float32(1.5), in.Float32) ast.Equal(3.5, in.Float64) } func TestUnmarshalJsonNumberInt64(t *testing.T) { for i := 0; i <= maxUintBitsToTest; i++ { var intValue int64 = 1 << uint(i) strValue := strconv.FormatInt(intValue, 10) var number = json.Number(strValue) m := map[string]interface{}{ "Id": number, } var v struct { Id int64 } assert.Nil(t, UnmarshalKey(m, &v)) assert.Equal(t, intValue, v.Id) } } func TestUnmarshalJsonNumberUint64(t *testing.T) { for i := 0; i <= maxUintBitsToTest; i++ { var intValue uint64 = 1 << uint(i) strValue := strconv.FormatUint(intValue, 10) var number = json.Number(strValue) m := map[string]interface{}{ "Id": number, } var v struct { Id uint64 } assert.Nil(t, UnmarshalKey(m, &v)) assert.Equal(t, intValue, v.Id) } } func TestUnmarshalJsonNumberUint64Ptr(t *testing.T) { for i := 0; i <= maxUintBitsToTest; i++ { var intValue uint64 = 1 << uint(i) strValue := strconv.FormatUint(intValue, 10) var number = json.Number(strValue) m := map[string]interface{}{ "Id": number, } var v struct { Id *uint64 } ast := assert.New(t) ast.Nil(UnmarshalKey(m, &v)) ast.NotNil(v.Id) ast.Equal(intValue, *v.Id) } } func TestUnmarshalMapOfInt(t *testing.T) { m := map[string]interface{}{ "Ids": map[string]bool{"first": true}, } var v struct { Ids map[string]bool } assert.Nil(t, UnmarshalKey(m, &v)) assert.True(t, v.Ids["first"]) } func TestUnmarshalMapOfStructError(t *testing.T) { m := map[string]interface{}{ "Ids": map[string]interface{}{"first": "second"}, } var v struct { Ids map[string]struct { Name string } } assert.NotNil(t, UnmarshalKey(m, &v)) } func TestUnmarshalSlice(t *testing.T) { m := map[string]interface{}{ "Ids": []interface{}{"first", "second"}, } var v struct { Ids []string } ast := assert.New(t) ast.Nil(UnmarshalKey(m, &v)) ast.Equal(2, len(v.Ids)) ast.Equal("first", v.Ids[0]) ast.Equal("second", v.Ids[1]) } func TestUnmarshalSliceOfStruct(t *testing.T) { m := map[string]interface{}{ "Ids": []map[string]interface{}{ { "First": 1, "Second": 2, }, }, } var v struct { Ids []struct { First int Second int } } ast := assert.New(t) ast.Nil(UnmarshalKey(m, &v)) ast.Equal(1, len(v.Ids)) ast.Equal(1, v.Ids[0].First) ast.Equal(2, v.Ids[0].Second) } func TestUnmarshalWithStringOptionsCorrect(t *testing.T) { type inner struct { Value string `key:"value,options=first|second"` Correct string `key:"correct,options=1|2"` } m := map[string]interface{}{ "value": "first", "correct": "2", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal("first", in.Value) ast.Equal("2", in.Correct) } func TestUnmarshalStringOptionsWithStringOptionsNotString(t *testing.T) { type inner struct { Value string `key:"value,options=first|second"` Correct string `key:"correct,options=1|2"` } m := map[string]interface{}{ "value": "first", "correct": 2, } var in inner unmarshaler := NewUnmarshaler(defaultKeyName, WithStringValues()) ast := assert.New(t) ast.NotNil(unmarshaler.Unmarshal(m, &in)) } func TestUnmarshalStringOptionsWithStringOptions(t *testing.T) { type inner struct { Value string `key:"value,options=first|second"` Correct string `key:"correct,options=1|2"` } m := map[string]interface{}{ "value": "first", "correct": "2", } var in inner unmarshaler := NewUnmarshaler(defaultKeyName, WithStringValues()) ast := assert.New(t) ast.Nil(unmarshaler.Unmarshal(m, &in)) ast.Equal("first", in.Value) ast.Equal("2", in.Correct) } func TestUnmarshalStringOptionsWithStringOptionsPtr(t *testing.T) { type inner struct { Value *string `key:"value,options=first|second"` Correct *int `key:"correct,options=1|2"` } m := map[string]interface{}{ "value": "first", "correct": "2", } var in inner unmarshaler := NewUnmarshaler(defaultKeyName, WithStringValues()) ast := assert.New(t) ast.Nil(unmarshaler.Unmarshal(m, &in)) ast.True(*in.Value == "first") ast.True(*in.Correct == 2) } func TestUnmarshalStringOptionsWithStringOptionsIncorrect(t *testing.T) { type inner struct { Value string `key:"value,options=first|second"` Correct string `key:"correct,options=1|2"` } m := map[string]interface{}{ "value": "third", "correct": "2", } var in inner unmarshaler := NewUnmarshaler(defaultKeyName, WithStringValues()) ast := assert.New(t) ast.NotNil(unmarshaler.Unmarshal(m, &in)) } func TestUnmarshalWithStringOptionsIncorrect(t *testing.T) { type inner struct { Value string `key:"value,options=first|second"` Incorrect string `key:"incorrect,options=1|2"` } m := map[string]interface{}{ "value": "first", "incorrect": "3", } var in inner assert.NotNil(t, UnmarshalKey(m, &in)) } func TestUnmarshalWithIntOptionsCorrect(t *testing.T) { type inner struct { Value string `key:"value,options=first|second"` Number int `key:"number,options=1|2"` } m := map[string]interface{}{ "value": "first", "number": 2, } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal("first", in.Value) ast.Equal(2, in.Number) } func TestUnmarshalWithIntOptionsCorrectPtr(t *testing.T) { type inner struct { Value *string `key:"value,options=first|second"` Number *int `key:"number,options=1|2"` } m := map[string]interface{}{ "value": "first", "number": 2, } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.True(*in.Value == "first") ast.True(*in.Number == 2) } func TestUnmarshalWithIntOptionsIncorrect(t *testing.T) { type inner struct { Value string `key:"value,options=first|second"` Incorrect int `key:"incorrect,options=1|2"` } m := map[string]interface{}{ "value": "first", "incorrect": 3, } var in inner assert.NotNil(t, UnmarshalKey(m, &in)) } func TestUnmarshalWithUintOptionsCorrect(t *testing.T) { type inner struct { Value string `key:"value,options=first|second"` Number uint `key:"number,options=1|2"` } m := map[string]interface{}{ "value": "first", "number": uint(2), } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal("first", in.Value) ast.Equal(uint(2), in.Number) } func TestUnmarshalWithUintOptionsIncorrect(t *testing.T) { type inner struct { Value string `key:"value,options=first|second"` Incorrect uint `key:"incorrect,options=1|2"` } m := map[string]interface{}{ "value": "first", "incorrect": uint(3), } var in inner assert.NotNil(t, UnmarshalKey(m, &in)) } func TestUnmarshalWithOptionsAndDefault(t *testing.T) { type inner struct { Value string `key:"value,options=first|second|third,default=second"` } m := map[string]interface{}{} var in inner assert.Nil(t, UnmarshalKey(m, &in)) assert.Equal(t, "second", in.Value) } func TestUnmarshalWithOptionsAndSet(t *testing.T) { type inner struct { Value string `key:"value,options=first|second|third,default=second"` } m := map[string]interface{}{ "value": "first", } var in inner assert.Nil(t, UnmarshalKey(m, &in)) assert.Equal(t, "first", in.Value) } func TestUnmarshalNestedKey(t *testing.T) { var c struct { Id int `json:"Persons.first.Id"` } m := map[string]interface{}{ "Persons": map[string]interface{}{ "first": map[string]interface{}{ "Id": 1, }, }, } assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &c)) assert.Equal(t, 1, c.Id) } func TestUnmarhsalNestedKeyArray(t *testing.T) { var c struct { First []struct { Id int } `json:"Persons.first"` } m := map[string]interface{}{ "Persons": map[string]interface{}{ "first": []map[string]interface{}{ {"Id": 1}, {"Id": 2}, }, }, } assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &c)) assert.Equal(t, 2, len(c.First)) assert.Equal(t, 1, c.First[0].Id) } func TestUnmarshalAnonymousOptionalRequiredProvided(t *testing.T) { type ( Foo struct { Value string `json:"v"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{ "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousOptionalRequiredMissed(t *testing.T) { type ( Foo struct { Value string `json:"v"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{} var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.True(t, len(b.Value) == 0) } func TestUnmarshalAnonymousOptionalOptionalProvided(t *testing.T) { type ( Foo struct { Value string `json:"v,optional"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{ "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousOptionalOptionalMissed(t *testing.T) { type ( Foo struct { Value string `json:"v,optional"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{} var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.True(t, len(b.Value) == 0) } func TestUnmarshalAnonymousOptionalRequiredBothProvided(t *testing.T) { type ( Foo struct { Name string `json:"n"` Value string `json:"v"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{ "n": "kevin", "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "kevin", b.Name) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousOptionalRequiredOneProvidedOneMissed(t *testing.T) { type ( Foo struct { Name string `json:"n"` Value string `json:"v"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{ "v": "anything", } var b Bar assert.NotNil(t, NewUnmarshaler("json").Unmarshal(m, &b)) } func TestUnmarshalAnonymousOptionalRequiredBothMissed(t *testing.T) { type ( Foo struct { Name string `json:"n"` Value string `json:"v"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{} var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.True(t, len(b.Name) == 0) assert.True(t, len(b.Value) == 0) } func TestUnmarshalAnonymousOptionalOneRequiredOneOptionalBothProvided(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{ "n": "kevin", "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "kevin", b.Name) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousOptionalOneRequiredOneOptionalBothMissed(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{} var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.True(t, len(b.Name) == 0) assert.True(t, len(b.Value) == 0) } func TestUnmarshalAnonymousOptionalOneRequiredOneOptionalRequiredProvidedOptionalMissed(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{ "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.True(t, len(b.Name) == 0) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousOptionalOneRequiredOneOptionalRequiredMissedOptionalProvided(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{ "n": "anything", } var b Bar assert.NotNil(t, NewUnmarshaler("json").Unmarshal(m, &b)) } func TestUnmarshalAnonymousOptionalBothOptionalBothProvided(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v,optional"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{ "n": "kevin", "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "kevin", b.Name) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousOptionalBothOptionalOneProvidedOneMissed(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v,optional"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{ "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.True(t, len(b.Name) == 0) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousOptionalBothOptionalBothMissed(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v,optional"` } Bar struct { Foo `json:",optional"` } ) m := map[string]interface{}{} var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.True(t, len(b.Name) == 0) assert.True(t, len(b.Value) == 0) } func TestUnmarshalAnonymousRequiredProvided(t *testing.T) { type ( Foo struct { Value string `json:"v"` } Bar struct { Foo } ) m := map[string]interface{}{ "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousRequiredMissed(t *testing.T) { type ( Foo struct { Value string `json:"v"` } Bar struct { Foo } ) m := map[string]interface{}{} var b Bar assert.NotNil(t, NewUnmarshaler("json").Unmarshal(m, &b)) } func TestUnmarshalAnonymousOptionalProvided(t *testing.T) { type ( Foo struct { Value string `json:"v,optional"` } Bar struct { Foo } ) m := map[string]interface{}{ "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousOptionalMissed(t *testing.T) { type ( Foo struct { Value string `json:"v,optional"` } Bar struct { Foo } ) m := map[string]interface{}{} var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.True(t, len(b.Value) == 0) } func TestUnmarshalAnonymousRequiredBothProvided(t *testing.T) { type ( Foo struct { Name string `json:"n"` Value string `json:"v"` } Bar struct { Foo } ) m := map[string]interface{}{ "n": "kevin", "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "kevin", b.Name) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousRequiredOneProvidedOneMissed(t *testing.T) { type ( Foo struct { Name string `json:"n"` Value string `json:"v"` } Bar struct { Foo } ) m := map[string]interface{}{ "v": "anything", } var b Bar assert.NotNil(t, NewUnmarshaler("json").Unmarshal(m, &b)) } func TestUnmarshalAnonymousRequiredBothMissed(t *testing.T) { type ( Foo struct { Name string `json:"n"` Value string `json:"v"` } Bar struct { Foo } ) m := map[string]interface{}{ "v": "anything", } var b Bar assert.NotNil(t, NewUnmarshaler("json").Unmarshal(m, &b)) } func TestUnmarshalAnonymousOneRequiredOneOptionalBothProvided(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v"` } Bar struct { Foo } ) m := map[string]interface{}{ "n": "kevin", "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "kevin", b.Name) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousOneRequiredOneOptionalBothMissed(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v"` } Bar struct { Foo } ) m := map[string]interface{}{} var b Bar assert.NotNil(t, NewUnmarshaler("json").Unmarshal(m, &b)) } func TestUnmarshalAnonymousOneRequiredOneOptionalRequiredProvidedOptionalMissed(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v"` } Bar struct { Foo } ) m := map[string]interface{}{ "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.True(t, len(b.Name) == 0) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousOneRequiredOneOptionalRequiredMissedOptionalProvided(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v"` } Bar struct { Foo } ) m := map[string]interface{}{ "n": "anything", } var b Bar assert.NotNil(t, NewUnmarshaler("json").Unmarshal(m, &b)) } func TestUnmarshalAnonymousBothOptionalBothProvided(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v,optional"` } Bar struct { Foo } ) m := map[string]interface{}{ "n": "kevin", "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "kevin", b.Name) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousBothOptionalOneProvidedOneMissed(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v,optional"` } Bar struct { Foo } ) m := map[string]interface{}{ "v": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.True(t, len(b.Name) == 0) assert.Equal(t, "anything", b.Value) } func TestUnmarshalAnonymousBothOptionalBothMissed(t *testing.T) { type ( Foo struct { Name string `json:"n,optional"` Value string `json:"v,optional"` } Bar struct { Foo } ) m := map[string]interface{}{} var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.True(t, len(b.Name) == 0) assert.True(t, len(b.Value) == 0) } func TestUnmarshalAnonymousWrappedToMuch(t *testing.T) { type ( Foo struct { Name string `json:"n"` Value string `json:"v"` } Bar struct { Foo } ) m := map[string]interface{}{ "Foo": map[string]interface{}{ "n": "name", "v": "anything", }, } var b Bar assert.NotNil(t, NewUnmarshaler("json").Unmarshal(m, &b)) } func TestUnmarshalWrappedObject(t *testing.T) { type ( Foo struct { Value string `json:"v"` } Bar struct { Inner Foo } ) m := map[string]interface{}{ "Inner": map[string]interface{}{ "v": "anything", }, } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "anything", b.Inner.Value) } func TestUnmarshalWrappedObjectOptional(t *testing.T) { type ( Foo struct { Hosts []string Key string } Bar struct { Inner Foo `json:",optional"` Name string } ) m := map[string]interface{}{ "Name": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "anything", b.Name) } func TestUnmarshalWrappedObjectOptionalFilled(t *testing.T) { type ( Foo struct { Hosts []string Key string } Bar struct { Inner Foo `json:",optional"` Name string } ) hosts := []string{"1", "2"} m := map[string]interface{}{ "Inner": map[string]interface{}{ "Hosts": hosts, "Key": "key", }, "Name": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.EqualValues(t, hosts, b.Inner.Hosts) assert.Equal(t, "key", b.Inner.Key) assert.Equal(t, "anything", b.Name) } func TestUnmarshalWrappedNamedObjectOptional(t *testing.T) { type ( Foo struct { Host string Key string } Bar struct { Inner Foo `json:",optional"` Name string } ) m := map[string]interface{}{ "Inner": map[string]interface{}{ "Host": "thehost", "Key": "thekey", }, "Name": "anything", } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "thehost", b.Inner.Host) assert.Equal(t, "thekey", b.Inner.Key) assert.Equal(t, "anything", b.Name) } func TestUnmarshalWrappedObjectNamedPtr(t *testing.T) { type ( Foo struct { Value string `json:"v"` } Bar struct { Inner *Foo `json:"foo,optional"` } ) m := map[string]interface{}{ "foo": map[string]interface{}{ "v": "anything", }, } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "anything", b.Inner.Value) } func TestUnmarshalWrappedObjectPtr(t *testing.T) { type ( Foo struct { Value string `json:"v"` } Bar struct { Inner *Foo } ) m := map[string]interface{}{ "Inner": map[string]interface{}{ "v": "anything", }, } var b Bar assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &b)) assert.Equal(t, "anything", b.Inner.Value) } func TestUnmarshalInt2String(t *testing.T) { type inner struct { Int string `key:"int"` } m := map[string]interface{}{ "int": 123, } var in inner assert.NotNil(t, UnmarshalKey(m, &in)) } func TestUnmarshalZeroValues(t *testing.T) { type inner struct { False bool `key:"no"` Int int `key:"int"` String string `key:"string"` } m := map[string]interface{}{ "no": false, "int": 0, "string": "", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.False(in.False) ast.Equal(0, in.Int) ast.Equal("", in.String) } func TestUnmarshalUsingDifferentKeys(t *testing.T) { type inner struct { False bool `key:"no"` Int int `key:"int"` String string `bson:"string"` } m := map[string]interface{}{ "no": false, "int": 9, "string": "value", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.False(in.False) ast.Equal(9, in.Int) ast.True(len(in.String) == 0) } func TestUnmarshalNumberRangeInt(t *testing.T) { type inner struct { Value1 int `key:"value1,range=[1:]"` Value2 int8 `key:"value2,range=[1:5]"` Value3 int16 `key:"value3,range=[1:5]"` Value4 int32 `key:"value4,range=[1:5]"` Value5 int64 `key:"value5,range=[1:5]"` Value6 uint `key:"value6,range=[:5]"` Value8 uint8 `key:"value8,range=[1:5],string"` Value9 uint16 `key:"value9,range=[1:5],string"` Value10 uint32 `key:"value10,range=[1:5],string"` Value11 uint64 `key:"value11,range=[1:5],string"` } m := map[string]interface{}{ "value1": 10, "value2": int8(1), "value3": int16(2), "value4": int32(4), "value5": int64(5), "value6": uint(0), "value8": "1", "value9": "2", "value10": "4", "value11": "5", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(10, in.Value1) ast.Equal(int8(1), in.Value2) ast.Equal(int16(2), in.Value3) ast.Equal(int32(4), in.Value4) ast.Equal(int64(5), in.Value5) ast.Equal(uint(0), in.Value6) ast.Equal(uint8(1), in.Value8) ast.Equal(uint16(2), in.Value9) ast.Equal(uint32(4), in.Value10) ast.Equal(uint64(5), in.Value11) } func TestUnmarshalNumberRangeJsonNumber(t *testing.T) { type inner struct { Value3 uint `key:"value3,range=(1:5]"` Value4 uint8 `key:"value4,range=(1:5]"` Value5 uint16 `key:"value5,range=(1:5]"` } m := map[string]interface{}{ "value3": json.Number("2"), "value4": json.Number("4"), "value5": json.Number("5"), } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(uint(2), in.Value3) ast.Equal(uint8(4), in.Value4) ast.Equal(uint16(5), in.Value5) type inner1 struct { Value int `key:"value,range=(1:5]"` } m = map[string]interface{}{ "value": json.Number("a"), } var in1 inner1 ast.NotNil(UnmarshalKey(m, &in1)) } func TestUnmarshalNumberRangeIntLeftExclude(t *testing.T) { type inner struct { Value3 uint `key:"value3,range=(1:5]"` Value4 uint32 `key:"value4,default=4,range=(1:5]"` Value5 uint64 `key:"value5,range=(1:5]"` Value9 int `key:"value9,range=(1:5],string"` Value10 int `key:"value10,range=(1:5],string"` Value11 int `key:"value11,range=(1:5],string"` } m := map[string]interface{}{ "value3": uint(2), "value4": uint32(4), "value5": uint64(5), "value9": "2", "value10": "4", "value11": "5", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(uint(2), in.Value3) ast.Equal(uint32(4), in.Value4) ast.Equal(uint64(5), in.Value5) ast.Equal(2, in.Value9) ast.Equal(4, in.Value10) ast.Equal(5, in.Value11) } func TestUnmarshalNumberRangeIntRightExclude(t *testing.T) { type inner struct { Value2 uint `key:"value2,range=[1:5)"` Value3 uint8 `key:"value3,range=[1:5)"` Value4 uint16 `key:"value4,range=[1:5)"` Value8 int `key:"value8,range=[1:5),string"` Value9 int `key:"value9,range=[1:5),string"` Value10 int `key:"value10,range=[1:5),string"` } m := map[string]interface{}{ "value2": uint(1), "value3": uint8(2), "value4": uint16(4), "value8": "1", "value9": "2", "value10": "4", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(uint(1), in.Value2) ast.Equal(uint8(2), in.Value3) ast.Equal(uint16(4), in.Value4) ast.Equal(1, in.Value8) ast.Equal(2, in.Value9) ast.Equal(4, in.Value10) } func TestUnmarshalNumberRangeIntExclude(t *testing.T) { type inner struct { Value3 int `key:"value3,range=(1:5)"` Value4 int `key:"value4,range=(1:5)"` Value9 int `key:"value9,range=(1:5),string"` Value10 int `key:"value10,range=(1:5),string"` } m := map[string]interface{}{ "value3": 2, "value4": 4, "value9": "2", "value10": "4", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(2, in.Value3) ast.Equal(4, in.Value4) ast.Equal(2, in.Value9) ast.Equal(4, in.Value10) } func TestUnmarshalNumberRangeIntOutOfRange(t *testing.T) { type inner1 struct { Value int64 `key:"value,default=3,range=(1:5)"` } var in1 inner1 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": int64(1), }, &in1)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": int64(0), }, &in1)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": int64(5), }, &in1)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": json.Number("6"), }, &in1)) type inner2 struct { Value int64 `key:"value,optional,range=[1:5)"` } var in2 inner2 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": int64(0), }, &in2)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": int64(5), }, &in2)) type inner3 struct { Value int64 `key:"value,range=(1:5]"` } var in3 inner3 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": int64(1), }, &in3)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": int64(6), }, &in3)) type inner4 struct { Value int64 `key:"value,range=[1:5]"` } var in4 inner4 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": int64(0), }, &in4)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": int64(6), }, &in4)) } func TestUnmarshalNumberRangeFloat(t *testing.T) { type inner struct { Value2 float32 `key:"value2,range=[1:5]"` Value3 float32 `key:"value3,range=[1:5]"` Value4 float64 `key:"value4,range=[1:5]"` Value5 float64 `key:"value5,range=[1:5]"` Value8 float64 `key:"value8,range=[1:5],string"` Value9 float64 `key:"value9,range=[1:5],string"` Value10 float64 `key:"value10,range=[1:5],string"` Value11 float64 `key:"value11,range=[1:5],string"` } m := map[string]interface{}{ "value2": float32(1), "value3": float32(2), "value4": float64(4), "value5": float64(5), "value8": "1", "value9": "2", "value10": "4", "value11": "5", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(float32(1), in.Value2) ast.Equal(float32(2), in.Value3) ast.Equal(float64(4), in.Value4) ast.Equal(float64(5), in.Value5) ast.Equal(float64(1), in.Value8) ast.Equal(float64(2), in.Value9) ast.Equal(float64(4), in.Value10) ast.Equal(float64(5), in.Value11) } func TestUnmarshalNumberRangeFloatLeftExclude(t *testing.T) { type inner struct { Value3 float64 `key:"value3,range=(1:5]"` Value4 float64 `key:"value4,range=(1:5]"` Value5 float64 `key:"value5,range=(1:5]"` Value9 float64 `key:"value9,range=(1:5],string"` Value10 float64 `key:"value10,range=(1:5],string"` Value11 float64 `key:"value11,range=(1:5],string"` } m := map[string]interface{}{ "value3": float64(2), "value4": float64(4), "value5": float64(5), "value9": "2", "value10": "4", "value11": "5", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(float64(2), in.Value3) ast.Equal(float64(4), in.Value4) ast.Equal(float64(5), in.Value5) ast.Equal(float64(2), in.Value9) ast.Equal(float64(4), in.Value10) ast.Equal(float64(5), in.Value11) } func TestUnmarshalNumberRangeFloatRightExclude(t *testing.T) { type inner struct { Value2 float64 `key:"value2,range=[1:5)"` Value3 float64 `key:"value3,range=[1:5)"` Value4 float64 `key:"value4,range=[1:5)"` Value8 float64 `key:"value8,range=[1:5),string"` Value9 float64 `key:"value9,range=[1:5),string"` Value10 float64 `key:"value10,range=[1:5),string"` } m := map[string]interface{}{ "value2": float64(1), "value3": float64(2), "value4": float64(4), "value8": "1", "value9": "2", "value10": "4", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(float64(1), in.Value2) ast.Equal(float64(2), in.Value3) ast.Equal(float64(4), in.Value4) ast.Equal(float64(1), in.Value8) ast.Equal(float64(2), in.Value9) ast.Equal(float64(4), in.Value10) } func TestUnmarshalNumberRangeFloatExclude(t *testing.T) { type inner struct { Value3 float64 `key:"value3,range=(1:5)"` Value4 float64 `key:"value4,range=(1:5)"` Value9 float64 `key:"value9,range=(1:5),string"` Value10 float64 `key:"value10,range=(1:5),string"` } m := map[string]interface{}{ "value3": float64(2), "value4": float64(4), "value9": "2", "value10": "4", } var in inner ast := assert.New(t) ast.Nil(UnmarshalKey(m, &in)) ast.Equal(float64(2), in.Value3) ast.Equal(float64(4), in.Value4) ast.Equal(float64(2), in.Value9) ast.Equal(float64(4), in.Value10) } func TestUnmarshalNumberRangeFloatOutOfRange(t *testing.T) { type inner1 struct { Value float64 `key:"value,range=(1:5)"` } var in1 inner1 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": float64(1), }, &in1)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": float64(0), }, &in1)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": float64(5), }, &in1)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": json.Number("6"), }, &in1)) type inner2 struct { Value float64 `key:"value,range=[1:5)"` } var in2 inner2 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": float64(0), }, &in2)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": float64(5), }, &in2)) type inner3 struct { Value float64 `key:"value,range=(1:5]"` } var in3 inner3 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": float64(1), }, &in3)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": float64(6), }, &in3)) type inner4 struct { Value float64 `key:"value,range=[1:5]"` } var in4 inner4 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": float64(0), }, &in4)) assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "value": float64(6), }, &in4)) } func TestUnmarshalRangeError(t *testing.T) { type inner1 struct { Value int `key:",range="` } var in1 inner1 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "Value": 1, }, &in1)) type inner2 struct { Value int `key:",range=["` } var in2 inner2 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "Value": 1, }, &in2)) type inner3 struct { Value int `key:",range=[:"` } var in3 inner3 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "Value": 1, }, &in3)) type inner4 struct { Value int `key:",range=[:]"` } var in4 inner4 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "Value": 1, }, &in4)) type inner5 struct { Value int `key:",range={:]"` } var in5 inner5 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "Value": 1, }, &in5)) type inner6 struct { Value int `key:",range=[:}"` } var in6 inner6 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "Value": 1, }, &in6)) type inner7 struct { Value int `key:",range=[]"` } var in7 inner7 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "Value": 1, }, &in7)) type inner8 struct { Value int `key:",range=[a:]"` } var in8 inner8 assert.NotNil(t, UnmarshalKey(map[string]interface{}{ "Value": 1, }, &in8)) type inner9 struct { Value int `key:",range=[:a]"` } var in9 inner9 assert.NotNil(t, UnmarshalKey(map[string]interface{}{ "Value": 1, }, &in9)) type inner10 struct { Value int `key:",range"` } var in10 inner10 assert.NotNil(t, UnmarshalKey(map[string]interface{}{ "Value": 1, }, &in10)) type inner11 struct { Value int `key:",range=[1,2]"` } var in11 inner11 assert.Equal(t, errNumberRange, UnmarshalKey(map[string]interface{}{ "Value": "a", }, &in11)) } func TestUnmarshalNestedMap(t *testing.T) { var c struct { Anything map[string]map[string]string `json:"anything"` } m := map[string]interface{}{ "anything": map[string]map[string]interface{}{ "inner": { "id": "1", "name": "any", }, }, } assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &c)) assert.Equal(t, "1", c.Anything["inner"]["id"]) } func TestUnmarshalNestedMapMismatch(t *testing.T) { var c struct { Anything map[string]map[string]map[string]string `json:"anything"` } m := map[string]interface{}{ "anything": map[string]map[string]interface{}{ "inner": { "name": "any", }, }, } assert.NotNil(t, NewUnmarshaler("json").Unmarshal(m, &c)) } func TestUnmarshalNestedMapSimple(t *testing.T) { var c struct { Anything map[string]string `json:"anything"` } m := map[string]interface{}{ "anything": map[string]interface{}{ "id": "1", "name": "any", }, } assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &c)) assert.Equal(t, "1", c.Anything["id"]) } func TestUnmarshalNestedMapSimpleTypeMatch(t *testing.T) { var c struct { Anything map[string]string `json:"anything"` } m := map[string]interface{}{ "anything": map[string]string{ "id": "1", "name": "any", }, } assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &c)) assert.Equal(t, "1", c.Anything["id"]) } func BenchmarkUnmarshalString(b *testing.B) { type inner struct { Value string `key:"value"` } m := map[string]interface{}{ "value": "first", } for i := 0; i < b.N; i++ { var in inner if err := UnmarshalKey(m, &in); err != nil { b.Fatal(err) } } } func BenchmarkUnmarshalStruct(b *testing.B) { b.ReportAllocs() m := map[string]interface{}{ "Ids": []map[string]interface{}{ { "First": 1, "Second": 2, }, }, } for i := 0; i < b.N; i++ { var v struct { Ids []struct { First int Second int } } if err := UnmarshalKey(m, &v); err != nil { b.Fatal(err) } } } func BenchmarkMapToStruct(b *testing.B) { data := map[string]interface{}{ "valid": "1", "age": "5", "name": "liao", } type anonymous struct { Valid bool Age int Name string } for i := 0; i < b.N; i++ { var an anonymous if valid, ok := data["valid"]; ok { an.Valid = valid == "1" } if age, ok := data["age"]; ok { ages, _ := age.(string) an.Age, _ = strconv.Atoi(ages) } if name, ok := data["name"]; ok { names, _ := name.(string) an.Name = names } } } func BenchmarkUnmarshal(b *testing.B) { data := map[string]interface{}{ "valid": "1", "age": "5", "name": "liao", } type anonymous struct { Valid bool `key:"valid,string"` Age int `key:"age,string"` Name string `key:"name"` } for i := 0; i < b.N; i++ { var an anonymous UnmarshalKey(data, &an) } }