neovim

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

decode_spec.lua (5836B)


      1 local t = require('test.unit.testutil')
      2 local itp = t.gen_itp(it)
      3 
      4 local cimport = t.cimport
      5 local eq = t.eq
      6 local neq = t.neq
      7 local ffi = t.ffi
      8 
      9 local decode = cimport(
     10  './src/nvim/eval/decode.h',
     11  './src/nvim/eval/typval.h',
     12  './src/nvim/globals.h',
     13  './src/nvim/memory.h',
     14  './src/nvim/message.h'
     15 )
     16 
     17 describe('json_decode_string()', function()
     18  local char = function(c)
     19    return ffi.gc(decode.xmemdup(c, 1), decode.xfree)
     20  end
     21 
     22  itp('does not overflow when running with `n…`, `t…`, `f…`', function()
     23    local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
     24    decode.emsg_silent = 1
     25    -- This will not crash, but if `len` argument will be ignored it will parse
     26    -- `null` as `null` and if not it will parse `null` as `n`.
     27    eq(0, decode.json_decode_string('null', 1, rettv))
     28    eq(decode.VAR_UNKNOWN, rettv.v_type)
     29    eq(0, decode.json_decode_string('true', 1, rettv))
     30    eq(decode.VAR_UNKNOWN, rettv.v_type)
     31    eq(0, decode.json_decode_string('false', 1, rettv))
     32    eq(decode.VAR_UNKNOWN, rettv.v_type)
     33    eq(0, decode.json_decode_string('null', 2, rettv))
     34    eq(decode.VAR_UNKNOWN, rettv.v_type)
     35    eq(0, decode.json_decode_string('true', 2, rettv))
     36    eq(decode.VAR_UNKNOWN, rettv.v_type)
     37    eq(0, decode.json_decode_string('false', 2, rettv))
     38    eq(decode.VAR_UNKNOWN, rettv.v_type)
     39    eq(0, decode.json_decode_string('null', 3, rettv))
     40    eq(decode.VAR_UNKNOWN, rettv.v_type)
     41    eq(0, decode.json_decode_string('true', 3, rettv))
     42    eq(decode.VAR_UNKNOWN, rettv.v_type)
     43    eq(0, decode.json_decode_string('false', 3, rettv))
     44    eq(decode.VAR_UNKNOWN, rettv.v_type)
     45    eq(0, decode.json_decode_string('false', 4, rettv))
     46    eq(decode.VAR_UNKNOWN, rettv.v_type)
     47  end)
     48 
     49  itp('does not overflow and crash when running with `n`, `t`, `f`', function()
     50    local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
     51    decode.emsg_silent = 1
     52    eq(0, decode.json_decode_string(char('n'), 1, rettv))
     53    eq(decode.VAR_UNKNOWN, rettv.v_type)
     54    eq(0, decode.json_decode_string(char('t'), 1, rettv))
     55    eq(decode.VAR_UNKNOWN, rettv.v_type)
     56    eq(0, decode.json_decode_string(char('f'), 1, rettv))
     57    eq(decode.VAR_UNKNOWN, rettv.v_type)
     58  end)
     59 
     60  itp('does not overflow when running with `"…`', function()
     61    local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
     62    decode.emsg_silent = 1
     63    eq(0, decode.json_decode_string('"t"', 2, rettv))
     64    eq(decode.VAR_UNKNOWN, rettv.v_type)
     65    eq(0, decode.json_decode_string('""', 1, rettv))
     66    eq(decode.VAR_UNKNOWN, rettv.v_type)
     67  end)
     68 
     69  local check_failure = function(s, len, msg)
     70    local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
     71    eq(0, decode.json_decode_string(s, len, rettv))
     72    eq(decode.VAR_UNKNOWN, rettv.v_type)
     73    neq(nil, decode.msg_hist_last)
     74    eq(msg, ffi.string(decode.msg_hist_last.msg.items[0].text.data))
     75  end
     76 
     77  itp('does not overflow in error messages', function()
     78    collectgarbage('restart')
     79    check_failure(']test', 1, 'E474: No container to close: ]')
     80    check_failure('[}test', 2, 'E474: Closing list with curly bracket: }')
     81    check_failure('{]test', 2, 'E474: Closing dictionary with square bracket: ]')
     82    check_failure('[1,]test', 4, 'E474: Trailing comma: ]')
     83    check_failure('{"1":}test', 6, 'E474: Expected value after colon: }')
     84    check_failure('{"1"}test', 5, 'E474: Expected value: }')
     85    check_failure(',test', 1, 'E474: Comma not inside container: ,')
     86    check_failure('[1,,1]test', 6, 'E474: Duplicate comma: ,1]')
     87    check_failure('{"1":,}test', 7, 'E474: Comma after colon: ,}')
     88    check_failure('{"1",}test', 6, 'E474: Using comma in place of colon: ,}')
     89    check_failure('{,}test', 3, 'E474: Leading comma: ,}')
     90    check_failure('[,]test', 3, 'E474: Leading comma: ,]')
     91    check_failure(':test', 1, 'E474: Colon not inside container: :')
     92    check_failure('[:]test', 3, 'E474: Using colon not in dictionary: :]')
     93    check_failure('{:}test', 3, 'E474: Unexpected colon: :}')
     94    check_failure('{"1"::1}test', 8, 'E474: Duplicate colon: :1}')
     95    check_failure('ntest', 1, 'E474: Expected null: n')
     96    check_failure('ttest', 1, 'E474: Expected true: t')
     97    check_failure('ftest', 1, 'E474: Expected false: f')
     98    check_failure('"\\test', 2, 'E474: Unfinished escape sequence: "\\')
     99    check_failure('"\\u"test', 4, 'E474: Unfinished unicode escape sequence: "\\u"')
    100    check_failure('"\\uXXXX"est', 8, 'E474: Expected four hex digits after \\u: \\uXXXX"')
    101    check_failure('"\\?"test', 4, 'E474: Unknown escape sequence: \\?"')
    102    check_failure(
    103      '"\t"test',
    104      3,
    105      'E474: ASCII control characters cannot be present inside string: \t"'
    106    )
    107    check_failure('"\194"test', 3, 'E474: Only UTF-8 strings allowed: \194"')
    108    check_failure(
    109      '"\252\144\128\128\128\128"test',
    110      8,
    111      'E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: \252\144\128\128\128\128"'
    112    )
    113    check_failure('"test', 1, 'E474: Expected string end: "')
    114    check_failure('-test', 1, 'E474: Missing number after minus sign: -')
    115    check_failure('-1.test', 3, 'E474: Missing number after decimal dot: -1.')
    116    check_failure('-1.0etest', 5, 'E474: Missing exponent: -1.0e')
    117    check_failure('?test', 1, 'E474: Unidentified byte: ?')
    118    check_failure('1?test', 2, 'E474: Trailing characters: ?')
    119    check_failure('[1test', 2, 'E474: Unexpected end of input: [1')
    120  end)
    121 
    122  itp('does not overflow with `-`', function()
    123    check_failure('-0', 1, 'E474: Missing number after minus sign: -')
    124  end)
    125 
    126  itp('does not overflow and crash when running with `"`', function()
    127    local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
    128    decode.emsg_silent = 1
    129    eq(0, decode.json_decode_string(char('"'), 1, rettv))
    130    eq(decode.VAR_UNKNOWN, rettv.v_type)
    131  end)
    132 end)