aboutsummaryrefslogtreecommitdiff
path: root/starlark/testdata/json.star
blob: 7c7b316c27d4652237dd7a3e448058b43dc38a58 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# Tests of json module.

load("assert.star", "assert")
load("json.star", "json")

assert.eq(dir(json), ["decode", "encode", "indent"])

# Some of these cases were inspired by github.com/nst/JSONTestSuite.

## json.encode

assert.eq(json.encode(None), "null")
assert.eq(json.encode(True), "true")
assert.eq(json.encode(False), "false")
assert.eq(json.encode(-123), "-123")
assert.eq(json.encode(12345*12345*12345*12345*12345*12345), "3539537889086624823140625")
assert.eq(json.encode(float(12345*12345*12345*12345*12345*12345)), "3.539537889086625e+24")
assert.eq(json.encode(12.345e67), "1.2345e+68")
assert.eq(json.encode("hello"), '"hello"')
assert.eq(json.encode([1, 2, 3]), "[1,2,3]")
assert.eq(json.encode((1, 2, 3)), "[1,2,3]")
assert.eq(json.encode(range(3)), "[0,1,2]") # a built-in iterable
assert.eq(json.encode(dict(x = 1, y = "two")), '{"x":1,"y":"two"}')
assert.eq(json.encode(dict(y = "two", x = 1)), '{"x":1,"y":"two"}') # key, not insertion, order
assert.eq(json.encode(struct(x = 1, y = "two")), '{"x":1,"y":"two"}')  # a user-defined HasAttrs
assert.eq(json.encode("😹"[:1]), '"\\ufffd"') # invalid UTF-8 -> replacement char

def encode_error(expr, error):
    assert.fails(lambda: json.encode(expr), error)

encode_error(float("NaN"), "json.encode: cannot encode non-finite float nan")
encode_error({1: "two"}, "dict has int key, want string")
encode_error(len, "cannot encode builtin_function_or_method as JSON")
encode_error(struct(x=[1, {"x": len}]), # nested failure
             'in field .x: at list index 1: in dict key "x": cannot encode...')
encode_error(struct(x=[1, {"x": len}]), # nested failure
             'in field .x: at list index 1: in dict key "x": cannot encode...')
encode_error({1: 2}, 'dict has int key, want string')

## json.decode

assert.eq(json.decode("null"), None)
assert.eq(json.decode("true"), True)
assert.eq(json.decode("false"), False)
assert.eq(json.decode("-123"), -123)
assert.eq(json.decode("-0"), -0)
assert.eq(json.decode("3539537889086624823140625"), 3539537889086624823140625)
assert.eq(json.decode("3539537889086624823140625.0"), float(3539537889086624823140625))
assert.eq(json.decode("3.539537889086625e+24"), 3.539537889086625e+24)
assert.eq(json.decode("0e+1"), 0)
assert.eq(json.decode("-0.0"), -0.0)
assert.eq(json.decode(
    "-0.000000000000000000000000000000000000000000000000000000000000000000000000000001"),
    -0.000000000000000000000000000000000000000000000000000000000000000000000000000001)
assert.eq(json.decode('[]'), [])
assert.eq(json.decode('[1]'), [1])
assert.eq(json.decode('[1,2,3]'), [1, 2, 3])
assert.eq(json.decode('{"one": 1, "two": 2}'), dict(one=1, two=2))
assert.eq(json.decode('{"foo\\u0000bar": 42}'), {"foo\x00bar": 42})
assert.eq(json.decode('"\\ud83d\\ude39\\ud83d\\udc8d"'), "πŸ˜ΉπŸ’")
assert.eq(json.decode('"\\u0123"'), 'Δ£')
assert.eq(json.decode('"\x7f"'), "\x7f")

def decode_error(expr, error):
    assert.fails(lambda: json.decode(expr), error)

decode_error('truefalse',
             "json.decode: at offset 4, unexpected character 'f' after value")

decode_error('"abc', "unclosed string literal")
decode_error('"ab\\gc"', "invalid character 'g' in string escape code")
decode_error("'abc'", "unexpected character '\\\\''")

decode_error("1.2.3", "invalid number: 1.2.3")
decode_error("+1", "unexpected character '\\+'")
decode_error("-abc", "invalid number: -")
decode_error("-", "invalid number: -")
decode_error("-00", "invalid number: -00")
decode_error("00", "invalid number: 00")
decode_error("--1", "invalid number: --1")
decode_error("-+1", "invalid number: -\\+1")
decode_error("1e1e1", "invalid number: 1e1e1")
decode_error("0123", "invalid number: 0123")
decode_error("000.123", "invalid number: 000.123")
decode_error("-0123", "invalid number: -0123")
decode_error("-000.123", "invalid number: -000.123")
decode_error("0x123", "unexpected character 'x' after value")

decode_error('[1, 2 ', "unexpected end of file")
decode_error('[1, 2, ', "unexpected end of file")
decode_error('[1, 2, ]', "unexpected character ']'")
decode_error('[1, 2, }', "unexpected character '}'")
decode_error('[1, 2}', "got '}', want ',' or ']'")

decode_error('{"one": 1', "unexpected end of file")
decode_error('{"one" 1', "after object key, got '1', want ':'")
decode_error('{"one": 1 "two": 2', "in object, got '\"', want ',' or '}'")
decode_error('{"one": 1,', "unexpected end of file")
decode_error('{"one": 1, }', "unexpected character '}'")
decode_error('{"one": 1]', "in object, got ']', want ',' or '}'")

def codec(x):
    return json.decode(json.encode(x))

# string round-tripping
strings = [
    "😿", # U+1F63F CRYING_CAT_FACE
    "πŸ±β€πŸ‘€", # CAT FACE + ZERO WIDTH JOINER + BUST IN SILHOUETTE
]
assert.eq(codec(strings), strings)

# codepoints is a string with every 16-bit code point.
codepoints = ''.join(['%c' % c for c in range(65536)])
assert.eq(codec(codepoints), codepoints)

# number round-tripping
numbers = [
    0, 1, -1, +1, 1.23e45, -1.23e-45,
    3539537889086624823140625,
    float(3539537889086624823140625),
]
assert.eq(codec(numbers), numbers)

## json.indent

s = json.encode(dict(x = 1, y = ["one", "two"]))

assert.eq(json.indent(s), '''{
	"x": 1,
	"y": [
		"one",
		"two"
	]
}''')

assert.eq(json.decode(json.indent(s)), {"x": 1, "y": ["one", "two"]})

assert.eq(json.indent(s, prefix='ΒΆ', indent='–––'), '''{
¢–––"x": 1,
¢–––"y": [
¢––––––"one",
¢––––––"two"
¢–––]
ΒΆ}''')

assert.fails(lambda: json.indent("!@#$%^& this is not json"), 'invalid character')
---