json_test.go 3.5 KB

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