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)