github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/rpc/lib/server/parse_test.go (about) 1 package server 2 3 import ( 4 "encoding/json" 5 "strconv" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/tendermint/tendermint/libs/bytes" 10 ) 11 12 func TestParseJSONMap(t *testing.T) { 13 assert := assert.New(t) 14 15 input := []byte(`{"value":"1234","height":22}`) 16 17 // naive is float,string 18 var p1 map[string]interface{} 19 err := json.Unmarshal(input, &p1) 20 if assert.Nil(err) { 21 h, ok := p1["height"].(float64) 22 if assert.True(ok, "%#v", p1["height"]) { 23 assert.EqualValues(22, h) 24 } 25 v, ok := p1["value"].(string) 26 if assert.True(ok, "%#v", p1["value"]) { 27 assert.EqualValues("1234", v) 28 } 29 } 30 31 // preloading map with values doesn't help 32 tmp := 0 33 p2 := map[string]interface{}{ 34 "value": &bytes.HexBytes{}, 35 "height": &tmp, 36 } 37 err = json.Unmarshal(input, &p2) 38 if assert.Nil(err) { 39 h, ok := p2["height"].(float64) 40 if assert.True(ok, "%#v", p2["height"]) { 41 assert.EqualValues(22, h) 42 } 43 v, ok := p2["value"].(string) 44 if assert.True(ok, "%#v", p2["value"]) { 45 assert.EqualValues("1234", v) 46 } 47 } 48 49 // preload here with *pointers* to the desired types 50 // struct has unknown types, but hard-coded keys 51 tmp = 0 52 p3 := struct { 53 Value interface{} `json:"value"` 54 Height interface{} `json:"height"` 55 }{ 56 Height: &tmp, 57 Value: &bytes.HexBytes{}, 58 } 59 err = json.Unmarshal(input, &p3) 60 if assert.Nil(err) { 61 h, ok := p3.Height.(*int) 62 if assert.True(ok, "%#v", p3.Height) { 63 assert.Equal(22, *h) 64 } 65 v, ok := p3.Value.(*bytes.HexBytes) 66 if assert.True(ok, "%#v", p3.Value) { 67 assert.EqualValues([]byte{0x12, 0x34}, *v) 68 } 69 } 70 71 // simplest solution, but hard-coded 72 p4 := struct { 73 Value bytes.HexBytes `json:"value"` 74 Height int `json:"height"` 75 }{} 76 err = json.Unmarshal(input, &p4) 77 if assert.Nil(err) { 78 assert.EqualValues(22, p4.Height) 79 assert.EqualValues([]byte{0x12, 0x34}, p4.Value) 80 } 81 82 // so, let's use this trick... 83 // dynamic keys on map, and we can deserialize to the desired types 84 var p5 map[string]*json.RawMessage 85 err = json.Unmarshal(input, &p5) 86 if assert.Nil(err) { 87 var h int 88 err = json.Unmarshal(*p5["height"], &h) 89 if assert.Nil(err) { 90 assert.Equal(22, h) 91 } 92 93 var v bytes.HexBytes 94 err = json.Unmarshal(*p5["value"], &v) 95 if assert.Nil(err) { 96 assert.Equal(bytes.HexBytes{0x12, 0x34}, v) 97 } 98 } 99 } 100 101 func TestParseJSONArray(t *testing.T) { 102 assert := assert.New(t) 103 104 input := []byte(`["1234",22]`) 105 106 // naive is float,string 107 var p1 []interface{} 108 err := json.Unmarshal(input, &p1) 109 if assert.Nil(err) { 110 v, ok := p1[0].(string) 111 if assert.True(ok, "%#v", p1[0]) { 112 assert.EqualValues("1234", v) 113 } 114 h, ok := p1[1].(float64) 115 if assert.True(ok, "%#v", p1[1]) { 116 assert.EqualValues(22, h) 117 } 118 } 119 120 // preloading map with values helps here (unlike map - p2 above) 121 tmp := 0 122 p2 := []interface{}{&bytes.HexBytes{}, &tmp} 123 err = json.Unmarshal(input, &p2) 124 if assert.Nil(err) { 125 v, ok := p2[0].(*bytes.HexBytes) 126 if assert.True(ok, "%#v", p2[0]) { 127 assert.EqualValues([]byte{0x12, 0x34}, *v) 128 } 129 h, ok := p2[1].(*int) 130 if assert.True(ok, "%#v", p2[1]) { 131 assert.EqualValues(22, *h) 132 } 133 } 134 } 135 136 func TestParseRPC(t *testing.T) { 137 assert := assert.New(t) 138 139 demo := func(height int, name string) {} 140 call := NewRPCFunc(demo, "height,name") 141 142 cases := []struct { 143 raw string 144 height int64 145 name string 146 fail bool 147 }{ 148 // should parse 149 {`[7, "flew"]`, 7, "flew", false}, 150 {`{"name": "john", "height": 22}`, 22, "john", false}, 151 // defaults 152 {`{"name": "solo", "unused": "stuff"}`, 0, "solo", false}, 153 // should fail - wrong types/length 154 {`["flew", 7]`, 0, "", true}, 155 {`[7,"flew",100]`, 0, "", true}, 156 {`{"name": -12, "height": "fred"}`, 0, "", true}, 157 } 158 for idx, tc := range cases { 159 i := strconv.Itoa(idx) 160 data := []byte(tc.raw) 161 vals, err := jsonParamsToArgs(call, data, 0) 162 if tc.fail { 163 assert.NotNil(err, i) 164 } else { 165 assert.Nil(err, "%s: %+v", i, err) 166 if assert.Equal(2, len(vals), i) { 167 assert.Equal(tc.height, vals[0].Int(), i) 168 assert.Equal(tc.name, vals[1].String(), i) 169 } 170 } 171 172 } 173 174 }