1*4947cdc7SCole Faust# Tests of json module. 2*4947cdc7SCole Faust 3*4947cdc7SCole Faustload("assert.star", "assert") 4*4947cdc7SCole Faustload("json.star", "json") 5*4947cdc7SCole Faust 6*4947cdc7SCole Faustassert.eq(dir(json), ["decode", "encode", "indent"]) 7*4947cdc7SCole Faust 8*4947cdc7SCole Faust# Some of these cases were inspired by github.com/nst/JSONTestSuite. 9*4947cdc7SCole Faust 10*4947cdc7SCole Faust## json.encode 11*4947cdc7SCole Faust 12*4947cdc7SCole Faustassert.eq(json.encode(None), "null") 13*4947cdc7SCole Faustassert.eq(json.encode(True), "true") 14*4947cdc7SCole Faustassert.eq(json.encode(False), "false") 15*4947cdc7SCole Faustassert.eq(json.encode(-123), "-123") 16*4947cdc7SCole Faustassert.eq(json.encode(12345*12345*12345*12345*12345*12345), "3539537889086624823140625") 17*4947cdc7SCole Faustassert.eq(json.encode(float(12345*12345*12345*12345*12345*12345)), "3.539537889086625e+24") 18*4947cdc7SCole Faustassert.eq(json.encode(12.345e67), "1.2345e+68") 19*4947cdc7SCole Faustassert.eq(json.encode("hello"), '"hello"') 20*4947cdc7SCole Faustassert.eq(json.encode([1, 2, 3]), "[1,2,3]") 21*4947cdc7SCole Faustassert.eq(json.encode((1, 2, 3)), "[1,2,3]") 22*4947cdc7SCole Faustassert.eq(json.encode(range(3)), "[0,1,2]") # a built-in iterable 23*4947cdc7SCole Faustassert.eq(json.encode(dict(x = 1, y = "two")), '{"x":1,"y":"two"}') 24*4947cdc7SCole Faustassert.eq(json.encode(dict(y = "two", x = 1)), '{"x":1,"y":"two"}') # key, not insertion, order 25*4947cdc7SCole Faustassert.eq(json.encode(struct(x = 1, y = "two")), '{"x":1,"y":"two"}') # a user-defined HasAttrs 26*4947cdc7SCole Faustassert.eq(json.encode(""[:1]), '"\\ufffd"') # invalid UTF-8 -> replacement char 27*4947cdc7SCole Faust 28*4947cdc7SCole Faustdef encode_error(expr, error): 29*4947cdc7SCole Faust assert.fails(lambda: json.encode(expr), error) 30*4947cdc7SCole Faust 31*4947cdc7SCole Faustencode_error(float("NaN"), "json.encode: cannot encode non-finite float nan") 32*4947cdc7SCole Faustencode_error({1: "two"}, "dict has int key, want string") 33*4947cdc7SCole Faustencode_error(len, "cannot encode builtin_function_or_method as JSON") 34*4947cdc7SCole Faustencode_error(struct(x=[1, {"x": len}]), # nested failure 35*4947cdc7SCole Faust 'in field .x: at list index 1: in dict key "x": cannot encode...') 36*4947cdc7SCole Faustencode_error(struct(x=[1, {"x": len}]), # nested failure 37*4947cdc7SCole Faust 'in field .x: at list index 1: in dict key "x": cannot encode...') 38*4947cdc7SCole Faustencode_error({1: 2}, 'dict has int key, want string') 39*4947cdc7SCole Faust 40*4947cdc7SCole Faust## json.decode 41*4947cdc7SCole Faust 42*4947cdc7SCole Faustassert.eq(json.decode("null"), None) 43*4947cdc7SCole Faustassert.eq(json.decode("true"), True) 44*4947cdc7SCole Faustassert.eq(json.decode("false"), False) 45*4947cdc7SCole Faustassert.eq(json.decode("-123"), -123) 46*4947cdc7SCole Faustassert.eq(json.decode("-0"), -0) 47*4947cdc7SCole Faustassert.eq(json.decode("3539537889086624823140625"), 3539537889086624823140625) 48*4947cdc7SCole Faustassert.eq(json.decode("3539537889086624823140625.0"), float(3539537889086624823140625)) 49*4947cdc7SCole Faustassert.eq(json.decode("3.539537889086625e+24"), 3.539537889086625e+24) 50*4947cdc7SCole Faustassert.eq(json.decode("0e+1"), 0) 51*4947cdc7SCole Faustassert.eq(json.decode("-0.0"), -0.0) 52*4947cdc7SCole Faustassert.eq(json.decode( 53*4947cdc7SCole Faust "-0.000000000000000000000000000000000000000000000000000000000000000000000000000001"), 54*4947cdc7SCole Faust -0.000000000000000000000000000000000000000000000000000000000000000000000000000001) 55*4947cdc7SCole Faustassert.eq(json.decode('[]'), []) 56*4947cdc7SCole Faustassert.eq(json.decode('[1]'), [1]) 57*4947cdc7SCole Faustassert.eq(json.decode('[1,2,3]'), [1, 2, 3]) 58*4947cdc7SCole Faustassert.eq(json.decode('{"one": 1, "two": 2}'), dict(one=1, two=2)) 59*4947cdc7SCole Faustassert.eq(json.decode('{"foo\\u0000bar": 42}'), {"foo\x00bar": 42}) 60*4947cdc7SCole Faustassert.eq(json.decode('"\\ud83d\\ude39\\ud83d\\udc8d"'), "") 61*4947cdc7SCole Faustassert.eq(json.decode('"\\u0123"'), 'ģ') 62*4947cdc7SCole Faustassert.eq(json.decode('"\x7f"'), "\x7f") 63*4947cdc7SCole Faust 64*4947cdc7SCole Faustdef decode_error(expr, error): 65*4947cdc7SCole Faust assert.fails(lambda: json.decode(expr), error) 66*4947cdc7SCole Faust 67*4947cdc7SCole Faustdecode_error('truefalse', 68*4947cdc7SCole Faust "json.decode: at offset 4, unexpected character 'f' after value") 69*4947cdc7SCole Faust 70*4947cdc7SCole Faustdecode_error('"abc', "unclosed string literal") 71*4947cdc7SCole Faustdecode_error('"ab\\gc"', "invalid character 'g' in string escape code") 72*4947cdc7SCole Faustdecode_error("'abc'", "unexpected character '\\\\''") 73*4947cdc7SCole Faust 74*4947cdc7SCole Faustdecode_error("1.2.3", "invalid number: 1.2.3") 75*4947cdc7SCole Faustdecode_error("+1", "unexpected character '\\+'") 76*4947cdc7SCole Faustdecode_error("-abc", "invalid number: -") 77*4947cdc7SCole Faustdecode_error("-", "invalid number: -") 78*4947cdc7SCole Faustdecode_error("-00", "invalid number: -00") 79*4947cdc7SCole Faustdecode_error("00", "invalid number: 00") 80*4947cdc7SCole Faustdecode_error("--1", "invalid number: --1") 81*4947cdc7SCole Faustdecode_error("-+1", "invalid number: -\\+1") 82*4947cdc7SCole Faustdecode_error("1e1e1", "invalid number: 1e1e1") 83*4947cdc7SCole Faustdecode_error("0123", "invalid number: 0123") 84*4947cdc7SCole Faustdecode_error("000.123", "invalid number: 000.123") 85*4947cdc7SCole Faustdecode_error("-0123", "invalid number: -0123") 86*4947cdc7SCole Faustdecode_error("-000.123", "invalid number: -000.123") 87*4947cdc7SCole Faustdecode_error("0x123", "unexpected character 'x' after value") 88*4947cdc7SCole Faust 89*4947cdc7SCole Faustdecode_error('[1, 2 ', "unexpected end of file") 90*4947cdc7SCole Faustdecode_error('[1, 2, ', "unexpected end of file") 91*4947cdc7SCole Faustdecode_error('[1, 2, ]', "unexpected character ']'") 92*4947cdc7SCole Faustdecode_error('[1, 2, }', "unexpected character '}'") 93*4947cdc7SCole Faustdecode_error('[1, 2}', "got '}', want ',' or ']'") 94*4947cdc7SCole Faust 95*4947cdc7SCole Faustdecode_error('{"one": 1', "unexpected end of file") 96*4947cdc7SCole Faustdecode_error('{"one" 1', "after object key, got '1', want ':'") 97*4947cdc7SCole Faustdecode_error('{"one": 1 "two": 2', "in object, got '\"', want ',' or '}'") 98*4947cdc7SCole Faustdecode_error('{"one": 1,', "unexpected end of file") 99*4947cdc7SCole Faustdecode_error('{"one": 1, }', "unexpected character '}'") 100*4947cdc7SCole Faustdecode_error('{"one": 1]', "in object, got ']', want ',' or '}'") 101*4947cdc7SCole Faust 102*4947cdc7SCole Faustdef codec(x): 103*4947cdc7SCole Faust return json.decode(json.encode(x)) 104*4947cdc7SCole Faust 105*4947cdc7SCole Faust# string round-tripping 106*4947cdc7SCole Fauststrings = [ 107*4947cdc7SCole Faust "", # U+1F63F CRYING_CAT_FACE 108*4947cdc7SCole Faust "", # CAT FACE + ZERO WIDTH JOINER + BUST IN SILHOUETTE 109*4947cdc7SCole Faust] 110*4947cdc7SCole Faustassert.eq(codec(strings), strings) 111*4947cdc7SCole Faust 112*4947cdc7SCole Faust# codepoints is a string with every 16-bit code point. 113*4947cdc7SCole Faustcodepoints = ''.join(['%c' % c for c in range(65536)]) 114*4947cdc7SCole Faustassert.eq(codec(codepoints), codepoints) 115*4947cdc7SCole Faust 116*4947cdc7SCole Faust# number round-tripping 117*4947cdc7SCole Faustnumbers = [ 118*4947cdc7SCole Faust 0, 1, -1, +1, 1.23e45, -1.23e-45, 119*4947cdc7SCole Faust 3539537889086624823140625, 120*4947cdc7SCole Faust float(3539537889086624823140625), 121*4947cdc7SCole Faust] 122*4947cdc7SCole Faustassert.eq(codec(numbers), numbers) 123*4947cdc7SCole Faust 124*4947cdc7SCole Faust## json.indent 125*4947cdc7SCole Faust 126*4947cdc7SCole Fausts = json.encode(dict(x = 1, y = ["one", "two"])) 127*4947cdc7SCole Faust 128*4947cdc7SCole Faustassert.eq(json.indent(s), '''{ 129*4947cdc7SCole Faust "x": 1, 130*4947cdc7SCole Faust "y": [ 131*4947cdc7SCole Faust "one", 132*4947cdc7SCole Faust "two" 133*4947cdc7SCole Faust ] 134*4947cdc7SCole Faust}''') 135*4947cdc7SCole Faust 136*4947cdc7SCole Faustassert.eq(json.decode(json.indent(s)), {"x": 1, "y": ["one", "two"]}) 137*4947cdc7SCole Faust 138*4947cdc7SCole Faustassert.eq(json.indent(s, prefix='¶', indent='–––'), '''{ 139*4947cdc7SCole Faust¶–––"x": 1, 140*4947cdc7SCole Faust¶–––"y": [ 141*4947cdc7SCole Faust¶––––––"one", 142*4947cdc7SCole Faust¶––––––"two" 143*4947cdc7SCole Faust¶–––] 144*4947cdc7SCole Faust¶}''') 145*4947cdc7SCole Faust 146*4947cdc7SCole Faustassert.fails(lambda: json.indent("!@#$%^& this is not json"), 'invalid character') 147*4947cdc7SCole Faust--- 148