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.

174 lines
3.9 KiB

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