json_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package test
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "strings"
  7. "testing"
  8. "github.com/davecgh/go-spew/spew"
  9. fuzz "github.com/google/gofuzz"
  10. jsoniter "github.com/json-iterator/go"
  11. )
  12. func Test_Roundtrip(t *testing.T) {
  13. fz := fuzz.New().MaxDepth(10).NilChance(0.3)
  14. for i := 0; i < 1000; i++ {
  15. var before T
  16. fz.Fuzz(&before)
  17. jbStd, err := json.Marshal(before)
  18. if err != nil {
  19. t.Fatalf("failed to marshal with stdlib: %v", err)
  20. }
  21. if len(strings.TrimSpace(string(jbStd))) == 0 {
  22. t.Fatal("stdlib marshal produced empty result and no error")
  23. }
  24. jbIter, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(before)
  25. if err != nil {
  26. t.Fatalf("failed to marshal with jsoniter: %v", err)
  27. }
  28. if len(strings.TrimSpace(string(jbIter))) == 0 {
  29. t.Fatal("jsoniter marshal produced empty result and no error")
  30. }
  31. if string(jbStd) != string(jbIter) {
  32. t.Fatalf("marshal expected:\n %s\ngot:\n %s\nobj:\n %s",
  33. indent(jbStd, " "), indent(jbIter, " "), dump(before))
  34. }
  35. var afterStd T
  36. err = json.Unmarshal(jbIter, &afterStd)
  37. if err != nil {
  38. t.Fatalf("failed to unmarshal with stdlib: %v", err)
  39. }
  40. var afterIter T
  41. err = jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(jbIter, &afterIter)
  42. if err != nil {
  43. t.Fatalf("failed to unmarshal with jsoniter: %v", err)
  44. }
  45. if fingerprint(afterStd) != fingerprint(afterIter) {
  46. t.Fatalf("unmarshal expected:\n %s\ngot:\n %s\nvia:\n %s",
  47. dump(afterStd), dump(afterIter), indent(jbIter, " "))
  48. }
  49. }
  50. }
  51. const indentStr = "> "
  52. func fingerprint(obj interface{}) string {
  53. c := spew.ConfigState{
  54. SortKeys: true,
  55. SpewKeys: true,
  56. }
  57. return c.Sprintf("%v", obj)
  58. }
  59. func dump(obj interface{}) string {
  60. cfg := spew.ConfigState{
  61. Indent: indentStr,
  62. }
  63. return cfg.Sdump(obj)
  64. }
  65. func indent(src []byte, prefix string) string {
  66. var buf bytes.Buffer
  67. err := json.Indent(&buf, src, prefix, indentStr)
  68. if err != nil {
  69. return fmt.Sprintf("!!! %v", err)
  70. }
  71. return buf.String()
  72. }
  73. func benchmarkMarshal(t *testing.B, name string, fn func(interface{}) ([]byte, error)) {
  74. t.ReportAllocs()
  75. t.ResetTimer()
  76. var obj T
  77. fz := fuzz.NewWithSeed(0).MaxDepth(10).NilChance(0.3)
  78. fz.Fuzz(&obj)
  79. for i := 0; i < t.N; i++ {
  80. jb, err := fn(obj)
  81. if err != nil {
  82. t.Fatalf("%s failed to marshal:\n input: %s\n error: %v", name, dump(obj), err)
  83. }
  84. _ = jb
  85. }
  86. }
  87. func benchmarkUnmarshal(t *testing.B, name string, fn func(data []byte, v interface{}) error) {
  88. t.ReportAllocs()
  89. t.ResetTimer()
  90. var before T
  91. fz := fuzz.NewWithSeed(0).MaxDepth(10).NilChance(0.3)
  92. fz.Fuzz(&before)
  93. jb, err := json.Marshal(before)
  94. if err != nil {
  95. t.Fatalf("failed to marshal: %v", err)
  96. }
  97. for i := 0; i < t.N; i++ {
  98. var after T
  99. err = fn(jb, &after)
  100. if err != nil {
  101. t.Fatalf("%s failed to unmarshal:\n input: %q\n error: %v", name, string(jb), err)
  102. }
  103. }
  104. }
  105. func BenchmarkStandardMarshal(t *testing.B) {
  106. benchmarkMarshal(t, "stdlib", json.Marshal)
  107. }
  108. func BenchmarkStandardUnmarshal(t *testing.B) {
  109. benchmarkUnmarshal(t, "stdlib", json.Unmarshal)
  110. }
  111. func BenchmarkJSONIterMarshalFastest(t *testing.B) {
  112. benchmarkMarshal(t, "jsoniter-fastest", jsoniter.ConfigFastest.Marshal)
  113. }
  114. func BenchmarkJSONIterUnmarshalFastest(t *testing.B) {
  115. benchmarkUnmarshal(t, "jsoniter-fastest", jsoniter.ConfigFastest.Unmarshal)
  116. }
  117. func BenchmarkJSONIterMarshalDefault(t *testing.B) {
  118. benchmarkMarshal(t, "jsoniter-default", jsoniter.Marshal)
  119. }
  120. func BenchmarkJSONIterUnmarshalDefault(t *testing.B) {
  121. benchmarkUnmarshal(t, "jsoniter-default", jsoniter.Unmarshal)
  122. }
  123. func BenchmarkJSONIterMarshalCompatible(t *testing.B) {
  124. benchmarkMarshal(t, "jsoniter-compat", jsoniter.ConfigCompatibleWithStandardLibrary.Marshal)
  125. }
  126. func BenchmarkJSONIterUnmarshalCompatible(t *testing.B) {
  127. benchmarkUnmarshal(t, "jsoniter-compat", jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal)
  128. }