github.com/evdatsion/aphelion-dpos-bft@v0.32.1/rpc/lib/server/parse_test.go (about)

     1  package rpcserver
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"strconv"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	amino "github.com/evdatsion/go-amino"
    12  	cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common"
    13  	types "github.com/evdatsion/aphelion-dpos-bft/rpc/lib/types"
    14  )
    15  
    16  func TestParseJSONMap(t *testing.T) {
    17  	input := []byte(`{"value":"1234","height":22}`)
    18  
    19  	// naive is float,string
    20  	var p1 map[string]interface{}
    21  	err := json.Unmarshal(input, &p1)
    22  	if assert.Nil(t, err) {
    23  		h, ok := p1["height"].(float64)
    24  		if assert.True(t, ok, "%#v", p1["height"]) {
    25  			assert.EqualValues(t, 22, h)
    26  		}
    27  		v, ok := p1["value"].(string)
    28  		if assert.True(t, ok, "%#v", p1["value"]) {
    29  			assert.EqualValues(t, "1234", v)
    30  		}
    31  	}
    32  
    33  	// preloading map with values doesn't help
    34  	tmp := 0
    35  	p2 := map[string]interface{}{
    36  		"value":  &cmn.HexBytes{},
    37  		"height": &tmp,
    38  	}
    39  	err = json.Unmarshal(input, &p2)
    40  	if assert.Nil(t, err) {
    41  		h, ok := p2["height"].(float64)
    42  		if assert.True(t, ok, "%#v", p2["height"]) {
    43  			assert.EqualValues(t, 22, h)
    44  		}
    45  		v, ok := p2["value"].(string)
    46  		if assert.True(t, ok, "%#v", p2["value"]) {
    47  			assert.EqualValues(t, "1234", v)
    48  		}
    49  	}
    50  
    51  	// preload here with *pointers* to the desired types
    52  	// struct has unknown types, but hard-coded keys
    53  	tmp = 0
    54  	p3 := struct {
    55  		Value  interface{} `json:"value"`
    56  		Height interface{} `json:"height"`
    57  	}{
    58  		Height: &tmp,
    59  		Value:  &cmn.HexBytes{},
    60  	}
    61  	err = json.Unmarshal(input, &p3)
    62  	if assert.Nil(t, err) {
    63  		h, ok := p3.Height.(*int)
    64  		if assert.True(t, ok, "%#v", p3.Height) {
    65  			assert.Equal(t, 22, *h)
    66  		}
    67  		v, ok := p3.Value.(*cmn.HexBytes)
    68  		if assert.True(t, ok, "%#v", p3.Value) {
    69  			assert.EqualValues(t, []byte{0x12, 0x34}, *v)
    70  		}
    71  	}
    72  
    73  	// simplest solution, but hard-coded
    74  	p4 := struct {
    75  		Value  cmn.HexBytes `json:"value"`
    76  		Height int          `json:"height"`
    77  	}{}
    78  	err = json.Unmarshal(input, &p4)
    79  	if assert.Nil(t, err) {
    80  		assert.EqualValues(t, 22, p4.Height)
    81  		assert.EqualValues(t, []byte{0x12, 0x34}, p4.Value)
    82  	}
    83  
    84  	// so, let's use this trick...
    85  	// dynamic keys on map, and we can deserialize to the desired types
    86  	var p5 map[string]*json.RawMessage
    87  	err = json.Unmarshal(input, &p5)
    88  	if assert.Nil(t, err) {
    89  		var h int
    90  		err = json.Unmarshal(*p5["height"], &h)
    91  		if assert.Nil(t, err) {
    92  			assert.Equal(t, 22, h)
    93  		}
    94  
    95  		var v cmn.HexBytes
    96  		err = json.Unmarshal(*p5["value"], &v)
    97  		if assert.Nil(t, err) {
    98  			assert.Equal(t, cmn.HexBytes{0x12, 0x34}, v)
    99  		}
   100  	}
   101  }
   102  
   103  func TestParseJSONArray(t *testing.T) {
   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(t, err) {
   110  		v, ok := p1[0].(string)
   111  		if assert.True(t, ok, "%#v", p1[0]) {
   112  			assert.EqualValues(t, "1234", v)
   113  		}
   114  		h, ok := p1[1].(float64)
   115  		if assert.True(t, ok, "%#v", p1[1]) {
   116  			assert.EqualValues(t, 22, h)
   117  		}
   118  	}
   119  
   120  	// preloading map with values helps here (unlike map - p2 above)
   121  	tmp := 0
   122  	p2 := []interface{}{&cmn.HexBytes{}, &tmp}
   123  	err = json.Unmarshal(input, &p2)
   124  	if assert.Nil(t, err) {
   125  		v, ok := p2[0].(*cmn.HexBytes)
   126  		if assert.True(t, ok, "%#v", p2[0]) {
   127  			assert.EqualValues(t, []byte{0x12, 0x34}, *v)
   128  		}
   129  		h, ok := p2[1].(*int)
   130  		if assert.True(t, ok, "%#v", p2[1]) {
   131  			assert.EqualValues(t, 22, *h)
   132  		}
   133  	}
   134  }
   135  
   136  func TestParseJSONRPC(t *testing.T) {
   137  	demo := func(ctx *types.Context, height int, name string) {}
   138  	call := NewRPCFunc(demo, "height,name")
   139  	cdc := amino.NewCodec()
   140  
   141  	cases := []struct {
   142  		raw    string
   143  		height int64
   144  		name   string
   145  		fail   bool
   146  	}{
   147  		// should parse
   148  		{`["7", "flew"]`, 7, "flew", false},
   149  		{`{"name": "john", "height": "22"}`, 22, "john", false},
   150  		// defaults
   151  		{`{"name": "solo", "unused": "stuff"}`, 0, "solo", false},
   152  		// should fail - wrong types/length
   153  		{`["flew", 7]`, 0, "", true},
   154  		{`[7,"flew",100]`, 0, "", true},
   155  		{`{"name": -12, "height": "fred"}`, 0, "", true},
   156  	}
   157  	for idx, tc := range cases {
   158  		i := strconv.Itoa(idx)
   159  		data := []byte(tc.raw)
   160  		vals, err := jsonParamsToArgs(call, cdc, data)
   161  		if tc.fail {
   162  			assert.NotNil(t, err, i)
   163  		} else {
   164  			assert.Nil(t, err, "%s: %+v", i, err)
   165  			if assert.Equal(t, 2, len(vals), i) {
   166  				assert.Equal(t, tc.height, vals[0].Int(), i)
   167  				assert.Equal(t, tc.name, vals[1].String(), i)
   168  			}
   169  		}
   170  
   171  	}
   172  }
   173  
   174  func TestParseURI(t *testing.T) {
   175  	demo := func(ctx *types.Context, height int, name string) {}
   176  	call := NewRPCFunc(demo, "height,name")
   177  	cdc := amino.NewCodec()
   178  
   179  	cases := []struct {
   180  		raw    []string
   181  		height int64
   182  		name   string
   183  		fail   bool
   184  	}{
   185  		// can parse numbers unquoted and strings quoted
   186  		{[]string{"7", `"flew"`}, 7, "flew", false},
   187  		{[]string{"22", `"john"`}, 22, "john", false},
   188  		{[]string{"-10", `"bob"`}, -10, "bob", false},
   189  		// can parse numbers quoted, too
   190  		{[]string{`"7"`, `"flew"`}, 7, "flew", false},
   191  		{[]string{`"-10"`, `"bob"`}, -10, "bob", false},
   192  		// cant parse strings uquoted
   193  		{[]string{`"-10"`, `bob`}, -10, "bob", true},
   194  	}
   195  	for idx, tc := range cases {
   196  		i := strconv.Itoa(idx)
   197  		// data := []byte(tc.raw)
   198  		url := fmt.Sprintf(
   199  			"test.com/method?height=%v&name=%v",
   200  			tc.raw[0], tc.raw[1])
   201  		req, err := http.NewRequest("GET", url, nil)
   202  		assert.NoError(t, err)
   203  		vals, err := httpParamsToArgs(call, cdc, req)
   204  		if tc.fail {
   205  			assert.NotNil(t, err, i)
   206  		} else {
   207  			assert.Nil(t, err, "%s: %+v", i, err)
   208  			if assert.Equal(t, 2, len(vals), i) {
   209  				assert.Equal(t, tc.height, vals[0].Int(), i)
   210  				assert.Equal(t, tc.name, vals[1].String(), i)
   211  			}
   212  		}
   213  
   214  	}
   215  }