1
2
3
4
5 package json
6
7 import (
8 "bytes"
9 "errors"
10 "fmt"
11 "io"
12 "math"
13 "net"
14 "path"
15 "reflect"
16 "strings"
17 "testing"
18 "testing/iotest"
19 )
20
21
22 func equalTokens(xs, ys []Token) bool {
23 if len(xs) != len(ys) {
24 return false
25 }
26 for i := range xs {
27 if !(reflect.DeepEqual(xs[i], ys[i]) || xs[i].String() == ys[i].String()) {
28 return false
29 }
30 }
31 return true
32 }
33
34
35 func TestDecoder(t *testing.T) {
36 for _, td := range coderTestdata {
37 for _, typeName := range []string{"Token", "Value", "TokenDelims"} {
38 t.Run(path.Join(td.name.name, typeName), func(t *testing.T) {
39 testDecoder(t, td.name.where, typeName, td)
40 })
41 }
42 }
43 }
44 func testDecoder(t *testing.T, where pc, typeName string, td coderTestdataEntry) {
45 dec := NewDecoder(bytes.NewBufferString(td.in))
46 switch typeName {
47 case "Token":
48 var tokens []Token
49 var pointers []string
50 for {
51 tok, err := dec.ReadToken()
52 if err != nil {
53 if err == io.EOF {
54 break
55 }
56 t.Fatalf("%s: Decoder.ReadToken error: %v", where, err)
57 }
58 tokens = append(tokens, tok.Clone())
59 if td.pointers != nil {
60 pointers = append(pointers, dec.StackPointer())
61 }
62 }
63 if !equalTokens(tokens, td.tokens) {
64 t.Fatalf("%s: tokens mismatch:\ngot %v\nwant %v", where, tokens, td.tokens)
65 }
66 if !reflect.DeepEqual(pointers, td.pointers) {
67 t.Fatalf("%s: pointers mismatch:\ngot %q\nwant %q", where, pointers, td.pointers)
68 }
69 case "Value":
70 val, err := dec.ReadValue()
71 if err != nil {
72 t.Fatalf("%s: Decoder.ReadValue error: %v", where, err)
73 }
74 got := string(val)
75 want := strings.TrimSpace(td.in)
76 if got != want {
77 t.Fatalf("%s: Decoder.ReadValue = %s, want %s", where, got, want)
78 }
79 case "TokenDelims":
80
81 var tokens []Token
82 loop:
83 for {
84 switch dec.PeekKind() {
85 case '{', '}', '[', ']':
86 tok, err := dec.ReadToken()
87 if err != nil {
88 if err == io.EOF {
89 break loop
90 }
91 t.Fatalf("%s: Decoder.ReadToken error: %v", where, err)
92 }
93 tokens = append(tokens, tok.Clone())
94 default:
95 val, err := dec.ReadValue()
96 if err != nil {
97 if err == io.EOF {
98 break loop
99 }
100 t.Fatalf("%s: Decoder.ReadValue error: %v", where, err)
101 }
102 tokens = append(tokens, rawToken(string(val)))
103 }
104 }
105 if !equalTokens(tokens, td.tokens) {
106 t.Fatalf("%s: tokens mismatch:\ngot %v\nwant %v", where, tokens, td.tokens)
107 }
108 }
109 }
110
111
112 func TestFaultyDecoder(t *testing.T) {
113 for _, td := range coderTestdata {
114 for _, typeName := range []string{"Token", "Value"} {
115 t.Run(path.Join(td.name.name, typeName), func(t *testing.T) {
116 testFaultyDecoder(t, td.name.where, typeName, td)
117 })
118 }
119 }
120 }
121 func testFaultyDecoder(t *testing.T, where pc, typeName string, td coderTestdataEntry) {
122 b := &FaultyBuffer{
123 B: []byte(td.in),
124 MaxBytes: 1,
125 MayError: io.ErrNoProgress,
126 }
127
128
129
130
131
132 dec := NewDecoder(b)
133 switch typeName {
134 case "Token":
135 var tokens []Token
136 for {
137 tok, err := dec.ReadToken()
138 if err != nil {
139 if err == io.EOF {
140 break
141 }
142 if !errors.Is(err, io.ErrNoProgress) {
143 t.Fatalf("%s: %d: Decoder.ReadToken error: %v", where, len(tokens), err)
144 }
145 continue
146 }
147 tokens = append(tokens, tok.Clone())
148 }
149 if !equalTokens(tokens, td.tokens) {
150 t.Fatalf("%s: tokens mismatch:\ngot %s\nwant %s", where, tokens, td.tokens)
151 }
152 case "Value":
153 for {
154 val, err := dec.ReadValue()
155 if err != nil {
156 if err == io.EOF {
157 break
158 }
159 if !errors.Is(err, io.ErrNoProgress) {
160 t.Fatalf("%s: Decoder.ReadValue error: %v", where, err)
161 }
162 continue
163 }
164 got := string(val)
165 want := strings.TrimSpace(td.in)
166 if got != want {
167 t.Fatalf("%s: Decoder.ReadValue = %s, want %s", where, got, want)
168 }
169 }
170 }
171 }
172
173 type decoderMethodCall struct {
174 wantKind Kind
175 wantOut tokOrVal
176 wantErr error
177 wantPointer string
178 }
179
180 var decoderErrorTestdata = []struct {
181 name testName
182 opts DecodeOptions
183 in string
184 calls []decoderMethodCall
185 wantOffset int
186 }{{
187 name: name("InvalidStart"),
188 in: ` #`,
189 calls: []decoderMethodCall{
190 {'#', zeroToken, newInvalidCharacterError([]byte("#"), "at start of token").withOffset(int64(len(" "))), ""},
191 {'#', zeroValue, newInvalidCharacterError([]byte("#"), "at start of value").withOffset(int64(len(" "))), ""},
192 },
193 }, {
194 name: name("StreamN0"),
195 in: ` `,
196 calls: []decoderMethodCall{
197 {0, zeroToken, io.EOF, ""},
198 {0, zeroValue, io.EOF, ""},
199 },
200 }, {
201 name: name("StreamN1"),
202 in: ` null `,
203 calls: []decoderMethodCall{
204 {'n', Null, nil, ""},
205 {0, zeroToken, io.EOF, ""},
206 {0, zeroValue, io.EOF, ""},
207 },
208 wantOffset: len(` null`),
209 }, {
210 name: name("StreamN2"),
211 in: ` nullnull `,
212 calls: []decoderMethodCall{
213 {'n', Null, nil, ""},
214 {'n', Null, nil, ""},
215 {0, zeroToken, io.EOF, ""},
216 {0, zeroValue, io.EOF, ""},
217 },
218 wantOffset: len(` nullnull`),
219 }, {
220 name: name("StreamN2/ExtraComma"),
221 in: ` null , null `,
222 calls: []decoderMethodCall{
223 {'n', Null, nil, ""},
224 {0, zeroToken, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` null `))), ""},
225 {0, zeroValue, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` null `))), ""},
226 },
227 wantOffset: len(` null`),
228 }, {
229 name: name("TruncatedNull"),
230 in: `nul`,
231 calls: []decoderMethodCall{
232 {'n', zeroToken, io.ErrUnexpectedEOF, ""},
233 {'n', zeroValue, io.ErrUnexpectedEOF, ""},
234 },
235 }, {
236 name: name("InvalidNull"),
237 in: `nulL`,
238 calls: []decoderMethodCall{
239 {'n', zeroToken, newInvalidCharacterError([]byte("L"), `within literal null (expecting 'l')`).withOffset(int64(len(`nul`))), ""},
240 {'n', zeroValue, newInvalidCharacterError([]byte("L"), `within literal null (expecting 'l')`).withOffset(int64(len(`nul`))), ""},
241 },
242 }, {
243 name: name("TruncatedFalse"),
244 in: `fals`,
245 calls: []decoderMethodCall{
246 {'f', zeroToken, io.ErrUnexpectedEOF, ""},
247 {'f', zeroValue, io.ErrUnexpectedEOF, ""},
248 },
249 }, {
250 name: name("InvalidFalse"),
251 in: `falsE`,
252 calls: []decoderMethodCall{
253 {'f', zeroToken, newInvalidCharacterError([]byte("E"), `within literal false (expecting 'e')`).withOffset(int64(len(`fals`))), ""},
254 {'f', zeroValue, newInvalidCharacterError([]byte("E"), `within literal false (expecting 'e')`).withOffset(int64(len(`fals`))), ""},
255 },
256 }, {
257 name: name("TruncatedTrue"),
258 in: `tru`,
259 calls: []decoderMethodCall{
260 {'t', zeroToken, io.ErrUnexpectedEOF, ""},
261 {'t', zeroValue, io.ErrUnexpectedEOF, ""},
262 },
263 }, {
264 name: name("InvalidTrue"),
265 in: `truE`,
266 calls: []decoderMethodCall{
267 {'t', zeroToken, newInvalidCharacterError([]byte("E"), `within literal true (expecting 'e')`).withOffset(int64(len(`tru`))), ""},
268 {'t', zeroValue, newInvalidCharacterError([]byte("E"), `within literal true (expecting 'e')`).withOffset(int64(len(`tru`))), ""},
269 },
270 }, {
271 name: name("TruncatedString"),
272 in: `"start`,
273 calls: []decoderMethodCall{
274 {'"', zeroToken, io.ErrUnexpectedEOF, ""},
275 {'"', zeroValue, io.ErrUnexpectedEOF, ""},
276 },
277 }, {
278 name: name("InvalidString"),
279 in: `"ok` + "\x00",
280 calls: []decoderMethodCall{
281 {'"', zeroToken, newInvalidCharacterError([]byte("\x00"), `within string (expecting non-control character)`).withOffset(int64(len(`"ok`))), ""},
282 {'"', zeroValue, newInvalidCharacterError([]byte("\x00"), `within string (expecting non-control character)`).withOffset(int64(len(`"ok`))), ""},
283 },
284 }, {
285 name: name("ValidString/AllowInvalidUTF8/Token"),
286 opts: DecodeOptions{AllowInvalidUTF8: true},
287 in: "\"living\xde\xad\xbe\xef\"",
288 calls: []decoderMethodCall{
289 {'"', rawToken("\"living\xde\xad\xbe\xef\""), nil, ""},
290 },
291 wantOffset: len("\"living\xde\xad\xbe\xef\""),
292 }, {
293 name: name("ValidString/AllowInvalidUTF8/Value"),
294 opts: DecodeOptions{AllowInvalidUTF8: true},
295 in: "\"living\xde\xad\xbe\xef\"",
296 calls: []decoderMethodCall{
297 {'"', RawValue("\"living\xde\xad\xbe\xef\""), nil, ""},
298 },
299 wantOffset: len("\"living\xde\xad\xbe\xef\""),
300 }, {
301 name: name("InvalidString/RejectInvalidUTF8"),
302 opts: DecodeOptions{AllowInvalidUTF8: false},
303 in: "\"living\xde\xad\xbe\xef\"",
304 calls: []decoderMethodCall{
305 {'"', zeroToken, (&SyntacticError{str: "invalid UTF-8 within string"}).withOffset(int64(len("\"living\xde\xad"))), ""},
306 {'"', zeroValue, (&SyntacticError{str: "invalid UTF-8 within string"}).withOffset(int64(len("\"living\xde\xad"))), ""},
307 },
308 }, {
309 name: name("TruncatedNumber"),
310 in: `0.`,
311 calls: []decoderMethodCall{
312 {'0', zeroToken, io.ErrUnexpectedEOF, ""},
313 {'0', zeroValue, io.ErrUnexpectedEOF, ""},
314 },
315 }, {
316 name: name("InvalidNumber"),
317 in: `0.e`,
318 calls: []decoderMethodCall{
319 {'0', zeroToken, newInvalidCharacterError([]byte("e"), "within number (expecting digit)").withOffset(int64(len(`0.`))), ""},
320 {'0', zeroValue, newInvalidCharacterError([]byte("e"), "within number (expecting digit)").withOffset(int64(len(`0.`))), ""},
321 },
322 }, {
323 name: name("TruncatedObject/AfterStart"),
324 in: `{`,
325 calls: []decoderMethodCall{
326 {'{', zeroValue, io.ErrUnexpectedEOF, ""},
327 {'{', ObjectStart, nil, ""},
328 {0, zeroToken, io.ErrUnexpectedEOF, ""},
329 {0, zeroValue, io.ErrUnexpectedEOF, ""},
330 },
331 wantOffset: len(`{`),
332 }, {
333 name: name("TruncatedObject/AfterName"),
334 in: `{"0"`,
335 calls: []decoderMethodCall{
336 {'{', zeroValue, io.ErrUnexpectedEOF, ""},
337 {'{', ObjectStart, nil, ""},
338 {'"', String("0"), nil, ""},
339 {0, zeroToken, io.ErrUnexpectedEOF, ""},
340 {0, zeroValue, io.ErrUnexpectedEOF, ""},
341 },
342 wantOffset: len(`{"0"`),
343 }, {
344 name: name("TruncatedObject/AfterColon"),
345 in: `{"0":`,
346 calls: []decoderMethodCall{
347 {'{', zeroValue, io.ErrUnexpectedEOF, ""},
348 {'{', ObjectStart, nil, ""},
349 {'"', String("0"), nil, ""},
350 {0, zeroToken, io.ErrUnexpectedEOF, ""},
351 {0, zeroValue, io.ErrUnexpectedEOF, ""},
352 },
353 wantOffset: len(`{"0"`),
354 }, {
355 name: name("TruncatedObject/AfterValue"),
356 in: `{"0":0`,
357 calls: []decoderMethodCall{
358 {'{', zeroValue, io.ErrUnexpectedEOF, ""},
359 {'{', ObjectStart, nil, ""},
360 {'"', String("0"), nil, ""},
361 {'0', Uint(0), nil, ""},
362 {0, zeroToken, io.ErrUnexpectedEOF, ""},
363 {0, zeroValue, io.ErrUnexpectedEOF, ""},
364 },
365 wantOffset: len(`{"0":0`),
366 }, {
367 name: name("TruncatedObject/AfterComma"),
368 in: `{"0":0,`,
369 calls: []decoderMethodCall{
370 {'{', zeroValue, io.ErrUnexpectedEOF, ""},
371 {'{', ObjectStart, nil, ""},
372 {'"', String("0"), nil, ""},
373 {'0', Uint(0), nil, ""},
374 {0, zeroToken, io.ErrUnexpectedEOF, ""},
375 {0, zeroValue, io.ErrUnexpectedEOF, ""},
376 },
377 wantOffset: len(`{"0":0`),
378 }, {
379 name: name("InvalidObject/MissingColon"),
380 in: ` { "fizz" "buzz" } `,
381 calls: []decoderMethodCall{
382 {'{', zeroValue, newInvalidCharacterError([]byte("\""), "after object name (expecting ':')").withOffset(int64(len(` { "fizz" `))), ""},
383 {'{', ObjectStart, nil, ""},
384 {'"', String("fizz"), nil, ""},
385 {0, zeroToken, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""},
386 {0, zeroValue, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""},
387 },
388 wantOffset: len(` { "fizz"`),
389 }, {
390 name: name("InvalidObject/MissingColon/GotComma"),
391 in: ` { "fizz" , "buzz" } `,
392 calls: []decoderMethodCall{
393 {'{', zeroValue, newInvalidCharacterError([]byte(","), "after object name (expecting ':')").withOffset(int64(len(` { "fizz" `))), ""},
394 {'{', ObjectStart, nil, ""},
395 {'"', String("fizz"), nil, ""},
396 {0, zeroToken, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""},
397 {0, zeroValue, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""},
398 },
399 wantOffset: len(` { "fizz"`),
400 }, {
401 name: name("InvalidObject/MissingColon/GotHash"),
402 in: ` { "fizz" # "buzz" } `,
403 calls: []decoderMethodCall{
404 {'{', zeroValue, newInvalidCharacterError([]byte("#"), "after object name (expecting ':')").withOffset(int64(len(` { "fizz" `))), ""},
405 {'{', ObjectStart, nil, ""},
406 {'"', String("fizz"), nil, ""},
407 {0, zeroToken, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""},
408 {0, zeroValue, errMissingColon.withOffset(int64(len(` { "fizz" `))), ""},
409 },
410 wantOffset: len(` { "fizz"`),
411 }, {
412 name: name("InvalidObject/MissingComma"),
413 in: ` { "fizz" : "buzz" "gazz" } `,
414 calls: []decoderMethodCall{
415 {'{', zeroValue, newInvalidCharacterError([]byte("\""), "after object value (expecting ',' or '}')").withOffset(int64(len(` { "fizz" : "buzz" `))), ""},
416 {'{', ObjectStart, nil, ""},
417 {'"', String("fizz"), nil, ""},
418 {'"', String("buzz"), nil, ""},
419 {0, zeroToken, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""},
420 {0, zeroValue, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""},
421 },
422 wantOffset: len(` { "fizz" : "buzz"`),
423 }, {
424 name: name("InvalidObject/MissingComma/GotColon"),
425 in: ` { "fizz" : "buzz" : "gazz" } `,
426 calls: []decoderMethodCall{
427 {'{', zeroValue, newInvalidCharacterError([]byte(":"), "after object value (expecting ',' or '}')").withOffset(int64(len(` { "fizz" : "buzz" `))), ""},
428 {'{', ObjectStart, nil, ""},
429 {'"', String("fizz"), nil, ""},
430 {'"', String("buzz"), nil, ""},
431 {0, zeroToken, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""},
432 {0, zeroValue, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""},
433 },
434 wantOffset: len(` { "fizz" : "buzz"`),
435 }, {
436 name: name("InvalidObject/MissingComma/GotHash"),
437 in: ` { "fizz" : "buzz" # "gazz" } `,
438 calls: []decoderMethodCall{
439 {'{', zeroValue, newInvalidCharacterError([]byte("#"), "after object value (expecting ',' or '}')").withOffset(int64(len(` { "fizz" : "buzz" `))), ""},
440 {'{', ObjectStart, nil, ""},
441 {'"', String("fizz"), nil, ""},
442 {'"', String("buzz"), nil, ""},
443 {0, zeroToken, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""},
444 {0, zeroValue, errMissingComma.withOffset(int64(len(` { "fizz" : "buzz" `))), ""},
445 },
446 wantOffset: len(` { "fizz" : "buzz"`),
447 }, {
448 name: name("InvalidObject/ExtraComma/AfterStart"),
449 in: ` { , } `,
450 calls: []decoderMethodCall{
451 {'{', zeroValue, newInvalidCharacterError([]byte(","), `at start of string (expecting '"')`).withOffset(int64(len(` { `))), ""},
452 {'{', ObjectStart, nil, ""},
453 {0, zeroToken, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` { `))), ""},
454 {0, zeroValue, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` { `))), ""},
455 },
456 wantOffset: len(` {`),
457 }, {
458 name: name("InvalidObject/ExtraComma/AfterValue"),
459 in: ` { "fizz" : "buzz" , } `,
460 calls: []decoderMethodCall{
461 {'{', zeroValue, newInvalidCharacterError([]byte("}"), `at start of string (expecting '"')`).withOffset(int64(len(` { "fizz" : "buzz" , `))), ""},
462 {'{', ObjectStart, nil, ""},
463 {'"', String("fizz"), nil, ""},
464 {'"', String("buzz"), nil, ""},
465 {0, zeroToken, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` { "fizz" : "buzz" `))), ""},
466 {0, zeroValue, newInvalidCharacterError([]byte(","), `before next token`).withOffset(int64(len(` { "fizz" : "buzz" `))), ""},
467 },
468 wantOffset: len(` { "fizz" : "buzz"`),
469 }, {
470 name: name("InvalidObject/InvalidName/GotNull"),
471 in: ` { null : null } `,
472 calls: []decoderMethodCall{
473 {'{', zeroValue, newInvalidCharacterError([]byte("n"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""},
474 {'{', ObjectStart, nil, ""},
475 {'n', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""},
476 {'n', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""},
477 },
478 wantOffset: len(` {`),
479 }, {
480 name: name("InvalidObject/InvalidName/GotFalse"),
481 in: ` { false : false } `,
482 calls: []decoderMethodCall{
483 {'{', zeroValue, newInvalidCharacterError([]byte("f"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""},
484 {'{', ObjectStart, nil, ""},
485 {'f', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""},
486 {'f', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""},
487 },
488 wantOffset: len(` {`),
489 }, {
490 name: name("InvalidObject/InvalidName/GotTrue"),
491 in: ` { true : true } `,
492 calls: []decoderMethodCall{
493 {'{', zeroValue, newInvalidCharacterError([]byte("t"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""},
494 {'{', ObjectStart, nil, ""},
495 {'t', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""},
496 {'t', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""},
497 },
498 wantOffset: len(` {`),
499 }, {
500 name: name("InvalidObject/InvalidName/GotNumber"),
501 in: ` { 0 : 0 } `,
502 calls: []decoderMethodCall{
503 {'{', zeroValue, newInvalidCharacterError([]byte("0"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""},
504 {'{', ObjectStart, nil, ""},
505 {'0', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""},
506 {'0', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""},
507 },
508 wantOffset: len(` {`),
509 }, {
510 name: name("InvalidObject/InvalidName/GotObject"),
511 in: ` { {} : {} } `,
512 calls: []decoderMethodCall{
513 {'{', zeroValue, newInvalidCharacterError([]byte("{"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""},
514 {'{', ObjectStart, nil, ""},
515 {'{', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""},
516 {'{', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""},
517 },
518 wantOffset: len(` {`),
519 }, {
520 name: name("InvalidObject/InvalidName/GotArray"),
521 in: ` { [] : [] } `,
522 calls: []decoderMethodCall{
523 {'{', zeroValue, newInvalidCharacterError([]byte("["), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""},
524 {'{', ObjectStart, nil, ""},
525 {'[', zeroToken, errMissingName.withOffset(int64(len(` { `))), ""},
526 {'[', zeroValue, errMissingName.withOffset(int64(len(` { `))), ""},
527 },
528 wantOffset: len(` {`),
529 }, {
530 name: name("InvalidObject/MismatchingDelim"),
531 in: ` { ] `,
532 calls: []decoderMethodCall{
533 {'{', zeroValue, newInvalidCharacterError([]byte("]"), "at start of string (expecting '\"')").withOffset(int64(len(` { `))), ""},
534 {'{', ObjectStart, nil, ""},
535 {']', zeroToken, errMismatchDelim.withOffset(int64(len(` { `))), ""},
536 {']', zeroValue, newInvalidCharacterError([]byte("]"), "at start of value").withOffset(int64(len(` { `))), ""},
537 },
538 wantOffset: len(` {`),
539 }, {
540 name: name("ValidObject/InvalidValue"),
541 in: ` { } `,
542 calls: []decoderMethodCall{
543 {'{', ObjectStart, nil, ""},
544 {'}', zeroValue, newInvalidCharacterError([]byte("}"), "at start of value").withOffset(int64(len(" { "))), ""},
545 },
546 wantOffset: len(` {`),
547 }, {
548 name: name("ValidObject/UniqueNames"),
549 in: `{"0":0,"1":1} `,
550 calls: []decoderMethodCall{
551 {'{', ObjectStart, nil, ""},
552 {'"', String("0"), nil, ""},
553 {'0', Uint(0), nil, ""},
554 {'"', String("1"), nil, ""},
555 {'0', Uint(1), nil, ""},
556 {'}', ObjectEnd, nil, ""},
557 },
558 wantOffset: len(`{"0":0,"1":1}`),
559 }, {
560 name: name("ValidObject/DuplicateNames"),
561 opts: DecodeOptions{AllowDuplicateNames: true},
562 in: `{"0":0,"0":0} `,
563 calls: []decoderMethodCall{
564 {'{', ObjectStart, nil, ""},
565 {'"', String("0"), nil, ""},
566 {'0', Uint(0), nil, ""},
567 {'"', String("0"), nil, ""},
568 {'0', Uint(0), nil, ""},
569 {'}', ObjectEnd, nil, ""},
570 },
571 wantOffset: len(`{"0":0,"0":0}`),
572 }, {
573 name: name("InvalidObject/DuplicateNames"),
574 in: `{"0":{},"1":{},"0":{}} `,
575 calls: []decoderMethodCall{
576 {'{', zeroValue, (&SyntacticError{str: `duplicate name "0" in object`}).withOffset(int64(len(`{"0":{},"1":{},`))), ""},
577 {'{', ObjectStart, nil, ""},
578 {'"', String("0"), nil, ""},
579 {'{', ObjectStart, nil, ""},
580 {'}', ObjectEnd, nil, ""},
581 {'"', String("1"), nil, ""},
582 {'{', ObjectStart, nil, ""},
583 {'}', ObjectEnd, nil, ""},
584 {'"', zeroToken, (&SyntacticError{str: `duplicate name "0" in object`}).withOffset(int64(len(`{"0":{},"1":{},`))), "/1"},
585 {'"', zeroValue, (&SyntacticError{str: `duplicate name "0" in object`}).withOffset(int64(len(`{"0":{},"1":{},`))), "/1"},
586 },
587 wantOffset: len(`{"0":{},"1":{}`),
588 }, {
589 name: name("TruncatedArray/AfterStart"),
590 in: `[`,
591 calls: []decoderMethodCall{
592 {'[', zeroValue, io.ErrUnexpectedEOF, ""},
593 {'[', ArrayStart, nil, ""},
594 {0, zeroToken, io.ErrUnexpectedEOF, ""},
595 {0, zeroValue, io.ErrUnexpectedEOF, ""},
596 },
597 wantOffset: len(`[`),
598 }, {
599 name: name("TruncatedArray/AfterValue"),
600 in: `[0`,
601 calls: []decoderMethodCall{
602 {'[', zeroValue, io.ErrUnexpectedEOF, ""},
603 {'[', ArrayStart, nil, ""},
604 {'0', Uint(0), nil, ""},
605 {0, zeroToken, io.ErrUnexpectedEOF, ""},
606 {0, zeroValue, io.ErrUnexpectedEOF, ""},
607 },
608 wantOffset: len(`[0`),
609 }, {
610 name: name("TruncatedArray/AfterComma"),
611 in: `[0,`,
612 calls: []decoderMethodCall{
613 {'[', zeroValue, io.ErrUnexpectedEOF, ""},
614 {'[', ArrayStart, nil, ""},
615 {'0', Uint(0), nil, ""},
616 {0, zeroToken, io.ErrUnexpectedEOF, ""},
617 {0, zeroValue, io.ErrUnexpectedEOF, ""},
618 },
619 wantOffset: len(`[0`),
620 }, {
621 name: name("InvalidArray/MissingComma"),
622 in: ` [ "fizz" "buzz" ] `,
623 calls: []decoderMethodCall{
624 {'[', zeroValue, newInvalidCharacterError([]byte("\""), "after array value (expecting ',' or ']')").withOffset(int64(len(` [ "fizz" `))), ""},
625 {'[', ArrayStart, nil, ""},
626 {'"', String("fizz"), nil, ""},
627 {0, zeroToken, errMissingComma.withOffset(int64(len(` [ "fizz" `))), ""},
628 {0, zeroValue, errMissingComma.withOffset(int64(len(` [ "fizz" `))), ""},
629 },
630 wantOffset: len(` [ "fizz"`),
631 }, {
632 name: name("InvalidArray/MismatchingDelim"),
633 in: ` [ } `,
634 calls: []decoderMethodCall{
635 {'[', zeroValue, newInvalidCharacterError([]byte("}"), "at start of value").withOffset(int64(len(` [ `))), ""},
636 {'[', ArrayStart, nil, ""},
637 {'}', zeroToken, errMismatchDelim.withOffset(int64(len(` { `))), ""},
638 {'}', zeroValue, newInvalidCharacterError([]byte("}"), "at start of value").withOffset(int64(len(` [ `))), ""},
639 },
640 wantOffset: len(` [`),
641 }, {
642 name: name("ValidArray/InvalidValue"),
643 in: ` [ ] `,
644 calls: []decoderMethodCall{
645 {'[', ArrayStart, nil, ""},
646 {']', zeroValue, newInvalidCharacterError([]byte("]"), "at start of value").withOffset(int64(len(" [ "))), ""},
647 },
648 wantOffset: len(` [`),
649 }}
650
651
652
653 func TestDecoderErrors(t *testing.T) {
654 for _, td := range decoderErrorTestdata {
655 t.Run(path.Join(td.name.name), func(t *testing.T) {
656 testDecoderErrors(t, td.name.where, td.opts, td.in, td.calls, td.wantOffset)
657 })
658 }
659 }
660 func testDecoderErrors(t *testing.T, where pc, opts DecodeOptions, in string, calls []decoderMethodCall, wantOffset int) {
661 src := bytes.NewBufferString(in)
662 dec := opts.NewDecoder(src)
663 for i, call := range calls {
664 gotKind := dec.PeekKind()
665 if gotKind != call.wantKind {
666 t.Fatalf("%s: %d: Decoder.PeekKind = %v, want %v", where, i, gotKind, call.wantKind)
667 }
668
669 var gotErr error
670 switch wantOut := call.wantOut.(type) {
671 case Token:
672 var gotOut Token
673 gotOut, gotErr = dec.ReadToken()
674 if gotOut.String() != wantOut.String() {
675 t.Fatalf("%s: %d: Decoder.ReadToken = %v, want %v", where, i, gotOut, wantOut)
676 }
677 case RawValue:
678 var gotOut RawValue
679 gotOut, gotErr = dec.ReadValue()
680 if string(gotOut) != string(wantOut) {
681 t.Fatalf("%s: %d: Decoder.ReadValue = %s, want %s", where, i, gotOut, wantOut)
682 }
683 }
684 if !reflect.DeepEqual(gotErr, call.wantErr) {
685 t.Fatalf("%s: %d: error mismatch: got %#v, want %#v", where, i, gotErr, call.wantErr)
686 }
687 if call.wantPointer != "" {
688 gotPointer := dec.StackPointer()
689 if gotPointer != call.wantPointer {
690 t.Fatalf("%s: %d: Decoder.StackPointer = %s, want %s", where, i, gotPointer, call.wantPointer)
691 }
692 }
693 }
694 gotOffset := int(dec.InputOffset())
695 if gotOffset != wantOffset {
696 t.Fatalf("%s: Decoder.InputOffset = %v, want %v", where, gotOffset, wantOffset)
697 }
698 gotUnread := string(dec.unreadBuffer())
699 wantUnread := in[wantOffset:]
700 if !strings.HasPrefix(wantUnread, gotUnread) {
701 t.Fatalf("%s: Decoder.UnreadBuffer = %v, want %v", where, gotUnread, wantUnread)
702 }
703 }
704
705 var resumableDecoderTestdata = []string{
706 `0`,
707 `123456789`,
708 `0.0`,
709 `0.123456789`,
710 `0e0`,
711 `0e+0`,
712 `0e123456789`,
713 `0e+123456789`,
714 `123456789.123456789e+123456789`,
715 `-0`,
716 `-123456789`,
717 `-0.0`,
718 `-0.123456789`,
719 `-0e0`,
720 `-0e-0`,
721 `-0e123456789`,
722 `-0e-123456789`,
723 `-123456789.123456789e-123456789`,
724
725 `""`,
726 `"a"`,
727 `"ab"`,
728 `"abc"`,
729 `"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"`,
730 `"\"\\\/\b\f\n\r\t"`,
731 `"\u0022\u005c\u002f\u0008\u000c\u000a\u000d\u0009"`,
732 `"\ud800\udead"`,
733 "\"\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602\"",
734 `"\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\ud83d\ude02"`,
735 }
736
737
738 func TestBufferDecoder(t *testing.T) {
739 bb := bytes.NewBufferString("[null, false, true]")
740 dec := NewDecoder(bb)
741 var err error
742 for {
743 if _, err = dec.ReadToken(); err != nil {
744 break
745 }
746 bb.WriteByte(' ')
747 }
748 want := &ioError{action: "read", err: errBufferWriteAfterNext}
749 if !reflect.DeepEqual(err, want) {
750 t.Fatalf("error mismatch: got %v, want %v", err, want)
751 }
752 }
753
754
755
756 func TestResumableDecoder(t *testing.T) {
757 for _, want := range resumableDecoderTestdata {
758 t.Run("", func(t *testing.T) {
759 dec := NewDecoder(iotest.OneByteReader(strings.NewReader(want)))
760 got, err := dec.ReadValue()
761 if err != nil {
762 t.Fatalf("Decoder.ReadValue error: %v", err)
763 }
764 if string(got) != want {
765 t.Fatalf("Decoder.ReadValue = %s, want %s", got, want)
766 }
767 })
768 }
769 }
770
771
772
773
774
775 func TestBlockingDecoder(t *testing.T) {
776 values := []string{"null", "false", "true", `""`, `{}`, `[]`}
777
778 r, w := net.Pipe()
779 defer r.Close()
780 defer w.Close()
781
782 enc := NewEncoder(w)
783 enc.options.omitTopLevelNewline = true
784 dec := NewDecoder(r)
785
786 errCh := make(chan error)
787
788
789 for _, want := range values {
790 go func() {
791 errCh <- enc.WriteValue(RawValue(want))
792 }()
793
794 tok, err := dec.ReadToken()
795 if err != nil {
796 t.Fatalf("Decoder.ReadToken error: %v", err)
797 }
798 got := tok.String()
799 switch tok.Kind() {
800 case '"':
801 got = `"` + got + `"`
802 case '{', '[':
803 tok, err := dec.ReadToken()
804 if err != nil {
805 t.Fatalf("Decoder.ReadToken error: %v", err)
806 }
807 got += tok.String()
808 }
809 if got != want {
810 t.Fatalf("ReadTokens = %s, want %s", got, want)
811 }
812
813 if err := <-errCh; err != nil {
814 t.Fatalf("Encoder.WriteValue error: %v", err)
815 }
816 }
817
818
819 for _, want := range values {
820 go func() {
821 errCh <- enc.WriteValue(RawValue(want))
822 }()
823
824 got, err := dec.ReadValue()
825 if err != nil {
826 t.Fatalf("Decoder.ReadValue error: %v", err)
827 }
828 if string(got) != want {
829 t.Fatalf("ReadValue = %s, want %s", got, want)
830 }
831
832 if err := <-errCh; err != nil {
833 t.Fatalf("Encoder.WriteValue error: %v", err)
834 }
835 }
836 }
837
838 func TestPeekableDecoder(t *testing.T) {
839 type operation any
840 type PeekKind struct {
841 want Kind
842 }
843 type ReadToken struct {
844 wantKind Kind
845 wantErr error
846 }
847 type ReadValue struct {
848 wantKind Kind
849 wantErr error
850 }
851 type WriteString struct {
852 in string
853 }
854 ops := []operation{
855 PeekKind{0},
856 WriteString{"[ "},
857 ReadToken{0, io.EOF},
858 ReadToken{'[', nil},
859
860 PeekKind{0},
861 WriteString{"] "},
862 ReadValue{0, io.ErrUnexpectedEOF},
863 ReadValue{0, newInvalidCharacterError([]byte("]"), "at start of value").withOffset(2)},
864 ReadToken{']', nil},
865
866 WriteString{"[ "},
867 ReadToken{'[', nil},
868
869 WriteString{" null "},
870 PeekKind{'n'},
871 PeekKind{'n'},
872 ReadToken{'n', nil},
873
874 WriteString{", "},
875 PeekKind{0},
876 WriteString{"fal"},
877 PeekKind{'f'},
878 ReadValue{0, io.ErrUnexpectedEOF},
879 WriteString{"se "},
880 ReadValue{'f', nil},
881
882 PeekKind{0},
883 WriteString{" , "},
884 PeekKind{0},
885 WriteString{` "" `},
886 ReadValue{0, io.ErrUnexpectedEOF},
887 ReadValue{'"', nil},
888
889 WriteString{" , 0"},
890 PeekKind{'0'},
891 ReadToken{'0', nil},
892
893 WriteString{" , {} , []"},
894 PeekKind{'{'},
895 ReadValue{'{', nil},
896 ReadValue{'[', nil},
897
898 WriteString{"]"},
899 ReadToken{']', nil},
900 }
901
902 bb := struct{ *bytes.Buffer }{new(bytes.Buffer)}
903 d := NewDecoder(bb)
904 for i, op := range ops {
905 switch op := op.(type) {
906 case PeekKind:
907 if got := d.PeekKind(); got != op.want {
908 t.Fatalf("%d: Decoder.PeekKind() = %v, want %v", i, got, op.want)
909 }
910 case ReadToken:
911 gotTok, gotErr := d.ReadToken()
912 gotKind := gotTok.Kind()
913 if gotKind != op.wantKind || !reflect.DeepEqual(gotErr, op.wantErr) {
914 t.Fatalf("%d: Decoder.ReadToken() = (%v, %v), want (%v, %v)", i, gotKind, gotErr, op.wantKind, op.wantErr)
915 }
916 case ReadValue:
917 gotVal, gotErr := d.ReadValue()
918 gotKind := gotVal.Kind()
919 if gotKind != op.wantKind || !reflect.DeepEqual(gotErr, op.wantErr) {
920 t.Fatalf("%d: Decoder.ReadValue() = (%v, %v), want (%v, %v)", i, gotKind, gotErr, op.wantKind, op.wantErr)
921 }
922 case WriteString:
923 bb.WriteString(op.in)
924 default:
925 panic(fmt.Sprintf("unknown operation: %T", op))
926 }
927 }
928 }
929
930 func TestConsumeWhitespace(t *testing.T) {
931 tests := []struct {
932 in string
933 want int
934 }{
935 {"", 0},
936 {"a", 0},
937 {" a", 1},
938 {" a ", 1},
939 {" \n\r\ta", 4},
940 {" \n\r\t \n\r\t \n\r\t \n\r\t", 16},
941 {"\u00a0", 0},
942 }
943
944 for _, tt := range tests {
945 t.Run("", func(t *testing.T) {
946 if got := consumeWhitespace([]byte(tt.in)); got != tt.want {
947 t.Errorf("consumeWhitespace(%q) = %v, want %v", tt.in, got, tt.want)
948 }
949 })
950 }
951 }
952
953 func TestConsumeLiteral(t *testing.T) {
954 tests := []struct {
955 literal string
956 in string
957 want int
958 wantErr error
959 }{
960 {"null", "", 0, io.ErrUnexpectedEOF},
961 {"null", "n", 1, io.ErrUnexpectedEOF},
962 {"null", "nu", 2, io.ErrUnexpectedEOF},
963 {"null", "nul", 3, io.ErrUnexpectedEOF},
964 {"null", "null", 4, nil},
965 {"null", "nullx", 4, nil},
966 {"null", "x", 0, newInvalidCharacterError([]byte("x"), "within literal null (expecting 'n')")},
967 {"null", "nuxx", 2, newInvalidCharacterError([]byte("x"), "within literal null (expecting 'l')")},
968
969 {"false", "", 0, io.ErrUnexpectedEOF},
970 {"false", "f", 1, io.ErrUnexpectedEOF},
971 {"false", "fa", 2, io.ErrUnexpectedEOF},
972 {"false", "fal", 3, io.ErrUnexpectedEOF},
973 {"false", "fals", 4, io.ErrUnexpectedEOF},
974 {"false", "false", 5, nil},
975 {"false", "falsex", 5, nil},
976 {"false", "x", 0, newInvalidCharacterError([]byte("x"), "within literal false (expecting 'f')")},
977 {"false", "falsx", 4, newInvalidCharacterError([]byte("x"), "within literal false (expecting 'e')")},
978
979 {"true", "", 0, io.ErrUnexpectedEOF},
980 {"true", "t", 1, io.ErrUnexpectedEOF},
981 {"true", "tr", 2, io.ErrUnexpectedEOF},
982 {"true", "tru", 3, io.ErrUnexpectedEOF},
983 {"true", "true", 4, nil},
984 {"true", "truex", 4, nil},
985 {"true", "x", 0, newInvalidCharacterError([]byte("x"), "within literal true (expecting 't')")},
986 {"true", "trux", 3, newInvalidCharacterError([]byte("x"), "within literal true (expecting 'e')")},
987 }
988
989 for _, tt := range tests {
990 t.Run("", func(t *testing.T) {
991 var got int
992 switch tt.literal {
993 case "null":
994 got = consumeNull([]byte(tt.in))
995 case "false":
996 got = consumeFalse([]byte(tt.in))
997 case "true":
998 got = consumeTrue([]byte(tt.in))
999 default:
1000 t.Errorf("invalid literal: %v", tt.literal)
1001 }
1002 switch {
1003 case tt.wantErr == nil && got != tt.want:
1004 t.Errorf("consume%v(%q) = %v, want %v", strings.Title(tt.literal), tt.in, got, tt.want)
1005 case tt.wantErr != nil && got != 0:
1006 t.Errorf("consume%v(%q) = %v, want %v", strings.Title(tt.literal), tt.in, got, 0)
1007 }
1008
1009 got, gotErr := consumeLiteral([]byte(tt.in), tt.literal)
1010 if got != tt.want || !reflect.DeepEqual(gotErr, tt.wantErr) {
1011 t.Errorf("consumeLiteral(%q, %q) = (%v, %v), want (%v, %v)", tt.in, tt.literal, got, gotErr, tt.want, tt.wantErr)
1012 }
1013 })
1014 }
1015 }
1016
1017 func TestConsumeString(t *testing.T) {
1018 tests := []struct {
1019 in string
1020 simple bool
1021 want int
1022 wantFlags valueFlags
1023 wantStr string
1024 wantErr error
1025 wantErrUTF8 error
1026 }{
1027 {``, false, 0, 0, "", io.ErrUnexpectedEOF, nil},
1028 {`"`, false, 1, 0, "", io.ErrUnexpectedEOF, nil},
1029 {`""`, true, 2, 0, "", nil, nil},
1030 {`""x`, true, 2, 0, "", nil, nil},
1031 {` ""x`, false, 0, 0, "", newInvalidCharacterError([]byte(" "), "at start of string (expecting '\"')"), nil},
1032 {`"hello`, false, 6, 0, "hello", io.ErrUnexpectedEOF, nil},
1033 {`"hello"`, true, 7, 0, "hello", nil, nil},
1034 {"\"\x00\"", false, 1, stringNonVerbatim | stringNonCanonical, "", newInvalidCharacterError([]byte("\x00"), "within string (expecting non-control character)"), nil},
1035 {`"\u0000"`, false, 8, stringNonVerbatim, "\x00", nil, nil},
1036 {"\"\x1f\"", false, 1, stringNonVerbatim | stringNonCanonical, "", newInvalidCharacterError([]byte("\x1f"), "within string (expecting non-control character)"), nil},
1037 {`"\u001f"`, false, 8, stringNonVerbatim, "\x1f", nil, nil},
1038 {`"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"`, true, 54, 0, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", nil, nil},
1039 {"\" !#$%&'()*+,-./0123456789:;<=>?@[]^_`{|}~\x7f\"", true, 44, 0, " !#$%&'()*+,-./0123456789:;<=>?@[]^_`{|}~\x7f", nil, nil},
1040 {"\"x\x80\"", false, 4, stringNonVerbatim | stringNonCanonical, "x\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}},
1041 {"\"x\xff\"", false, 4, stringNonVerbatim | stringNonCanonical, "x\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}},
1042 {"\"x\xc0", false, 3, stringNonVerbatim | stringNonCanonical, "x\ufffd", io.ErrUnexpectedEOF, &SyntacticError{str: "invalid UTF-8 within string"}},
1043 {"\"x\xc0\x80\"", false, 5, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}},
1044 {"\"x\xe0", false, 2, 0, "x", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1045 {"\"x\xe0\x80", false, 4, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd", io.ErrUnexpectedEOF, &SyntacticError{str: "invalid UTF-8 within string"}},
1046 {"\"x\xe0\x80\x80\"", false, 6, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}},
1047 {"\"x\xf0", false, 2, 0, "x", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1048 {"\"x\xf0\x80", false, 4, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd", io.ErrUnexpectedEOF, &SyntacticError{str: "invalid UTF-8 within string"}},
1049 {"\"x\xf0\x80\x80", false, 5, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd\ufffd", io.ErrUnexpectedEOF, &SyntacticError{str: "invalid UTF-8 within string"}},
1050 {"\"x\xf0\x80\x80\x80\"", false, 7, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd\ufffd\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}},
1051 {"\"x\xed\xba\xad\"", false, 6, stringNonVerbatim | stringNonCanonical, "x\ufffd\ufffd\ufffd", nil, &SyntacticError{str: "invalid UTF-8 within string"}},
1052 {"\"\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602\"", false, 25, 0, "\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602", nil, nil},
1053 {`"¢"`[:2], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1054 {`"¢"`[:3], false, 3, 0, "¢", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1055 {`"¢"`[:4], false, 4, 0, "¢", nil, nil},
1056 {`"€"`[:2], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1057 {`"€"`[:3], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1058 {`"€"`[:4], false, 4, 0, "€", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1059 {`"€"`[:5], false, 5, 0, "€", nil, nil},
1060 {`"𐍈"`[:2], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1061 {`"𐍈"`[:3], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1062 {`"𐍈"`[:4], false, 1, 0, "", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1063 {`"𐍈"`[:5], false, 5, 0, "𐍈", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1064 {`"𐍈"`[:6], false, 6, 0, "𐍈", nil, nil},
1065 {`"x\`, false, 2, stringNonVerbatim, "x", io.ErrUnexpectedEOF, nil},
1066 {`"x\"`, false, 4, stringNonVerbatim, "x\"", io.ErrUnexpectedEOF, nil},
1067 {`"x\x"`, false, 2, stringNonVerbatim | stringNonCanonical, "x", &SyntacticError{str: `invalid escape sequence "\\x" within string`}, nil},
1068 {`"\"\\\b\f\n\r\t"`, false, 16, stringNonVerbatim, "\"\\\b\f\n\r\t", nil, nil},
1069 {`"/"`, true, 3, 0, "/", nil, nil},
1070 {`"\/"`, false, 4, stringNonVerbatim | stringNonCanonical, "/", nil, nil},
1071 {`"\u002f"`, false, 8, stringNonVerbatim | stringNonCanonical, "/", nil, nil},
1072 {`"\u`, false, 1, stringNonVerbatim, "", io.ErrUnexpectedEOF, nil},
1073 {`"\uf`, false, 1, stringNonVerbatim, "", io.ErrUnexpectedEOF, nil},
1074 {`"\uff`, false, 1, stringNonVerbatim, "", io.ErrUnexpectedEOF, nil},
1075 {`"\ufff`, false, 1, stringNonVerbatim, "", io.ErrUnexpectedEOF, nil},
1076 {`"\ufffd`, false, 7, stringNonVerbatim | stringNonCanonical, "\ufffd", io.ErrUnexpectedEOF, nil},
1077 {`"\ufffd"`, false, 8, stringNonVerbatim | stringNonCanonical, "\ufffd", nil, nil},
1078 {`"\uABCD"`, false, 8, stringNonVerbatim | stringNonCanonical, "\uabcd", nil, nil},
1079 {`"\uefX0"`, false, 1, stringNonVerbatim | stringNonCanonical, "", &SyntacticError{str: `invalid escape sequence "\\uefX0" within string`}, nil},
1080 {`"\uDEAD`, false, 7, stringNonVerbatim | stringNonCanonical, "\ufffd", io.ErrUnexpectedEOF, io.ErrUnexpectedEOF},
1081 {`"\uDEAD"`, false, 8, stringNonVerbatim | stringNonCanonical, "\ufffd", nil, &SyntacticError{str: `invalid escape sequence "\"" within string`}},
1082 {`"\uDEAD______"`, false, 14, stringNonVerbatim | stringNonCanonical, "\ufffd______", nil, &SyntacticError{str: "invalid unpaired surrogate half within string"}},
1083 {`"\uDEAD\uXXXX"`, false, 7, stringNonVerbatim | stringNonCanonical, "\ufffd", &SyntacticError{str: `invalid escape sequence "\\uXXXX" within string`}, nil},
1084 {`"\uDEAD\uBEEF"`, false, 14, stringNonVerbatim | stringNonCanonical, "\ufffd\ubeef", nil, &SyntacticError{str: `invalid surrogate pair in string`}},
1085 {`"\uD800\udead"`, false, 14, stringNonVerbatim | stringNonCanonical, "\U000102ad", nil, nil},
1086 {`"\u0022\u005c\u002f\u0008\u000c\u000a\u000d\u0009"`, false, 50, stringNonVerbatim | stringNonCanonical, "\"\\/\b\f\n\r\t", nil, nil},
1087 {`"\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\ud83d\ude02"`, false, 56, stringNonVerbatim | stringNonCanonical, "\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602", nil, nil},
1088 }
1089
1090 for _, tt := range tests {
1091 t.Run("", func(t *testing.T) {
1092 switch got := consumeSimpleString([]byte(tt.in)); {
1093 case tt.simple && got != tt.want:
1094 t.Errorf("consumeSimpleString(%q) = %v, want %v", tt.in, got, tt.want)
1095 case !tt.simple && got != 0:
1096 t.Errorf("consumeSimpleString(%q) = %v, want %v", tt.in, got, 0)
1097 }
1098
1099 var gotFlags valueFlags
1100 got, gotErr := consumeString(&gotFlags, []byte(tt.in), false)
1101 if gotFlags != tt.wantFlags {
1102 t.Errorf("consumeString(%q, false) flags = %v, want %v", tt.in, gotFlags, tt.wantFlags)
1103 }
1104 if got != tt.want || !reflect.DeepEqual(gotErr, tt.wantErr) {
1105 t.Errorf("consumeString(%q, false) = (%v, %v), want (%v, %v)", tt.in, got, gotErr, tt.want, tt.wantErr)
1106 }
1107 switch got, gotErr := consumeString(&gotFlags, []byte(tt.in), true); {
1108 case tt.wantErrUTF8 == nil && (got != tt.want || !reflect.DeepEqual(gotErr, tt.wantErr)):
1109 t.Errorf("consumeString(%q, true) = (%v, %v), want (%v, %v)", tt.in, got, gotErr, tt.want, tt.wantErr)
1110 case tt.wantErrUTF8 != nil && (got > tt.want || !reflect.DeepEqual(gotErr, tt.wantErrUTF8)):
1111 t.Errorf("consumeString(%q, true) = (%v, %v), want (%v, %v)", tt.in, got, gotErr, tt.want, tt.wantErrUTF8)
1112 }
1113
1114 gotStr, gotOk := unescapeString(nil, []byte(tt.in[:got]))
1115 wantOk := tt.wantErr == nil
1116 if string(gotStr) != tt.wantStr || gotOk != wantOk {
1117 t.Errorf("unescapeString(nil, %q) = (%q, %v), want (%q, %v)", tt.in[:got], gotStr, gotOk, tt.wantStr, wantOk)
1118 }
1119 if _, gotOk := unescapeString(nil, []byte(tt.in)); got < len(tt.in) && gotOk {
1120 t.Errorf("unescapeString(nil, %q) = (_, true), want (_, false)", tt.in)
1121 }
1122 })
1123 }
1124 }
1125
1126 func TestConsumeNumber(t *testing.T) {
1127 tests := []struct {
1128 in string
1129 simple bool
1130 want int
1131 wantErr error
1132 }{
1133 {"", false, 0, io.ErrUnexpectedEOF},
1134 {`"NaN"`, false, 0, newInvalidCharacterError([]byte("\""), "within number (expecting digit)")},
1135 {`"Infinity"`, false, 0, newInvalidCharacterError([]byte("\""), "within number (expecting digit)")},
1136 {`"-Infinity"`, false, 0, newInvalidCharacterError([]byte("\""), "within number (expecting digit)")},
1137 {".0", false, 0, newInvalidCharacterError([]byte("."), "within number (expecting digit)")},
1138 {"0", true, 1, nil},
1139 {"-0", false, 2, nil},
1140 {"+0", false, 0, newInvalidCharacterError([]byte("+"), "within number (expecting digit)")},
1141 {"1", true, 1, nil},
1142 {"-1", false, 2, nil},
1143 {"00", true, 1, nil},
1144 {"-00", false, 2, nil},
1145 {"01", true, 1, nil},
1146 {"-01", false, 2, nil},
1147 {"0i", true, 1, nil},
1148 {"-0i", false, 2, nil},
1149 {"0f", true, 1, nil},
1150 {"-0f", false, 2, nil},
1151 {"9876543210", true, 10, nil},
1152 {"-9876543210", false, 11, nil},
1153 {"9876543210x", true, 10, nil},
1154 {"-9876543210x", false, 11, nil},
1155 {" 9876543210", true, 0, newInvalidCharacterError([]byte(" "), "within number (expecting digit)")},
1156 {"- 9876543210", false, 1, newInvalidCharacterError([]byte(" "), "within number (expecting digit)")},
1157 {strings.Repeat("9876543210", 1000), true, 10000, nil},
1158 {"-" + strings.Repeat("9876543210", 1000), false, 1 + 10000, nil},
1159 {"0.", false, 1, io.ErrUnexpectedEOF},
1160 {"-0.", false, 2, io.ErrUnexpectedEOF},
1161 {"0e", false, 1, io.ErrUnexpectedEOF},
1162 {"-0e", false, 2, io.ErrUnexpectedEOF},
1163 {"0E", false, 1, io.ErrUnexpectedEOF},
1164 {"-0E", false, 2, io.ErrUnexpectedEOF},
1165 {"0.0", false, 3, nil},
1166 {"-0.0", false, 4, nil},
1167 {"0e0", false, 3, nil},
1168 {"-0e0", false, 4, nil},
1169 {"0E0", false, 3, nil},
1170 {"-0E0", false, 4, nil},
1171 {"0.0123456789", false, 12, nil},
1172 {"-0.0123456789", false, 13, nil},
1173 {"1.f", false, 2, newInvalidCharacterError([]byte("f"), "within number (expecting digit)")},
1174 {"-1.f", false, 3, newInvalidCharacterError([]byte("f"), "within number (expecting digit)")},
1175 {"1.e", false, 2, newInvalidCharacterError([]byte("e"), "within number (expecting digit)")},
1176 {"-1.e", false, 3, newInvalidCharacterError([]byte("e"), "within number (expecting digit)")},
1177 {"1e0", false, 3, nil},
1178 {"-1e0", false, 4, nil},
1179 {"1E0", false, 3, nil},
1180 {"-1E0", false, 4, nil},
1181 {"1Ex", false, 2, newInvalidCharacterError([]byte("x"), "within number (expecting digit)")},
1182 {"-1Ex", false, 3, newInvalidCharacterError([]byte("x"), "within number (expecting digit)")},
1183 {"1e-0", false, 4, nil},
1184 {"-1e-0", false, 5, nil},
1185 {"1e+0", false, 4, nil},
1186 {"-1e+0", false, 5, nil},
1187 {"1E-0", false, 4, nil},
1188 {"-1E-0", false, 5, nil},
1189 {"1E+0", false, 4, nil},
1190 {"-1E+0", false, 5, nil},
1191 {"1E+00500", false, 8, nil},
1192 {"-1E+00500", false, 9, nil},
1193 {"1E+00500x", false, 8, nil},
1194 {"-1E+00500x", false, 9, nil},
1195 {"9876543210.0123456789e+01234589x", false, 31, nil},
1196 {"-9876543210.0123456789e+01234589x", false, 32, nil},
1197 {"1_000_000", true, 1, nil},
1198 {"0x12ef", true, 1, nil},
1199 {"0x1p-2", true, 1, nil},
1200 }
1201
1202 for _, tt := range tests {
1203 t.Run("", func(t *testing.T) {
1204 switch got := consumeSimpleNumber([]byte(tt.in)); {
1205 case tt.simple && got != tt.want:
1206 t.Errorf("consumeSimpleNumber(%q) = %v, want %v", tt.in, got, tt.want)
1207 case !tt.simple && got != 0:
1208 t.Errorf("consumeSimpleNumber(%q) = %v, want %v", tt.in, got, 0)
1209 }
1210
1211 got, gotErr := consumeNumber([]byte(tt.in))
1212 if got != tt.want || !reflect.DeepEqual(gotErr, tt.wantErr) {
1213 t.Errorf("consumeNumber(%q) = (%v, %v), want (%v, %v)", tt.in, got, gotErr, tt.want, tt.wantErr)
1214 }
1215 })
1216 }
1217 }
1218
1219 func TestParseHexUint16(t *testing.T) {
1220 tests := []struct {
1221 in string
1222 want uint16
1223 wantOk bool
1224 }{
1225 {"", 0, false},
1226 {"a", 0, false},
1227 {"ab", 0, false},
1228 {"abc", 0, false},
1229 {"abcd", 0xabcd, true},
1230 {"abcde", 0, false},
1231 {"9eA1", 0x9ea1, true},
1232 {"gggg", 0, false},
1233 {"0000", 0x0000, true},
1234 {"1234", 0x1234, true},
1235 }
1236
1237 for _, tt := range tests {
1238 t.Run("", func(t *testing.T) {
1239 got, gotOk := parseHexUint16([]byte(tt.in))
1240 if got != tt.want || gotOk != tt.wantOk {
1241 t.Errorf("parseHexUint16(%q) = (0x%04x, %v), want (0x%04x, %v)", tt.in, got, gotOk, tt.want, tt.wantOk)
1242 }
1243 })
1244 }
1245 }
1246
1247 func TestParseDecUint(t *testing.T) {
1248 tests := []struct {
1249 in string
1250 want uint64
1251 wantOk bool
1252 }{
1253 {"", 0, false},
1254 {"0", 0, true},
1255 {"1", 1, true},
1256 {"-1", 0, false},
1257 {"1f", 0, false},
1258 {"00", 0, true},
1259 {"01", 1, true},
1260 {"10", 10, true},
1261 {"10.9", 0, false},
1262 {" 10", 0, false},
1263 {"10 ", 0, false},
1264 {"123456789", 123456789, true},
1265 {"123456789d", 0, false},
1266 {"18446744073709551614", math.MaxUint64 - 1, true},
1267 {"18446744073709551615", math.MaxUint64, true},
1268 {"99999999999999999999999999999999", math.MaxUint64, false},
1269 {"99999999999999999999999999999999f", 0, false},
1270 }
1271
1272 for _, tt := range tests {
1273 t.Run("", func(t *testing.T) {
1274 got, gotOk := parseDecUint([]byte(tt.in))
1275 if got != tt.want || gotOk != tt.wantOk {
1276 t.Errorf("parseDecUint(%q) = (%v, %v), want (%v, %v)", tt.in, got, gotOk, tt.want, tt.wantOk)
1277 }
1278 })
1279 }
1280 }
1281
1282 func TestParseFloat(t *testing.T) {
1283 tests := []struct {
1284 in string
1285 want32 float64
1286 want64 float64
1287 wantOk bool
1288 }{
1289 {"0", 0, 0, true},
1290 {"-1", -1, -1, true},
1291 {"1", 1, 1, true},
1292
1293 {"-16777215", -16777215, -16777215, true},
1294 {"16777215", 16777215, 16777215, true},
1295 {"-16777216", -16777216, -16777216, true},
1296 {"16777216", 16777216, 16777216, true},
1297 {"-16777217", -16777216, -16777217, true},
1298 {"16777217", 16777216, 16777217, true},
1299
1300 {"-9007199254740991", -9007199254740992, -9007199254740991, true},
1301 {"9007199254740991", 9007199254740992, 9007199254740991, true},
1302 {"-9007199254740992", -9007199254740992, -9007199254740992, true},
1303 {"9007199254740992", 9007199254740992, 9007199254740992, true},
1304 {"-9007199254740993", -9007199254740992, -9007199254740992, true},
1305 {"9007199254740993", 9007199254740992, 9007199254740992, true},
1306
1307 {"-1e1000", -math.MaxFloat32, -math.MaxFloat64, true},
1308 {"1e1000", +math.MaxFloat32, +math.MaxFloat64, true},
1309 }
1310
1311 for _, tt := range tests {
1312 t.Run("", func(t *testing.T) {
1313 got32, gotOk32 := parseFloat([]byte(tt.in), 32)
1314 if got32 != tt.want32 || gotOk32 != tt.wantOk {
1315 t.Errorf("parseFloat(%q, 32) = (%v, %v), want (%v, %v)", tt.in, got32, gotOk32, tt.want32, tt.wantOk)
1316 }
1317
1318 got64, gotOk64 := parseFloat([]byte(tt.in), 64)
1319 if got64 != tt.want64 || gotOk64 != tt.wantOk {
1320 t.Errorf("parseFloat(%q, 64) = (%v, %v), want (%v, %v)", tt.in, got64, gotOk64, tt.want64, tt.wantOk)
1321 }
1322 })
1323 }
1324 }
1325
View as plain text