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