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.

188 lines
5.4 KiB

  1. package jsontypes_test
  2. import (
  3. "testing"
  4. "github.com/tendermint/tendermint/internal/jsontypes"
  5. )
  6. type testPtrType struct {
  7. Field string `json:"field"`
  8. }
  9. func (*testPtrType) TypeTag() string { return "test/PointerType" }
  10. func (t *testPtrType) Value() string { return t.Field }
  11. type testBareType struct {
  12. Field string `json:"field"`
  13. }
  14. func (testBareType) TypeTag() string { return "test/BareType" }
  15. func (t testBareType) Value() string { return t.Field }
  16. type fielder interface{ Value() string }
  17. func TestRoundTrip(t *testing.T) {
  18. t.Run("MustRegister_ok", func(t *testing.T) {
  19. defer func() {
  20. if x := recover(); x != nil {
  21. t.Fatalf("Registration panicked: %v", x)
  22. }
  23. }()
  24. jsontypes.MustRegister((*testPtrType)(nil))
  25. jsontypes.MustRegister(testBareType{})
  26. })
  27. t.Run("MustRegister_fail", func(t *testing.T) {
  28. defer func() {
  29. if x := recover(); x != nil {
  30. t.Logf("Got expected panic: %v", x)
  31. }
  32. }()
  33. jsontypes.MustRegister((*testPtrType)(nil))
  34. t.Fatal("Registration should not have succeeded")
  35. })
  36. t.Run("Marshal_nilTagged", func(t *testing.T) {
  37. bits, err := jsontypes.Marshal(nil)
  38. if err != nil {
  39. t.Fatalf("Marshal failed: %v", err)
  40. }
  41. if got := string(bits); got != "null" {
  42. t.Errorf("Marshal nil: got %#q, want null", got)
  43. }
  44. })
  45. t.Run("RoundTrip_pointerType", func(t *testing.T) {
  46. const wantEncoded = `{"type":"test/PointerType","value":{"field":"hello"}}`
  47. obj := testPtrType{Field: "hello"}
  48. bits, err := jsontypes.Marshal(&obj)
  49. if err != nil {
  50. t.Fatalf("Marshal %T failed: %v", obj, err)
  51. }
  52. if got := string(bits); got != wantEncoded {
  53. t.Errorf("Marshal %T: got %#q, want %#q", obj, got, wantEncoded)
  54. }
  55. var cmp testPtrType
  56. if err := jsontypes.Unmarshal(bits, &cmp); err != nil {
  57. t.Errorf("Unmarshal %#q failed: %v", string(bits), err)
  58. }
  59. if obj != cmp {
  60. t.Errorf("Unmarshal %#q: got %+v, want %+v", string(bits), cmp, obj)
  61. }
  62. })
  63. t.Run("RoundTrip_bareType", func(t *testing.T) {
  64. const wantEncoded = `{"type":"test/BareType","value":{"field":"hello"}}`
  65. obj := testBareType{Field: "hello"}
  66. bits, err := jsontypes.Marshal(&obj)
  67. if err != nil {
  68. t.Fatalf("Marshal %T failed: %v", obj, err)
  69. }
  70. if got := string(bits); got != wantEncoded {
  71. t.Errorf("Marshal %T: got %#q, want %#q", obj, got, wantEncoded)
  72. }
  73. var cmp testBareType
  74. if err := jsontypes.Unmarshal(bits, &cmp); err != nil {
  75. t.Errorf("Unmarshal %#q failed: %v", string(bits), err)
  76. }
  77. if obj != cmp {
  78. t.Errorf("Unmarshal %#q: got %+v, want %+v", string(bits), cmp, obj)
  79. }
  80. })
  81. t.Run("Unmarshal_nilPointer", func(t *testing.T) {
  82. var obj *testBareType
  83. // Unmarshaling to a nil pointer target should report an error.
  84. if err := jsontypes.Unmarshal([]byte(`null`), obj); err == nil {
  85. t.Errorf("Unmarshal nil: got %+v, wanted error", obj)
  86. } else {
  87. t.Logf("Unmarshal correctly failed: %v", err)
  88. }
  89. })
  90. t.Run("Unmarshal_bareType", func(t *testing.T) {
  91. const want = "foobar"
  92. const input = `{"type":"test/BareType","value":{"field":"` + want + `"}}`
  93. var obj testBareType
  94. if err := jsontypes.Unmarshal([]byte(input), &obj); err != nil {
  95. t.Fatalf("Unmarshal failed: %v", err)
  96. }
  97. if obj.Field != want {
  98. t.Errorf("Unmarshal result: got %q, want %q", obj.Field, want)
  99. }
  100. })
  101. t.Run("Unmarshal_bareType_interface", func(t *testing.T) {
  102. const want = "foobar"
  103. const input = `{"type":"test/BareType","value":{"field":"` + want + `"}}`
  104. var obj fielder
  105. if err := jsontypes.Unmarshal([]byte(input), &obj); err != nil {
  106. t.Fatalf("Unmarshal failed: %v", err)
  107. }
  108. if got := obj.Value(); got != want {
  109. t.Errorf("Unmarshal result: got %q, want %q", got, want)
  110. }
  111. })
  112. t.Run("Unmarshal_pointerType", func(t *testing.T) {
  113. const want = "bazquux"
  114. const input = `{"type":"test/PointerType","value":{"field":"` + want + `"}}`
  115. var obj testPtrType
  116. if err := jsontypes.Unmarshal([]byte(input), &obj); err != nil {
  117. t.Fatalf("Unmarshal failed: %v", err)
  118. }
  119. if obj.Field != want {
  120. t.Errorf("Unmarshal result: got %q, want %q", obj.Field, want)
  121. }
  122. })
  123. t.Run("Unmarshal_pointerType_interface", func(t *testing.T) {
  124. const want = "foobar"
  125. const input = `{"type":"test/PointerType","value":{"field":"` + want + `"}}`
  126. var obj fielder
  127. if err := jsontypes.Unmarshal([]byte(input), &obj); err != nil {
  128. t.Fatalf("Unmarshal failed: %v", err)
  129. }
  130. if got := obj.Value(); got != want {
  131. t.Errorf("Unmarshal result: got %q, want %q", got, want)
  132. }
  133. })
  134. t.Run("Unmarshal_unknownTypeTag", func(t *testing.T) {
  135. const input = `{"type":"test/Nonesuch","value":null}`
  136. // An unregistered type tag in a valid envelope should report an error.
  137. var obj interface{}
  138. if err := jsontypes.Unmarshal([]byte(input), &obj); err == nil {
  139. t.Errorf("Unmarshal: got %+v, wanted error", obj)
  140. } else {
  141. t.Logf("Unmarshal correctly failed: %v", err)
  142. }
  143. })
  144. t.Run("Unmarshal_similarTarget", func(t *testing.T) {
  145. const want = "zootie-zoot-zoot"
  146. const input = `{"type":"test/PointerType","value":{"field":"` + want + `"}}`
  147. // The target has a compatible (i.e., assignable) shape to the registered
  148. // type. This should work even though it's not the original named type.
  149. var cmp struct {
  150. Field string `json:"field"`
  151. }
  152. if err := jsontypes.Unmarshal([]byte(input), &cmp); err != nil {
  153. t.Errorf("Unmarshal %#q failed: %v", input, err)
  154. } else if cmp.Field != want {
  155. t.Errorf("Unmarshal result: got %q, want %q", cmp.Field, want)
  156. }
  157. })
  158. }