blob: c29d50879b99c31ee8dcba6427c9a9dd666e7618 [file] [log] [blame]
Herbie Ongd3f8f2d2019-03-06 00:28:23 -08001// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package json_test
6
7import (
8 "strings"
9 "testing"
10 "unicode/utf8"
11
Damien Neile89e6242019-05-13 23:55:40 -070012 "google.golang.org/protobuf/internal/encoding/json"
Herbie Ongd3f8f2d2019-03-06 00:28:23 -080013)
14
15type R struct {
Herbie Ongc96a79d2019-03-08 10:49:17 -080016 // T is expected Type returned from calling Decoder.Read.
Herbie Ongd3f8f2d2019-03-06 00:28:23 -080017 T json.Type
Herbie Ongc96a79d2019-03-08 10:49:17 -080018 // E is expected error substring from calling Decoder.Read if set.
Herbie Ongd3f8f2d2019-03-06 00:28:23 -080019 E string
20 // V is expected value from calling
21 // Value.{Bool()|Float()|Int()|Uint()|String()} depending on type.
22 V interface{}
23 // VE is expected error substring from calling
24 // Value.{Bool()|Float()|Int()|Uint()|String()} depending on type if set.
25 VE string
26}
27
28func TestDecoder(t *testing.T) {
29 const space = " \n\r\t"
30
31 tests := []struct {
32 input string
33 // want is a list of expected values returned from calling
Herbie Ongc96a79d2019-03-08 10:49:17 -080034 // Decoder.Read. An item makes the test code invoke
35 // Decoder.Read and compare against R.T and R.E. For Bool,
Herbie Ongd3f8f2d2019-03-06 00:28:23 -080036 // Number and String tokens, it invokes the corresponding getter method
37 // and compares the returned value against R.V or R.VE if it returned an
38 // error.
39 want []R
40 }{
41 {
42 input: ``,
43 want: []R{{T: json.EOF}},
44 },
45 {
46 input: space,
47 want: []R{{T: json.EOF}},
48 },
49 {
Herbie Ongc96a79d2019-03-08 10:49:17 -080050 // Calling Read after EOF will keep returning EOF for
51 // succeeding Read calls.
Herbie Ongd3f8f2d2019-03-06 00:28:23 -080052 input: space,
53 want: []R{
54 {T: json.EOF},
55 {T: json.EOF},
56 {T: json.EOF},
57 },
58 },
59
60 // JSON literals.
61 {
62 input: space + `null` + space,
63 want: []R{
64 {T: json.Null},
65 {T: json.EOF},
66 },
67 },
68 {
69 input: space + `true` + space,
70 want: []R{
71 {T: json.Bool, V: true},
72 {T: json.EOF},
73 },
74 },
75 {
76 input: space + `false` + space,
77 want: []R{
78 {T: json.Bool, V: false},
79 {T: json.EOF},
80 },
81 },
82 {
83 // Error returned will produce the same error again.
84 input: space + `foo` + space,
85 want: []R{
86 {E: `invalid value foo`},
87 {E: `invalid value foo`},
88 },
89 },
90
91 // JSON strings.
92 {
93 input: space + `""` + space,
94 want: []R{
95 {T: json.String, V: ""},
96 {T: json.EOF},
97 },
98 },
99 {
100 input: space + `"hello"` + space,
101 want: []R{
102 {T: json.String, V: "hello"},
103 {T: json.EOF},
104 },
105 },
106 {
107 input: `"hello`,
108 want: []R{{E: `unexpected EOF`}},
109 },
110 {
111 input: "\"\x00\"",
112 want: []R{{E: `invalid character '\x00' in string`}},
113 },
114 {
115 input: "\"\u0031\u0032\"",
116 want: []R{
117 {T: json.String, V: "12"},
118 {T: json.EOF},
119 },
120 },
121 {
Herbie Ongc96a79d2019-03-08 10:49:17 -0800122 // Invalid UTF-8 error is returned in ReadString instead of Read.
Herbie Ongd3f8f2d2019-03-06 00:28:23 -0800123 input: "\"\xff\"",
Damien Neil8c86fc52019-06-19 09:28:29 -0700124 want: []R{{E: `syntax error (line 1:1): invalid UTF-8 in string`}},
Herbie Ongd3f8f2d2019-03-06 00:28:23 -0800125 },
126 {
127 input: `"` + string(utf8.RuneError) + `"`,
128 want: []R{
129 {T: json.String, V: string(utf8.RuneError)},
130 {T: json.EOF},
131 },
132 },
133 {
134 input: `"\uFFFD"`,
135 want: []R{
136 {T: json.String, V: string(utf8.RuneError)},
137 {T: json.EOF},
138 },
139 },
140 {
141 input: `"\x"`,
142 want: []R{{E: `invalid escape code "\\x" in string`}},
143 },
144 {
145 input: `"\uXXXX"`,
146 want: []R{{E: `invalid escape code "\\uXXXX" in string`}},
147 },
148 {
149 input: `"\uDEAD"`, // unmatched surrogate pair
150 want: []R{{E: `unexpected EOF`}},
151 },
152 {
153 input: `"\uDEAD\uBEEF"`, // invalid surrogate half
154 want: []R{{E: `invalid escape code "\\uBEEF" in string`}},
155 },
156 {
157 input: `"\uD800\udead"`, // valid surrogate pair
158 want: []R{
159 {T: json.String, V: `𐊭`},
160 {T: json.EOF},
161 },
162 },
163 {
164 input: `"\u0000\"\\\/\b\f\n\r\t"`,
165 want: []R{
166 {T: json.String, V: "\u0000\"\\/\b\f\n\r\t"},
167 {T: json.EOF},
168 },
169 },
170
171 // Invalid JSON numbers.
172 {
173 input: `-`,
174 want: []R{{E: `invalid number -`}},
175 },
176 {
177 input: `+0`,
178 want: []R{{E: `invalid value +0`}},
179 },
180 {
181 input: `-+`,
182 want: []R{{E: `invalid number -+`}},
183 },
184 {
185 input: `0.`,
186 want: []R{{E: `invalid number 0.`}},
187 },
188 {
189 input: `.1`,
190 want: []R{{E: `invalid value .1`}},
191 },
192 {
193 input: `1.0.1`,
194 want: []R{{E: `invalid number 1.0.1`}},
195 },
196 {
197 input: `1..1`,
198 want: []R{{E: `invalid number 1..1`}},
199 },
200 {
201 input: `-1-2`,
202 want: []R{{E: `invalid number -1-2`}},
203 },
204 {
205 input: `01`,
206 want: []R{{E: `invalid number 01`}},
207 },
208 {
209 input: `1e`,
210 want: []R{{E: `invalid number 1e`}},
211 },
212 {
213 input: `1e1.2`,
214 want: []R{{E: `invalid number 1e1.2`}},
215 },
216 {
217 input: `1Ee`,
218 want: []R{{E: `invalid number 1Ee`}},
219 },
220 {
221 input: `1.e1`,
222 want: []R{{E: `invalid number 1.e1`}},
223 },
224 {
225 input: `1.e+`,
226 want: []R{{E: `invalid number 1.e+`}},
227 },
228 {
229 input: `1e+-2`,
230 want: []R{{E: `invalid number 1e+-2`}},
231 },
232 {
233 input: `1e--2`,
234 want: []R{{E: `invalid number 1e--2`}},
235 },
236 {
237 input: `1.0true`,
238 want: []R{{E: `invalid number 1.0true`}},
239 },
240
241 // JSON numbers as floating point.
242 {
243 input: space + `0.0` + space,
244 want: []R{
245 {T: json.Number, V: float32(0)},
246 {T: json.EOF},
247 },
248 },
249 {
250 input: space + `0` + space,
251 want: []R{
252 {T: json.Number, V: float32(0)},
253 {T: json.EOF},
254 },
255 },
256 {
257 input: space + `-0` + space,
258 want: []R{
259 {T: json.Number, V: float32(0)},
260 {T: json.EOF},
261 },
262 },
263 {
264 input: `-1.02`,
265 want: []R{
266 {T: json.Number, V: float32(-1.02)},
267 {T: json.EOF},
268 },
269 },
270 {
271 input: `1.020000`,
272 want: []R{
273 {T: json.Number, V: float32(1.02)},
274 {T: json.EOF},
275 },
276 },
277 {
278 input: `-1.0e0`,
279 want: []R{
280 {T: json.Number, V: float32(-1)},
281 {T: json.EOF},
282 },
283 },
284 {
285 input: `1.0e-000`,
286 want: []R{
287 {T: json.Number, V: float32(1)},
288 {T: json.EOF},
289 },
290 },
291 {
292 input: `1e+00`,
293 want: []R{
294 {T: json.Number, V: float32(1)},
295 {T: json.EOF},
296 },
297 },
298 {
299 input: `1.02e3`,
300 want: []R{
301 {T: json.Number, V: float32(1.02e3)},
302 {T: json.EOF},
303 },
304 },
305 {
306 input: `-1.02E03`,
307 want: []R{
308 {T: json.Number, V: float32(-1.02e3)},
309 {T: json.EOF},
310 },
311 },
312 {
313 input: `1.0200e+3`,
314 want: []R{
315 {T: json.Number, V: float32(1.02e3)},
316 {T: json.EOF},
317 },
318 },
319 {
320 input: `-1.0200E+03`,
321 want: []R{
322 {T: json.Number, V: float32(-1.02e3)},
323 {T: json.EOF},
324 },
325 },
326 {
327 input: `1.0200e-3`,
328 want: []R{
329 {T: json.Number, V: float32(1.02e-3)},
330 {T: json.EOF},
331 },
332 },
333 {
334 input: `-1.0200E-03`,
335 want: []R{
336 {T: json.Number, V: float32(-1.02e-3)},
337 {T: json.EOF},
338 },
339 },
340 {
341 // Exceeds max float32 limit, but should be ok for float64.
342 input: `3.4e39`,
343 want: []R{
344 {T: json.Number, V: float64(3.4e39)},
345 {T: json.EOF},
346 },
347 },
348 {
349 // Exceeds max float32 limit.
350 input: `3.4e39`,
351 want: []R{
352 {T: json.Number, V: float32(0), VE: `value out of range`},
353 {T: json.EOF},
354 },
355 },
356 {
357 // Less than negative max float32 limit.
358 input: `-3.4e39`,
359 want: []R{
360 {T: json.Number, V: float32(0), VE: `value out of range`},
361 {T: json.EOF},
362 },
363 },
364 {
365 // Exceeds max float64 limit.
366 input: `1.79e+309`,
367 want: []R{
368 {T: json.Number, V: float64(0), VE: `value out of range`},
369 {T: json.EOF},
370 },
371 },
372 {
373 // Less than negative max float64 limit.
374 input: `-1.79e+309`,
375 want: []R{
376 {T: json.Number, V: float64(0), VE: `value out of range`},
377 {T: json.EOF},
378 },
379 },
380
381 // JSON numbers as signed integers.
382 {
383 input: space + `0` + space,
384 want: []R{
385 {T: json.Number, V: int32(0)},
386 {T: json.EOF},
387 },
388 },
389 {
390 input: space + `-0` + space,
391 want: []R{
392 {T: json.Number, V: int32(0)},
393 {T: json.EOF},
394 },
395 },
396 {
397 // Fractional part equals 0 is ok.
398 input: `1.00000`,
399 want: []R{
400 {T: json.Number, V: int32(1)},
401 {T: json.EOF},
402 },
403 },
404 {
405 // Fractional part not equals 0 returns error.
406 input: `1.0000000001`,
407 want: []R{
408 {T: json.Number, V: int32(0), VE: `cannot convert 1.0000000001 to integer`},
409 {T: json.EOF},
410 },
411 },
412 {
413 input: `0e0`,
414 want: []R{
415 {T: json.Number, V: int32(0)},
416 {T: json.EOF},
417 },
418 },
419 {
420 input: `0.0E0`,
421 want: []R{
422 {T: json.Number, V: int32(0)},
423 {T: json.EOF},
424 },
425 },
426 {
427 input: `0.0E10`,
428 want: []R{
429 {T: json.Number, V: int32(0)},
430 {T: json.EOF},
431 },
432 },
433 {
434 input: `-1`,
435 want: []R{
436 {T: json.Number, V: int32(-1)},
437 {T: json.EOF},
438 },
439 },
440 {
441 input: `1.0e+0`,
442 want: []R{
443 {T: json.Number, V: int32(1)},
444 {T: json.EOF},
445 },
446 },
447 {
448 input: `-1E-0`,
449 want: []R{
450 {T: json.Number, V: int32(-1)},
451 {T: json.EOF},
452 },
453 },
454 {
455 input: `1E1`,
456 want: []R{
457 {T: json.Number, V: int32(10)},
458 {T: json.EOF},
459 },
460 },
461 {
462 input: `-100.00e-02`,
463 want: []R{
464 {T: json.Number, V: int32(-1)},
465 {T: json.EOF},
466 },
467 },
468 {
469 input: `0.1200E+02`,
470 want: []R{
471 {T: json.Number, V: int64(12)},
472 {T: json.EOF},
473 },
474 },
475 {
476 input: `0.012e2`,
477 want: []R{
478 {T: json.Number, V: int32(0), VE: `cannot convert 0.012e2 to integer`},
479 {T: json.EOF},
480 },
481 },
482 {
483 input: `12e-2`,
484 want: []R{
485 {T: json.Number, V: int32(0), VE: `cannot convert 12e-2 to integer`},
486 {T: json.EOF},
487 },
488 },
489 {
490 // Exceeds math.MaxInt32.
491 input: `2147483648`,
492 want: []R{
493 {T: json.Number, V: int32(0), VE: `value out of range`},
494 {T: json.EOF},
495 },
496 },
497 {
498 // Exceeds math.MinInt32.
499 input: `-2147483649`,
500 want: []R{
501 {T: json.Number, V: int32(0), VE: `value out of range`},
502 {T: json.EOF},
503 },
504 },
505 {
506 // Exceeds math.MaxInt32, but ok for int64.
507 input: `2147483648`,
508 want: []R{
509 {T: json.Number, V: int64(2147483648)},
510 {T: json.EOF},
511 },
512 },
513 {
514 // Exceeds math.MinInt32, but ok for int64.
515 input: `-2147483649`,
516 want: []R{
517 {T: json.Number, V: int64(-2147483649)},
518 {T: json.EOF},
519 },
520 },
521 {
522 // Exceeds math.MaxInt64.
523 input: `9223372036854775808`,
524 want: []R{
525 {T: json.Number, V: int64(0), VE: `value out of range`},
526 {T: json.EOF},
527 },
528 },
529 {
530 // Exceeds math.MinInt64.
531 input: `-9223372036854775809`,
532 want: []R{
533 {T: json.Number, V: int64(0), VE: `value out of range`},
534 {T: json.EOF},
535 },
536 },
537
538 // JSON numbers as unsigned integers.
539 {
540 input: space + `0` + space,
541 want: []R{
542 {T: json.Number, V: uint32(0)},
543 {T: json.EOF},
544 },
545 },
546 {
547 input: space + `-0` + space,
548 want: []R{
549 {T: json.Number, V: uint32(0)},
550 {T: json.EOF},
551 },
552 },
553 {
554 input: `-1`,
555 want: []R{
556 {T: json.Number, V: uint32(0), VE: `invalid syntax`},
557 {T: json.EOF},
558 },
559 },
560 {
561 // Exceeds math.MaxUint32.
562 input: `4294967296`,
563 want: []R{
564 {T: json.Number, V: uint32(0), VE: `value out of range`},
565 {T: json.EOF},
566 },
567 },
568 {
569 // Exceeds math.MaxUint64.
570 input: `18446744073709551616`,
571 want: []R{
572 {T: json.Number, V: uint64(0), VE: `value out of range`},
573 {T: json.EOF},
574 },
575 },
576
577 // JSON sequence of values.
578 {
579 input: `true null`,
580 want: []R{
581 {T: json.Bool, V: true},
582 {E: `unexpected value null`},
583 },
584 },
585 {
586 input: "null false",
587 want: []R{
588 {T: json.Null},
589 {E: `unexpected value false`},
590 },
591 },
592 {
593 input: `true,false`,
594 want: []R{
595 {T: json.Bool, V: true},
596 {E: `unexpected character ,`},
597 },
598 },
599 {
600 input: `47"hello"`,
601 want: []R{
602 {T: json.Number, V: int32(47)},
603 {E: `unexpected value "hello"`},
604 },
605 },
606 {
607 input: `47 "hello"`,
608 want: []R{
609 {T: json.Number, V: int32(47)},
610 {E: `unexpected value "hello"`},
611 },
612 },
613 {
614 input: `true 42`,
615 want: []R{
616 {T: json.Bool, V: true},
617 {E: `unexpected value 42`},
618 },
619 },
620
621 // JSON arrays.
622 {
623 input: space + `[]` + space,
624 want: []R{
625 {T: json.StartArray},
626 {T: json.EndArray},
627 {T: json.EOF},
628 },
629 },
630 {
631 input: space + `[` + space + `]` + space,
632 want: []R{
633 {T: json.StartArray},
634 {T: json.EndArray},
635 {T: json.EOF},
636 },
637 },
638 {
639 input: space + `[` + space,
640 want: []R{
641 {T: json.StartArray},
642 {E: `unexpected EOF`},
643 },
644 },
645 {
646 input: space + `]` + space,
647 want: []R{{E: `unexpected character ]`}},
648 },
649 {
650 input: `[null,true,false, 1e1, "hello" ]`,
651 want: []R{
652 {T: json.StartArray},
653 {T: json.Null},
654 {T: json.Bool, V: true},
655 {T: json.Bool, V: false},
656 {T: json.Number, V: int32(10)},
657 {T: json.String, V: "hello"},
658 {T: json.EndArray},
659 {T: json.EOF},
660 },
661 },
662 {
663 input: `[` + space + `true` + space + `,` + space + `"hello"` + space + `]`,
664 want: []R{
665 {T: json.StartArray},
666 {T: json.Bool, V: true},
667 {T: json.String, V: "hello"},
668 {T: json.EndArray},
669 {T: json.EOF},
670 },
671 },
672 {
673 input: `[` + space + `true` + space + `,` + space + `]`,
674 want: []R{
675 {T: json.StartArray},
676 {T: json.Bool, V: true},
677 {E: `unexpected character ]`},
678 },
679 },
680 {
681 input: `[` + space + `false` + space + `]`,
682 want: []R{
683 {T: json.StartArray},
684 {T: json.Bool, V: false},
685 {T: json.EndArray},
686 {T: json.EOF},
687 },
688 },
689 {
690 input: `[` + space + `1` + space + `0` + space + `]`,
691 want: []R{
692 {T: json.StartArray},
693 {T: json.Number, V: int64(1)},
694 {E: `unexpected value 0`},
695 },
696 },
697 {
698 input: `[null`,
699 want: []R{
700 {T: json.StartArray},
701 {T: json.Null},
702 {E: `unexpected EOF`},
703 },
704 },
705 {
706 input: `[foo]`,
707 want: []R{
708 {T: json.StartArray},
709 {E: `invalid value foo`},
710 },
711 },
712 {
713 input: `[{}, "hello", [true, false], null]`,
714 want: []R{
715 {T: json.StartArray},
716 {T: json.StartObject},
717 {T: json.EndObject},
718 {T: json.String, V: "hello"},
719 {T: json.StartArray},
720 {T: json.Bool, V: true},
721 {T: json.Bool, V: false},
722 {T: json.EndArray},
723 {T: json.Null},
724 {T: json.EndArray},
725 {T: json.EOF},
726 },
727 },
728 {
729 input: `[{ ]`,
730 want: []R{
731 {T: json.StartArray},
732 {T: json.StartObject},
733 {E: `unexpected character ]`},
734 },
735 },
736 {
737 input: `[[ ]`,
738 want: []R{
739 {T: json.StartArray},
740 {T: json.StartArray},
741 {T: json.EndArray},
742 {E: `unexpected EOF`},
743 },
744 },
745 {
746 input: `[,]`,
747 want: []R{
748 {T: json.StartArray},
749 {E: `unexpected character ,`},
750 },
751 },
752 {
753 input: `[true "hello"]`,
754 want: []R{
755 {T: json.StartArray},
756 {T: json.Bool, V: true},
757 {E: `unexpected value "hello"`},
758 },
759 },
760 {
761 input: `[] null`,
762 want: []R{
763 {T: json.StartArray},
764 {T: json.EndArray},
765 {E: `unexpected value null`},
766 },
767 },
768 {
769 input: `true []`,
770 want: []R{
771 {T: json.Bool, V: true},
772 {E: `unexpected character [`},
773 },
774 },
775
776 // JSON objects.
777 {
778 input: space + `{}` + space,
779 want: []R{
780 {T: json.StartObject},
781 {T: json.EndObject},
782 {T: json.EOF},
783 },
784 },
785 {
786 input: space + `{` + space + `}` + space,
787 want: []R{
788 {T: json.StartObject},
789 {T: json.EndObject},
790 {T: json.EOF},
791 },
792 },
793 {
794 input: space + `{` + space,
795 want: []R{
796 {T: json.StartObject},
797 {E: `unexpected EOF`},
798 },
799 },
800 {
801 input: space + `}` + space,
802 want: []R{{E: `unexpected character }`}},
803 },
804 {
805 input: `{` + space + `null` + space + `}`,
806 want: []R{
807 {T: json.StartObject},
808 {E: `unexpected value null`},
809 },
810 },
811 {
812 input: `{[]}`,
813 want: []R{
814 {T: json.StartObject},
815 {E: `unexpected character [`},
816 },
817 },
818 {
819 input: `{,}`,
820 want: []R{
821 {T: json.StartObject},
822 {E: `unexpected character ,`},
823 },
824 },
825 {
826 input: `{"345678"}`,
827 want: []R{
828 {T: json.StartObject},
829 {E: `unexpected character }, missing ":" after object name`},
830 },
831 },
832 {
833 input: `{` + space + `"hello"` + space + `:` + space + `"world"` + space + `}`,
834 want: []R{
835 {T: json.StartObject},
836 {T: json.Name, V: "hello"},
837 {T: json.String, V: "world"},
838 {T: json.EndObject},
839 {T: json.EOF},
840 },
841 },
842 {
843 input: `{"hello" "world"}`,
844 want: []R{
845 {T: json.StartObject},
846 {E: `unexpected character ", missing ":" after object name`},
847 },
848 },
849 {
850 input: `{"hello":`,
851 want: []R{
852 {T: json.StartObject},
853 {T: json.Name, V: "hello"},
854 {E: `unexpected EOF`},
855 },
856 },
857 {
858 input: `{"hello":"world"`,
859 want: []R{
860 {T: json.StartObject},
861 {T: json.Name, V: "hello"},
862 {T: json.String, V: "world"},
863 {E: `unexpected EOF`},
864 },
865 },
866 {
867 input: `{"hello":"world",`,
868 want: []R{
869 {T: json.StartObject},
870 {T: json.Name, V: "hello"},
871 {T: json.String, V: "world"},
872 {E: `unexpected EOF`},
873 },
874 },
875 {
876 input: `{"34":"89",}`,
877 want: []R{
878 {T: json.StartObject},
879 {T: json.Name, V: "34"},
880 {T: json.String, V: "89"},
881 {E: `syntax error (line 1:12): unexpected character }`},
882 },
883 },
884 {
885 input: `{
886 "number": 123e2,
887 "bool" : false,
888 "object": {"string": "world"},
889 "null" : null,
890 "array" : [1.01, "hello", true],
891 "string": "hello"
892}`,
893 want: []R{
894 {T: json.StartObject},
895
896 {T: json.Name, V: "number"},
897 {T: json.Number, V: int32(12300)},
898
899 {T: json.Name, V: "bool"},
900 {T: json.Bool, V: false},
901
902 {T: json.Name, V: "object"},
903 {T: json.StartObject},
904 {T: json.Name, V: "string"},
905 {T: json.String, V: "world"},
906 {T: json.EndObject},
907
908 {T: json.Name, V: "null"},
909 {T: json.Null},
910
911 {T: json.Name, V: "array"},
912 {T: json.StartArray},
913 {T: json.Number, V: float32(1.01)},
914 {T: json.String, V: "hello"},
915 {T: json.Bool, V: true},
916 {T: json.EndArray},
917
918 {T: json.Name, V: "string"},
919 {T: json.String, V: "hello"},
920
921 {T: json.EndObject},
922 {T: json.EOF},
923 },
924 },
925 {
926 input: `[
927 {"object": {"number": 47}},
928 ["list"],
929 null
930]`,
931 want: []R{
932 {T: json.StartArray},
933
934 {T: json.StartObject},
935 {T: json.Name, V: "object"},
936 {T: json.StartObject},
937 {T: json.Name, V: "number"},
938 {T: json.Number, V: uint32(47)},
939 {T: json.EndObject},
940 {T: json.EndObject},
941
942 {T: json.StartArray},
943 {T: json.String, V: "list"},
944 {T: json.EndArray},
945
946 {T: json.Null},
947
948 {T: json.EndArray},
949 {T: json.EOF},
950 },
951 },
952
953 // Tests for line and column info.
954 {
955 input: `12345678 x`,
956 want: []R{
957 {T: json.Number, V: int64(12345678)},
958 {E: `syntax error (line 1:10): invalid value x`},
959 },
960 },
961 {
962 input: "\ntrue\n x",
963 want: []R{
964 {T: json.Bool, V: true},
965 {E: `syntax error (line 3:4): invalid value x`},
966 },
967 },
968 {
969 input: `"💩"x`,
970 want: []R{
971 {T: json.String, V: "💩"},
972 {E: `syntax error (line 1:4): invalid value x`},
973 },
974 },
975 {
976 input: "\n\n[\"🔥🔥🔥\"x",
977 want: []R{
978 {T: json.StartArray},
979 {T: json.String, V: "🔥🔥🔥"},
980 {E: `syntax error (line 3:7): invalid value x`},
981 },
982 },
983 {
984 // Multi-rune emojis.
985 input: `["👍🏻👍🏿"x`,
986 want: []R{
987 {T: json.StartArray},
988 {T: json.String, V: "👍🏻👍🏿"},
989 {E: `syntax error (line 1:8): invalid value x`},
990 },
991 },
992 {
993 input: `{
994 "45678":-1
995}`,
996 want: []R{
997 {T: json.StartObject},
998 {T: json.Name, V: "45678"},
999 {T: json.Number, V: uint64(1), VE: "error (line 2:11)"},
1000 },
1001 },
1002 }
1003
1004 for _, tc := range tests {
1005 tc := tc
1006 t.Run("", func(t *testing.T) {
1007 dec := json.NewDecoder([]byte(tc.input))
1008 for i, want := range tc.want {
Herbie Ongc96a79d2019-03-08 10:49:17 -08001009 typ := dec.Peek()
1010 if typ != want.T {
1011 t.Errorf("input: %v\nPeek() got %v want %v", tc.input, typ, want.T)
1012 }
1013 value, err := dec.Read()
Herbie Ongd3f8f2d2019-03-06 00:28:23 -08001014 if err != nil {
1015 if want.E == "" {
Herbie Ongc96a79d2019-03-08 10:49:17 -08001016 t.Errorf("input: %v\nRead() got unexpected error: %v", tc.input, err)
Herbie Ongd3f8f2d2019-03-06 00:28:23 -08001017
1018 } else if !strings.Contains(err.Error(), want.E) {
Herbie Ongc96a79d2019-03-08 10:49:17 -08001019 t.Errorf("input: %v\nRead() got %q, want %q", tc.input, err, want.E)
Herbie Ongd3f8f2d2019-03-06 00:28:23 -08001020 }
1021 } else {
1022 if want.E != "" {
Herbie Ongc96a79d2019-03-08 10:49:17 -08001023 t.Errorf("input: %v\nRead() got nil error, want %q", tc.input, want.E)
Herbie Ongd3f8f2d2019-03-06 00:28:23 -08001024 }
1025 }
1026 token := value.Type()
1027 if token != want.T {
Herbie Ongc96a79d2019-03-08 10:49:17 -08001028 t.Errorf("input: %v\nRead() got %v, want %v", tc.input, token, want.T)
Herbie Ongd3f8f2d2019-03-06 00:28:23 -08001029 break
1030 }
1031 checkValue(t, value, i, want)
1032 }
1033 })
1034 }
1035}
1036
1037func checkValue(t *testing.T, value json.Value, wantIdx int, want R) {
1038 var got interface{}
1039 var err error
1040 switch value.Type() {
1041 case json.Bool:
1042 got, err = value.Bool()
1043 case json.String:
1044 got = value.String()
1045 case json.Name:
1046 got, err = value.Name()
1047 case json.Number:
1048 switch want.V.(type) {
1049 case float32:
1050 got, err = value.Float(32)
1051 got = float32(got.(float64))
1052 case float64:
1053 got, err = value.Float(64)
1054 case int32:
1055 got, err = value.Int(32)
1056 got = int32(got.(int64))
1057 case int64:
1058 got, err = value.Int(64)
1059 case uint32:
1060 got, err = value.Uint(32)
1061 got = uint32(got.(uint64))
1062 case uint64:
1063 got, err = value.Uint(64)
1064 }
1065 default:
1066 return
1067 }
1068
1069 if err != nil {
1070 if want.VE == "" {
1071 t.Errorf("want%d: %v got unexpected error: %v", wantIdx, value, err)
1072 } else if !strings.Contains(err.Error(), want.VE) {
1073 t.Errorf("want#%d: %v got %q, want %q", wantIdx, value, err, want.VE)
1074 }
1075 return
1076 } else {
1077 if want.VE != "" {
1078 t.Errorf("want#%d: %v got nil error, want %q", wantIdx, value, want.VE)
1079 return
1080 }
1081 }
1082
1083 if got != want.V {
1084 t.Errorf("want#%d: %v got %v, want %v", wantIdx, value, got, want.V)
1085 }
1086}
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001087
1088func TestClone(t *testing.T) {
1089 input := `{"outer":{"str":"hello", "number": 123}}`
1090 dec := json.NewDecoder([]byte(input))
1091
1092 // Clone at the start should produce the same reads as the original.
1093 clone := dec.Clone()
1094 compareDecoders(t, dec, clone)
1095
1096 // Advance to inner object, clone and compare again.
1097 dec.Read() // Read StartObject.
1098 dec.Read() // Read Name.
1099 clone = dec.Clone()
1100 compareDecoders(t, dec, clone)
1101}
1102
1103func compareDecoders(t *testing.T, d1 *json.Decoder, d2 *json.Decoder) {
1104 for {
1105 v1, err1 := d1.Read()
1106 v2, err2 := d2.Read()
1107 if v1.Type() != v2.Type() {
1108 t.Errorf("cloned decoder: got Type %v, want %v", v2.Type(), v1.Type())
1109 }
1110 if v1.Raw() != v2.Raw() {
1111 t.Errorf("cloned decoder: got Raw %v, want %v", v2.Raw(), v1.Raw())
1112 }
1113 if err1 != err2 {
1114 t.Errorf("cloned decoder: got error %v, want %v", err2, err1)
1115 }
1116 if v1.Type() == json.EOF {
1117 break
1118 }
1119 }
1120}