1
2
3
4
5
6
7 package jsontext
8
9 import (
10 "bytes"
11 "errors"
12 "io"
13 "math"
14 "math/rand"
15 "path"
16 "reflect"
17 "strings"
18 "testing"
19
20 "encoding/json/internal/jsontest"
21 "encoding/json/internal/jsonwire"
22 )
23
24 func E(err error) *SyntacticError {
25 return &SyntacticError{Err: err}
26 }
27
28 func newInvalidCharacterError(prefix, where string) *SyntacticError {
29 return E(jsonwire.NewInvalidCharacterError(prefix, where))
30 }
31
32 func newInvalidEscapeSequenceError(what string) *SyntacticError {
33 return E(jsonwire.NewInvalidEscapeSequenceError(what))
34 }
35
36 func (e *SyntacticError) withPos(prefix string, pointer Pointer) *SyntacticError {
37 e.ByteOffset = int64(len(prefix))
38 e.JSONPointer = pointer
39 return e
40 }
41
42 func equalError(x, y error) bool {
43 return reflect.DeepEqual(x, y)
44 }
45
46 var (
47 zeroToken Token
48 zeroValue Value
49 )
50
51
52 type tokOrVal interface{ Kind() Kind }
53
54 type coderTestdataEntry struct {
55 name jsontest.CaseName
56 in string
57 outCompacted string
58 outEscaped string
59 outIndented string
60 outCanonicalized string
61 tokens []Token
62 pointers []Pointer
63 }
64
65 var coderTestdata = []coderTestdataEntry{{
66 name: jsontest.Name("Null"),
67 in: ` null `,
68 outCompacted: `null`,
69 tokens: []Token{Null},
70 pointers: []Pointer{""},
71 }, {
72 name: jsontest.Name("False"),
73 in: ` false `,
74 outCompacted: `false`,
75 tokens: []Token{False},
76 }, {
77 name: jsontest.Name("True"),
78 in: ` true `,
79 outCompacted: `true`,
80 tokens: []Token{True},
81 }, {
82 name: jsontest.Name("EmptyString"),
83 in: ` "" `,
84 outCompacted: `""`,
85 tokens: []Token{String("")},
86 }, {
87 name: jsontest.Name("SimpleString"),
88 in: ` "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" `,
89 outCompacted: `"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"`,
90 outEscaped: `"\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u006a\u006b\u006c\u006d\u006e\u006f\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007a\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005a"`,
91 tokens: []Token{String("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")},
92 }, {
93 name: jsontest.Name("ComplicatedString"),
94 in: " \"Hello, δΈη πβ
ββ©π " + "\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602" + ` \ud800\udead \"\\\/\b\f\n\r\t \u0022\u005c\u002f\u0008\u000c\u000a\u000d\u0009" `,
95 outCompacted: "\"Hello, δΈη πβ
ββ©π " + "\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602" + " π \\\"\\\\/\\b\\f\\n\\r\\t \\\"\\\\/\\b\\f\\n\\r\\t\"",
96 outEscaped: `"\u0048\u0065\u006c\u006c\u006f\u002c\u0020\u4e16\u754c\u0020\ud83c\udf1f\u2605\u2606\u2729\ud83c\udf20\u0020\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\ud83d\ude02\u0020\ud800\udead\u0020\u0022\u005c\u002f\u0008\u000c\u000a\u000d\u0009\u0020\u0022\u005c\u002f\u0008\u000c\u000a\u000d\u0009"`,
97 outCanonicalized: `"Hello, δΈη πβ
ββ©π ΒΓΆβ¬νξדּ�π π \"\\/\b\f\n\r\t \"\\/\b\f\n\r\t"`,
98 tokens: []Token{rawToken("\"Hello, δΈη πβ
ββ©π " + "\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602" + " π \\\"\\\\/\\b\\f\\n\\r\\t \\\"\\\\/\\b\\f\\n\\r\\t\"")},
99 }, {
100 name: jsontest.Name("ZeroNumber"),
101 in: ` 0 `,
102 outCompacted: `0`,
103 tokens: []Token{Uint(0)},
104 }, {
105 name: jsontest.Name("SimpleNumber"),
106 in: ` 123456789 `,
107 outCompacted: `123456789`,
108 tokens: []Token{Uint(123456789)},
109 }, {
110 name: jsontest.Name("NegativeNumber"),
111 in: ` -123456789 `,
112 outCompacted: `-123456789`,
113 tokens: []Token{Int(-123456789)},
114 }, {
115 name: jsontest.Name("FractionalNumber"),
116 in: " 0.123456789 ",
117 outCompacted: `0.123456789`,
118 tokens: []Token{Float(0.123456789)},
119 }, {
120 name: jsontest.Name("ExponentNumber"),
121 in: " 0e12456789 ",
122 outCompacted: `0e12456789`,
123 outCanonicalized: `0`,
124 tokens: []Token{rawToken(`0e12456789`)},
125 }, {
126 name: jsontest.Name("ExponentNumberP"),
127 in: " 0e+12456789 ",
128 outCompacted: `0e+12456789`,
129 outCanonicalized: `0`,
130 tokens: []Token{rawToken(`0e+12456789`)},
131 }, {
132 name: jsontest.Name("ExponentNumberN"),
133 in: " 0e-12456789 ",
134 outCompacted: `0e-12456789`,
135 outCanonicalized: `0`,
136 tokens: []Token{rawToken(`0e-12456789`)},
137 }, {
138 name: jsontest.Name("ComplicatedNumber"),
139 in: ` -123456789.987654321E+0123456789 `,
140 outCompacted: `-123456789.987654321E+0123456789`,
141 outCanonicalized: `-1.7976931348623157e+308`,
142 tokens: []Token{rawToken(`-123456789.987654321E+0123456789`)},
143 }, {
144 name: jsontest.Name("Numbers"),
145 in: ` [
146 0, -0, 0.0, -0.0, 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001, 1e1000,
147 -5e-324, 1e+100, 1.7976931348623157e+308,
148 9007199254740990, 9007199254740991, 9007199254740992, 9007199254740993, 9007199254740994,
149 -9223372036854775808, 9223372036854775807, 0, 18446744073709551615
150 ] `,
151 outCompacted: "[0,-0,0.0,-0.0,1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,1e1000,-5e-324,1e+100,1.7976931348623157e+308,9007199254740990,9007199254740991,9007199254740992,9007199254740993,9007199254740994,-9223372036854775808,9223372036854775807,0,18446744073709551615]",
152 outIndented: `[
153 0,
154 -0,
155 0.0,
156 -0.0,
157 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,
158 1e1000,
159 -5e-324,
160 1e+100,
161 1.7976931348623157e+308,
162 9007199254740990,
163 9007199254740991,
164 9007199254740992,
165 9007199254740993,
166 9007199254740994,
167 -9223372036854775808,
168 9223372036854775807,
169 0,
170 18446744073709551615
171 ]`,
172 outCanonicalized: `[0,0,0,0,1,1.7976931348623157e+308,-5e-324,1e+100,1.7976931348623157e+308,9007199254740990,9007199254740991,9007199254740992,9007199254740992,9007199254740994,-9223372036854776000,9223372036854776000,0,18446744073709552000]`,
173 tokens: []Token{
174 BeginArray,
175 Float(0), Float(math.Copysign(0, -1)), rawToken(`0.0`), rawToken(`-0.0`), rawToken(`1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001`), rawToken(`1e1000`),
176 Float(-5e-324), Float(1e100), Float(1.7976931348623157e+308),
177 Float(9007199254740990), Float(9007199254740991), Float(9007199254740992), rawToken(`9007199254740993`), rawToken(`9007199254740994`),
178 Int(minInt64), Int(maxInt64), Uint(minUint64), Uint(maxUint64),
179 EndArray,
180 },
181 pointers: []Pointer{
182 "", "/0", "/1", "/2", "/3", "/4", "/5", "/6", "/7", "/8", "/9", "/10", "/11", "/12", "/13", "/14", "/15", "/16", "/17", "",
183 },
184 }, {
185 name: jsontest.Name("ObjectN0"),
186 in: ` { } `,
187 outCompacted: `{}`,
188 tokens: []Token{BeginObject, EndObject},
189 pointers: []Pointer{"", ""},
190 }, {
191 name: jsontest.Name("ObjectN1"),
192 in: ` { "0" : 0 } `,
193 outCompacted: `{"0":0}`,
194 outEscaped: `{"\u0030":0}`,
195 outIndented: `{
196 "0": 0
197 }`,
198 tokens: []Token{BeginObject, String("0"), Uint(0), EndObject},
199 pointers: []Pointer{"", "/0", "/0", ""},
200 }, {
201 name: jsontest.Name("ObjectN2"),
202 in: ` { "0" : 0 , "1" : 1 } `,
203 outCompacted: `{"0":0,"1":1}`,
204 outEscaped: `{"\u0030":0,"\u0031":1}`,
205 outIndented: `{
206 "0": 0,
207 "1": 1
208 }`,
209 tokens: []Token{BeginObject, String("0"), Uint(0), String("1"), Uint(1), EndObject},
210 pointers: []Pointer{"", "/0", "/0", "/1", "/1", ""},
211 }, {
212 name: jsontest.Name("ObjectNested"),
213 in: ` { "0" : { "1" : { "2" : { "3" : { "4" : { } } } } } } `,
214 outCompacted: `{"0":{"1":{"2":{"3":{"4":{}}}}}}`,
215 outEscaped: `{"\u0030":{"\u0031":{"\u0032":{"\u0033":{"\u0034":{}}}}}}`,
216 outIndented: `{
217 "0": {
218 "1": {
219 "2": {
220 "3": {
221 "4": {}
222 }
223 }
224 }
225 }
226 }`,
227 tokens: []Token{BeginObject, String("0"), BeginObject, String("1"), BeginObject, String("2"), BeginObject, String("3"), BeginObject, String("4"), BeginObject, EndObject, EndObject, EndObject, EndObject, EndObject, EndObject},
228 pointers: []Pointer{
229 "",
230 "/0", "/0",
231 "/0/1", "/0/1",
232 "/0/1/2", "/0/1/2",
233 "/0/1/2/3", "/0/1/2/3",
234 "/0/1/2/3/4", "/0/1/2/3/4",
235 "/0/1/2/3/4",
236 "/0/1/2/3",
237 "/0/1/2",
238 "/0/1",
239 "/0",
240 "",
241 },
242 }, {
243 name: jsontest.Name("ObjectSuperNested"),
244 in: `{"": {
245 "44444": {
246 "6666666": "ccccccc",
247 "77777777": "bb",
248 "555555": "aaaa"
249 },
250 "0": {
251 "3333": "bbb",
252 "11": "",
253 "222": "aaaaa"
254 }
255 }}`,
256 outCompacted: `{"":{"44444":{"6666666":"ccccccc","77777777":"bb","555555":"aaaa"},"0":{"3333":"bbb","11":"","222":"aaaaa"}}}`,
257 outEscaped: `{"":{"\u0034\u0034\u0034\u0034\u0034":{"\u0036\u0036\u0036\u0036\u0036\u0036\u0036":"\u0063\u0063\u0063\u0063\u0063\u0063\u0063","\u0037\u0037\u0037\u0037\u0037\u0037\u0037\u0037":"\u0062\u0062","\u0035\u0035\u0035\u0035\u0035\u0035":"\u0061\u0061\u0061\u0061"},"\u0030":{"\u0033\u0033\u0033\u0033":"\u0062\u0062\u0062","\u0031\u0031":"","\u0032\u0032\u0032":"\u0061\u0061\u0061\u0061\u0061"}}}`,
258 outIndented: `{
259 "": {
260 "44444": {
261 "6666666": "ccccccc",
262 "77777777": "bb",
263 "555555": "aaaa"
264 },
265 "0": {
266 "3333": "bbb",
267 "11": "",
268 "222": "aaaaa"
269 }
270 }
271 }`,
272 outCanonicalized: `{"":{"0":{"11":"","222":"aaaaa","3333":"bbb"},"44444":{"555555":"aaaa","6666666":"ccccccc","77777777":"bb"}}}`,
273 tokens: []Token{
274 BeginObject,
275 String(""),
276 BeginObject,
277 String("44444"),
278 BeginObject,
279 String("6666666"), String("ccccccc"),
280 String("77777777"), String("bb"),
281 String("555555"), String("aaaa"),
282 EndObject,
283 String("0"),
284 BeginObject,
285 String("3333"), String("bbb"),
286 String("11"), String(""),
287 String("222"), String("aaaaa"),
288 EndObject,
289 EndObject,
290 EndObject,
291 },
292 pointers: []Pointer{
293 "",
294 "/", "/",
295 "//44444", "//44444",
296 "//44444/6666666", "//44444/6666666",
297 "//44444/77777777", "//44444/77777777",
298 "//44444/555555", "//44444/555555",
299 "//44444",
300 "//0", "//0",
301 "//0/3333", "//0/3333",
302 "//0/11", "//0/11",
303 "//0/222", "//0/222",
304 "//0",
305 "/",
306 "",
307 },
308 }, {
309 name: jsontest.Name("ArrayN0"),
310 in: ` [ ] `,
311 outCompacted: `[]`,
312 tokens: []Token{BeginArray, EndArray},
313 pointers: []Pointer{"", ""},
314 }, {
315 name: jsontest.Name("ArrayN1"),
316 in: ` [ 0 ] `,
317 outCompacted: `[0]`,
318 outIndented: `[
319 0
320 ]`,
321 tokens: []Token{BeginArray, Uint(0), EndArray},
322 pointers: []Pointer{"", "/0", ""},
323 }, {
324 name: jsontest.Name("ArrayN2"),
325 in: ` [ 0 , 1 ] `,
326 outCompacted: `[0,1]`,
327 outIndented: `[
328 0,
329 1
330 ]`,
331 tokens: []Token{BeginArray, Uint(0), Uint(1), EndArray},
332 }, {
333 name: jsontest.Name("ArrayNested"),
334 in: ` [ [ [ [ [ ] ] ] ] ] `,
335 outCompacted: `[[[[[]]]]]`,
336 outIndented: `[
337 [
338 [
339 [
340 []
341 ]
342 ]
343 ]
344 ]`,
345 tokens: []Token{BeginArray, BeginArray, BeginArray, BeginArray, BeginArray, EndArray, EndArray, EndArray, EndArray, EndArray},
346 pointers: []Pointer{
347 "",
348 "/0",
349 "/0/0",
350 "/0/0/0",
351 "/0/0/0/0",
352 "/0/0/0/0",
353 "/0/0/0",
354 "/0/0",
355 "/0",
356 "",
357 },
358 }, {
359 name: jsontest.Name("Everything"),
360 in: ` {
361 "literals" : [ null , false , true ],
362 "string" : "Hello, δΈη" ,
363 "number" : 3.14159 ,
364 "arrayN0" : [ ] ,
365 "arrayN1" : [ 0 ] ,
366 "arrayN2" : [ 0 , 1 ] ,
367 "objectN0" : { } ,
368 "objectN1" : { "0" : 0 } ,
369 "objectN2" : { "0" : 0 , "1" : 1 }
370 } `,
371 outCompacted: `{"literals":[null,false,true],"string":"Hello, δΈη","number":3.14159,"arrayN0":[],"arrayN1":[0],"arrayN2":[0,1],"objectN0":{},"objectN1":{"0":0},"objectN2":{"0":0,"1":1}}`,
372 outEscaped: `{"\u006c\u0069\u0074\u0065\u0072\u0061\u006c\u0073":[null,false,true],"\u0073\u0074\u0072\u0069\u006e\u0067":"\u0048\u0065\u006c\u006c\u006f\u002c\u0020\u4e16\u754c","\u006e\u0075\u006d\u0062\u0065\u0072":3.14159,"\u0061\u0072\u0072\u0061\u0079\u004e\u0030":[],"\u0061\u0072\u0072\u0061\u0079\u004e\u0031":[0],"\u0061\u0072\u0072\u0061\u0079\u004e\u0032":[0,1],"\u006f\u0062\u006a\u0065\u0063\u0074\u004e\u0030":{},"\u006f\u0062\u006a\u0065\u0063\u0074\u004e\u0031":{"\u0030":0},"\u006f\u0062\u006a\u0065\u0063\u0074\u004e\u0032":{"\u0030":0,"\u0031":1}}`,
373 outIndented: `{
374 "literals": [
375 null,
376 false,
377 true
378 ],
379 "string": "Hello, δΈη",
380 "number": 3.14159,
381 "arrayN0": [],
382 "arrayN1": [
383 0
384 ],
385 "arrayN2": [
386 0,
387 1
388 ],
389 "objectN0": {},
390 "objectN1": {
391 "0": 0
392 },
393 "objectN2": {
394 "0": 0,
395 "1": 1
396 }
397 }`,
398 outCanonicalized: `{"arrayN0":[],"arrayN1":[0],"arrayN2":[0,1],"literals":[null,false,true],"number":3.14159,"objectN0":{},"objectN1":{"0":0},"objectN2":{"0":0,"1":1},"string":"Hello, δΈη"}`,
399 tokens: []Token{
400 BeginObject,
401 String("literals"), BeginArray, Null, False, True, EndArray,
402 String("string"), String("Hello, δΈη"),
403 String("number"), Float(3.14159),
404 String("arrayN0"), BeginArray, EndArray,
405 String("arrayN1"), BeginArray, Uint(0), EndArray,
406 String("arrayN2"), BeginArray, Uint(0), Uint(1), EndArray,
407 String("objectN0"), BeginObject, EndObject,
408 String("objectN1"), BeginObject, String("0"), Uint(0), EndObject,
409 String("objectN2"), BeginObject, String("0"), Uint(0), String("1"), Uint(1), EndObject,
410 EndObject,
411 },
412 pointers: []Pointer{
413 "",
414 "/literals", "/literals",
415 "/literals/0",
416 "/literals/1",
417 "/literals/2",
418 "/literals",
419 "/string", "/string",
420 "/number", "/number",
421 "/arrayN0", "/arrayN0", "/arrayN0",
422 "/arrayN1", "/arrayN1",
423 "/arrayN1/0",
424 "/arrayN1",
425 "/arrayN2", "/arrayN2",
426 "/arrayN2/0",
427 "/arrayN2/1",
428 "/arrayN2",
429 "/objectN0", "/objectN0", "/objectN0",
430 "/objectN1", "/objectN1",
431 "/objectN1/0", "/objectN1/0",
432 "/objectN1",
433 "/objectN2", "/objectN2",
434 "/objectN2/0", "/objectN2/0",
435 "/objectN2/1", "/objectN2/1",
436 "/objectN2",
437 "",
438 },
439 }}
440
441
442
443
444 func TestCoderInterleaved(t *testing.T) {
445 for _, td := range coderTestdata {
446
447
448 for _, modeName := range []string{"TokenFirst", "ValueFirst", "TokenDelims"} {
449 t.Run(path.Join(td.name.Name, modeName), func(t *testing.T) {
450 testCoderInterleaved(t, td.name.Where, modeName, td)
451 })
452 }
453 }
454 }
455 func testCoderInterleaved(t *testing.T, where jsontest.CasePos, modeName string, td coderTestdataEntry) {
456 src := strings.NewReader(td.in)
457 dst := new(bytes.Buffer)
458 dec := NewDecoder(src)
459 enc := NewEncoder(dst)
460 tickTock := modeName == "TokenFirst"
461 for {
462 if modeName == "TokenDelims" {
463 switch dec.PeekKind() {
464 case '{', '}', '[', ']':
465 tickTock = true
466 default:
467 tickTock = false
468 }
469 }
470 if tickTock {
471 tok, err := dec.ReadToken()
472 if err != nil {
473 if err == io.EOF {
474 break
475 }
476 t.Fatalf("%s: Decoder.ReadToken error: %v", where, err)
477 }
478 if err := enc.WriteToken(tok); err != nil {
479 t.Fatalf("%s: Encoder.WriteToken error: %v", where, err)
480 }
481 } else {
482 val, err := dec.ReadValue()
483 if err != nil {
484
485
486
487 expectError := dec.PeekKind() == '}' || dec.PeekKind() == ']'
488 if expectError {
489 if !errors.As(err, new(*SyntacticError)) {
490 t.Fatalf("%s: Decoder.ReadToken error is %T, want %T", where, err, new(SyntacticError))
491 }
492 tickTock = !tickTock
493 continue
494 }
495
496 if err == io.EOF {
497 break
498 }
499 t.Fatalf("%s: Decoder.ReadValue error: %v", where, err)
500 }
501 if err := enc.WriteValue(val); err != nil {
502 t.Fatalf("%s: Encoder.WriteValue error: %v", where, err)
503 }
504 }
505 tickTock = !tickTock
506 }
507
508 got := dst.String()
509 want := td.outCompacted + "\n"
510 if got != want {
511 t.Fatalf("%s: output mismatch:\ngot %q\nwant %q", where, got, want)
512 }
513 }
514
515 func TestCoderStackPointer(t *testing.T) {
516 tests := []struct {
517 token Token
518 want Pointer
519 }{
520 {Null, ""},
521
522 {BeginArray, ""},
523 {EndArray, ""},
524
525 {BeginArray, ""},
526 {Bool(true), "/0"},
527 {EndArray, ""},
528
529 {BeginArray, ""},
530 {String("hello"), "/0"},
531 {String("goodbye"), "/1"},
532 {EndArray, ""},
533
534 {BeginObject, ""},
535 {EndObject, ""},
536
537 {BeginObject, ""},
538 {String("hello"), "/hello"},
539 {String("goodbye"), "/hello"},
540 {EndObject, ""},
541
542 {BeginObject, ""},
543 {String(""), "/"},
544 {Null, "/"},
545 {String("0"), "/0"},
546 {Null, "/0"},
547 {String("~"), "/~0"},
548 {Null, "/~0"},
549 {String("/"), "/~1"},
550 {Null, "/~1"},
551 {String("a//b~/c/~d~~e"), "/a~1~1b~0~1c~1~0d~0~0e"},
552 {Null, "/a~1~1b~0~1c~1~0d~0~0e"},
553 {String(" \r\n\t"), "/ \r\n\t"},
554 {Null, "/ \r\n\t"},
555 {EndObject, ""},
556
557 {BeginArray, ""},
558 {BeginObject, "/0"},
559 {String(""), "/0/"},
560 {BeginArray, "/0/"},
561 {BeginObject, "/0//0"},
562 {String("#"), "/0//0/#"},
563 {Null, "/0//0/#"},
564 {EndObject, "/0//0"},
565 {EndArray, "/0/"},
566 {EndObject, "/0"},
567 {EndArray, ""},
568 }
569
570 for _, allowDupes := range []bool{false, true} {
571 var name string
572 switch allowDupes {
573 case false:
574 name = "RejectDuplicateNames"
575 case true:
576 name = "AllowDuplicateNames"
577 }
578
579 t.Run(name, func(t *testing.T) {
580 bb := new(bytes.Buffer)
581
582 enc := NewEncoder(bb, AllowDuplicateNames(allowDupes))
583 for i, tt := range tests {
584 if err := enc.WriteToken(tt.token); err != nil {
585 t.Fatalf("%d: Encoder.WriteToken error: %v", i, err)
586 }
587 if got := enc.StackPointer(); got != tests[i].want {
588 t.Fatalf("%d: Encoder.StackPointer = %v, want %v", i, got, tests[i].want)
589 }
590 }
591
592 dec := NewDecoder(bb, AllowDuplicateNames(allowDupes))
593 for i := range tests {
594 if _, err := dec.ReadToken(); err != nil {
595 t.Fatalf("%d: Decoder.ReadToken error: %v", i, err)
596 }
597 if got := dec.StackPointer(); got != tests[i].want {
598 t.Fatalf("%d: Decoder.StackPointer = %v, want %v", i, got, tests[i].want)
599 }
600 }
601 })
602 }
603 }
604
605 func TestCoderMaxDepth(t *testing.T) {
606 trimArray := func(b []byte) []byte { return b[len(`[`) : len(b)-len(`]`)] }
607 maxArrays := []byte(strings.Repeat(`[`, maxNestingDepth+1) + strings.Repeat(`]`, maxNestingDepth+1))
608 trimObject := func(b []byte) []byte { return b[len(`{"":`) : len(b)-len(`}`)] }
609 maxObjects := []byte(strings.Repeat(`{"":`, maxNestingDepth+1) + `""` + strings.Repeat(`}`, maxNestingDepth+1))
610
611 t.Run("Decoder", func(t *testing.T) {
612 var dec Decoder
613 checkReadToken := func(t *testing.T, wantKind Kind, wantErr error) {
614 t.Helper()
615 if tok, err := dec.ReadToken(); tok.Kind() != wantKind || !equalError(err, wantErr) {
616 t.Fatalf("Decoder.ReadToken = (%q, %v), want (%q, %v)", byte(tok.Kind()), err, byte(wantKind), wantErr)
617 }
618 }
619 checkReadValue := func(t *testing.T, wantLen int, wantErr error) {
620 t.Helper()
621 if val, err := dec.ReadValue(); len(val) != wantLen || !equalError(err, wantErr) {
622 t.Fatalf("Decoder.ReadValue = (%d, %v), want (%d, %v)", len(val), err, wantLen, wantErr)
623 }
624 }
625
626 t.Run("ArraysValid/SingleValue", func(t *testing.T) {
627 dec.s.reset(trimArray(maxArrays), nil)
628 checkReadValue(t, maxNestingDepth*len(`[]`), nil)
629 })
630 t.Run("ArraysValid/TokenThenValue", func(t *testing.T) {
631 dec.s.reset(trimArray(maxArrays), nil)
632 checkReadToken(t, '[', nil)
633 checkReadValue(t, (maxNestingDepth-1)*len(`[]`), nil)
634 checkReadToken(t, ']', nil)
635 })
636 t.Run("ArraysValid/AllTokens", func(t *testing.T) {
637 dec.s.reset(trimArray(maxArrays), nil)
638 for range maxNestingDepth {
639 checkReadToken(t, '[', nil)
640 }
641 for range maxNestingDepth {
642 checkReadToken(t, ']', nil)
643 }
644 })
645
646 wantErr := &SyntacticError{
647 ByteOffset: maxNestingDepth,
648 JSONPointer: Pointer(strings.Repeat("/0", maxNestingDepth)),
649 Err: errMaxDepth,
650 }
651 t.Run("ArraysInvalid/SingleValue", func(t *testing.T) {
652 dec.s.reset(maxArrays, nil)
653 checkReadValue(t, 0, wantErr)
654 })
655 t.Run("ArraysInvalid/TokenThenValue", func(t *testing.T) {
656 dec.s.reset(maxArrays, nil)
657 checkReadToken(t, '[', nil)
658 checkReadValue(t, 0, wantErr)
659 })
660 t.Run("ArraysInvalid/AllTokens", func(t *testing.T) {
661 dec.s.reset(maxArrays, nil)
662 for range maxNestingDepth {
663 checkReadToken(t, '[', nil)
664 }
665 checkReadValue(t, 0, wantErr)
666 })
667
668 t.Run("ObjectsValid/SingleValue", func(t *testing.T) {
669 dec.s.reset(trimObject(maxObjects), nil)
670 checkReadValue(t, maxNestingDepth*len(`{"":}`)+len(`""`), nil)
671 })
672 t.Run("ObjectsValid/TokenThenValue", func(t *testing.T) {
673 dec.s.reset(trimObject(maxObjects), nil)
674 checkReadToken(t, '{', nil)
675 checkReadToken(t, '"', nil)
676 checkReadValue(t, (maxNestingDepth-1)*len(`{"":}`)+len(`""`), nil)
677 checkReadToken(t, '}', nil)
678 })
679 t.Run("ObjectsValid/AllTokens", func(t *testing.T) {
680 dec.s.reset(trimObject(maxObjects), nil)
681 for range maxNestingDepth {
682 checkReadToken(t, '{', nil)
683 checkReadToken(t, '"', nil)
684 }
685 checkReadToken(t, '"', nil)
686 for range maxNestingDepth {
687 checkReadToken(t, '}', nil)
688 }
689 })
690
691 wantErr = &SyntacticError{
692 ByteOffset: maxNestingDepth * int64(len(`{"":`)),
693 JSONPointer: Pointer(strings.Repeat("/", maxNestingDepth)),
694 Err: errMaxDepth,
695 }
696 t.Run("ObjectsInvalid/SingleValue", func(t *testing.T) {
697 dec.s.reset(maxObjects, nil)
698 checkReadValue(t, 0, wantErr)
699 })
700 t.Run("ObjectsInvalid/TokenThenValue", func(t *testing.T) {
701 dec.s.reset(maxObjects, nil)
702 checkReadToken(t, '{', nil)
703 checkReadToken(t, '"', nil)
704 checkReadValue(t, 0, wantErr)
705 })
706 t.Run("ObjectsInvalid/AllTokens", func(t *testing.T) {
707 dec.s.reset(maxObjects, nil)
708 for range maxNestingDepth {
709 checkReadToken(t, '{', nil)
710 checkReadToken(t, '"', nil)
711 }
712 checkReadToken(t, 0, wantErr)
713 })
714 })
715
716 t.Run("Encoder", func(t *testing.T) {
717 var enc Encoder
718 checkWriteToken := func(t *testing.T, tok Token, wantErr error) {
719 t.Helper()
720 if err := enc.WriteToken(tok); !equalError(err, wantErr) {
721 t.Fatalf("Encoder.WriteToken = %v, want %v", err, wantErr)
722 }
723 }
724 checkWriteValue := func(t *testing.T, val Value, wantErr error) {
725 t.Helper()
726 if err := enc.WriteValue(val); !equalError(err, wantErr) {
727 t.Fatalf("Encoder.WriteValue = %v, want %v", err, wantErr)
728 }
729 }
730
731 wantErr := &SyntacticError{
732 ByteOffset: maxNestingDepth,
733 JSONPointer: Pointer(strings.Repeat("/0", maxNestingDepth)),
734 Err: errMaxDepth,
735 }
736 t.Run("Arrays/SingleValue", func(t *testing.T) {
737 enc.s.reset(enc.s.Buf[:0], nil)
738 checkWriteValue(t, maxArrays, wantErr)
739 checkWriteValue(t, trimArray(maxArrays), nil)
740 })
741 t.Run("Arrays/TokenThenValue", func(t *testing.T) {
742 enc.s.reset(enc.s.Buf[:0], nil)
743 checkWriteToken(t, BeginArray, nil)
744 checkWriteValue(t, trimArray(maxArrays), wantErr)
745 checkWriteValue(t, trimArray(trimArray(maxArrays)), nil)
746 checkWriteToken(t, EndArray, nil)
747 })
748 t.Run("Arrays/AllTokens", func(t *testing.T) {
749 enc.s.reset(enc.s.Buf[:0], nil)
750 for range maxNestingDepth {
751 checkWriteToken(t, BeginArray, nil)
752 }
753 checkWriteToken(t, BeginArray, wantErr)
754 for range maxNestingDepth {
755 checkWriteToken(t, EndArray, nil)
756 }
757 })
758
759 wantErr = &SyntacticError{
760 ByteOffset: maxNestingDepth * int64(len(`{"":`)),
761 JSONPointer: Pointer(strings.Repeat("/", maxNestingDepth)),
762 Err: errMaxDepth,
763 }
764 t.Run("Objects/SingleValue", func(t *testing.T) {
765 enc.s.reset(enc.s.Buf[:0], nil)
766 checkWriteValue(t, maxObjects, wantErr)
767 checkWriteValue(t, trimObject(maxObjects), nil)
768 })
769 t.Run("Objects/TokenThenValue", func(t *testing.T) {
770 enc.s.reset(enc.s.Buf[:0], nil)
771 checkWriteToken(t, BeginObject, nil)
772 checkWriteToken(t, String(""), nil)
773 checkWriteValue(t, trimObject(maxObjects), wantErr)
774 checkWriteValue(t, trimObject(trimObject(maxObjects)), nil)
775 checkWriteToken(t, EndObject, nil)
776 })
777 t.Run("Objects/AllTokens", func(t *testing.T) {
778 enc.s.reset(enc.s.Buf[:0], nil)
779 for range maxNestingDepth - 1 {
780 checkWriteToken(t, BeginObject, nil)
781 checkWriteToken(t, String(""), nil)
782 }
783 checkWriteToken(t, BeginObject, nil)
784 checkWriteToken(t, String(""), nil)
785 checkWriteToken(t, BeginObject, wantErr)
786 checkWriteToken(t, String(""), nil)
787 for range maxNestingDepth {
788 checkWriteToken(t, EndObject, nil)
789 }
790 })
791 })
792 }
793
794
795
796
797 type FaultyBuffer struct {
798 B []byte
799
800
801
802
803 MaxBytes int
804
805
806
807 MayError error
808
809
810
811 Rand rand.Source
812 }
813
814 func (p *FaultyBuffer) Read(b []byte) (int, error) {
815 b = b[:copy(b[:p.mayTruncate(len(b))], p.B)]
816 p.B = p.B[len(b):]
817 if len(p.B) == 0 && (len(b) == 0 || p.randN(2) == 0) {
818 return len(b), io.EOF
819 }
820 return len(b), p.mayError()
821 }
822
823 func (p *FaultyBuffer) Write(b []byte) (int, error) {
824 b2 := b[:p.mayTruncate(len(b))]
825 p.B = append(p.B, b2...)
826 if len(b2) < len(b) {
827 return len(b2), io.ErrShortWrite
828 }
829 return len(b2), p.mayError()
830 }
831
832
833 func (p *FaultyBuffer) mayTruncate(n int) int {
834 if p.MaxBytes > 0 {
835 if n > p.MaxBytes {
836 n = p.MaxBytes
837 }
838 return p.randN(n + 1)
839 }
840 return n
841 }
842
843
844 func (p *FaultyBuffer) mayError() error {
845 if p.MayError != nil && p.randN(2) == 0 {
846 return p.MayError
847 }
848 return nil
849 }
850
851 func (p *FaultyBuffer) randN(n int) int {
852 if p.Rand == nil {
853 p.Rand = rand.NewSource(0)
854 }
855 return int(p.Rand.Int63() % int64(n))
856 }
857
View as plain text