mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 11:58:17 +00:00
viml/executor: Directly generate typval_T values
Note: this will *still* crash when using API in cases similar to the one described in first commit. Just it needs different code to reproduce.
This commit is contained in:
143
test/functional/lua_spec.lua
Normal file
143
test/functional/lua_spec.lua
Normal file
@@ -0,0 +1,143 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local eq = helpers.eq
|
||||
local neq = helpers.neq
|
||||
local NIL = helpers.NIL
|
||||
local eval = helpers.eval
|
||||
local clear = helpers.clear
|
||||
local funcs = helpers.funcs
|
||||
local meths = helpers.meths
|
||||
local exc_exec = helpers.exc_exec
|
||||
local curbufmeths = helpers.curbufmeths
|
||||
|
||||
local function startswith(expected, actual)
|
||||
eq(expected, actual:sub(1, #expected))
|
||||
end
|
||||
|
||||
before_each(clear)
|
||||
|
||||
describe('luaeval() function', function()
|
||||
local nested_by_level = {}
|
||||
local nested = {}
|
||||
local nested_s = '{}'
|
||||
for i=1,100 do
|
||||
if i % 2 == 0 then
|
||||
nested = {nested}
|
||||
nested_s = '{' .. nested_s .. '}'
|
||||
else
|
||||
nested = {nested=nested}
|
||||
nested_s = '{nested=' .. nested_s .. '}'
|
||||
end
|
||||
nested_by_level[i] = {o=nested, s=nested_s}
|
||||
end
|
||||
|
||||
it('correctly evaluates scalars', function()
|
||||
eq(1, funcs.luaeval('1'))
|
||||
eq(0, eval('type(luaeval("1"))'))
|
||||
|
||||
eq(1.5, funcs.luaeval('1.5'))
|
||||
eq(5, eval('type(luaeval("1.5"))'))
|
||||
|
||||
eq("test", funcs.luaeval('"test"'))
|
||||
eq(1, eval('type(luaeval("\'test\'"))'))
|
||||
|
||||
eq('', funcs.luaeval('""'))
|
||||
eq({_TYPE={}, _VAL={'\n'}}, funcs.luaeval([['\0']]))
|
||||
eq({_TYPE={}, _VAL={'\n', '\n'}}, funcs.luaeval([['\0\n\0']]))
|
||||
eq(1, eval([[luaeval('"\0\n\0"')._TYPE is v:msgpack_types.binary]]))
|
||||
|
||||
eq(true, funcs.luaeval('true'))
|
||||
eq(false, funcs.luaeval('false'))
|
||||
eq(NIL, funcs.luaeval('nil'))
|
||||
end)
|
||||
|
||||
it('correctly evaluates containers', function()
|
||||
eq({}, funcs.luaeval('{}'))
|
||||
eq(3, eval('type(luaeval("{}"))'))
|
||||
|
||||
eq({test=1, foo=2}, funcs.luaeval('{test=1, foo=2}'))
|
||||
eq(4, eval('type(luaeval("{test=1, foo=2}"))'))
|
||||
|
||||
eq({4, 2}, funcs.luaeval('{4, 2}'))
|
||||
eq(3, eval('type(luaeval("{4, 2}"))'))
|
||||
|
||||
local level = 30
|
||||
eq(nested_by_level[level].o, funcs.luaeval(nested_by_level[level].s))
|
||||
|
||||
eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, {_TYPE={}, _VAL={'\n', '\n\n'}}}}},
|
||||
funcs.luaeval([[{['\0\n\0']='\0\n\0\0'}]]))
|
||||
eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._TYPE is v:msgpack_types.map]]))
|
||||
eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0]._TYPE is v:msgpack_types.string]]))
|
||||
eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][1]._TYPE is v:msgpack_types.binary]]))
|
||||
eq({nested={{_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, {_TYPE={}, _VAL={'\n', '\n\n'}}}}}}},
|
||||
funcs.luaeval([[{nested={{['\0\n\0']='\0\n\0\0'}}}]]))
|
||||
end)
|
||||
|
||||
it('correctly passes scalars as argument', function()
|
||||
eq(1, funcs.luaeval('_A', 1))
|
||||
eq(1.5, funcs.luaeval('_A', 1.5))
|
||||
eq('', funcs.luaeval('_A', ''))
|
||||
eq('test', funcs.luaeval('_A', 'test'))
|
||||
eq(NIL, funcs.luaeval('_A', NIL))
|
||||
eq(true, funcs.luaeval('_A', true))
|
||||
eq(false, funcs.luaeval('_A', false))
|
||||
end)
|
||||
|
||||
it('correctly passes containers as argument', function()
|
||||
eq({}, funcs.luaeval('_A', {}))
|
||||
eq({test=1}, funcs.luaeval('_A', {test=1}))
|
||||
eq({4, 2}, funcs.luaeval('_A', {4, 2}))
|
||||
local level = 28
|
||||
eq(nested_by_level[level].o, funcs.luaeval('_A', nested_by_level[level].o))
|
||||
end)
|
||||
|
||||
local function sp(typ, val)
|
||||
return ('{"_TYPE": v:msgpack_types.%s, "_VAL": %s}'):format(typ, val)
|
||||
end
|
||||
local function mapsp(...)
|
||||
local val = ''
|
||||
for i=1,(select('#', ...)/2) do
|
||||
val = ('%s[%s,%s],'):format(val, select(i * 2 - 1, ...),
|
||||
select(i * 2, ...))
|
||||
end
|
||||
return sp('map', '[' .. val .. ']')
|
||||
end
|
||||
local function luaevalarg(argexpr, expr)
|
||||
return eval(([=[
|
||||
[
|
||||
extend(g:, {'_ret': luaeval(%s, %s)})._ret,
|
||||
type(g:_ret)==type({})&&has_key(g:_ret, '_TYPE')
|
||||
? [
|
||||
get(keys(filter(copy(v:msgpack_types), 'v:val is g:_ret._TYPE')), 0,
|
||||
g:_ret._TYPE),
|
||||
get(g:_ret, '_VAL', g:_ret)
|
||||
]
|
||||
: [0, g:_ret]][1]
|
||||
]=]):format(expr or '"_A"', argexpr):gsub('\n', ''))
|
||||
end
|
||||
|
||||
it('correctly passes special dictionaries', function()
|
||||
eq({'binary', {'\n', '\n'}}, luaevalarg(sp('binary', '["\\n", "\\n"]')))
|
||||
eq({'binary', {'\n', '\n'}}, luaevalarg(sp('string', '["\\n", "\\n"]')))
|
||||
eq({0, true}, luaevalarg(sp('boolean', 1)))
|
||||
eq({0, false}, luaevalarg(sp('boolean', 0)))
|
||||
eq({0, NIL}, luaevalarg(sp('nil', 0)))
|
||||
eq({0, {[""]=""}}, luaevalarg(mapsp(sp('binary', '[""]'), '""')))
|
||||
eq({0, {[""]=""}}, luaevalarg(mapsp(sp('string', '[""]'), '""')))
|
||||
end)
|
||||
|
||||
it('issues an error in some cases', function()
|
||||
eq("Vim(call):E5100: Cannot convert given lua table: table should either have a sequence of positive integer keys or contain only string keys",
|
||||
exc_exec('call luaeval("{1, foo=2}")'))
|
||||
eq("Vim(call):E5101: Cannot convert given lua type",
|
||||
exc_exec('call luaeval("vim.api.buffer_get_line_slice")'))
|
||||
startswith("Vim(call):E5107: Error while creating lua chunk for luaeval(): ",
|
||||
exc_exec('call luaeval("1, 2, 3")'))
|
||||
startswith("Vim(call):E5108: Error while calling lua chunk for luaeval(): ",
|
||||
exc_exec('call luaeval("(nil)()")'))
|
||||
|
||||
-- The following should not crash: conversion error happens inside
|
||||
eq("Vim(call):E5101: Cannot convert given lua type",
|
||||
exc_exec('call luaeval("vim.api")'))
|
||||
end)
|
||||
end)
|
Reference in New Issue
Block a user