1
2
3
4
5
6
7 package jsontext
8
9 import (
10 "bytes"
11 "errors"
12 "io"
13 "math/rand"
14 "slices"
15 "testing"
16
17 "encoding/json/internal/jsontest"
18 )
19
20 func FuzzCoder(f *testing.F) {
21
22 for _, td := range coderTestdata {
23 f.Add(int64(0), []byte(td.in))
24 }
25 for _, td := range decoderErrorTestdata {
26 f.Add(int64(0), []byte(td.in))
27 }
28 for _, td := range encoderErrorTestdata {
29 f.Add(int64(0), []byte(td.wantOut))
30 }
31 for _, td := range jsontest.Data {
32 f.Add(int64(0), td.Data())
33 }
34
35 f.Fuzz(func(t *testing.T, seed int64, b []byte) {
36 var tokVals []tokOrVal
37 rn := rand.NewSource(seed)
38
39
40
41 src := bytes.NewReader(b)
42 dec := NewDecoder(src)
43 for {
44 if rn.Int63()%8 > 0 {
45 tok, err := dec.ReadToken()
46 if err != nil {
47 if err == io.EOF {
48 break
49 }
50 t.Skipf("Decoder.ReadToken error: %v", err)
51 }
52 tokVals = append(tokVals, tok.Clone())
53 } else {
54 val, err := dec.ReadValue()
55 if err != nil {
56 expectError := dec.PeekKind() == '}' || dec.PeekKind() == ']'
57 if expectError && errors.As(err, new(*SyntacticError)) {
58 continue
59 }
60 if err == io.EOF {
61 break
62 }
63 t.Skipf("Decoder.ReadValue error: %v", err)
64 }
65 tokVals = append(tokVals, append(zeroValue, val...))
66 }
67 }
68
69
70
71 dst := new(bytes.Buffer)
72 enc := NewEncoder(dst)
73 for _, tokVal := range tokVals {
74 switch tokVal := tokVal.(type) {
75 case Token:
76 if err := enc.WriteToken(tokVal); err != nil {
77 t.Fatalf("Encoder.WriteToken error: %v", err)
78 }
79 case Value:
80 if err := enc.WriteValue(tokVal); err != nil {
81 t.Fatalf("Encoder.WriteValue error: %v", err)
82 }
83 }
84 }
85
86
87 var got, want []Token
88 for dec := NewDecoder(bytes.NewReader(b)); dec.PeekKind() > 0; {
89 tok, err := dec.ReadToken()
90 if err != nil {
91 t.Fatalf("Decoder.ReadToken error: %v", err)
92 }
93 got = append(got, tok.Clone())
94 }
95 for dec := NewDecoder(dst); dec.PeekKind() > 0; {
96 tok, err := dec.ReadToken()
97 if err != nil {
98 t.Fatalf("Decoder.ReadToken error: %v", err)
99 }
100 want = append(want, tok.Clone())
101 }
102 if !equalTokens(got, want) {
103 t.Fatalf("mismatching output:\ngot %v\nwant %v", got, want)
104 }
105 })
106 }
107
108 func FuzzResumableDecoder(f *testing.F) {
109 for _, td := range resumableDecoderTestdata {
110 f.Add(int64(0), []byte(td))
111 }
112
113 f.Fuzz(func(t *testing.T, seed int64, b []byte) {
114 rn := rand.NewSource(seed)
115
116
117
118 t.Run("ReadToken", func(t *testing.T) {
119 decGot := NewDecoder(&FaultyBuffer{B: b, MaxBytes: 8, Rand: rn})
120 decWant := NewDecoder(bytes.NewReader(b))
121 gotTok, gotErr := decGot.ReadToken()
122 wantTok, wantErr := decWant.ReadToken()
123 if gotTok.String() != wantTok.String() || !equalError(gotErr, wantErr) {
124 t.Errorf("Decoder.ReadToken = (%v, %v), want (%v, %v)", gotTok, gotErr, wantTok, wantErr)
125 }
126 })
127 t.Run("ReadValue", func(t *testing.T) {
128 decGot := NewDecoder(&FaultyBuffer{B: b, MaxBytes: 8, Rand: rn})
129 decWant := NewDecoder(bytes.NewReader(b))
130 gotVal, gotErr := decGot.ReadValue()
131 wantVal, wantErr := decWant.ReadValue()
132 if !slices.Equal(gotVal, wantVal) || !equalError(gotErr, wantErr) {
133 t.Errorf("Decoder.ReadValue = (%s, %v), want (%s, %v)", gotVal, gotErr, wantVal, wantErr)
134 }
135 })
136 })
137 }
138
139 func FuzzValueFormat(f *testing.F) {
140 for _, td := range valueTestdata {
141 f.Add(int64(0), []byte(td.in))
142 }
143
144
145 isValid := func(b []byte, opts ...Options) bool {
146 d := NewDecoder(bytes.NewReader(b), opts...)
147 _, errVal := d.ReadValue()
148 _, errEOF := d.ReadToken()
149 return errVal == nil && errEOF == io.EOF
150 }
151
152
153 stripWhitespace := func(in []byte) (out []byte) {
154 out = make([]byte, 0, len(in))
155 for _, c := range in {
156 switch c {
157 case ' ', '\n', '\r', '\t':
158 default:
159 out = append(out, c)
160 }
161 }
162 return out
163 }
164
165 allOptions := []Options{
166 AllowDuplicateNames(true),
167 AllowInvalidUTF8(true),
168 EscapeForHTML(true),
169 EscapeForJS(true),
170 PreserveRawStrings(true),
171 CanonicalizeRawInts(true),
172 CanonicalizeRawFloats(true),
173 ReorderRawObjects(true),
174 SpaceAfterColon(true),
175 SpaceAfterComma(true),
176 Multiline(true),
177 WithIndent("\t"),
178 WithIndentPrefix(" "),
179 }
180
181 f.Fuzz(func(t *testing.T, seed int64, b []byte) {
182 validRFC7159 := isValid(b, AllowInvalidUTF8(true), AllowDuplicateNames(true))
183 validRFC8259 := isValid(b, AllowInvalidUTF8(false), AllowDuplicateNames(true))
184 validRFC7493 := isValid(b, AllowInvalidUTF8(false), AllowDuplicateNames(false))
185 switch {
186 case !validRFC7159 && validRFC8259:
187 t.Errorf("invalid input per RFC 7159 implies invalid per RFC 8259")
188 case !validRFC8259 && validRFC7493:
189 t.Errorf("invalid input per RFC 8259 implies invalid per RFC 7493")
190 }
191
192 gotValid := Value(b).IsValid()
193 wantValid := validRFC7493
194 if gotValid != wantValid {
195 t.Errorf("Value.IsValid = %v, want %v", gotValid, wantValid)
196 }
197
198 gotCompacted := Value(string(b))
199 gotCompactOk := gotCompacted.Compact() == nil
200 wantCompactOk := validRFC7159
201 if !bytes.Equal(stripWhitespace(gotCompacted), stripWhitespace(b)) {
202 t.Errorf("stripWhitespace(Value.Compact) = %s, want %s", stripWhitespace(gotCompacted), stripWhitespace(b))
203 }
204 if gotCompactOk != wantCompactOk {
205 t.Errorf("Value.Compact success mismatch: got %v, want %v", gotCompactOk, wantCompactOk)
206 }
207
208 gotIndented := Value(string(b))
209 gotIndentOk := gotIndented.Indent() == nil
210 wantIndentOk := validRFC7159
211 if !bytes.Equal(stripWhitespace(gotIndented), stripWhitespace(b)) {
212 t.Errorf("stripWhitespace(Value.Indent) = %s, want %s", stripWhitespace(gotIndented), stripWhitespace(b))
213 }
214 if gotIndentOk != wantIndentOk {
215 t.Errorf("Value.Indent success mismatch: got %v, want %v", gotIndentOk, wantIndentOk)
216 }
217
218 gotCanonicalized := Value(string(b))
219 gotCanonicalizeOk := gotCanonicalized.Canonicalize() == nil
220 wantCanonicalizeOk := validRFC7493
221 if gotCanonicalizeOk != wantCanonicalizeOk {
222 t.Errorf("Value.Canonicalize success mismatch: got %v, want %v", gotCanonicalizeOk, wantCanonicalizeOk)
223 }
224
225
226 var opts []Options
227 rn := rand.New(rand.NewSource(seed))
228 for _, opt := range allOptions {
229 if rn.Intn(len(allOptions)/4) == 0 {
230 opts = append(opts, opt)
231 }
232 }
233 v := Value(b)
234 v.Format(opts...)
235 })
236 }
237
View as plain text