neovim/test/functional/lua/api_spec.lua
Björn Linse dab40f43b1 Add v:lua.func() vimL syntax for calling lua
Also simplify error messages when calling lua from vimL.
2019-11-16 22:33:21 +01:00

205 lines
11 KiB
Lua

-- Test suite for testing interactions with API bindings
local helpers = require('test.functional.helpers')(after_each)
local exc_exec = helpers.exc_exec
local funcs = helpers.funcs
local clear = helpers.clear
local eval = helpers.eval
local NIL = helpers.NIL
local eq = helpers.eq
before_each(clear)
describe('luaeval(vim.api.…)', function()
describe('with channel_id and buffer handle', function()
describe('nvim_buf_get_lines', function()
it('works', function()
funcs.setline(1, {"abc", "def", "a\nb", "ttt"})
eq({{_TYPE={}, _VAL={'a\nb'}}},
funcs.luaeval('vim.api.nvim_buf_get_lines(1, 2, 3, false)'))
end)
end)
describe('nvim_buf_set_lines', function()
it('works', function()
funcs.setline(1, {"abc", "def", "a\nb", "ttt"})
eq(NIL, funcs.luaeval('vim.api.nvim_buf_set_lines(1, 1, 2, false, {"b\\0a"})'))
eq({'abc', {_TYPE={}, _VAL={'b\na'}}, {_TYPE={}, _VAL={'a\nb'}}, 'ttt'},
funcs.luaeval('vim.api.nvim_buf_get_lines(1, 0, 4, false)'))
end)
end)
end)
describe('with errors', function()
it('transforms API error from nvim_buf_set_lines into lua error', function()
funcs.setline(1, {"abc", "def", "a\nb", "ttt"})
eq({false, 'String cannot contain newlines'},
funcs.luaeval('{pcall(vim.api.nvim_buf_set_lines, 1, 1, 2, false, {"b\\na"})}'))
end)
it('transforms API error from nvim_win_set_cursor into lua error', function()
eq({false, 'Argument "pos" must be a [row, col] array'},
funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {1, 2, 3})}'))
-- Used to produce a memory leak due to a bug in nvim_win_set_cursor
eq({false, 'Invalid window id'},
funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, -1, {1, 2, 3})}'))
end)
it('transforms API error from nvim_win_set_cursor + same array as in first test into lua error',
function()
eq({false, 'Argument "pos" must be a [row, col] array'},
funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {"b\\na"})}'))
end)
end)
it('correctly evaluates API code which calls luaeval', function()
local str = (([===[vim.api.nvim_eval([==[
luaeval('vim.api.nvim_eval([=[
luaeval("vim.api.nvim_eval([[
luaeval(1)
]])")
]=])')
]==])]===]):gsub('\n', ' '))
eq(1, funcs.luaeval(str))
end)
it('correctly converts from API objects', function()
eq(1, funcs.luaeval('vim.api.nvim_eval("1")'))
eq('1', funcs.luaeval([[vim.api.nvim_eval('"1"')]]))
eq({}, funcs.luaeval('vim.api.nvim_eval("[]")'))
eq({}, funcs.luaeval('vim.api.nvim_eval("{}")'))
eq(1, funcs.luaeval('vim.api.nvim_eval("1.0")'))
eq(true, funcs.luaeval('vim.api.nvim_eval("v:true")'))
eq(false, funcs.luaeval('vim.api.nvim_eval("v:false")'))
eq(NIL, funcs.luaeval('vim.api.nvim_eval("v:null")'))
eq(0, eval([[type(luaeval('vim.api.nvim_eval("1")'))]]))
eq(1, eval([[type(luaeval('vim.api.nvim_eval("''1''")'))]]))
eq(3, eval([[type(luaeval('vim.api.nvim_eval("[]")'))]]))
eq(4, eval([[type(luaeval('vim.api.nvim_eval("{}")'))]]))
eq(5, eval([[type(luaeval('vim.api.nvim_eval("1.0")'))]]))
eq(6, eval([[type(luaeval('vim.api.nvim_eval("v:true")'))]]))
eq(6, eval([[type(luaeval('vim.api.nvim_eval("v:false")'))]]))
eq(7, eval([[type(luaeval('vim.api.nvim_eval("v:null")'))]]))
eq({foo=42}, funcs.luaeval([[vim.api.nvim_eval('{"foo": 42}')]]))
eq({42}, funcs.luaeval([[vim.api.nvim_eval('[42]')]]))
eq({foo={bar=42}, baz=50}, funcs.luaeval([[vim.api.nvim_eval('{"foo": {"bar": 42}, "baz": 50}')]]))
eq({{42}, {}}, funcs.luaeval([=[vim.api.nvim_eval('[[42], []]')]=]))
end)
it('correctly converts to API objects', function()
eq(1, funcs.luaeval('vim.api.nvim__id(1)'))
eq('1', funcs.luaeval('vim.api.nvim__id("1")'))
eq({1}, funcs.luaeval('vim.api.nvim__id({1})'))
eq({foo=1}, funcs.luaeval('vim.api.nvim__id({foo=1})'))
eq(1.5, funcs.luaeval('vim.api.nvim__id(1.5)'))
eq(true, funcs.luaeval('vim.api.nvim__id(true)'))
eq(false, funcs.luaeval('vim.api.nvim__id(false)'))
eq(NIL, funcs.luaeval('vim.api.nvim__id(nil)'))
eq(0, eval([[type(luaeval('vim.api.nvim__id(1)'))]]))
eq(1, eval([[type(luaeval('vim.api.nvim__id("1")'))]]))
eq(3, eval([[type(luaeval('vim.api.nvim__id({1})'))]]))
eq(4, eval([[type(luaeval('vim.api.nvim__id({foo=1})'))]]))
eq(5, eval([[type(luaeval('vim.api.nvim__id(1.5)'))]]))
eq(6, eval([[type(luaeval('vim.api.nvim__id(true)'))]]))
eq(6, eval([[type(luaeval('vim.api.nvim__id(false)'))]]))
eq(7, eval([[type(luaeval('vim.api.nvim__id(nil)'))]]))
eq({foo=1, bar={42, {{baz=true}, 5}}}, funcs.luaeval('vim.api.nvim__id({foo=1, bar={42, {{baz=true}, 5}}})'))
end)
it('correctly converts container objects with type_idx to API objects', function()
eq(5, eval('type(luaeval("vim.api.nvim__id({[vim.type_idx]=vim.types.float, [vim.val_idx]=0})"))'))
eq(4, eval([[type(luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.dictionary})'))]]))
eq(3, eval([[type(luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array})'))]]))
eq({}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array})'))
-- Presence of type_idx makes Vim ignore some keys
eq({42}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'))
eq({foo=2}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'))
eq(10, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'))
eq({}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})'))
end)
it('correctly converts arrays with type_idx to API objects', function()
eq(3, eval([[type(luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array})'))]]))
eq({}, funcs.luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array})'))
eq({42}, funcs.luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'))
eq({{foo=2}}, funcs.luaeval('vim.api.nvim__id_array({{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'))
eq({10}, funcs.luaeval('vim.api.nvim__id_array({{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'))
eq({}, funcs.luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})'))
eq({}, funcs.luaeval('vim.api.nvim__id_array({})'))
eq(3, eval([[type(luaeval('vim.api.nvim__id_array({})'))]]))
end)
it('correctly converts dictionaries with type_idx to API objects', function()
eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]]))
eq({}, funcs.luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})'))
eq({v={42}}, funcs.luaeval('vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'))
eq({foo=2}, funcs.luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'))
eq({v=10}, funcs.luaeval('vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'))
eq({v={}}, funcs.luaeval('vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2}})'))
-- If API requests dictionary, then empty table will be the one. This is not
-- the case normally because empty table is an empty arrray.
eq({}, funcs.luaeval('vim.api.nvim__id_dictionary({})'))
eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({})'))]]))
end)
it('errors out correctly when working with API', function()
-- Conversion errors
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type',
exc_exec([[call luaeval("vim.api.nvim__id(vim.api.nvim__id)")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua table',
exc_exec([[call luaeval("vim.api.nvim__id({1, foo=42})")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type',
exc_exec([[call luaeval("vim.api.nvim__id({42, vim.api.nvim__id})")]]))
-- Errors in number of arguments
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument',
exc_exec([[call luaeval("vim.api.nvim__id()")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument',
exc_exec([[call luaeval("vim.api.nvim__id(1, 2)")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 2 arguments',
exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2, 3)")]]))
-- Error in argument types
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua string',
exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2)")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua number',
exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 'test', 1, false)")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Number is not integral',
exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 1.5, 1, false)")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table',
exc_exec([[call luaeval("vim.api.nvim__id_float('test')")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type',
exc_exec([[call luaeval("vim.api.nvim__id_float({[vim.type_idx]=vim.types.dictionary})")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table',
exc_exec([[call luaeval("vim.api.nvim__id_array(1)")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type',
exc_exec([[call luaeval("vim.api.nvim__id_array({[vim.type_idx]=vim.types.dictionary})")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table',
exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]]))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type',
exc_exec([[call luaeval("vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.array})")]]))
-- TODO: check for errors with Tabpage argument
-- TODO: check for errors with Window argument
-- TODO: check for errors with Buffer argument
end)
it('accepts any value as API Boolean', function()
eq('', funcs.luaeval('vim.api.nvim_replace_termcodes("", vim, false, nil)'))
eq('', funcs.luaeval('vim.api.nvim_replace_termcodes("", 0, 1.5, "test")'))
eq('', funcs.luaeval('vim.api.nvim_replace_termcodes("", true, {}, {[vim.type_idx]=vim.types.array})'))
end)
end)