1 ## oils_failures_allowed: 2
2 ## tags: dev-minimal
3
4 #### usage errors
5
6 json read zz
7 echo status=$?
8
9 json write
10
11 ## status: 3
12 ## STDOUT:
13 status=2
14 ## END
15
16 #### json write STRING
17 shopt --set parse_proc
18
19 json write ('foo')
20 var s = 'foo'
21 json write (s)
22 ## STDOUT:
23 "foo"
24 "foo"
25 ## END
26
27 #### json write ARRAY
28 json write (:|foo.cc foo.h|)
29 json write (['foo.cc', 'foo.h'], space=0)
30 ## STDOUT:
31 [
32 "foo.cc",
33 "foo.h"
34 ]
35 ["foo.cc","foo.h"]
36 ## END
37
38 #### json write Dict
39 json write ({k: 'v', k2: [4, 5]})
40
41 json write ([{k: 'v', k2: 'v2'}, {}])
42
43 ## STDOUT:
44 {
45 "k": "v",
46 "k2": [
47 4,
48 5
49 ]
50 }
51 [
52 {
53 "k": "v",
54 "k2": "v2"
55 },
56 {}
57 ]
58 ## END
59
60 #### json write space=0, space=4
61 shopt --set parse_proc
62
63 var mydict = {name: "bob", age: 30}
64
65 json write (mydict, space=0)
66 json write (mydict, space=4)
67 ## STDOUT:
68 {"name":"bob","age":30}
69 {
70 "name": "bob",
71 "age": 30
72 }
73 ## END
74
75 #### json write in command sub
76 shopt -s oil:all # for echo
77 var mydict = {name: "bob", age: 30}
78 json write (mydict)
79 var x = $(json write (mydict))
80 echo $x
81 ## STDOUT:
82 {
83 "name": "bob",
84 "age": 30
85 }
86 {
87 "name": "bob",
88 "age": 30
89 }
90 ## END
91
92 #### json read passed invalid args
93
94 # EOF
95 json read
96 echo status=$?
97
98 json read 'z z'
99 echo status=$?
100
101 json read a b c
102 echo status=$?
103
104 ## STDOUT:
105 status=1
106 status=2
107 status=2
108 ## END
109
110 #### json read uses $_reply var
111
112 # space before true
113 echo ' true' | json read
114 json write (_reply)
115
116 ## STDOUT:
117 true
118 ## END
119
120 #### json read then json write
121
122 # BUG with space before true
123 echo '{"name": "bob", "age": 42, "ok": true}' | json read
124 json write (_reply)
125
126 echo '{"name": "bob", "age": 42, "ok":true}' | json read
127 json write (_reply)
128
129 echo '{"name": {}, "age": {}, "x":-1, "y": -0}' | json read
130 json write (_reply)
131
132 ## STDOUT:
133 {
134 "name": "bob",
135 "age": 42,
136 "ok": true
137 }
138 {
139 "name": "bob",
140 "age": 42,
141 "ok": true
142 }
143 {
144 "name": {},
145 "age": {},
146 "x": -1,
147 "y": 0
148 }
149 ## END
150
151 #### json read with redirect
152 echo '{"age": 42}' > $TMP/foo.txt
153 json read (&x) < $TMP/foo.txt
154 pp cell_ x
155 ## STDOUT:
156 x = (Cell exported:F readonly:F nameref:F val:(Dict_ d:[Dict age (value.Int i:42)]))
157 ## END
158
159 #### json read at end of pipeline (relies on lastpipe)
160 echo '{"age": 43}' | json read (&y)
161 pp cell_ y
162 ## STDOUT:
163 y = (Cell exported:F readonly:F nameref:F val:(Dict_ d:[Dict age (value.Int i:43)]))
164 ## END
165
166 #### invalid JSON
167 echo '{' | json read (&y)
168 echo pipeline status = $?
169 pp test_ (y)
170 ## status: 1
171 ## STDOUT:
172 pipeline status = 1
173 ## END
174
175 #### Extra data after valid JSON
176
177 # Trailing space is OK
178 echo '42 ' | json read
179 echo num space $?
180
181 echo '{} ' | json read
182 echo obj space $?
183
184 echo '42 # comment' | json8 read
185 echo num comment $?
186
187 echo '{} # comment ' | json8 read
188 echo obj comment $?
189
190 echo '42]' | json read
191 echo num bracket $?
192
193 echo '{}]' | json read
194 echo obj bracket $?
195
196 ## STDOUT:
197 num space 0
198 obj space 0
199 num comment 0
200 obj comment 0
201 num bracket 1
202 obj bracket 1
203 ## END
204
205 #### json write expression
206 json write ([1,2,3], space=0)
207 echo status=$?
208
209 json write (5, 6) # to many args
210 echo status=$?
211
212 ## status: 3
213 ## STDOUT:
214 [1,2,3]
215 status=0
216 ## END
217
218 #### json write evaluation error
219
220 #var block = ^(echo hi)
221 #json write (block)
222 #echo status=$?
223
224 # undefined var
225 json write (a)
226 echo 'should have failed'
227
228 ## status: 1
229 ## STDOUT:
230 ## END
231
232 #### json write of List in cycle
233
234 var L = [1, 2, 3]
235 setvar L[0] = L
236
237 shopt -s ysh:upgrade
238 fopen >tmp.txt {
239 pp test_ (L)
240 }
241 fgrep -n -o '[ -->' tmp.txt
242
243 json write (L)
244 echo 'should have failed'
245
246 ## status: 1
247 ## STDOUT:
248 1:[ -->
249 ## END
250
251 #### json write of Dict in cycle
252
253 var d = {}
254 setvar d.k = d
255
256 shopt -s ysh:upgrade
257 fopen >tmp.txt {
258 pp test_ (d)
259 }
260 fgrep -n -o '{ -->' tmp.txt
261
262 json write (d)
263 echo 'should have failed'
264
265 ## status: 1
266 ## STDOUT:
267 1:{ -->
268 ## END
269
270 #### json write of List/Dict referenced twice (bug fix)
271
272 var mylist = [1,2,3]
273 var mydict = {foo: "bar"}
274
275 var top = {k: mylist, k2: mylist, k3: mydict, k4: mydict}
276
277 # BUG!
278 json write (top, space=0)
279
280 ## STDOUT:
281 {"k":[1,2,3],"k2":[1,2,3],"k3":{"foo":"bar"},"k4":{"foo":"bar"}}
282 ## END
283
284 #### json read doesn't accept u'' or b'' strings
285
286 json read <<EOF
287 {"key": u'val'}
288 EOF
289 echo status=$?
290
291 #pp test_ (_reply)
292
293 json read <<EOF
294 {"key": b'val'}
295 EOF
296 echo status=$?
297
298 ## STDOUT:
299 status=1
300 status=1
301 ## END
302
303 #### json read doesn't accept comments, but json8 does
304
305 json8 read <<EOF
306 { # comment
307 "key": # zz
308 b'val', # yy
309 "k2": "v2" #
310 }
311 EOF
312 echo status=$?
313
314 json8 write (_reply)
315
316 json read <<EOF
317 {"key": "val"} # comment
318 EOF
319 echo status=$?
320 ## STDOUT:
321 status=0
322 {
323 "key": "val",
324 "k2": "v2"
325 }
326 status=1
327 ## END
328
329
330 #### json write emits Unicode replacement char for binary data \yff
331
332 json write ([3, "foo", $'-\xff\xfe---\xfd=']) > tmp.txt
333
334 # Round trip it for good measure
335 json read < tmp.txt
336
337 json write (_reply)
338
339 ## STDOUT:
340 [
341 3,
342 "foo",
343 "-��---�="
344 ]
345 ## END
346
347 #### json8 accepts j"" prefix, but json doesn't
348
349 var msg = r'j"foo\nbar"'
350
351 echo "$msg" | json read
352 echo json=$?
353 echo
354
355 echo "$msg" | json8 read
356 echo json8=$?
357 pp test_ (_reply)
358 echo
359
360 var msg = r'j"\u0041"'
361 echo "$msg" | json8 read
362 echo json8=$?
363 pp test_ (_reply)
364
365
366 ## STDOUT:
367 json=1
368
369 json8=0
370 (Str) "foo\nbar"
371
372 json8=0
373 (Str) "A"
374 ## END
375
376 #### j"" prefix not accepted in YSH (could be added later)
377
378 shopt -s ysh:all
379
380 # denied by YSH
381 # echo j"\u{7f}"
382
383 var s = j"\u{7f}"
384
385 ## status: 2
386 ## STDOUT:
387 ## END
388
389
390 #### json8 write emits b'' strings for binary data \yff
391
392 json8 write ([3, "foo", $'-\xff\xfe-\xfd='])
393
394 ## STDOUT:
395 [
396 3,
397 "foo",
398 b'-\yff\yfe-\yfd='
399 ]
400 ## END
401
402
403 #### json8 write bytes vs unicode string
404
405 u=$'mu \u03bc \x01 \" \\ \b\f\n\r\t'
406 u2=$'\x01\x1f' # this is a valid unicode string
407
408 b=$'\xff' # this isn't valid unicode
409
410 json8 write (u)
411 json8 write (u2)
412
413 json8 write (b)
414
415 ## STDOUT:
416 "mu μ \u0001 \" \\ \b\f\n\r\t"
417 "\u0001\u001f"
418 b'\yff'
419 ## END
420
421 #### JSON \/ escapes supported
422
423 msg='"\/"'
424
425 echo "$msg" | python3 -c 'import json, sys; print(json.load(sys.stdin))'
426
427 echo "$msg" | json read
428 echo reply=$_reply
429
430 j8="b'\\/'"
431 echo "$msg" | json read
432 echo reply=$_reply
433
434
435 ## STDOUT:
436 /
437 reply=/
438 reply=/
439 ## END
440
441 #### JSON string can have unescaped ' and J8 string can have unescaped "
442
443 json read <<EOF
444 "'"
445 EOF
446
447 pp test_ (_reply)
448
449 json8 read <<EOF
450 u'"'
451 EOF
452
453 pp test_ (_reply)
454
455 ## STDOUT:
456 (Str) "'"
457 (Str) "\""
458 ## END
459
460
461 #### J8 supports superfluous \" escapes, but JSON doesn't support \' escapes
462
463 json8 read <<'EOF'
464 b'\"'
465 EOF
466 echo reply=$_reply
467
468 json8 read <<'EOF'
469 b'\'\'\b\f\n\r\t\"\\'
470 EOF
471 pp test_ (_reply)
472
473 # Suppress traceback
474 python3 -c 'import json, sys; print(json.load(sys.stdin))' 2>/dev/null <<'EOF'
475 "\'"
476 EOF
477 echo python3=$?
478
479 json read <<'EOF'
480 "\'"
481 EOF
482 echo json=$?
483
484 ## STDOUT:
485 reply="
486 (Str) "''\b\f\n\r\t\"\\"
487 python3=1
488 json=1
489 ## END
490
491 #### Escaping uses \u0001 in "", but \u{1} in b''
492
493 s1=$'\x01'
494 s2=$'\x01\xff\x1f' # byte string
495
496 json8 write (s1)
497 json8 write (s2)
498
499 ## STDOUT:
500 "\u0001"
501 b'\u{1}\yff\u{1f}'
502 ## END
503
504
505 #### json8 read
506
507 echo '{ }' | json8 read
508 pp test_ (_reply)
509
510 echo '[ ]' | json8 read
511 pp test_ (_reply)
512
513 echo '[42]' | json8 read
514 pp test_ (_reply)
515
516 echo '[true, false]' | json8 read
517 pp test_ (_reply)
518
519 echo '{"k": "v"}' | json8 read
520 pp test_ (_reply)
521
522 echo '{"k": null}' | json8 read
523 pp test_ (_reply)
524
525 echo '{"k": 1, "k2": 2}' | json8 read
526 pp test_ (_reply)
527
528 echo "{u'k': {b'k2': null}}" | json8 read
529 pp test_ (_reply)
530
531 echo '{"k": {"k2": "v2"}, "k3": "backslash \\ \" \n line 2 \u03bc "}' | json8 read
532 pp test_ (_reply)
533
534 json8 read (&x) <<'EOF'
535 {u'k': {u'k2': u'v2'}, u'k3': u'backslash \\ \" \n line 2 \u{3bc} '}
536 EOF
537 pp test_ (x)
538
539 ## STDOUT:
540 (Dict) {}
541 (List) []
542 (List) [42]
543 (List) [true,false]
544 (Dict) {"k":"v"}
545 (Dict) {"k":null}
546 (Dict) {"k":1,"k2":2}
547 (Dict) {"k":{"k2":null}}
548 (Dict) {"k":{"k2":"v2"},"k3":"backslash \\ \" \n line 2 μ "}
549 (Dict) {"k":{"k2":"v2"},"k3":"backslash \\ \" \n line 2 μ "}
550 ## END
551
552 #### json8 round trip
553
554 var obj = [42, 1.5, null, true, "hi", b'\yff\yfe\b\n""']
555
556 json8 write (obj, space=0) > j
557
558 cat j
559
560 json8 read < j
561
562 json8 write (_reply)
563
564 ## STDOUT:
565 [42,1.5,null,true,"hi",b'\yff\yfe\b\n""']
566 [
567 42,
568 1.5,
569 null,
570 true,
571 "hi",
572 b'\yff\yfe\b\n""'
573 ]
574 ## END
575
576 #### json round trip (regression)
577
578 var d = {
579 short: '-v', long: '--verbose', type: null, default: '', help: 'Enable verbose logging'
580 }
581
582 json write (d) | json read
583
584 pp test_ (_reply)
585
586 ## STDOUT:
587 (Dict) {"short":"-v","long":"--verbose","type":null,"default":"","help":"Enable verbose logging"}
588 ## END
589
590 #### round trip: decode surrogate pair and encode
591
592 var j = r'"\ud83e\udd26"'
593 echo $j | json read (&c1)
594
595 json write (c1)
596
597 var j = r'"\uD83E\uDD26"'
598 echo $j | json read (&c2)
599
600 json write (c2)
601
602 # Not a surrogate pair
603 var j = r'"\u0001\u0002"'
604 echo $j | json read (&c3)
605
606 json write (c3)
607
608 var j = r'"\u0100\u0101\u0102"'
609 echo $j | json read (&c4)
610
611 json write (c4)
612
613 ## STDOUT:
614 "🤦"
615 "🤦"
616 "\u0001\u0002"
617 "ĀāĂ"
618 ## END
619
620 #### round trip: decode surrogate half and encode
621
622 shopt -s ysh:upgrade
623
624 for j in '"\ud83e"' '"\udd26"' {
625 var s = fromJson(j)
626 write -- "$j"
627 pp test_ (s)
628
629 write -n 'json '; json write (s)
630
631 write -n 'json8 '; json8 write (s)
632
633 echo
634 }
635
636 ## STDOUT:
637 "\ud83e"
638 (Str) b'\yed\ya0\ybe'
639 json "\ud83e"
640 json8 b'\yed\ya0\ybe'
641
642 "\udd26"
643 (Str) b'\yed\yb4\ya6'
644 json "\udd26"
645 json8 b'\yed\yb4\ya6'
646
647 ## END
648
649 #### toJson() toJson8()
650
651 var obj = [42, 1.5, null, true, "hi", b'\yf0']
652
653 echo $[toJson(obj)]
654 echo $[toJson8(obj)]
655
656 var obj2 = [3, 4]
657 echo $[toJson(obj2, space=0)] # same as the default
658 echo $[toJson8(obj2, space=0)]
659
660 echo $[toJson(obj2, space=2)]
661 echo $[toJson8(obj2, space=2)]
662
663 # fully specify this behavior
664 echo $[toJson(obj2, space=-2)]
665 echo $[toJson8(obj2, space=-2)]
666
667 ## STDOUT:
668 [42,1.5,null,true,"hi","�"]
669 [42,1.5,null,true,"hi",b'\yf0']
670 [3,4]
671 [3,4]
672 [
673 3,
674 4
675 ]
676 [
677 3,
678 4
679 ]
680 [3,4]
681 [3,4]
682 ## END
683
684 #### fromJson() fromJson8()
685
686 var m1 = '[42,1.5,null,true,"hi"]'
687
688 # JSON8 message
689 var m2 = '[42,1.5,null,true,"hi",' ++ "u''" ++ ']'
690
691 pp test_ (fromJson8(m1))
692 pp test_ (fromJson(m1))
693
694 pp test_ (fromJson8(m2))
695 pp test_ (fromJson(m2)) # fails
696
697 ## status: 4
698 ## STDOUT:
699 (List) [42,1.5,null,true,"hi"]
700 (List) [42,1.5,null,true,"hi"]
701 (List) [42,1.5,null,true,"hi",""]
702 ## END
703
704 #### User can handle errors - toJson() toJson8()
705 shopt -s ysh:upgrade
706
707 var obj = []
708 call obj->append(obj)
709
710 try {
711 echo $[toJson(obj)]
712 }
713 echo status=$_status
714 echo "encode error $[_error.message]" | sed 's/0x[a-f0-9]\+/(object id)/'
715
716 try { # use different style
717 echo $[toJson8( /d+/ )]
718 }
719 echo status=$_status
720 echo "encode error $[_error.message]"
721
722 # This makes the interpreter fail with a message
723 echo $[toJson(obj)]
724
725 ## status: 4
726 ## STDOUT:
727 status=4
728 encode error Can't encode List (object id) in object cycle
729 status=4
730 encode error Can't serialize object of type Eggex
731 ## END
732
733 #### User can handle errors - fromJson() fromJson8()
734 shopt -s ysh:upgrade
735
736 var message ='[42,1.5,null,true,"hi"'
737
738 try {
739 var obj = fromJson(message)
740 }
741 echo status=$_status
742 echo "decode error $[_error.message]" | egrep -o '.*Expected.*RBracket'
743
744 try {
745 var obj = fromJson8(message)
746 }
747 echo status=$_status
748 echo "decode error $[_error.message]" | egrep -o '.*Expected.*RBracket'
749
750 try {
751 var obj = fromJson('[+]')
752 }
753 echo "positions $[_error.start_pos] - $[_error.end_pos]"
754
755 # This makes the interpreter fail with a message
756 var obj = fromJson(message)
757
758 ## status: 4
759 ## STDOUT:
760 status=4
761 decode error Expected Id.J8_RBracket
762 status=4
763 decode error Expected Id.J8_RBracket
764 positions 1 - 2
765 ## END
766
767
768 #### ASCII control chars can't appear literally in messages
769 shopt -s ysh:upgrade
770
771 var message=$'"\x01"'
772 #echo $message | od -c
773
774 try {
775 var obj = fromJson(message)
776 }
777 echo status=$_status
778 echo "$[_error.message]" | egrep -o 'ASCII control chars'
779
780 ## STDOUT:
781 status=4
782 ASCII control chars
783 ## END
784
785
786 #### \yff can't appear in u'' code strings (command)
787
788 shopt -s ysh:upgrade
789
790 echo -n b'\yfd' | od -A n -t x1
791 echo -n u'\yfd' | od -A n -t x1
792
793 ## status: 2
794 ## STDOUT:
795 fd
796 ## END
797
798 #### \yff can't appear in u'' code strings (expr)
799
800 var x = b'\yfe'
801 write -n -- $x | od -A n -t x1
802
803 var x = u'\yfe'
804 write -n -- $x | od -A n -t x1
805
806 ## status: 2
807 ## STDOUT:
808 fe
809 ## END
810
811 #### \yff can't appear in u'' multiline code strings
812
813 shopt -s ysh:upgrade
814
815 echo -n b'''\yfc''' | od -A n -t x1
816 echo -n u'''\yfd''' | od -A n -t x1
817
818 ## status: 2
819 ## STDOUT:
820 fc
821 ## END
822
823 #### \yff can't appear in u'' data strings
824
825 #shopt -s ysh:upgrade
826
827 json8 read (&b) <<'EOF'
828 b'\yfe'
829 EOF
830 pp test_ (b)
831
832 json8 read (&u) <<'EOF'
833 u'\yfe'
834 EOF
835 pp test_ (u) # undefined
836
837 ## status: 1
838 ## STDOUT:
839 (Str) b'\yfe'
840 ## END
841
842 #### \u{dc00} can't be in surrogate range in code (command)
843
844 shopt -s ysh:upgrade
845
846 echo -n u'\u{dc00}' | od -A n -t x1
847
848 ## status: 2
849 ## STDOUT:
850 ## END
851
852 #### \u{dc00} can't be in surrogate range in code (expr)
853
854 shopt -s ysh:upgrade
855
856 var x = u'\u{dc00}'
857 echo $x | od -A n -t x1
858
859 ## status: 2
860 ## STDOUT:
861 ## END
862
863 #### \u{dc00} can't be in surrogate range in data
864
865 json8 read <<'EOF'
866 ["long string", u'hello \u{d7ff}', "other"]
867 EOF
868 echo status=$?
869
870 json8 read <<'EOF'
871 ["long string", u'hello \u{d800}', "other"]
872 EOF
873 echo status=$?
874
875 json8 read <<'EOF'
876 ["long string", u'hello \u{dfff}', "other"]
877 EOF
878 echo status=$?
879
880 json8 read <<'EOF'
881 ["long string", u'hello \u{e000}', "other"]
882 EOF
883 echo status=$?
884
885
886 ## STDOUT:
887 status=0
888 status=1
889 status=1
890 status=0
891 ## END
892
893
894 #### Inf is encoded as null, like JavaScript
895
896 # WRONG LOCATION! Gah
897 #var x = fromJson(repeat('123', 20))
898
899 shopt --set ysh:upgrade
900
901 source $LIB_YSH/list.ysh
902
903 # Create inf
904 var big = repeat('12345678', 100) ++ '.0'
905 #pp test_ (s)
906 var inf = fromJson(big)
907 var neg_inf = fromJson('-' ++ big)
908
909 # Can be printed
910 pp test_ (inf)
911 pp test_ (neg_inf)
912 echo --
913
914 # Can't be serialized
915 try {
916 json write (inf)
917 }
918 echo error=$[_error.code]
919
920 try {
921 json write (neg_inf)
922 }
923 echo error=$[_error.code]
924
925 echo --
926 echo $[toJson(inf)]
927 echo $[toJson(neg_inf)]
928
929 ## STDOUT:
930 (Float) INFINITY
931 (Float) -INFINITY
932 --
933 null
934 error=0
935 null
936 error=0
937 --
938 null
939 null
940 ## END
941
942 #### NaN is encoded as null, like JavaScript
943
944 pp test_ (NAN)
945
946 json write (NAN)
947
948 echo $[toJson(NAN)]
949
950 ## STDOUT:
951 (Float) NAN
952 null
953 null
954 ## END
955
956
957 #### Invalid UTF-8 in JSON is rejected
958
959 echo $'"\xff"' | json read
960 echo status=$?
961
962 echo $'"\xff"' | json8 read
963 echo status=$?
964
965 echo $'\xff' | json read
966 echo status=$?
967
968 echo $'\xff' | json8 read
969 echo status=$?
970
971 ## STDOUT:
972 status=1
973 status=1
974 status=1
975 status=1
976 ## END
977
978 #### Invalid JSON in J8 is rejected
979
980 json8 read <<EOF
981 b'$(echo -e -n '\xff')'
982 EOF
983 echo status=$?
984
985 json8 read <<EOF
986 u'$(echo -e -n '\xff')'
987 EOF
988 echo status=$?
989
990 ## STDOUT:
991 status=1
992 status=1
993 ## END
994
995 #### '' means the same thing as u''
996
997 echo "''" | json8 read
998 pp test_ (_reply)
999
1000 echo "'\u{3bc}'" | json8 read
1001 pp test_ (_reply)
1002
1003 echo "'\yff'" | json8 read
1004 echo status=$?
1005
1006 ## STDOUT:
1007 (Str) ""
1008 (Str) "μ"
1009 status=1
1010 ## END
1011
1012 #### decode integer larger than 2^32
1013
1014 json=$(( 1 << 33 ))
1015 echo $json
1016
1017 echo $json | json read
1018 pp test_ (_reply)
1019
1020 ## STDOUT:
1021 8589934592
1022 (Int) 8589934592
1023 ## END
1024
1025 #### decode integer larger than 2^64
1026
1027 $SH <<'EOF'
1028 json read <<< '123456789123456789123456789'
1029 echo status=$?
1030 pp test_ (_reply)
1031 EOF
1032
1033 $SH <<'EOF'
1034 json read <<< '-123456789123456789123456789'
1035 echo status=$?
1036 pp test_ (_reply)
1037 EOF
1038
1039 echo ok
1040
1041 ## STDOUT:
1042 status=1
1043 status=1
1044 ok
1045 ## END
1046
1047
1048 #### round trip: read/write with ysh
1049
1050 var file = "$REPO_ROOT/spec/testdata/bug.json"
1051 #cat $file
1052 cat $file | json read (&cfg)
1053 json write (cfg) > ysh-json
1054
1055 diff -u $file ysh-json
1056 echo diff=$?
1057
1058 ## STDOUT:
1059 diff=0
1060 ## END
1061
1062 #### round trip: read/write with ysh, read/write with Python 3 (bug regression)
1063
1064 var file = "$REPO_ROOT/spec/testdata/bug.json"
1065 #cat $file
1066 cat $file | json read (&cfg)
1067 json write (cfg) > ysh-json
1068
1069 cat ysh-json | python3 -c \
1070 'import json, sys; obj = json.load(sys.stdin); json.dump(obj, sys.stdout, indent=2); print()' \
1071 > py-json
1072
1073 diff -u $file py-json
1074 echo diff=$?
1075
1076 ## STDOUT:
1077 diff=0
1078 ## END
1079
1080 #### Encoding bytes that don't hit UTF8_REJECT immediately (bug fix)
1081
1082 var x = $'\xce'
1083 json8 write (x)
1084 declare -p x
1085 echo
1086
1087 var y = $'\xbc'
1088 json8 write (y)
1089 declare -p y
1090 echo
1091
1092 var z = $'\xf0\x9f\xa4\xff'
1093 json8 write (z)
1094 declare -p z
1095
1096 ## STDOUT:
1097 b'\yce'
1098 declare -- x=$'\xce'
1099
1100 b'\ybc'
1101 declare -- y=$'\xbc'
1102
1103 b'\yf0\y9f\ya4\yff'
1104 declare -- z=$'\xf0\x9f\xa4\xff'
1105 ## END
1106
1107 #### NIL8 token in JSON / JSON8
1108
1109 echo "(" | json read
1110 echo status=$?
1111
1112 echo ")" | json8 read
1113 echo status=$?
1114
1115 ## STDOUT:
1116 status=1
1117 status=1
1118 ## END
1119
1120 #### Data after internal NUL (issue #2026)
1121
1122 $SH <<'EOF'
1123 pp test_ (fromJson(b'123\y00abc'))
1124 EOF
1125 echo status=$?
1126
1127 $SH <<'EOF'
1128 pp test_ (fromJson(b'123\y01abc'))
1129 EOF
1130 echo status=$?
1131
1132 $SH <<'EOF'
1133 shopt --set ysh:upgrade # b'' syntax
1134 json read <<< b'123\y00abc'
1135 EOF
1136 echo status=$?
1137
1138 $SH <<'EOF'
1139 shopt --set ysh:upgrade # b'' syntax
1140 json read <<< b'123\y01abc'
1141 EOF
1142 echo status=$?
1143
1144 ## STDOUT:
1145 status=4
1146 status=4
1147 status=1
1148 status=1
1149 ## END
1150
1151 #### Float too big
1152
1153 $SH <<'EOF'
1154 json read <<< '123456789123456789123456789.12345e67890'
1155 echo status=$?
1156 pp test_ (_reply)
1157 EOF
1158
1159 $SH <<'EOF'
1160 json read <<< '-123456789123456789123456789.12345e67890'
1161 echo status=$?
1162 pp test_ (_reply)
1163 EOF
1164
1165 ## STDOUT:
1166 status=0
1167 (Float) INFINITY
1168 status=0
1169 (Float) -INFINITY
1170 ## END
1171
1172 #### Many [[[ , but not too many
1173
1174 shopt -s ysh:upgrade
1175
1176 proc pairs(n) {
1177 var m = int(n) # TODO: 1 .. n should auto-convert?
1178
1179 for i in (1 .. m) {
1180 write -n -- '['
1181 }
1182 for i in (1 .. m) {
1183 write -n -- ']'
1184 }
1185 }
1186
1187 # This is all Python can handle; C++ can handle more
1188 msg=$(pairs 50)
1189
1190 #echo $msg
1191
1192 echo "$msg" | json read
1193 pp test_ (_reply)
1194 echo len=$[len(_reply)]
1195
1196 ## STDOUT:
1197 (List) [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
1198 len=1
1199 ## END
1200
1201
1202 #### Too many opening [[[ - blocking stack
1203
1204 python2 -c 'print("[" * 10000)' | json read
1205 pp test_ (_reply)
1206
1207 python2 -c 'print("{" * 10000)' | json read
1208 pp test_ (_reply)
1209
1210 ## STDOUT:
1211 ## END
1212
1213 #### BashArray can be serialized
1214
1215 declare -a empty_array
1216
1217 declare -a array=(x y)
1218 array[5]=z
1219
1220 json write (empty_array)
1221 json write (array)
1222
1223 ## STDOUT:
1224 {
1225 "type": "BashArray",
1226 "data": {}
1227 }
1228 {
1229 "type": "BashArray",
1230 "data": {
1231 "0": "x",
1232 "1": "y",
1233 "5": "z"
1234 }
1235 }
1236 ## END
1237
1238 #### BashAssoc can be serialized
1239
1240 declare -A empty_assoc
1241
1242 declare -A assoc=([foo]=bar [42]=43)
1243
1244 json write (empty_assoc)
1245 json write (assoc)
1246
1247 ## STDOUT:
1248 {
1249 "type": "BashAssoc",
1250 "data": {}
1251 }
1252 {
1253 "type": "BashAssoc",
1254 "data": {
1255 "foo": "bar",
1256 "42": "43"
1257 }
1258 }
1259 ## END