python: Serial JSON via Python's json lib.
[cascardo/ovs.git] / tests / json.at
1 m4_define([JSON_CHECK_POSITIVE_C],
2   [AT_SETUP([$1])
3    AT_KEYWORDS([json positive])
4    AT_CHECK([printf %s "AS_ESCAPE([$2])" > input])
5    AT_CAPTURE_FILE([input])
6    AT_CHECK([ovstest test-json $4 input], [0], [stdout], [])
7    AT_CHECK([cat stdout], [0], [$3
8 ])
9    AT_CLEANUP])
10
11 # JSON_CHECK_POSITIVE_PY(TITLE, INPUT, OUTPUT, TEST-JSON-ARGS,
12 #                        PYTHON-CHCEK, PYTHON-BIN)
13 #
14 m4_define([JSON_CHECK_POSITIVE_PY],
15   [AT_SETUP([$1])
16    AT_KEYWORDS([json positive Python])
17    AT_SKIP_IF([test $5 = no])
18    AT_CHECK([printf %s "AS_ESCAPE([$2])" > input])
19    AT_CAPTURE_FILE([input])
20    AT_CHECK([$6 $srcdir/test-json.py $4 input], [0], [stdout], [])
21    AT_CHECK([cat stdout], [0], [$3
22 ])
23    AT_CLEANUP])
24
25 m4_define([JSON_CHECK_POSITIVE_UCS4PY],
26   [AT_SETUP([$1])
27    AT_KEYWORDS([json positive Python])
28    AT_SKIP_IF([test $HAVE_PYTHON = no])
29    AT_XFAIL_IF([$PYTHON -c "exit(len(u'\U00010800'))"; test $? -ne 1])
30    AT_CHECK([printf %s "AS_ESCAPE([$2])" > input])
31    AT_CAPTURE_FILE([input])
32    AT_CHECK([$PYTHON $srcdir/test-json.py $4 input], [0], [stdout], [])
33    AT_CHECK([cat stdout], [0], [$3
34 ])
35    AT_CLEANUP])
36
37 m4_define([JSON_CHECK_POSITIVE],
38   [JSON_CHECK_POSITIVE_C([$1 - C], [$2], [$3], [$4])
39    JSON_CHECK_POSITIVE_PY([$1 - Python2], [$2], [$3], [$4],
40                           [$HAVE_PYTHON], [$PYTHON])
41    JSON_CHECK_POSITIVE_PY([$1 - Python3], [$2], [$3], [$4],
42                           [$HAVE_PYTHON3], [$PYTHON3])])
43
44 m4_define([JSON_CHECK_POSITIVE_PY23],
45   [JSON_CHECK_POSITIVE_PY([$1 - Python2], [$2], [$3], [$4],
46                           [$HAVE_PYTHON], [$PYTHON])
47    JSON_CHECK_POSITIVE_PY([$1 - Python3], [$2], [$3], [$4],
48                           [$HAVE_PYTHON3], [$PYTHON3])])
49
50 m4_define([JSON_CHECK_NEGATIVE_C],
51   [AT_SETUP([$1])
52    AT_KEYWORDS([json negative])
53    AT_CHECK([printf %s "AS_ESCAPE([$2])" > input])
54    AT_CAPTURE_FILE([input])
55    AT_CHECK([ovstest test-json $4 input], [1], [stdout], [])
56    AT_CHECK([[sed 's/^error: [^:]*:/error:/' < stdout]], [0], [$3
57 ])
58    AT_CLEANUP])
59
60 # JSON_CHECK_NEGATIVE_PY(TITLE, INPUT, OUTPUT, TEST-JSON-ARGS,
61 #                        PYTHON-CHCEK, PYTHON-BIN)
62 #
63 m4_define([JSON_CHECK_NEGATIVE_PY], 
64   [AT_SETUP([$1])
65    AT_KEYWORDS([json negative Python])
66    AT_SKIP_IF([test $5 = no])
67    AT_CHECK([printf %s "AS_ESCAPE([$2])" > input])
68    AT_CAPTURE_FILE([input])
69    AT_CHECK([$6 $srcdir/test-json.py $4 input], [1], [stdout], [])
70    AT_CHECK([[sed 's/^error: [^:]*:/error:/' < stdout]], [0], [$3
71 ])
72    AT_CLEANUP])
73
74 m4_define([JSON_CHECK_NEGATIVE],
75   [JSON_CHECK_NEGATIVE_C([$1 - C], [$2], [$3], [$4])
76    JSON_CHECK_NEGATIVE_PY([$1 - Python2], [$2], [$3], [$4],
77                           [$HAVE_PYTHON], [$PYTHON])
78    JSON_CHECK_NEGATIVE_PY([$1 - Python3], [$2], [$3], [$4],
79                           [$HAVE_PYTHON3], [$PYTHON3])])
80
81 AT_BANNER([JSON -- arrays])
82
83 JSON_CHECK_POSITIVE([empty array], [[ [   ] ]], [[[]]])
84 JSON_CHECK_POSITIVE([single-element array], [[ [ 1 ] ]], [[[1]]])
85 JSON_CHECK_POSITIVE([2-element array], [[ [ 1, 2 ] ]], [[[1,2]]])
86 JSON_CHECK_POSITIVE([many-element array],
87                     [[ [ 1, 2, 3, 4, 5 ] ]],
88                     [[[1,2,3,4,5]]])
89 JSON_CHECK_NEGATIVE([missing comma], [[ [ 1, 2, 3 4, 5 ] ]],
90                     [error: syntax error expecting '@:>@' or ','])
91 JSON_CHECK_NEGATIVE([trailing comma not allowed], 
92                     [[[1,2,]]], [error: syntax error expecting value])
93 JSON_CHECK_NEGATIVE([doubled comma not allowed], 
94                     [[[1,,2]]], [error: syntax error expecting value])
95
96 AT_BANNER([JSON -- strings])
97
98 JSON_CHECK_POSITIVE([empty string], [[[ "" ]]], [[[""]]])
99 JSON_CHECK_POSITIVE([1-character strings], 
100                     [[[ "a", "b", "c" ]]],
101                     [[["a","b","c"]]])
102 JSON_CHECK_POSITIVE([escape sequences], 
103   [[[ " \" \\ \/ \b \f \n \r \t" ]]],
104   [[[" \" \\ / \b \f \n \r \t"]]])
105 JSON_CHECK_POSITIVE([Unicode escape sequences], 
106   [[[ " \u0022 \u005c \u002F \u0008 \u000c \u000A \u000d \u0009" ]]],
107   [[[" \" \\ / \b \f \n \r \t"]]])
108 JSON_CHECK_POSITIVE_C([surrogate pairs - C],
109   [[["\ud834\udd1e"]]],
110   [[["𝄞"]]])
111 JSON_CHECK_POSITIVE_UCS4PY([surrogate pairs - Python],
112   [[["\ud834\udd1e"]]],
113   [[["𝄞"]]])
114 JSON_CHECK_NEGATIVE([a string by itself is not valid JSON], ["xxx"],
115                     [error: syntax error at beginning of input])
116 JSON_CHECK_NEGATIVE([end of line in quoted string],
117                     [[["xxx
118 "]]],
119                     [error: U+000A must be escaped in quoted string])
120 JSON_CHECK_NEGATIVE([formfeed in quoted string],
121                     [[["xxx\f"]]],
122                     [error: U+000C must be escaped in quoted string])
123 JSON_CHECK_NEGATIVE([bad escape in quoted string],
124                     [[["\x12"]]],
125                     [error: bad escape \x])
126 JSON_CHECK_NEGATIVE([\u must be followed by 4 hex digits (1)],
127                     [[["\u1x"]]],
128                     [error: quoted string ends within \u escape])
129 JSON_CHECK_NEGATIVE([\u must be followed by 4 hex digits (2)],
130                     [[["\u1xyz"]]],
131                     [error: malformed \u escape])
132 JSON_CHECK_NEGATIVE([isolated leading surrogate not allowed],
133                     [[["\ud834xxx"]]],
134                     [error: malformed escaped surrogate pair])
135 JSON_CHECK_NEGATIVE([surrogatess must paired properly],
136                     [[["\ud834\u1234"]]],
137                     [error: second half of escaped surrogate pair is not trailing surrogate])
138 JSON_CHECK_NEGATIVE([null bytes not allowed], 
139                     [[["\u0000"]]], 
140                     [error: null bytes not supported in quoted strings])
141 dnl Check for regression against a prior bug.
142 JSON_CHECK_POSITIVE([properly quoted backslash at end of string],
143   [[["\\"]]],
144   [[["\\"]]])
145 JSON_CHECK_NEGATIVE([stray backslash at end of string],
146   [[["abcd\"]]],
147   [error: unexpected end of input in quoted string])
148
149 AT_SETUP([end of input in quoted string - C])
150 AT_KEYWORDS([json negative])
151 AT_CHECK([printf '"xxx' | ovstest test-json -], [1],
152   [error: line 0, column 4, byte 4: unexpected end of input in quoted string
153 ])
154 AT_CLEANUP
155
156 AT_SETUP([end of input in quoted string - Python])
157 AT_KEYWORDS([json negative Python])
158 AT_SKIP_IF([test $HAVE_PYTHON = no])
159 AT_CHECK([printf '"xxx' > input
160 $PYTHON $srcdir/test-json.py input], [1],
161   [error: line 0, column 4, byte 4: unexpected end of input in quoted string
162 ])
163 AT_CLEANUP
164
165 AT_BANNER([JSON -- objects])
166
167 JSON_CHECK_POSITIVE([empty object], [[{ }]], [[{}]])
168 JSON_CHECK_POSITIVE([simple object],
169                     [[{"b": 2, "a": 1, "c": 3}]],
170                     [[{"a":1,"b":2,"c":3}]])
171 JSON_CHECK_NEGATIVE([bad value], [[{"a": }, "b": 2]], 
172                     [error: syntax error expecting value])
173 JSON_CHECK_NEGATIVE([missing colon], [[{"b": 2, "a" 1, "c": 3}]],
174                     [error: syntax error parsing object expecting ':'])
175 JSON_CHECK_NEGATIVE([missing comma], [[{"b": 2 "a" 1, "c": 3}]],
176                     [error: syntax error expecting '}' or ','])
177 JSON_CHECK_NEGATIVE([trailing comma not allowed],
178                     [[{"b": 2, "a": 1, "c": 3, }]],
179                     [[error: syntax error parsing object expecting string]])
180 JSON_CHECK_NEGATIVE([doubled comma not allowed],
181                     [[{"b": 2, "a": 1,, "c": 3}]],
182                     [[error: syntax error parsing object expecting string]])
183 JSON_CHECK_NEGATIVE([names must be strings],
184                     [[{1: 2}]],
185                     [[error: syntax error parsing object expecting string]])
186
187 AT_BANNER([JSON -- literal names])
188
189 JSON_CHECK_POSITIVE([null], [[[ null ]]], [[[null]]])
190 JSON_CHECK_POSITIVE([false], [[[ false ]]], [[[false]]])
191 JSON_CHECK_POSITIVE([true], [[[ true ]]], [[[true]]])
192 JSON_CHECK_NEGATIVE([a literal by itself is not valid JSON], [null],
193                     [error: syntax error at beginning of input])
194 JSON_CHECK_NEGATIVE([nullify is invalid], [[[ nullify ]]], 
195                     [error: invalid keyword 'nullify'])
196 JSON_CHECK_NEGATIVE([nubs is invalid], [[[ nubs ]]],
197                     [error: invalid keyword 'nubs'])
198 JSON_CHECK_NEGATIVE([xxx is invalid], [[[ xxx ]]], 
199                     [error: invalid keyword 'xxx'])
200
201 AT_BANNER([JSON -- numbers])
202
203 JSON_CHECK_POSITIVE(
204   [integers expressed as reals],
205   [[[1.0000000000,
206      2.00000000000000000000000000000000000,
207      2e5,
208      2.1234e4,
209      2.1230e3,
210      0e-10000,
211      0e10000]]],
212   [[[1,2,200000,21234,2123,0,0]]])
213 JSON_CHECK_POSITIVE(
214   [large integers], 
215   [[[9223372036854775807, -9223372036854775808]]],
216   [[[9223372036854775807,-9223372036854775808]]])
217 JSON_CHECK_POSITIVE(
218   [large integers expressed as reals], 
219   [[[9223372036854775807.0, -9223372036854775808.0,
220      92233720.36854775807e11, -9.223372036854775808e18]]],
221   [[[9223372036854775807,-9223372036854775808,9223372036854775807,-9223372036854775808]]])
222 # It seems likely that the following test will fail on some system that
223 # rounds slightly differently in arithmetic or in printf, but I'd like
224 # to keep it this way until we run into such a system.
225 JSON_CHECK_POSITIVE_C(
226   [C - large integers that overflow to reals],
227   [[[9223372036854775807000, -92233720368547758080000]]],
228   [[[9.22337203685478e+21,-9.22337203685478e+22]]])
229 JSON_CHECK_POSITIVE_PY23(
230   [large integers that overflow to reals],
231   [[[9223372036854775807000, -92233720368547758080000]]],
232   [[[9.223372036854776e+21,-9.223372036854776e+22]]])
233
234 JSON_CHECK_POSITIVE(
235   [negative zero],
236   [[[-0, -0.0, 1e-9999, -1e-9999]]],
237   [[[0,0,0,0]]])
238
239 JSON_CHECK_POSITIVE(
240   [reals], 
241   [[[0.0, 1.0, 2.0, 3.0, 3.5, 81.250]]],
242   [[[0,1,2,3,3.5,81.25]]])
243 JSON_CHECK_POSITIVE(
244   [scientific notation],
245   [[[1e3, 1E3, 2.5E2, 1e+3, 125e-3, 3.125e-2, 3125e-05, 1.525878906e-5]]],
246   [[[1000,1000,250,1000,0.125,0.03125,0.03125,1.525878906e-05]]])
247 # It seems likely that the following test will fail on some system that
248 # rounds slightly differently in arithmetic or in printf, but I'd like
249 # to keep it this way until we run into such a system.
250 JSON_CHECK_POSITIVE_C(
251   [C - +/- DBL_MAX],
252   [[[1.7976931348623157e+308, -1.7976931348623157e+308]]],
253   [[[1.79769313486232e+308,-1.79769313486232e+308]]])
254 JSON_CHECK_POSITIVE_PY23(
255   [+/- DBL_MAX],
256   [[[1.7976931348623157e+308, -1.7976931348623157e+308]]],
257   [[[1.7976931348623157e+308,-1.7976931348623157e+308]]])
258
259 JSON_CHECK_POSITIVE(
260   [negative reals], 
261   [[[-0, -1.0, -2.0, -3.0, -3.5, -8.1250]]],
262   [[[0,-1,-2,-3,-3.5,-8.125]]])
263 JSON_CHECK_POSITIVE(
264   [negative scientific notation],
265   [[[-1e3, -1E3, -2.5E2, -1e+3, -125e-3, -3.125e-2, -3125e-05, -1.525878906e-5]]],
266   [[[-1000,-1000,-250,-1000,-0.125,-0.03125,-0.03125,-1.525878906e-05]]])
267 JSON_CHECK_POSITIVE(
268   [1e-9999 underflows to 0],
269   [[[1e-9999]]],
270   [[[0]]])
271 JSON_CHECK_NEGATIVE([a number by itself is not valid JSON], [1],
272                     [error: syntax error at beginning of input])
273 JSON_CHECK_NEGATIVE(
274   [leading zeros not allowed],
275   [[[0123]]],
276   [error: leading zeros not allowed])
277 JSON_CHECK_NEGATIVE(
278   [1e9999 is too big],
279   [[[1e9999]]],
280   [error: number outside valid range])
281 JSON_CHECK_NEGATIVE(
282   [exponent bigger than INT_MAX],
283   [[[1e9999999999999999999]]],
284   [error: exponent outside valid range])
285 JSON_CHECK_NEGATIVE(
286   [decimal point must be followed by digit],
287   [[[1.]]],
288   [error: decimal point must be followed by digit])
289 JSON_CHECK_NEGATIVE(
290   [exponent must contain at least one digit (1)],
291   [[[1e]]],
292   [error: exponent must contain at least one digit])
293 JSON_CHECK_NEGATIVE(
294   [exponent must contain at least one digit (2)],
295   [[[1e+]]],
296   [error: exponent must contain at least one digit])
297 JSON_CHECK_NEGATIVE(
298   [exponent must contain at least one digit (3)],
299   [[[1e-]]],
300   [error: exponent must contain at least one digit])
301
302 AT_BANNER([JSON -- RFC 4627 examples])
303
304 JSON_CHECK_POSITIVE([RFC 4267 object example],
305 [[{
306    "Image": {
307        "Width":  800,
308        "Height": 600,
309        "Title":  "View from 15th Floor",
310        "Thumbnail": {
311            "Url":    "http://www.example.com/image/481989943",
312            "Height": 125,
313            "Width":  "100"
314        },
315        "IDs": [116, 943, 234, 38793]
316      }
317 }]],
318 [[{"Image":{"Height":600,"IDs":[116,943,234,38793],"Thumbnail":{"Height":125,"Url":"http://www.example.com/image/481989943","Width":"100"},"Title":"View from 15th Floor","Width":800}}]])
319
320 JSON_CHECK_POSITIVE([RFC 4267 array example],
321 [[[
322    {
323       "precision": "zip",
324       "Latitude":  37.7668,
325       "Longitude": -122.3959,
326       "Address":   "",
327       "City":      "SAN FRANCISCO",
328       "State":     "CA",
329       "Zip":       "94107",
330       "Country":   "US"
331    },
332    {
333       "precision": "zip",
334       "Latitude":  37.371991,
335       "Longitude": -122.026020,
336       "Address":   "",
337       "City":      "SUNNYVALE",
338       "State":     "CA",
339       "Zip":       "94085",
340       "Country":   "US"
341    }
342 ]]],
343 [[[{"Address":"","City":"SAN FRANCISCO","Country":"US","Latitude":37.7668,"Longitude":-122.3959,"State":"CA","Zip":"94107","precision":"zip"},{"Address":"","City":"SUNNYVALE","Country":"US","Latitude":37.371991,"Longitude":-122.02602,"State":"CA","Zip":"94085","precision":"zip"}]]])
344
345 AT_BANNER([JSON -- pathological cases])
346
347 JSON_CHECK_NEGATIVE([trailing garbage], [[[1]null]],
348                     [error: trailing garbage at end of input])
349 JSON_CHECK_NEGATIVE([formfeeds are not valid white space],
350                     [[[\f]]], [error: invalid character U+000c])
351 JSON_CHECK_NEGATIVE([';' is not a valid token],
352                     [;], [error: invalid character ';'])
353 JSON_CHECK_NEGATIVE([arrays nesting too deep],
354                     [m4_for([i], [0], [1002], [1], [@<:@])dnl
355                      m4_for([i], [0], [1002], [1], [@:>@])],
356                     [error: input exceeds maximum nesting depth 1000])
357 JSON_CHECK_NEGATIVE([objects nesting too deep],
358                     [m4_for([i], [0], [1002], [1], [{"x":])dnl
359                      m4_for([i], [0], [1002], [1], [}])],
360                     [error: input exceeds maximum nesting depth 1000])
361
362 AT_SETUP([input may not be empty])
363 AT_KEYWORDS([json negative])
364 AT_CHECK([ovstest test-json /dev/null], [1], [error: line 0, column 0, byte 0: empty input stream
365 ])
366 AT_CLEANUP
367
368 AT_BANNER([JSON -- multiple inputs])
369
370 JSON_CHECK_POSITIVE([multiple adjacent objects], [[{}{}{}]], [[{}
371 {}
372 {}]],
373   [--multiple])
374
375 JSON_CHECK_POSITIVE([multiple space-separated objects], [[{}  {}  {}]], [[{}
376 {}
377 {}]],
378   [--multiple])
379
380 JSON_CHECK_POSITIVE([multiple objects on separate lines], [[{}
381 {}
382 {}]], [[{}
383 {}
384 {}]],
385   [--multiple])
386
387 JSON_CHECK_POSITIVE([multiple objects and arrays], [[{}[]{}[]]], [[{}
388 []
389 {}
390 []]],
391   [--multiple])
392
393 JSON_CHECK_NEGATIVE([garbage between multiple objects], [[{}x{}]], [[{}
394 error: invalid keyword 'x'
395 {}]], [--multiple])
396
397 JSON_CHECK_NEGATIVE([garbage after multiple objects], [[{}{}x]], [[{}
398 {}
399 error: invalid keyword 'x']], [--multiple])