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