xref: /aosp_15_r20/external/starlark-go/starlark/testdata/json.star (revision 4947cdc739c985f6d86941e22894f5cefe7c9e9a)
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