File: json.test.lua

package info (click to toggle)
tarantool 2.6.0-1.4
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 85,412 kB
  • sloc: ansic: 513,775; cpp: 69,493; sh: 25,650; python: 19,190; perl: 14,973; makefile: 4,178; yacc: 1,329; sql: 1,074; pascal: 620; ruby: 190; awk: 18; lisp: 7
file content (157 lines) | stat: -rwxr-xr-x 6,803 bytes parent folder | download | duplicates (3)
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
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/env tarantool

package.path = "lua/?.lua;"..package.path

local ffi = require('ffi')
local tap = require('tap')
local common = require('serializer_test')

local function is_map(s)
    return string.sub(s, 1, 1) == "{"
end

local function is_array(s)
    return string.sub(s, 1, 1) == "["
end

local function test_misc(test, s)
    test:plan(2)
    test:iscdata(s.NULL, 'void *', '.NULL is cdata')
    test:ok(s.NULL == nil, '.NULL == nil')
end

tap.test("json", function(test)
    local serializer = require('json')
    test:plan(40)

    test:test("unsigned", common.test_unsigned, serializer)
    test:test("signed", common.test_signed, serializer)
    test:test("double", common.test_double, serializer)
    test:test("boolean", common.test_boolean, serializer)
    test:test("string", common.test_string, serializer)
    test:test("nil", common.test_nil, serializer)
    test:test("table", common.test_table, serializer, is_array, is_map)
    test:test("ucdata", common.test_ucdata, serializer)
    test:test("depth", common.test_depth, serializer)
    test:test("misc", test_misc, serializer)

    --
    -- gh-2888: Check the possibility of using options in encode()/decode().
    --
    local orig_encode_deep_as_nil = serializer.cfg.encode_deep_as_nil
    local orig_encode_max_depth = serializer.cfg.encode_max_depth
    local sub = {a = 1, { b = {c = 1, d = {e = 1}}}}
    serializer.cfg({encode_max_depth = 1, encode_deep_as_nil = true})
    test:ok(serializer.encode(sub) == '{"1":null,"a":1}',
            'depth of encoding is 1 with .cfg')
    serializer.cfg({encode_max_depth = orig_encode_max_depth})
    test:ok(serializer.encode(sub, {encode_max_depth = 1}) == '{"1":null,"a":1}',
            'depth of encoding is 1 with .encode')
    test:is(serializer.cfg.encode_max_depth, orig_encode_max_depth,
            'global option remains unchanged')

    local orig_encode_invalid_numbers = serializer.cfg.encode_invalid_numbers
    local nan = 1/0
    serializer.cfg({encode_invalid_numbers = false})
    test:ok(not pcall(serializer.encode, {a = nan}),
            'expected error with NaN encoding with .cfg')
    serializer.cfg({encode_invalid_numbers = orig_encode_invalid_numbers})
    test:ok(not pcall(serializer.encode, {a = nan},
                      {encode_invalid_numbers = false}),
            'expected error with NaN encoding with .encode')
    test:is(serializer.cfg.encode_invalid_numbers, orig_encode_invalid_numbers,
            'global option remains unchanged')

    local orig_encode_number_precision = serializer.cfg.encode_number_precision
    local number = 0.12345
    serializer.cfg({encode_number_precision = 3})
    test:ok(serializer.encode({a = number}) == '{"a":0.123}',
            'precision is 3')
    serializer.cfg({encode_number_precision = orig_encode_number_precision})
    test:ok(serializer.encode({a = number}, {encode_number_precision = 3}) ==
            '{"a":0.123}', 'precision is 3')
    test:is(serializer.cfg.encode_number_precision, orig_encode_number_precision,
            'global option remains unchanged')

    local orig_decode_invalid_numbers = serializer.cfg.decode_invalid_numbers
    serializer.cfg({decode_invalid_numbers = false})
    test:ok(not pcall(serializer.decode, '{"a":inf}'),
            'expected error with NaN decoding with .cfg')
    serializer.cfg({decode_invalid_numbers = orig_decode_invalid_numbers})
    test:ok(not pcall(serializer.decode, '{"a":inf}',
                      {decode_invalid_numbers = false}),
            'expected error with NaN decoding with .decode')
    test:is(serializer.cfg.decode_invalid_numbers, orig_decode_invalid_numbers,
            'global option remains unchanged')

    local orig_decode_max_depth = serializer.cfg.decode_max_depth
    serializer.cfg({decode_max_depth = 2})
    test:ok(not pcall(serializer.decode, '{"1":{"b":{"c":1,"d":null}},"a":1}'),
            'error: too many nested data structures')
    serializer.cfg({decode_max_depth = orig_decode_max_depth})
    test:ok(not pcall(serializer.decode, '{"1":{"b":{"c":1,"d":null}},"a":1}',
                      {decode_max_depth = 2}),
            'error: too many nested data structures')
    test:is(serializer.cfg.decode_max_depth, orig_decode_max_depth,
            'global option remains unchanged')

    --
    -- gh-3514: fix parsing integers with exponent in json
    --
    test:is(serializer.decode('{"var":2.0e+3}')["var"], 2000)
    test:is(serializer.decode('{"var":2.0e+3}')["var"], 2000)
    test:is(serializer.decode('{"var":2.0e+3}')["var"], 2000)
    test:is(serializer.decode('{"var":2.0e+3}')["var"], 2000)

    --
    -- gh-4366: segmentation fault with recursive table
    --
    serializer.cfg({encode_max_depth = 2})
    local rec1 = {}
    rec1[1] = rec1
    test:is(serializer.encode(rec1), '[[null]]')
    local rec2 = {}
    rec2['x'] = rec2
    test:is(serializer.encode(rec2), '{"x":{"x":null}}')
    local rec3 = {}
    rec3[1] = rec3
    rec3[2] = rec3
    test:is(serializer.encode(rec3), '[[null,null],[null,null]]')
    local rec4 = {}
    rec4['a'] = rec4
    rec4['b'] = rec4
    test:is(serializer.encode(rec4),
            '{"a":{"a":null,"b":null},"b":{"a":null,"b":null}}')
    serializer.cfg({encode_max_depth = orig_encode_max_depth,
                    encode_deep_as_nil = orig_encode_deep_as_nil})

    --
    -- gh-3316: Make sure that line number is printed in the error
    -- message.
    --
    local _, err_msg
    _, err_msg = pcall(serializer.decode, 'a{"hello": \n"world"}')
    test:ok(string.find(err_msg, 'line 1 at character 1') ~= nil,
            'mistake on first line')
    _, err_msg = pcall(serializer.decode, '{"hello": \n"world"a}')
    test:ok(string.find(err_msg, 'line 2 at character 8') ~= nil,
            'mistake on second line')
    _, err_msg = pcall(serializer.decode, '\n\n\n\n{"hello": "world"a}')
    test:ok(string.find(err_msg, 'line 5 at character 18') ~= nil,
            'mistake on fifth line')
    serializer.cfg{decode_max_depth = 1}
    _, err_msg = pcall(serializer.decode,
                       '{"hello": {"world": {"hello": "world"}}}')
    test:ok(string.find(err_msg, 'line 1 at character 11') ~= nil,
            'mistake on first line')
    _, err_msg = pcall(serializer.decode,
                       '{"hello": \n{"world": {"hello": "world"}}}')
    test:ok(string.find(err_msg, 'line 2 at character 1') ~= nil,
            'mistake on second line')
    _, err_msg = pcall(serializer.decode, "{ 100: 200 }")
    test:ok(string.find(err_msg, 'line 1 at character 3') ~= nil,
            'mistake on first line')
    _, err_msg = pcall(serializer.decode, '{"hello": "world",\n 100: 200}')
    test:ok(string.find(err_msg, 'line 2 at character 2') ~= nil,
            'mistake on second line')
end)