package test import ( "bytes" "encoding/json" "testing" "github.com/davecgh/go-spew/spew" fuzz "github.com/google/gofuzz" jsoniter "github.com/json-iterator/go" ) func Test_Roundtrip(t *testing.T) { fz := fuzz.New().MaxDepth(10).NilChance(0.3) for i := 0; i < 1000; i++ { var before T fz.Fuzz(&before) jbStd, err := json.Marshal(before) if err != nil { t.Errorf("failed to marshal with stdlib: %v", err) } jbIter, err := jsoniter.Marshal(before) if err != nil { t.Errorf("failed to marshal with jsoniter: %v", err) } if string(jbStd) != string(jbIter) { t.Errorf("marshal expected:\n %s\ngot:\n %s\nobj:\n %s", indent(jbStd, " "), indent(jbIter, " "), dump(before)) } var afterStd T err = json.Unmarshal(jbIter, &afterStd) if err != nil { t.Errorf("failed to unmarshal with stdlib: %v", err) } var afterIter T err = jsoniter.Unmarshal(jbIter, &afterIter) if err != nil { t.Errorf("failed to unmarshal with jsoniter: %v", err) } if fingerprint(afterStd) != fingerprint(afterIter) { t.Errorf("unmarshal expected:\n %s\ngot:\n %s\nvia:\n %s", dump(afterStd), dump(afterIter), indent(jbIter, " ")) } } } const indentStr = "> " func fingerprint(obj interface{}) string { c := spew.ConfigState{ SortKeys: true, SpewKeys: true, } return c.Sprintf("%v", obj) } func dump(obj interface{}) string { cfg := spew.ConfigState{ Indent: indentStr, } return cfg.Sdump(obj) } func indent(src []byte, prefix string) string { var buf bytes.Buffer json.Indent(&buf, src, prefix, indentStr) return buf.String() } func BenchmarkStandardMarshal(t *testing.B) { t.ReportAllocs() t.ResetTimer() var obj T fz := fuzz.NewWithSeed(0).MaxDepth(10).NilChance(0.3) fz.Fuzz(&obj) for i := 0; i < t.N; i++ { jb, err := json.Marshal(obj) if err != nil { t.Fatalf("failed to marshal:\n input: %s\n error: %v", dump(obj), err) } _ = jb } } func BenchmarkStandardUnmarshal(t *testing.B) { t.ReportAllocs() t.ResetTimer() var before T fz := fuzz.NewWithSeed(0).MaxDepth(10).NilChance(0.3) fz.Fuzz(&before) jb, err := json.Marshal(before) if err != nil { t.Fatalf("failed to marshal: %v", err) } for i := 0; i < t.N; i++ { var after T err = json.Unmarshal(jb, &after) if err != nil { t.Fatalf("failed to unmarshal:\n input: %q\n error: %v", string(jb), err) } } } func BenchmarkJSONIterMarshal(t *testing.B) { t.ReportAllocs() t.ResetTimer() var obj T fz := fuzz.NewWithSeed(0).MaxDepth(10).NilChance(0.3) fz.Fuzz(&obj) for i := 0; i < t.N; i++ { jb, err := jsoniter.Marshal(obj) if err != nil { t.Fatalf("failed to marshal:\n input: %s\n error: %v", dump(obj), err) } _ = jb } } func BenchmarkJSONIterUnmarshal(t *testing.B) { t.ReportAllocs() t.ResetTimer() var before T fz := fuzz.NewWithSeed(0).MaxDepth(10).NilChance(0.3) fz.Fuzz(&before) jb, err := json.Marshal(before) if err != nil { t.Fatalf("failed to marshal: %v", err) } for i := 0; i < t.N; i++ { var after T err = jsoniter.Unmarshal(jb, &after) if err != nil { t.Fatalf("failed to unmarshal:\n input: %q\n error: %v", string(jb), err) } } }