neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

json_spec.lua (12844B)


      1 local t = require('test.testutil')
      2 local n = require('test.functional.testnvim')()
      3 
      4 local clear = n.clear
      5 local exec_lua = n.exec_lua
      6 local eq = t.eq
      7 local pcall_err = t.pcall_err
      8 
      9 describe('vim.json.decode()', function()
     10  before_each(function()
     11    clear()
     12  end)
     13 
     14  it('parses null, true, false', function()
     15    eq(vim.NIL, exec_lua([[return vim.json.decode('null')]]))
     16    eq(true, exec_lua([[return vim.json.decode('true')]]))
     17    eq(false, exec_lua([[return vim.json.decode('false')]]))
     18  end)
     19 
     20  it('validation', function()
     21    eq(
     22      'Expected object key string but found invalid token at character 2',
     23      pcall_err(exec_lua, [[return vim.json.decode('{a:"b"}')]])
     24    )
     25  end)
     26 
     27  it('options', function()
     28    local jsonstr = '{"arr":[1,2,null],"bar":[3,7],"foo":{"a":"b"},"baz":null}'
     29    eq({
     30      arr = { 1, 2, vim.NIL },
     31      bar = { 3, 7 },
     32      baz = vim.NIL,
     33      foo = { a = 'b' },
     34    }, exec_lua([[return vim.json.decode(..., {})]], jsonstr))
     35    eq(
     36      {
     37        arr = { 1, 2, vim.NIL },
     38        bar = { 3, 7 },
     39        baz = vim.NIL,
     40        foo = { a = 'b' },
     41      },
     42      exec_lua(
     43        [[return vim.json.decode(..., { luanil = { array = false, object = false } })]],
     44        jsonstr
     45      )
     46    )
     47    eq({
     48      arr = { 1, 2, vim.NIL },
     49      bar = { 3, 7 },
     50      -- baz = nil,
     51      foo = { a = 'b' },
     52    }, exec_lua([[return vim.json.decode(..., { luanil = { object = true } })]], jsonstr))
     53    eq({
     54      arr = { 1, 2 },
     55      bar = { 3, 7 },
     56      baz = vim.NIL,
     57      foo = { a = 'b' },
     58    }, exec_lua([[return vim.json.decode(..., { luanil = { array = true } })]], jsonstr))
     59    eq(
     60      {
     61        arr = { 1, 2 },
     62        bar = { 3, 7 },
     63        -- baz = nil,
     64        foo = { a = 'b' },
     65      },
     66      exec_lua(
     67        [[return vim.json.decode(..., { luanil = { array = true, object = true } })]],
     68        jsonstr
     69      )
     70    )
     71  end)
     72 
     73  it('parses integer numbers', function()
     74    eq(100000, exec_lua([[return vim.json.decode('100000')]]))
     75    eq(-100000, exec_lua([[return vim.json.decode('-100000')]]))
     76    eq(100000, exec_lua([[return vim.json.decode('  100000  ')]]))
     77    eq(-100000, exec_lua([[return vim.json.decode('  -100000  ')]]))
     78    eq(0, exec_lua([[return vim.json.decode('0')]]))
     79    eq(0, exec_lua([[return vim.json.decode('-0')]]))
     80    eq(3053700806959403, exec_lua([[return vim.json.decode('3053700806959403')]]))
     81  end)
     82 
     83  it('parses floating-point numbers', function()
     84    -- This behavior differs from vim.fn.json_decode, which return '100000.0'
     85    eq('100000', exec_lua([[return tostring(vim.json.decode('100000.0'))]]))
     86    eq(100000.5, exec_lua([[return vim.json.decode('100000.5')]]))
     87    eq(-100000.5, exec_lua([[return vim.json.decode('-100000.5')]]))
     88    eq(-100000.5e50, exec_lua([[return vim.json.decode('-100000.5e50')]]))
     89    eq(100000.5e50, exec_lua([[return vim.json.decode('100000.5e50')]]))
     90    eq(100000.5e50, exec_lua([[return vim.json.decode('100000.5e+50')]]))
     91    eq(-100000.5e-50, exec_lua([[return vim.json.decode('-100000.5e-50')]]))
     92    eq(100000.5e-50, exec_lua([[return vim.json.decode('100000.5e-50')]]))
     93    eq(100000e-50, exec_lua([[return vim.json.decode('100000e-50')]]))
     94    eq(0.5, exec_lua([[return vim.json.decode('0.5')]]))
     95    eq(0.005, exec_lua([[return vim.json.decode('0.005')]]))
     96    eq(0.005, exec_lua([[return vim.json.decode('0.00500')]]))
     97    eq(0.5, exec_lua([[return vim.json.decode('0.00500e+002')]]))
     98    eq(0.00005, exec_lua([[return vim.json.decode('0.00500e-002')]]))
     99 
    100    eq(-0.0, exec_lua([[return vim.json.decode('-0.0')]]))
    101    eq(-0.0, exec_lua([[return vim.json.decode('-0.0e0')]]))
    102    eq(-0.0, exec_lua([[return vim.json.decode('-0.0e+0')]]))
    103    eq(-0.0, exec_lua([[return vim.json.decode('-0.0e-0')]]))
    104    eq(-0.0, exec_lua([[return vim.json.decode('-0e-0')]]))
    105    eq(-0.0, exec_lua([[return vim.json.decode('-0e-2')]]))
    106    eq(-0.0, exec_lua([[return vim.json.decode('-0e+2')]]))
    107 
    108    eq(0.0, exec_lua([[return vim.json.decode('0.0')]]))
    109    eq(0.0, exec_lua([[return vim.json.decode('0.0e0')]]))
    110    eq(0.0, exec_lua([[return vim.json.decode('0.0e+0')]]))
    111    eq(0.0, exec_lua([[return vim.json.decode('0.0e-0')]]))
    112    eq(0.0, exec_lua([[return vim.json.decode('0e-0')]]))
    113    eq(0.0, exec_lua([[return vim.json.decode('0e-2')]]))
    114    eq(0.0, exec_lua([[return vim.json.decode('0e+2')]]))
    115  end)
    116 
    117  it('parses containers', function()
    118    eq({ 1 }, exec_lua([[return vim.json.decode('[1]')]]))
    119    eq({ vim.NIL, 1 }, exec_lua([[return vim.json.decode('[null, 1]')]]))
    120    eq({ ['1'] = 2 }, exec_lua([[return vim.json.decode('{"1": 2}')]]))
    121    eq(
    122      { ['1'] = 2, ['3'] = { { ['4'] = { ['5'] = { {}, 1 } } } } },
    123      exec_lua([[return vim.json.decode('{"1": 2, "3": [{"4": {"5": [ [], 1]}}]}')]])
    124    )
    125    -- Empty string is a valid key. #20757
    126    eq({ [''] = 42 }, exec_lua([[return vim.json.decode('{"": 42}')]]))
    127  end)
    128 
    129  it('parses strings properly', function()
    130    eq('\n', exec_lua([=[return vim.json.decode([["\n"]])]=]))
    131    eq('', exec_lua([=[return vim.json.decode([[""]])]=]))
    132    eq('\\/"\t\b\n\r\f', exec_lua([=[return vim.json.decode([["\\\/\"\t\b\n\r\f"]])]=]))
    133    eq('/a', exec_lua([=[return vim.json.decode([["\/a"]])]=]))
    134    -- Unicode characters: 2-byte, 3-byte
    135    eq('«', exec_lua([=[return vim.json.decode([["«"]])]=]))
    136    eq('ફ', exec_lua([=[return vim.json.decode([["ફ"]])]=]))
    137  end)
    138 
    139  it('parses surrogate pairs properly', function()
    140    eq('\240\144\128\128', exec_lua([[return vim.json.decode('"\\uD800\\uDC00"')]]))
    141  end)
    142 
    143  it('accepts all spaces in every position where space may be put', function()
    144    local s =
    145      ' \t\n\r \t\r\n \n\t\r \n\r\t \r\t\n \r\n\t\t \n\r\t \r\n\t\n \r\t\n\r \t\r \n\t\r\n \n \t\r\n \r\t\n\t \r\n\t\r \n\r \t\n\r\t \r \t\n\r \n\t\r\t \n\r\t\n \r\n \t\r\n\t'
    146    local str = ('%s{%s"key"%s:%s[%s"val"%s,%s"val2"%s]%s,%s"key2"%s:%s1%s}%s'):gsub('%%s', s)
    147    eq({ key = { 'val', 'val2' }, key2 = 1 }, exec_lua([[return vim.json.decode(...)]], str))
    148  end)
    149 
    150  it('skip_comments', function()
    151    eq({}, exec_lua([[return vim.json.decode('{//comment\n}', { skip_comments = true })]]))
    152    eq({}, exec_lua([[return vim.json.decode('{//comment\r\n}', { skip_comments = true })]]))
    153    eq(
    154      'test // /* */ string',
    155      exec_lua(
    156        [[return vim.json.decode('"test // /* */ string"//comment', { skip_comments = true })]]
    157      )
    158    )
    159    eq(
    160      {},
    161      exec_lua([[return vim.json.decode('{/* A multi-line\ncomment*/}', { skip_comments = true })]])
    162    )
    163    eq(
    164      { a = 1 },
    165      exec_lua([[return vim.json.decode('{"a" /* Comment */: 1}', { skip_comments = true })]])
    166    )
    167    eq(
    168      { a = 1 },
    169      exec_lua([[return vim.json.decode('{"a": /* Comment */ 1}', { skip_comments = true })]])
    170    )
    171    eq({}, exec_lua([[return vim.json.decode('/*first*//*second*/{}', { skip_comments = true })]]))
    172    eq(
    173      'Expected the end but found unclosed multi-line comment at character 13',
    174      pcall_err(exec_lua, [[return vim.json.decode('{}/*Unclosed', { skip_comments = true })]])
    175    )
    176    eq(
    177      'Expected comma or object end but found T_INTEGER at character 12',
    178      pcall_err(exec_lua, [[return vim.json.decode('{"a":1/*x*/0}', { skip_comments = true })]])
    179    )
    180  end)
    181 end)
    182 
    183 describe('vim.json.encode()', function()
    184  before_each(function()
    185    clear()
    186  end)
    187 
    188  it('escape_slash', function()
    189    -- With slash
    190    eq('"Test\\/"', exec_lua([[return vim.json.encode('Test/', { escape_slash = true })]]))
    191    eq(
    192      'Test/',
    193      exec_lua([[return vim.json.decode(vim.json.encode('Test/', { escape_slash = true }))]])
    194    )
    195 
    196    -- Without slash
    197    eq('"Test/"', exec_lua([[return vim.json.encode('Test/')]]))
    198    eq('"Test/"', exec_lua([[return vim.json.encode('Test/', {})]]))
    199    eq('"Test/"', exec_lua([[return vim.json.encode('Test/', { _invalid = true })]]))
    200    eq('"Test/"', exec_lua([[return vim.json.encode('Test/', { escape_slash = false })]]))
    201    eq(
    202      '"Test/"',
    203      exec_lua([[return vim.json.encode('Test/', { _invalid = true, escape_slash = false })]])
    204    )
    205    eq(
    206      'Test/',
    207      exec_lua([[return vim.json.decode(vim.json.encode('Test/', { escape_slash = false }))]])
    208    )
    209 
    210    -- Checks for for global side-effects
    211    eq(
    212      '"Test/"',
    213      exec_lua([[
    214        vim.json.encode('Test/', { escape_slash = true })
    215        return vim.json.encode('Test/')
    216      ]])
    217    )
    218    eq(
    219      '"Test\\/"',
    220      exec_lua([[
    221        vim.json.encode('Test/', { escape_slash = false })
    222        return vim.json.encode('Test/', { escape_slash = true })
    223      ]])
    224    )
    225  end)
    226 
    227  it('indent', function()
    228    eq('"Test"', exec_lua([[return vim.json.encode('Test', { indent = "  " })]]))
    229    eq('[]', exec_lua([[return vim.json.encode({}, { indent = "  " })]]))
    230    eq('{}', exec_lua([[return vim.json.encode(vim.empty_dict(), { indent = "  " })]]))
    231    eq(
    232      '[\n  {\n    "a": "a"\n  },\n  {\n    "b": "b"\n  }\n]',
    233      exec_lua([[return vim.json.encode({ { a = "a" }, { b = "b" } }, { indent = "  " })]])
    234    )
    235    eq(
    236      '{\n  "a": {\n    "b": 1\n  }\n}',
    237      exec_lua([[return vim.json.encode({ a = { b = 1 } }, { indent = "  " })]])
    238    )
    239    eq(
    240      '[{"a":"a"},{"b":"b"}]',
    241      exec_lua([[return vim.json.encode({ { a = "a" }, { b = "b" } }, { indent = "" })]])
    242    )
    243    eq(
    244      '[\n  [\n    1,\n    2\n  ],\n  [\n    3,\n    4\n  ]\n]',
    245      exec_lua([[return vim.json.encode({ { 1, 2 }, { 3, 4 } }, { indent = "  " })]])
    246    )
    247    eq(
    248      '{\nabc"a": {\nabcabc"b": 1\nabc}\n}',
    249      exec_lua([[return vim.json.encode({ a = { b = 1 } }, { indent = "abc" })]])
    250    )
    251 
    252    -- Checks for for global side-effects
    253    eq(
    254      '[{"a":"a"},{"b":"b"}]',
    255      exec_lua([[
    256        vim.json.encode('', { indent = "  " })
    257        return vim.json.encode({ { a = "a" }, { b = "b" } })
    258      ]])
    259    )
    260  end)
    261 
    262  it('sort_keys', function()
    263    eq('"string"', exec_lua([[return vim.json.encode('string', { sort_keys = true })]]))
    264    eq('[]', exec_lua([[return vim.json.encode({}, { sort_keys = true })]]))
    265    eq('{}', exec_lua([[return vim.json.encode(vim.empty_dict(), { sort_keys = true })]]))
    266    eq(
    267      '{"$":0,"%":0,"1":0,"4":0,"a":0,"ab":0,"b":0}',
    268      exec_lua(
    269        [[return vim.json.encode({ a = 0, b = 0, ab = 0, [1] = 0, ["$"] = 0, [4] = 0, ["%"] = 0 }, { sort_keys = true })]]
    270      )
    271    )
    272    eq(
    273      '{"aa":1,"ab":2,"ba":3,"bc":4,"cc":5}',
    274      exec_lua(
    275        [[return vim.json.encode({ aa = 1, ba = 3, ab = 2, bc = 4, cc = 5 }, { sort_keys = true })]]
    276      )
    277    )
    278    eq(
    279      '{"a":{"a":1,"b":2,"c":3},"b":{"a":{"a":0,"b":0},"b":{"a":0,"b":0}},"c":0}',
    280      exec_lua(
    281        [[return vim.json.encode({ a = { b = 2, a = 1, c = 3 }, c = 0, b = { b = { a = 0, b = 0 }, a = { a = 0, b = 0 } } }, { sort_keys = true })]]
    282      )
    283    )
    284    eq(
    285      '[{"1":0,"4":0,"a":0,"b":0},{"10":0,"5":0,"f":0,"x":0},{"-2":0,"2":0,"c":0,"d":0}]',
    286      exec_lua([[return vim.json.encode({
    287        { a = 0, [1] = 0, [4] = 0, b = 0 },
    288        { f = 0, [5] = 0, [10] = 0, x = 0 },
    289        { c = 0, [-2] = 0, [2] = 0, d = 0 },
    290      }, { sort_keys = true })]])
    291    )
    292    eq(
    293      '{"a":2,"ß":3,"é":1,"中":4}',
    294      exec_lua(
    295        [[return vim.json.encode({ ["é"] = 1, ["a"] = 2, ["ß"] = 3, ["中"] = 4 }, { sort_keys = true })]]
    296      )
    297    )
    298  end)
    299 
    300  it('dumps strings', function()
    301    eq('"Test"', exec_lua([[return vim.json.encode('Test')]]))
    302    eq('""', exec_lua([[return vim.json.encode('')]]))
    303    eq('"\\t"', exec_lua([[return vim.json.encode('\t')]]))
    304    eq('"\\n"', exec_lua([[return vim.json.encode('\n')]]))
    305    -- vim.fn.json_encode return \\u001B
    306    eq('"\\u001b"', exec_lua([[return vim.json.encode('\27')]]))
    307    eq('"þÿþ"', exec_lua([[return vim.json.encode('þÿþ')]]))
    308  end)
    309 
    310  it('dumps numbers', function()
    311    eq('0', exec_lua([[return vim.json.encode(0)]]))
    312    eq('10', exec_lua([[return vim.json.encode(10)]]))
    313    eq('-10', exec_lua([[return vim.json.encode(-10)]]))
    314  end)
    315 
    316  it('dumps floats', function()
    317    eq('3053700806959403', exec_lua([[return vim.json.encode(3053700806959403)]]))
    318    eq('10.5', exec_lua([[return vim.json.encode(10.5)]]))
    319    eq('-10.5', exec_lua([[return vim.json.encode(-10.5)]]))
    320    eq('-1e-05', exec_lua([[return vim.json.encode(-1e-5)]]))
    321  end)
    322 
    323  it('dumps lists', function()
    324    eq('[]', exec_lua([[return vim.json.encode({})]]))
    325    eq('[[]]', exec_lua([[return vim.json.encode({{}})]]))
    326    eq('[[],[]]', exec_lua([[return vim.json.encode({{}, {}})]]))
    327  end)
    328 
    329  it('dumps dictionaries', function()
    330    eq('{}', exec_lua([[return vim.json.encode(vim.empty_dict())]]))
    331    eq('{"d":[]}', exec_lua([[return vim.json.encode({d={}})]]))
    332    -- Empty string is a valid key. #20757
    333    eq('{"":42}', exec_lua([[return vim.json.encode({['']=42})]]))
    334  end)
    335 
    336  it('dumps vim.NIL', function()
    337    eq('null', exec_lua([[return vim.json.encode(vim.NIL)]]))
    338  end)
    339 end)