From 257f45b768d9fba1f7acf678c4fc1c847d017dab Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 28 Apr 2017 22:01:46 +0200 Subject: [PATCH] ebuchman: added some demos on how to parse unknown types --- rpc/lib/server/parse_test.go | 133 +++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 rpc/lib/server/parse_test.go diff --git a/rpc/lib/server/parse_test.go b/rpc/lib/server/parse_test.go new file mode 100644 index 00000000..5b0478b6 --- /dev/null +++ b/rpc/lib/server/parse_test.go @@ -0,0 +1,133 @@ +package rpcserver + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/tendermint/go-wire/data" +) + +func TestParseJSONMap(t *testing.T) { + assert := assert.New(t) + + input := []byte(`{"value":"1234","height":22}`) + + // naive is float,string + var p1 map[string]interface{} + err := json.Unmarshal(input, &p1) + if assert.Nil(err) { + h, ok := p1["height"].(float64) + if assert.True(ok, "%#v", p1["height"]) { + assert.EqualValues(22, h) + } + v, ok := p1["value"].(string) + if assert.True(ok, "%#v", p1["value"]) { + assert.EqualValues("1234", v) + } + } + + // preloading map with values doesn't help + tmp := 0 + p2 := map[string]interface{}{ + "value": &data.Bytes{}, + "height": &tmp, + } + err = json.Unmarshal(input, &p2) + if assert.Nil(err) { + h, ok := p2["height"].(float64) + if assert.True(ok, "%#v", p2["height"]) { + assert.EqualValues(22, h) + } + v, ok := p2["value"].(string) + if assert.True(ok, "%#v", p2["value"]) { + assert.EqualValues("1234", v) + } + } + + // preload here with *pointers* to the desired types + // struct has unknown types, but hard-coded keys + tmp = 0 + p3 := struct { + Value interface{} `json:"value"` + Height interface{} `json:"height"` + }{ + Height: &tmp, + Value: &data.Bytes{}, + } + err = json.Unmarshal(input, &p3) + if assert.Nil(err) { + h, ok := p3.Height.(*int) + if assert.True(ok, "%#v", p3.Height) { + assert.Equal(22, *h) + } + v, ok := p3.Value.(*data.Bytes) + if assert.True(ok, "%#v", p3.Value) { + assert.EqualValues([]byte{0x12, 0x34}, *v) + } + } + + // simplest solution, but hard-coded + p4 := struct { + Value data.Bytes `json:"value"` + Height int `json:"height"` + }{} + err = json.Unmarshal(input, &p4) + if assert.Nil(err) { + assert.EqualValues(22, p4.Height) + assert.EqualValues([]byte{0x12, 0x34}, p4.Value) + } + + // so, let's use this trick... + // dynamic keys on map, and we can deserialize to the desired types + var p5 map[string]*json.RawMessage + err = json.Unmarshal(input, &p5) + if assert.Nil(err) { + var h int + err = json.Unmarshal(*p5["height"], &h) + if assert.Nil(err) { + assert.Equal(22, h) + } + + var v data.Bytes + err = json.Unmarshal(*p5["value"], &v) + if assert.Nil(err) { + assert.Equal(data.Bytes{0x12, 0x34}, v) + } + } +} + +func TestParseJSONArray(t *testing.T) { + assert := assert.New(t) + + input := []byte(`["1234",22]`) + + // naive is float,string + var p1 []interface{} + err := json.Unmarshal(input, &p1) + if assert.Nil(err) { + v, ok := p1[0].(string) + if assert.True(ok, "%#v", p1[0]) { + assert.EqualValues("1234", v) + } + h, ok := p1[1].(float64) + if assert.True(ok, "%#v", p1[1]) { + assert.EqualValues(22, h) + } + } + + // preloading map with values helps here (unlike map - p2 above) + tmp := 0 + p2 := []interface{}{&data.Bytes{}, &tmp} + err = json.Unmarshal(input, &p2) + if assert.Nil(err) { + v, ok := p2[0].(*data.Bytes) + if assert.True(ok, "%#v", p2[0]) { + assert.EqualValues([]byte{0x12, 0x34}, *v) + } + h, ok := p2[1].(*int) + if assert.True(ok, "%#v", p2[1]) { + assert.EqualValues(22, *h) + } + } +}