github.com/516108736/tendermint@v0.36.0/libs/json/decoder_test.go (about) 1 package json_test 2 3 import ( 4 "reflect" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 "github.com/tendermint/tendermint/libs/json" 12 ) 13 14 func TestUnmarshal(t *testing.T) { 15 i64Nil := (*int64)(nil) 16 str := "string" 17 strPtr := &str 18 structNil := (*Struct)(nil) 19 i32 := int32(32) 20 i64 := int64(64) 21 22 testcases := map[string]struct { 23 json string 24 value interface{} 25 err bool 26 }{ 27 "bool true": {"true", true, false}, 28 "bool false": {"false", false, false}, 29 "float32": {"3.14", float32(3.14), false}, 30 "float64": {"3.14", float64(3.14), false}, 31 "int32": {`32`, int32(32), false}, 32 "int32 string": {`"32"`, int32(32), true}, 33 "int32 ptr": {`32`, &i32, false}, 34 "int64": {`"64"`, int64(64), false}, 35 "int64 noend": {`"64`, int64(64), true}, 36 "int64 number": {`64`, int64(64), true}, 37 "int64 ptr": {`"64"`, &i64, false}, 38 "int64 ptr nil": {`null`, i64Nil, false}, 39 "string": {`"foo"`, "foo", false}, 40 "string noend": {`"foo`, "foo", true}, 41 "string ptr": {`"string"`, &str, false}, 42 "slice byte": {`"AQID"`, []byte{1, 2, 3}, false}, 43 "slice bytes": {`["AQID"]`, [][]byte{{1, 2, 3}}, false}, 44 "slice int32": {`[1,2,3]`, []int32{1, 2, 3}, false}, 45 "slice int64": {`["1","2","3"]`, []int64{1, 2, 3}, false}, 46 "slice int64 number": {`[1,2,3]`, []int64{1, 2, 3}, true}, 47 "slice int64 ptr": {`["64"]`, []*int64{&i64}, false}, 48 "slice int64 empty": {`[]`, []int64(nil), false}, 49 "slice int64 null": {`null`, []int64(nil), false}, 50 "array byte": {`"AQID"`, [3]byte{1, 2, 3}, false}, 51 "array byte large": {`"AQID"`, [4]byte{1, 2, 3, 4}, true}, 52 "array byte small": {`"AQID"`, [2]byte{1, 2}, true}, 53 "array int32": {`[1,2,3]`, [3]int32{1, 2, 3}, false}, 54 "array int64": {`["1","2","3"]`, [3]int64{1, 2, 3}, false}, 55 "array int64 number": {`[1,2,3]`, [3]int64{1, 2, 3}, true}, 56 "array int64 large": {`["1","2","3"]`, [4]int64{1, 2, 3, 4}, true}, 57 "array int64 small": {`["1","2","3"]`, [2]int64{1, 2}, true}, 58 "map bytes": {`{"b":"AQID"}`, map[string][]byte{"b": {1, 2, 3}}, false}, 59 "map int32": {`{"a":1,"b":2}`, map[string]int32{"a": 1, "b": 2}, false}, 60 "map int64": {`{"a":"1","b":"2"}`, map[string]int64{"a": 1, "b": 2}, false}, 61 "map int64 empty": {`{}`, map[string]int64{}, false}, 62 "map int64 null": {`null`, map[string]int64(nil), false}, 63 "map int key": {`{}`, map[int]int{}, true}, 64 "time": {`"2020-06-03T17:35:30Z"`, time.Date(2020, 6, 3, 17, 35, 30, 0, time.UTC), false}, 65 "time non-utc": {`"2020-06-03T17:35:30+02:00"`, time.Time{}, true}, 66 "time nozone": {`"2020-06-03T17:35:30"`, time.Time{}, true}, 67 "car": {`{"type":"vehicle/car","value":{"Wheels":4}}`, Car{Wheels: 4}, false}, 68 "car ptr": {`{"type":"vehicle/car","value":{"Wheels":4}}`, &Car{Wheels: 4}, false}, 69 "car iface": {`{"type":"vehicle/car","value":{"Wheels":4}}`, Vehicle(&Car{Wheels: 4}), false}, 70 "boat": {`{"type":"vehicle/boat","value":{"Sail":true}}`, Boat{Sail: true}, false}, 71 "boat ptr": {`{"type":"vehicle/boat","value":{"Sail":true}}`, &Boat{Sail: true}, false}, 72 "boat iface": {`{"type":"vehicle/boat","value":{"Sail":true}}`, Vehicle(Boat{Sail: true}), false}, 73 "boat into car": {`{"type":"vehicle/boat","value":{"Sail":true}}`, Car{}, true}, 74 "boat into car iface": {`{"type":"vehicle/boat","value":{"Sail":true}}`, Vehicle(&Car{}), true}, 75 "shoes": {`{"type":"vehicle/shoes","value":{"Soles":"rubber"}}`, Car{}, true}, 76 "shoes ptr": {`{"type":"vehicle/shoes","value":{"Soles":"rubber"}}`, &Car{}, true}, 77 "shoes iface": {`{"type":"vehicle/shoes","value":{"Soles":"rubbes"}}`, Vehicle(&Car{}), true}, 78 "key public": {`{"type":"key/public","value":"AQIDBAUGBwg="}`, PublicKey{1, 2, 3, 4, 5, 6, 7, 8}, false}, 79 "key wrong": {`{"type":"key/public","value":"AQIDBAUGBwg="}`, PrivateKey{1, 2, 3, 4, 5, 6, 7, 8}, true}, 80 "key into car": {`{"type":"key/public","value":"AQIDBAUGBwg="}`, Vehicle(&Car{}), true}, 81 "tags": { 82 `{"name":"name","OmitEmpty":"foo","Hidden":"bar","tags":{"name":"child"}}`, 83 Tags{JSONName: "name", OmitEmpty: "foo", Tags: &Tags{JSONName: "child"}}, 84 false, 85 }, 86 "tags ptr": { 87 `{"name":"name","OmitEmpty":"foo","tags":null}`, 88 &Tags{JSONName: "name", OmitEmpty: "foo"}, 89 false, 90 }, 91 "tags real name": {`{"JSONName":"name"}`, Tags{}, false}, 92 "struct": { 93 `{ 94 "Bool":true, "Float64":3.14, "Int32":32, "Int64":"64", "Int64Ptr":"64", 95 "String":"foo", "StringPtrPtr": "string", "Bytes":"AQID", 96 "Time":"2020-06-02T16:05:13.004346374Z", 97 "Car":{"Wheels":4}, 98 "Boat":{"Sail":true}, 99 "Vehicles":[ 100 {"type":"vehicle/car","value":{"Wheels":4}}, 101 {"type":"vehicle/boat","value":{"Sail":true}} 102 ], 103 "Child":{ 104 "Bool":false, "Float64":0, "Int32":0, "Int64":"0", "Int64Ptr":null, 105 "String":"child", "StringPtrPtr":null, "Bytes":null, 106 "Time":"0001-01-01T00:00:00Z", 107 "Car":null, "Boat":{"Sail":false}, "Vehicles":null, "Child":null 108 }, 109 "private": "foo", "unknown": "bar" 110 }`, 111 Struct{ 112 Bool: true, Float64: 3.14, Int32: 32, Int64: 64, Int64Ptr: &i64, 113 String: "foo", StringPtrPtr: &strPtr, Bytes: []byte{1, 2, 3}, 114 Time: time.Date(2020, 6, 2, 16, 5, 13, 4346374, time.UTC), 115 Car: &Car{Wheels: 4}, Boat: Boat{Sail: true}, Vehicles: []Vehicle{ 116 Vehicle(&Car{Wheels: 4}), 117 Vehicle(Boat{Sail: true}), 118 }, 119 Child: &Struct{Bool: false, String: "child"}, 120 }, 121 false, 122 }, 123 "struct key into vehicle": {`{"Vehicles":[ 124 {"type":"vehicle/car","value":{"Wheels":4}}, 125 {"type":"key/public","value":"MTIzNDU2Nzg="} 126 ]}`, Struct{}, true}, 127 "struct ptr null": {`null`, structNil, false}, 128 "custom value": {`{"Value":"foo"}`, CustomValue{}, false}, 129 "custom ptr": {`"foo"`, &CustomPtr{Value: "custom"}, false}, 130 "custom ptr value": {`"foo"`, CustomPtr{Value: "custom"}, false}, 131 "invalid type": {`"foo"`, Struct{}, true}, 132 } 133 for name, tc := range testcases { 134 tc := tc 135 t.Run(name, func(t *testing.T) { 136 // Create a target variable as a pointer to the zero value of the tc.value type, 137 // and wrap it in an empty interface. Decode into that interface. 138 target := reflect.New(reflect.TypeOf(tc.value)).Interface() 139 err := json.Unmarshal([]byte(tc.json), target) 140 if tc.err { 141 require.Error(t, err) 142 return 143 } 144 require.NoError(t, err) 145 146 // Unwrap the target pointer and get the value behind the interface. 147 actual := reflect.ValueOf(target).Elem().Interface() 148 assert.Equal(t, tc.value, actual) 149 }) 150 } 151 }