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  }