You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
4.0 KiB

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