summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-02-10 23:38:26 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2023-02-25 01:18:17 -0700
commitd35495540df2b6d3ba16c84ce21627d9dbae000c (patch)
tree064ee24fe155ae4f45fd85914935904f07c6a859
parent5c33db4970fcb35ae3823d61f9576fd65b5fcbdf (diff)
Fuzz for equivalence between stdlib and lowmemjson
-rw-r--r--compat/json/equiv_test.go160
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/0064ebc3507e959b2
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/19981bffc2abbaf12
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/57365320c09686112
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/5cd6893f25481dae2
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/6a6612e05e0f9e322
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/77e6e971d8684f842
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/8727b16d337d7b812
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/96aac43014471adc2
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/9cc52906ed53ef5f2
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/a0b9ecf4e99fd85d2
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/a5775dd298b90a6c2
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/af9bedcb9e0a31e82
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/f6b0960dd3331a002
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/fbbce5ea61559cc62
-rw-r--r--compat/json/testdata/fuzz/FuzzEquiv/fd29ccbb2af92d4f2
16 files changed, 190 insertions, 0 deletions
diff --git a/compat/json/equiv_test.go b/compat/json/equiv_test.go
new file mode 100644
index 0000000..246e4b3
--- /dev/null
+++ b/compat/json/equiv_test.go
@@ -0,0 +1,160 @@
+// Copyright (C) 2023 Luke Shumaker <lukeshu@lukeshu.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package json_test
+
+import (
+ "bytes"
+ std "encoding/json"
+ "errors"
+ "io"
+ "strconv"
+ "strings"
+ "testing"
+ "unicode/utf8"
+
+ "github.com/stretchr/testify/assert"
+
+ low "git.lukeshu.com/go/lowmemjson/compat/json"
+)
+
+func assertEquivErr(t *testing.T, stdErr, lowErr error) {
+ if (stdErr == nil) || (lowErr == nil) {
+ // Nil-equal.
+ assert.Equal(t, stdErr, lowErr)
+ return
+ }
+ switch stdErr.(type) {
+ case *std.SyntaxError:
+ if lowErr != nil {
+ stdMsg := stdErr.Error()
+ lowMsg := lowErr.Error()
+
+ // https://github.com/golang/go/issues/58680
+ if strings.HasPrefix(stdMsg, `invalid character ' ' `) &&
+ (errors.Is(lowErr, io.ErrUnexpectedEOF) || lowMsg == "unexpected end of JSON input") {
+ return
+ }
+
+ // https://github.com/golang/go/issues/58713
+ prefix := `invalid character '`
+ if stdMsg != lowMsg && strings.HasPrefix(stdMsg, prefix) && strings.HasPrefix(lowMsg, prefix) {
+ stdRune, stdRuneSize := utf8.DecodeRuneInString(stdMsg[len(prefix):])
+ lowByte := lowMsg[len(prefix)]
+ if lowByte == '\\' {
+ switch lowMsg[len(prefix)+1] {
+ case 'u':
+ lowRune, _ := strconv.ParseUint(lowMsg[len(prefix)+2:][:4], 16, 32)
+ var buf [4]byte
+ utf8.EncodeRune(buf[:], rune(lowRune))
+ lowByte = buf[0]
+ case 'U':
+ lowRune, _ := strconv.ParseUint(lowMsg[len(prefix)+2:][:8], 16, 32)
+ var buf [4]byte
+ utf8.EncodeRune(buf[:], rune(lowRune))
+ lowByte = buf[0]
+ }
+ }
+ if stdRune == rune(lowByte) {
+ lowRuneStr := lowMsg[len(prefix):]
+ lowRuneStr = lowRuneStr[:strings.IndexByte(lowRuneStr, '\'')]
+ stdMsg = prefix + lowRuneStr + stdMsg[len(prefix)+stdRuneSize:]
+ stdErr = errors.New(stdMsg)
+ }
+ }
+ }
+ // Text-equal.
+ assert.Equal(t, stdErr.Error(), lowErr.Error())
+ // TODO: Assert that they are deep-equal (but be permissive of these not being type aliases).
+ case *std.MarshalerError:
+ // Text-equal.
+ assert.Equal(t, stdErr.Error(), lowErr.Error())
+ // TODO: Assert that they are deep-equal (but be permissive of these not being type aliases).
+ default:
+ // Text-equal.
+ assert.Equal(t, stdErr.Error(), lowErr.Error())
+ // TODO: Assert that they are deep-equal.
+ }
+}
+
+func FuzzEquiv(f *testing.F) {
+ f.Fuzz(func(t *testing.T, str []byte) {
+ t.Logf("str=%q", str)
+ t.Run("HTMLEscape", func(t *testing.T) {
+ var stdOut bytes.Buffer
+ std.HTMLEscape(&stdOut, str)
+
+ var lowOut bytes.Buffer
+ low.HTMLEscape(&lowOut, str)
+
+ assert.Equal(t, stdOut.String(), lowOut.String())
+ })
+ t.Run("Compact", func(t *testing.T) {
+ var stdOut bytes.Buffer
+ stdErr := std.Compact(&stdOut, str)
+
+ var lowOut bytes.Buffer
+ lowErr := low.Compact(&lowOut, str)
+
+ assert.Equal(t, stdOut.String(), lowOut.String())
+ assertEquivErr(t, stdErr, lowErr)
+ })
+ t.Run("Indent", func(t *testing.T) {
+ var stdOut bytes.Buffer
+ stdErr := std.Indent(&stdOut, str, "»", "\t")
+
+ var lowOut bytes.Buffer
+ lowErr := low.Indent(&lowOut, str, "»", "\t")
+
+ assert.Equal(t, stdOut.String(), lowOut.String())
+ assertEquivErr(t, stdErr, lowErr)
+ })
+ t.Run("Valid", func(t *testing.T) {
+ stdValid := std.Valid(str) && utf8.Valid(str) // https://github.com/golang/go/issues/58517
+ lowValid := low.Valid(str)
+ assert.Equal(t, stdValid, lowValid)
+ })
+ t.Run("Decode-Encode", func(t *testing.T) {
+ var stdObj any
+ stdErr := std.NewDecoder(bytes.NewReader(str)).Decode(&stdObj)
+
+ var lowObj any
+ lowErr := low.NewDecoder(bytes.NewReader(str)).Decode(&lowObj)
+
+ assert.Equal(t, stdObj, lowObj)
+ assertEquivErr(t, stdErr, lowErr)
+ if t.Failed() {
+ return
+ }
+
+ var stdOut bytes.Buffer
+ stdErr = std.NewEncoder(&stdOut).Encode(stdObj)
+
+ var lowOut bytes.Buffer
+ lowErr = low.NewEncoder(&lowOut).Encode(lowObj)
+
+ assert.Equal(t, stdOut.String(), lowOut.String())
+ assertEquivErr(t, stdErr, lowErr)
+ })
+ t.Run("Unmarshal-Marshal", func(t *testing.T) {
+ var stdObj any
+ stdErr := std.Unmarshal(str, &stdObj)
+
+ var lowObj any
+ lowErr := low.Unmarshal(str, &lowObj)
+
+ assert.Equal(t, stdObj, lowObj)
+ assertEquivErr(t, stdErr, lowErr)
+ if t.Failed() {
+ return
+ }
+
+ stdOut, stdErr := std.Marshal(stdObj)
+ lowOut, lowErr := low.Marshal(lowObj)
+
+ assert.Equal(t, string(stdOut), string(lowOut))
+ assertEquivErr(t, stdErr, lowErr)
+ })
+ })
+}
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/0064ebc3507e959b b/compat/json/testdata/fuzz/FuzzEquiv/0064ebc3507e959b
new file mode 100644
index 0000000..96e9e53
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/0064ebc3507e959b
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("𐠁")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/19981bffc2abbaf1 b/compat/json/testdata/fuzz/FuzzEquiv/19981bffc2abbaf1
new file mode 100644
index 0000000..ecbe8af
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/19981bffc2abbaf1
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("A")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/57365320c0968611 b/compat/json/testdata/fuzz/FuzzEquiv/57365320c0968611
new file mode 100644
index 0000000..5aace7f
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/57365320c0968611
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("[200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/5cd6893f25481dae b/compat/json/testdata/fuzz/FuzzEquiv/5cd6893f25481dae
new file mode 100644
index 0000000..a51778b
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/5cd6893f25481dae
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("0E00")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/6a6612e05e0f9e32 b/compat/json/testdata/fuzz/FuzzEquiv/6a6612e05e0f9e32
new file mode 100644
index 0000000..fe2e128
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/6a6612e05e0f9e32
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("\"\\uD800\"")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/77e6e971d8684f84 b/compat/json/testdata/fuzz/FuzzEquiv/77e6e971d8684f84
new file mode 100644
index 0000000..e3c530f
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/77e6e971d8684f84
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("\uebae")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/8727b16d337d7b81 b/compat/json/testdata/fuzz/FuzzEquiv/8727b16d337d7b81
new file mode 100644
index 0000000..e8000f3
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/8727b16d337d7b81
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("00")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/96aac43014471adc b/compat/json/testdata/fuzz/FuzzEquiv/96aac43014471adc
new file mode 100644
index 0000000..9461c7a
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/96aac43014471adc
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("\"\\")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/9cc52906ed53ef5f b/compat/json/testdata/fuzz/FuzzEquiv/9cc52906ed53ef5f
new file mode 100644
index 0000000..1edfb06
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/9cc52906ed53ef5f
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("\"")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/a0b9ecf4e99fd85d b/compat/json/testdata/fuzz/FuzzEquiv/a0b9ecf4e99fd85d
new file mode 100644
index 0000000..b3c523c
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/a0b9ecf4e99fd85d
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("0.")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/a5775dd298b90a6c b/compat/json/testdata/fuzz/FuzzEquiv/a5775dd298b90a6c
new file mode 100644
index 0000000..ca6f6f5
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/a5775dd298b90a6c
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("\"\\u")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/af9bedcb9e0a31e8 b/compat/json/testdata/fuzz/FuzzEquiv/af9bedcb9e0a31e8
new file mode 100644
index 0000000..778cc61
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/af9bedcb9e0a31e8
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("0 ")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/f6b0960dd3331a00 b/compat/json/testdata/fuzz/FuzzEquiv/f6b0960dd3331a00
new file mode 100644
index 0000000..9644b51
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/f6b0960dd3331a00
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("\"0\x85\xcd\xc0\xf3\xcb\xc1\xb3\xf2\xf5\xa4\xc1\xd40\xba\xe9\"")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/fbbce5ea61559cc6 b/compat/json/testdata/fuzz/FuzzEquiv/fbbce5ea61559cc6
new file mode 100644
index 0000000..712fab9
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/fbbce5ea61559cc6
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("\U00054516")
diff --git a/compat/json/testdata/fuzz/FuzzEquiv/fd29ccbb2af92d4f b/compat/json/testdata/fuzz/FuzzEquiv/fd29ccbb2af92d4f
new file mode 100644
index 0000000..9dc2675
--- /dev/null
+++ b/compat/json/testdata/fuzz/FuzzEquiv/fd29ccbb2af92d4f
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("Ǒ")