From f551df17f33e7f38b7e5693eb923118ca1542d27 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 10 Jul 2016 08:03:14 +0300 Subject: 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. --- test/functional/lua_spec.lua | 143 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 test/functional/lua_spec.lua (limited to 'test') diff --git a/test/functional/lua_spec.lua b/test/functional/lua_spec.lua new file mode 100644 index 0000000000..fdfd9b4c2d --- /dev/null +++ b/test/functional/lua_spec.lua @@ -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) -- cgit From ed3115bd26047c9b125798d9cb56d09b155a243b Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 11 Jul 2016 20:42:27 +0300 Subject: executor: Make sure it works with API values --- test/functional/lua_spec.lua | 94 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/lua_spec.lua b/test/functional/lua_spec.lua index fdfd9b4c2d..4f00189519 100644 --- a/test/functional/lua_spec.lua +++ b/test/functional/lua_spec.lua @@ -8,7 +8,7 @@ local clear = helpers.clear local funcs = helpers.funcs local meths = helpers.meths local exc_exec = helpers.exc_exec -local curbufmeths = helpers.curbufmeths +local redir_exec = helpers.redir_exec local function startswith(expected, actual) eq(expected, actual:sub(1, #expected)) @@ -139,5 +139,97 @@ describe('luaeval() function', function() -- The following should not crash: conversion error happens inside eq("Vim(call):E5101: Cannot convert given lua type", exc_exec('call luaeval("vim.api")')) + -- The following should not show internal error + eq("\nE5101: Cannot convert given lua type\n0", + redir_exec('echo luaeval("vim.api")')) end) + + it('correctly converts containers with type_idx', function() + eq(5, eval('type(luaeval("{[vim.type_idx]=vim.types.float, [vim.val_idx]=0}"))')) + eq(4, eval([[type(luaeval('{[vim.type_idx]=vim.types.dictionary}'))]])) + eq(3, eval([[type(luaeval('{[vim.type_idx]=vim.types.array}'))]])) + + eq({}, funcs.luaeval('{[vim.type_idx]=vim.types.array}')) + + -- Presence of type_idx makes Vim ignore some keys + eq({42}, funcs.luaeval('{[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) + eq({foo=2}, funcs.luaeval('{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) + eq(10, funcs.luaeval('{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) + + -- The following should not crash + eq({}, funcs.luaeval('{[vim.type_idx]=vim.types.dictionary}')) + end) + + it('correctly converts from API objects', function() + eq(1, funcs.luaeval('vim.api.vim_eval("1")')) + eq('1', funcs.luaeval([[vim.api.vim_eval('"1"')]])) + eq({}, funcs.luaeval('vim.api.vim_eval("[]")')) + eq({}, funcs.luaeval('vim.api.vim_eval("{}")')) + eq(1, funcs.luaeval('vim.api.vim_eval("1.0")')) + eq(true, funcs.luaeval('vim.api.vim_eval("v:true")')) + eq(false, funcs.luaeval('vim.api.vim_eval("v:false")')) + eq(NIL, funcs.luaeval('vim.api.vim_eval("v:null")')) + + eq(0, eval([[type(luaeval('vim.api.vim_eval("1")'))]])) + eq(1, eval([[type(luaeval('vim.api.vim_eval("''1''")'))]])) + eq(3, eval([[type(luaeval('vim.api.vim_eval("[]")'))]])) + eq(4, eval([[type(luaeval('vim.api.vim_eval("{}")'))]])) + eq(5, eval([[type(luaeval('vim.api.vim_eval("1.0")'))]])) + eq(6, eval([[type(luaeval('vim.api.vim_eval("v:true")'))]])) + eq(6, eval([[type(luaeval('vim.api.vim_eval("v:false")'))]])) + eq(7, eval([[type(luaeval('vim.api.vim_eval("v:null")'))]])) + + eq({foo=42}, funcs.luaeval([[vim.api.vim_eval('{"foo": 42}')]])) + eq({42}, funcs.luaeval([[vim.api.vim_eval('[42]')]])) + + eq({foo={bar=42}, baz=50}, funcs.luaeval([[vim.api.vim_eval('{"foo": {"bar": 42}, "baz": 50}')]])) + eq({{42}, {}}, funcs.luaeval([=[vim.api.vim_eval('[[42], []]')]=])) + end) + + it('correctly converts to API objects', function() + eq(1, funcs.luaeval('vim.api._vim_id(1)')) + eq('1', funcs.luaeval('vim.api._vim_id("1")')) + eq({1}, funcs.luaeval('vim.api._vim_id({1})')) + eq({foo=1}, funcs.luaeval('vim.api._vim_id({foo=1})')) + eq(1.5, funcs.luaeval('vim.api._vim_id(1.5)')) + eq(true, funcs.luaeval('vim.api._vim_id(true)')) + eq(false, funcs.luaeval('vim.api._vim_id(false)')) + eq(NIL, funcs.luaeval('vim.api._vim_id(nil)')) + + eq(0, eval([[type(luaeval('vim.api._vim_id(1)'))]])) + eq(1, eval([[type(luaeval('vim.api._vim_id("1")'))]])) + eq(3, eval([[type(luaeval('vim.api._vim_id({1})'))]])) + eq(4, eval([[type(luaeval('vim.api._vim_id({foo=1})'))]])) + eq(5, eval([[type(luaeval('vim.api._vim_id(1.5)'))]])) + eq(6, eval([[type(luaeval('vim.api._vim_id(true)'))]])) + eq(6, eval([[type(luaeval('vim.api._vim_id(false)'))]])) + eq(7, eval([[type(luaeval('vim.api._vim_id(nil)'))]])) + + eq({foo=1, bar={42, {{baz=true}, 5}}}, funcs.luaeval('vim.api._vim_id({foo=1, bar={42, {{baz=true}, 5}}})')) + end) + + it('correctly converts containers with type_idx to API objects', function() + -- TODO: Similar tests with _vim_array_id and _vim_dictionary_id, that will + -- follow slightly different code paths. + eq(5, eval('type(luaeval("vim.api._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=0})"))')) + eq(4, eval([[type(luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.dictionary})'))]])) + eq(3, eval([[type(luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array})'))]])) + + eq({}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array})')) + + -- Presence of type_idx makes Vim ignore some keys + -- FIXME + -- eq({42}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) + eq({foo=2}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) + eq(10, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) + end) + -- TODO: check what happens when it errors out on second list item +--[[FIXME + [ + [ it('correctly converts self-containing containers', function() + [ meths.set_var('l', {}) + [ eval('add(l, l)') + [ eq(true, eval('luaeval("_A == _A[1]", l)')) + [ end) + ]] end) -- cgit From 3fa4ca81880bc5113c32a89de965ce593e9b001f Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 12 Jul 2016 19:04:12 +0300 Subject: executor/converter: Fix conversion of self-containing containers --- test/functional/lua_spec.lua | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'test') diff --git a/test/functional/lua_spec.lua b/test/functional/lua_spec.lua index 4f00189519..5c6dee90a3 100644 --- a/test/functional/lua_spec.lua +++ b/test/functional/lua_spec.lua @@ -224,12 +224,23 @@ describe('luaeval() function', function() eq(10, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) end) -- TODO: check what happens when it errors out on second list item ---[[FIXME - [ - [ it('correctly converts self-containing containers', function() - [ meths.set_var('l', {}) - [ eval('add(l, l)') - [ eq(true, eval('luaeval("_A == _A[1]", l)')) - [ end) - ]] + -- TODO: check what happens if API function receives wrong number of + -- arguments. + -- TODO: check what happens if API function receives wrong argument types. + + it('correctly converts self-containing containers', function() + meths.set_var('l', {}) + eval('add(l, l)') + eq(true, eval('luaeval("_A == _A[1]", l)')) + eq(true, eval('luaeval("_A[1] == _A[1][1]", [l])')) + eq(true, eval('luaeval("_A.d == _A.d[1]", {"d": l})')) + eq(true, eval('luaeval("_A ~= _A[1]", [l])')) + + meths.set_var('d', {foo=42}) + eval('extend(d, {"d": d})') + eq(true, eval('luaeval("_A == _A.d", d)')) + eq(true, eval('luaeval("_A[1] == _A[1].d", [d])')) + eq(true, eval('luaeval("_A.d == _A.d.d", {"d": d})')) + eq(true, eval('luaeval("_A ~= _A.d", {"d": d})')) + end) end) -- cgit From 9297d941e2f1576006d77bfd6391cecc3bea37b0 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 12 Jul 2016 19:20:57 +0300 Subject: executor/converter: Fix how maxidx is determined --- test/functional/lua_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/lua_spec.lua b/test/functional/lua_spec.lua index 5c6dee90a3..e16f41dba2 100644 --- a/test/functional/lua_spec.lua +++ b/test/functional/lua_spec.lua @@ -218,10 +218,10 @@ describe('luaeval() function', function() eq({}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array})')) -- Presence of type_idx makes Vim ignore some keys - -- FIXME - -- eq({42}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) + eq({42}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) eq({foo=2}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) eq(10, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) + eq({}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})')) end) -- TODO: check what happens when it errors out on second list item -- TODO: check what happens if API function receives wrong number of -- cgit From 425d348f0f9f680a44af31fc3cecd20a07374bb5 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 16 Jul 2016 00:34:24 +0300 Subject: executor/converter: Make nlua_pop_Object not recursive --- test/functional/lua_spec.lua | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test/functional/lua_spec.lua b/test/functional/lua_spec.lua index e16f41dba2..bd1ed51c2d 100644 --- a/test/functional/lua_spec.lua +++ b/test/functional/lua_spec.lua @@ -31,6 +31,9 @@ describe('luaeval() function', function() nested_by_level[i] = {o=nested, s=nested_s} end + -- Not checked: funcrefs converted to NIL. To be altered to something more + -- meaningful later. + it('correctly evaluates scalars', function() eq(1, funcs.luaeval('1')) eq(0, eval('type(luaeval("1"))')) @@ -135,6 +138,10 @@ describe('luaeval() function', function() exc_exec('call luaeval("1, 2, 3")')) startswith("Vim(call):E5108: Error while calling lua chunk for luaeval(): ", exc_exec('call luaeval("(nil)()")')) + eq("Vim(call):E5101: Cannot convert given lua type", + exc_exec('call luaeval("{42, vim.api}")')) + eq("Vim(call):E5101: Cannot convert given lua type", + exc_exec('call luaeval("{foo=42, baz=vim.api}")')) -- The following should not crash: conversion error happens inside eq("Vim(call):E5101: Cannot convert given lua type", @@ -208,9 +215,7 @@ describe('luaeval() function', function() eq({foo=1, bar={42, {{baz=true}, 5}}}, funcs.luaeval('vim.api._vim_id({foo=1, bar={42, {{baz=true}, 5}}})')) end) - it('correctly converts containers with type_idx to API objects', function() - -- TODO: Similar tests with _vim_array_id and _vim_dictionary_id, that will - -- follow slightly different code paths. + it('correctly converts container objects with type_idx to API objects', function() eq(5, eval('type(luaeval("vim.api._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=0})"))')) eq(4, eval([[type(luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.dictionary})'))]])) eq(3, eval([[type(luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array})'))]])) @@ -223,10 +228,18 @@ describe('luaeval() function', function() eq(10, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) eq({}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})')) end) - -- TODO: check what happens when it errors out on second list item - -- TODO: check what happens if API function receives wrong number of - -- arguments. - -- TODO: check what happens if API function receives wrong argument types. + + it('correctly converts arrays with type_idx to API objects', function() + eq(3, eval([[type(luaeval('vim.api._vim_id_array({[vim.type_idx]=vim.types.array})'))]])) + + eq({}, funcs.luaeval('vim.api._vim_id_array({[vim.type_idx]=vim.types.array})')) + + -- Presence of type_idx makes Vim ignore some keys + eq({42}, funcs.luaeval('vim.api._vim_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._vim_id_array({{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) + eq({10}, funcs.luaeval('vim.api._vim_id_array({{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) + eq({}, funcs.luaeval('vim.api._vim_id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})')) + end) it('correctly converts self-containing containers', function() meths.set_var('l', {}) @@ -243,4 +256,14 @@ describe('luaeval() function', function() eq(true, eval('luaeval("_A.d == _A.d.d", {"d": d})')) eq(true, eval('luaeval("_A ~= _A.d", {"d": d})')) end) + + it('errors out correctly when working with API', function() + eq(0, exc_exec([[call luaeval("vim.api.id")]])) + end) + + -- TODO: check buffer/window/etc. + -- TODO: check what happens when it errors out on second list item + -- TODO: check what happens if API function receives wrong number of + -- arguments. + -- TODO: check what happens if API function receives wrong argument types. end) -- cgit From 7a013e93e0364f78a2bc04eadaaeeaa689d0258a Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 16 Jul 2016 00:48:25 +0300 Subject: executor/converter: Make it possible to supply `{}` to Dictionary arg --- test/functional/lua_spec.lua | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/lua_spec.lua b/test/functional/lua_spec.lua index bd1ed51c2d..082efe4c0e 100644 --- a/test/functional/lua_spec.lua +++ b/test/functional/lua_spec.lua @@ -234,11 +234,29 @@ describe('luaeval() function', function() eq({}, funcs.luaeval('vim.api._vim_id_array({[vim.type_idx]=vim.types.array})')) - -- Presence of type_idx makes Vim ignore some keys eq({42}, funcs.luaeval('vim.api._vim_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._vim_id_array({{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) eq({10}, funcs.luaeval('vim.api._vim_id_array({{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) eq({}, funcs.luaeval('vim.api._vim_id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})')) + + eq({}, funcs.luaeval('vim.api._vim_id_array({})')) + eq(3, eval([[type(luaeval('vim.api._vim_id_array({})'))]])) + end) + + it('correctly converts dictionaries with type_idx to API objects', function() + eq(4, eval([[type(luaeval('vim.api._vim_id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]])) + + eq({}, funcs.luaeval('vim.api._vim_id_dictionary({[vim.type_idx]=vim.types.dictionary})')) + + eq({v={42}}, funcs.luaeval('vim.api._vim_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._vim_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._vim_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._vim_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._vim_id_dictionary({})')) + eq(4, eval([[type(luaeval('vim.api._vim_id_dictionary({})'))]])) end) it('correctly converts self-containing containers', function() -- cgit From ba2f615cd40d5d809d1a141c7b098e3bd22ff7bb Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 16 Jul 2016 02:26:04 +0300 Subject: functests: Test for error conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During testing found the following bugs: 1. msgpack-gen.lua script is completely unprepared for Float values either in return type or in arguments. Specifically: 1. At the time of writing relevant code FLOAT_OBJ did not exist as well as FLOATING_OBJ, but it would be used by msgpack-gen.lua should return type be Float. I added FLOATING_OBJ macros later because did not know that msgpack-gen.lua uses these _OBJ macros, otherwise it would be FLOAT_OBJ. 2. msgpack-gen.lua should use .data.floating in place of .data.float. But it did not expect that .data subattribute may have name different from lowercased type name. 2. vim_replace_termcodes returned its argument as-is if it receives an empty string (as well as _vim_id*() functions did). But if something in returned argument lives in an allocated memory such action will cause double free: once when freeing arguments, then when freeing return value. It did not cause problems yet because msgpack bindings return empty string as {NULL, 0} and nothing was actually allocated. 3. New code in msgpack-gen.lua popped arguments in reversed order, making lua bindings’ signatures be different from API ones. --- test/functional/api/vim_spec.lua | 11 +++++++++ test/functional/lua_spec.lua | 51 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 3348368a36..24ed0afe67 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -219,6 +219,17 @@ describe('api', function() eq('\128\253\44', helpers.nvim('replace_termcodes', '', true, true, true)) end) + + it('does not crash when transforming an empty string', function() + -- Actually does not test anything, because current code will use NULL for + -- an empty string. + -- + -- Problem here is that if String argument has .data in allocated memory + -- then `return str` in vim_replace_termcodes body will make Neovim free + -- `str.data` twice: once when freeing arguments, then when freeing return + -- value. + eq('', meths.replace_termcodes('', true, true, true)) + end) end) describe('nvim_feedkeys', function() diff --git a/test/functional/lua_spec.lua b/test/functional/lua_spec.lua index 082efe4c0e..8ca47718aa 100644 --- a/test/functional/lua_spec.lua +++ b/test/functional/lua_spec.lua @@ -276,12 +276,53 @@ describe('luaeval() function', function() end) it('errors out correctly when working with API', function() - eq(0, exc_exec([[call luaeval("vim.api.id")]])) + -- Conversion errors + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Cannot convert given lua type', + exc_exec([[call luaeval("vim.api._vim_id(vim.api._vim_id)")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Cannot convert given lua table', + exc_exec([[call luaeval("vim.api._vim_id({1, foo=42})")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Cannot convert given lua type', + exc_exec([[call luaeval("vim.api._vim_id({42, vim.api._vim_id})")]])) + -- Errors in number of arguments + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected 1 argument', + exc_exec([[call luaeval("vim.api._vim_id()")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected 1 argument', + exc_exec([[call luaeval("vim.api._vim_id(1, 2)")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected 2 arguments', + exc_exec([[call luaeval("vim.api.vim_set_var(1, 2, 3)")]])) + -- Error in argument types + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected lua string', + exc_exec([[call luaeval("vim.api.vim_set_var(1, 2)")]])) + + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected lua number', + exc_exec([[call luaeval("vim.api.buffer_get_line(0, 'test')")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Number is not integral', + exc_exec([[call luaeval("vim.api.buffer_get_line(0, 1.5)")]])) + + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected lua table', + exc_exec([[call luaeval("vim.api._vim_id_float('test')")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Unexpected type', + exc_exec([[call luaeval("vim.api._vim_id_float({[vim.type_idx]=vim.types.dictionary})")]])) + + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected lua table', + exc_exec([[call luaeval("vim.api._vim_id_array(1)")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Unexpected type', + exc_exec([[call luaeval("vim.api._vim_id_array({[vim.type_idx]=vim.types.dictionary})")]])) + + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected lua table', + exc_exec([[call luaeval("vim.api._vim_id_dictionary(1)")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Unexpected type', + exc_exec([[call luaeval("vim.api._vim_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.vim_replace_termcodes("", vim, false, nil)')) + eq('', funcs.luaeval('vim.api.vim_replace_termcodes("", 0, 1.5, "test")')) + eq('', funcs.luaeval('vim.api.vim_replace_termcodes("", true, {}, {[vim.type_idx]=vim.types.array})')) end) -- TODO: check buffer/window/etc. - -- TODO: check what happens when it errors out on second list item - -- TODO: check what happens if API function receives wrong number of - -- arguments. - -- TODO: check what happens if API function receives wrong argument types. end) -- cgit From a3ea05c1e5965ca23b1b926c41b00597e9d0211c Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 21 Jan 2017 00:00:47 +0300 Subject: functests: Add some tests --- test/functional/lua/api_spec.lua | 36 ++++++++++++++++++++ test/functional/lua/commands_spec.lua | 4 +++ test/functional/lua/luaeval_spec.lua | 63 +++++++++++++++++++++++++++++++++++ test/helpers.lua | 9 +++++ 4 files changed, 112 insertions(+) create mode 100644 test/functional/lua/api_spec.lua create mode 100644 test/functional/lua/commands_spec.lua create mode 100644 test/functional/lua/luaeval_spec.lua (limited to 'test') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua new file mode 100644 index 0000000000..6652c60adb --- /dev/null +++ b/test/functional/lua/api_spec.lua @@ -0,0 +1,36 @@ +-- Test suite for testing interactions with API bindings +local helpers = require('test.functional.helpers')(after_each) + +local funcs = helpers.funcs +local clear = helpers.clear +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 errors into lua errors', 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) + end) +end) diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua new file mode 100644 index 0000000000..191504bfaa --- /dev/null +++ b/test/functional/lua/commands_spec.lua @@ -0,0 +1,4 @@ +-- Test suite for checking :lua* commands +local helpers = require('test.functional.helpers')(after_each) + +local eq = helpers.eq diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua new file mode 100644 index 0000000000..5b7f365ef3 --- /dev/null +++ b/test/functional/lua/luaeval_spec.lua @@ -0,0 +1,63 @@ +-- Test suite for testing luaeval() function +local helpers = require('test.functional.helpers')(after_each) + +local command = helpers.command +local meths = helpers.meths +local funcs = helpers.funcs +local clear = helpers.clear +local NIL = helpers.NIL +local eq = helpers.eq + +before_each(clear) + +describe('luaeval()', function() + describe('second argument', function() + it('is successfully received', function() + local t = {t=true, f=false, --[[n=NIL,]] d={l={'string', 42, 0.42}}} + eq(t, funcs.luaeval("_A", t)) + -- Not tested: nil, funcrefs, returned object identity: behaviour will + -- most likely change. + end) + end) + describe('lua values', function() + it('are successfully transformed', function() + eq({n=1, f=1.5, s='string', l={4, 2}}, + funcs.luaeval('{n=1, f=1.5, s="string", l={4, 2}}')) + -- Not tested: nil inside containers: behaviour will most likely change. + eq(NIL, funcs.luaeval('nil')) + end) + end) + describe('recursive lua values', function() + it('are successfully transformed', function() + funcs.luaeval('rawset(_G, "d", {})') + funcs.luaeval('rawset(d, "d", d)') + eq('\n{\'d\': {...@0}}', funcs.execute('echo luaeval("d")')) + + funcs.luaeval('rawset(_G, "l", {})') + funcs.luaeval('table.insert(l, l)') + eq('\n[[...@0]]', funcs.execute('echo luaeval("l")')) + end) + end) + describe('strings', function() + it('are successfully converted to special dictionaries', function() + command([[let s = luaeval('"\0"')]]) + eq({_TYPE={}, _VAL={'\n'}}, meths.get_var('s')) + eq(1, funcs.eval('s._TYPE is v:msgpack_types.binary')) + end) + it('are successfully converted to special dictionaries in table keys', + function() + command([[let d = luaeval('{["\0"]=1}')]]) + eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n'}}, 1}}}, meths.get_var('d')) + eq(1, funcs.eval('d._TYPE is v:msgpack_types.map')) + eq(1, funcs.eval('d._VAL[0][0]._TYPE is v:msgpack_types.string')) + end) + it('are successfully converted to special dictionaries from a list', + function() + command([[let l = luaeval('{"abc", "a\0b", "c\0d", "def"}')]]) + eq({'abc', {_TYPE={}, _VAL={'a\nb'}}, {_TYPE={}, _VAL={'c\nd'}}, 'def'}, + meths.get_var('l')) + eq(1, funcs.eval('l[1]._TYPE is v:msgpack_types.binary')) + eq(1, funcs.eval('l[2]._TYPE is v:msgpack_types.binary')) + end) + end) +end) diff --git a/test/helpers.lua b/test/helpers.lua index e5224349c2..18f47e950b 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -225,6 +225,14 @@ local function which(exe) end end +local function shallowcopy(orig) + local copy = {} + for orig_key, orig_value in pairs(orig) do + copy[orig_key] = orig_value + end + return copy +end + return { eq = eq, neq = neq, @@ -238,4 +246,5 @@ return { check_cores = check_cores, hasenv = hasenv, which = which, + shallowcopy = shallowcopy, } -- cgit From bca9c2f3c4af9c132439bbfeaed028ac3171db48 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 21 Jan 2017 01:10:44 +0300 Subject: functests: Move existing tests from lua_spec to lua/*, fix them --- test/functional/lua/api_spec.lua | 143 +++++++++++++++ test/functional/lua/luaeval_spec.lua | 181 +++++++++++++++++++ test/functional/lua_spec.lua | 328 ----------------------------------- 3 files changed, 324 insertions(+), 328 deletions(-) delete mode 100644 test/functional/lua_spec.lua (limited to 'test') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index 6652c60adb..31c855c2c1 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -1,8 +1,10 @@ -- 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 @@ -33,4 +35,145 @@ describe('luaeval(vim.api.…)', function() funcs.luaeval('{pcall(vim.api.nvim_buf_set_lines, 1, 1, 2, false, {"b\\na"})}')) end) 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._vim_id(1)')) + eq('1', funcs.luaeval('vim.api._vim_id("1")')) + eq({1}, funcs.luaeval('vim.api._vim_id({1})')) + eq({foo=1}, funcs.luaeval('vim.api._vim_id({foo=1})')) + eq(1.5, funcs.luaeval('vim.api._vim_id(1.5)')) + eq(true, funcs.luaeval('vim.api._vim_id(true)')) + eq(false, funcs.luaeval('vim.api._vim_id(false)')) + eq(NIL, funcs.luaeval('vim.api._vim_id(nil)')) + + eq(0, eval([[type(luaeval('vim.api._vim_id(1)'))]])) + eq(1, eval([[type(luaeval('vim.api._vim_id("1")'))]])) + eq(3, eval([[type(luaeval('vim.api._vim_id({1})'))]])) + eq(4, eval([[type(luaeval('vim.api._vim_id({foo=1})'))]])) + eq(5, eval([[type(luaeval('vim.api._vim_id(1.5)'))]])) + eq(6, eval([[type(luaeval('vim.api._vim_id(true)'))]])) + eq(6, eval([[type(luaeval('vim.api._vim_id(false)'))]])) + eq(7, eval([[type(luaeval('vim.api._vim_id(nil)'))]])) + + eq({foo=1, bar={42, {{baz=true}, 5}}}, funcs.luaeval('vim.api._vim_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._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=0})"))')) + eq(4, eval([[type(luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.dictionary})'))]])) + eq(3, eval([[type(luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array})'))]])) + + eq({}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array})')) + + -- Presence of type_idx makes Vim ignore some keys + eq({42}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) + eq({foo=2}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) + eq(10, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) + eq({}, funcs.luaeval('vim.api._vim_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._vim_id_array({[vim.type_idx]=vim.types.array})'))]])) + + eq({}, funcs.luaeval('vim.api._vim_id_array({[vim.type_idx]=vim.types.array})')) + + eq({42}, funcs.luaeval('vim.api._vim_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._vim_id_array({{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) + eq({10}, funcs.luaeval('vim.api._vim_id_array({{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) + eq({}, funcs.luaeval('vim.api._vim_id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})')) + + eq({}, funcs.luaeval('vim.api._vim_id_array({})')) + eq(3, eval([[type(luaeval('vim.api._vim_id_array({})'))]])) + end) + + it('correctly converts dictionaries with type_idx to API objects', function() + eq(4, eval([[type(luaeval('vim.api._vim_id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]])) + + eq({}, funcs.luaeval('vim.api._vim_id_dictionary({[vim.type_idx]=vim.types.dictionary})')) + + eq({v={42}}, funcs.luaeval('vim.api._vim_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._vim_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._vim_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._vim_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._vim_id_dictionary({})')) + eq(4, eval([[type(luaeval('vim.api._vim_id_dictionary({})'))]])) + end) + + it('errors out correctly when working with API', function() + -- Conversion errors + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Cannot convert given lua type', + exc_exec([[call luaeval("vim.api._vim_id(vim.api._vim_id)")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Cannot convert given lua table', + exc_exec([[call luaeval("vim.api._vim_id({1, foo=42})")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Cannot convert given lua type', + exc_exec([[call luaeval("vim.api._vim_id({42, vim.api._vim_id})")]])) + -- Errors in number of arguments + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected 1 argument', + exc_exec([[call luaeval("vim.api._vim_id()")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected 1 argument', + exc_exec([[call luaeval("vim.api._vim_id(1, 2)")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]: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 while calling lua chunk for luaeval(): [string ""]:1: Expected lua string', + exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2)")]])) + + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected lua number', + exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 'test', 1, false)")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]: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 while calling lua chunk for luaeval(): [string ""]:1: Expected lua table', + exc_exec([[call luaeval("vim.api._vim_id_float('test')")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Unexpected type', + exc_exec([[call luaeval("vim.api._vim_id_float({[vim.type_idx]=vim.types.dictionary})")]])) + + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected lua table', + exc_exec([[call luaeval("vim.api._vim_id_array(1)")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Unexpected type', + exc_exec([[call luaeval("vim.api._vim_id_array({[vim.type_idx]=vim.types.dictionary})")]])) + + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected lua table', + exc_exec([[call luaeval("vim.api._vim_id_dictionary(1)")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Unexpected type', + exc_exec([[call luaeval("vim.api._vim_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) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 5b7f365ef3..345848cfff 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -1,16 +1,37 @@ -- Test suite for testing luaeval() function local helpers = require('test.functional.helpers')(after_each) +local redir_exec = helpers.redir_exec +local exc_exec = helpers.exc_exec local command = helpers.command local meths = helpers.meths local funcs = helpers.funcs local clear = helpers.clear +local eval = helpers.eval local NIL = helpers.NIL local eq = helpers.eq before_each(clear) +local function startswith(expected, actual) + eq(expected, actual:sub(1, #expected)) +end + describe('luaeval()', 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 + describe('second argument', function() it('is successfully received', function() local t = {t=true, f=false, --[[n=NIL,]] d={l={'string', 42, 0.42}}} @@ -60,4 +81,164 @@ describe('luaeval()', function() eq(1, funcs.eval('l[2]._TYPE is v:msgpack_types.binary')) end) end) + + -- Not checked: funcrefs converted to NIL. To be altered to something more + -- meaningful later. + + 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.nvim_buf_get_lines")')) + 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)()")')) + eq("Vim(call):E5101: Cannot convert given lua type", + exc_exec('call luaeval("{42, vim.api}")')) + eq("Vim(call):E5101: Cannot convert given lua type", + exc_exec('call luaeval("{foo=42, baz=vim.api}")')) + + -- The following should not crash: conversion error happens inside + eq("Vim(call):E5101: Cannot convert given lua type", + exc_exec('call luaeval("vim.api")')) + -- The following should not show internal error + eq("\nE5101: Cannot convert given lua type\n0", + redir_exec('echo luaeval("vim.api")')) + end) + + it('correctly converts containers with type_idx', function() + eq(5, eval('type(luaeval("{[vim.type_idx]=vim.types.float, [vim.val_idx]=0}"))')) + eq(4, eval([[type(luaeval('{[vim.type_idx]=vim.types.dictionary}'))]])) + eq(3, eval([[type(luaeval('{[vim.type_idx]=vim.types.array}'))]])) + + eq({}, funcs.luaeval('{[vim.type_idx]=vim.types.array}')) + + -- Presence of type_idx makes Vim ignore some keys + eq({42}, funcs.luaeval('{[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) + eq({foo=2}, funcs.luaeval('{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) + eq(10, funcs.luaeval('{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) + + -- The following should not crash + eq({}, funcs.luaeval('{[vim.type_idx]=vim.types.dictionary}')) + end) + + it('correctly converts self-containing containers', function() + meths.set_var('l', {}) + eval('add(l, l)') + eq(true, eval('luaeval("_A == _A[1]", l)')) + eq(true, eval('luaeval("_A[1] == _A[1][1]", [l])')) + eq(true, eval('luaeval("_A.d == _A.d[1]", {"d": l})')) + eq(true, eval('luaeval("_A ~= _A[1]", [l])')) + + meths.set_var('d', {foo=42}) + eval('extend(d, {"d": d})') + eq(true, eval('luaeval("_A == _A.d", d)')) + eq(true, eval('luaeval("_A[1] == _A[1].d", [d])')) + eq(true, eval('luaeval("_A.d == _A.d.d", {"d": d})')) + eq(true, eval('luaeval("_A ~= _A.d", {"d": d})')) + end) + + it('errors out correctly when doing incorrect things in lua', function() + -- Conversion errors + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: attempt to call field \'xxx_nonexistent_key_xxx\' (a nil value)', + exc_exec([[call luaeval("vim.xxx_nonexistent_key_xxx()")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: ERROR', + exc_exec([[call luaeval("error('ERROR')")]])) + end) end) diff --git a/test/functional/lua_spec.lua b/test/functional/lua_spec.lua deleted file mode 100644 index 8ca47718aa..0000000000 --- a/test/functional/lua_spec.lua +++ /dev/null @@ -1,328 +0,0 @@ -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 redir_exec = helpers.redir_exec - -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 - - -- Not checked: funcrefs converted to NIL. To be altered to something more - -- meaningful later. - - 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)()")')) - eq("Vim(call):E5101: Cannot convert given lua type", - exc_exec('call luaeval("{42, vim.api}")')) - eq("Vim(call):E5101: Cannot convert given lua type", - exc_exec('call luaeval("{foo=42, baz=vim.api}")')) - - -- The following should not crash: conversion error happens inside - eq("Vim(call):E5101: Cannot convert given lua type", - exc_exec('call luaeval("vim.api")')) - -- The following should not show internal error - eq("\nE5101: Cannot convert given lua type\n0", - redir_exec('echo luaeval("vim.api")')) - end) - - it('correctly converts containers with type_idx', function() - eq(5, eval('type(luaeval("{[vim.type_idx]=vim.types.float, [vim.val_idx]=0}"))')) - eq(4, eval([[type(luaeval('{[vim.type_idx]=vim.types.dictionary}'))]])) - eq(3, eval([[type(luaeval('{[vim.type_idx]=vim.types.array}'))]])) - - eq({}, funcs.luaeval('{[vim.type_idx]=vim.types.array}')) - - -- Presence of type_idx makes Vim ignore some keys - eq({42}, funcs.luaeval('{[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) - eq({foo=2}, funcs.luaeval('{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) - eq(10, funcs.luaeval('{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) - - -- The following should not crash - eq({}, funcs.luaeval('{[vim.type_idx]=vim.types.dictionary}')) - end) - - it('correctly converts from API objects', function() - eq(1, funcs.luaeval('vim.api.vim_eval("1")')) - eq('1', funcs.luaeval([[vim.api.vim_eval('"1"')]])) - eq({}, funcs.luaeval('vim.api.vim_eval("[]")')) - eq({}, funcs.luaeval('vim.api.vim_eval("{}")')) - eq(1, funcs.luaeval('vim.api.vim_eval("1.0")')) - eq(true, funcs.luaeval('vim.api.vim_eval("v:true")')) - eq(false, funcs.luaeval('vim.api.vim_eval("v:false")')) - eq(NIL, funcs.luaeval('vim.api.vim_eval("v:null")')) - - eq(0, eval([[type(luaeval('vim.api.vim_eval("1")'))]])) - eq(1, eval([[type(luaeval('vim.api.vim_eval("''1''")'))]])) - eq(3, eval([[type(luaeval('vim.api.vim_eval("[]")'))]])) - eq(4, eval([[type(luaeval('vim.api.vim_eval("{}")'))]])) - eq(5, eval([[type(luaeval('vim.api.vim_eval("1.0")'))]])) - eq(6, eval([[type(luaeval('vim.api.vim_eval("v:true")'))]])) - eq(6, eval([[type(luaeval('vim.api.vim_eval("v:false")'))]])) - eq(7, eval([[type(luaeval('vim.api.vim_eval("v:null")'))]])) - - eq({foo=42}, funcs.luaeval([[vim.api.vim_eval('{"foo": 42}')]])) - eq({42}, funcs.luaeval([[vim.api.vim_eval('[42]')]])) - - eq({foo={bar=42}, baz=50}, funcs.luaeval([[vim.api.vim_eval('{"foo": {"bar": 42}, "baz": 50}')]])) - eq({{42}, {}}, funcs.luaeval([=[vim.api.vim_eval('[[42], []]')]=])) - end) - - it('correctly converts to API objects', function() - eq(1, funcs.luaeval('vim.api._vim_id(1)')) - eq('1', funcs.luaeval('vim.api._vim_id("1")')) - eq({1}, funcs.luaeval('vim.api._vim_id({1})')) - eq({foo=1}, funcs.luaeval('vim.api._vim_id({foo=1})')) - eq(1.5, funcs.luaeval('vim.api._vim_id(1.5)')) - eq(true, funcs.luaeval('vim.api._vim_id(true)')) - eq(false, funcs.luaeval('vim.api._vim_id(false)')) - eq(NIL, funcs.luaeval('vim.api._vim_id(nil)')) - - eq(0, eval([[type(luaeval('vim.api._vim_id(1)'))]])) - eq(1, eval([[type(luaeval('vim.api._vim_id("1")'))]])) - eq(3, eval([[type(luaeval('vim.api._vim_id({1})'))]])) - eq(4, eval([[type(luaeval('vim.api._vim_id({foo=1})'))]])) - eq(5, eval([[type(luaeval('vim.api._vim_id(1.5)'))]])) - eq(6, eval([[type(luaeval('vim.api._vim_id(true)'))]])) - eq(6, eval([[type(luaeval('vim.api._vim_id(false)'))]])) - eq(7, eval([[type(luaeval('vim.api._vim_id(nil)'))]])) - - eq({foo=1, bar={42, {{baz=true}, 5}}}, funcs.luaeval('vim.api._vim_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._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=0})"))')) - eq(4, eval([[type(luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.dictionary})'))]])) - eq(3, eval([[type(luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array})'))]])) - - eq({}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array})')) - - -- Presence of type_idx makes Vim ignore some keys - eq({42}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) - eq({foo=2}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) - eq(10, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) - eq({}, funcs.luaeval('vim.api._vim_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._vim_id_array({[vim.type_idx]=vim.types.array})'))]])) - - eq({}, funcs.luaeval('vim.api._vim_id_array({[vim.type_idx]=vim.types.array})')) - - eq({42}, funcs.luaeval('vim.api._vim_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._vim_id_array({{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) - eq({10}, funcs.luaeval('vim.api._vim_id_array({{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) - eq({}, funcs.luaeval('vim.api._vim_id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})')) - - eq({}, funcs.luaeval('vim.api._vim_id_array({})')) - eq(3, eval([[type(luaeval('vim.api._vim_id_array({})'))]])) - end) - - it('correctly converts dictionaries with type_idx to API objects', function() - eq(4, eval([[type(luaeval('vim.api._vim_id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]])) - - eq({}, funcs.luaeval('vim.api._vim_id_dictionary({[vim.type_idx]=vim.types.dictionary})')) - - eq({v={42}}, funcs.luaeval('vim.api._vim_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._vim_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._vim_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._vim_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._vim_id_dictionary({})')) - eq(4, eval([[type(luaeval('vim.api._vim_id_dictionary({})'))]])) - end) - - it('correctly converts self-containing containers', function() - meths.set_var('l', {}) - eval('add(l, l)') - eq(true, eval('luaeval("_A == _A[1]", l)')) - eq(true, eval('luaeval("_A[1] == _A[1][1]", [l])')) - eq(true, eval('luaeval("_A.d == _A.d[1]", {"d": l})')) - eq(true, eval('luaeval("_A ~= _A[1]", [l])')) - - meths.set_var('d', {foo=42}) - eval('extend(d, {"d": d})') - eq(true, eval('luaeval("_A == _A.d", d)')) - eq(true, eval('luaeval("_A[1] == _A[1].d", [d])')) - eq(true, eval('luaeval("_A.d == _A.d.d", {"d": d})')) - eq(true, eval('luaeval("_A ~= _A.d", {"d": d})')) - end) - - it('errors out correctly when working with API', function() - -- Conversion errors - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Cannot convert given lua type', - exc_exec([[call luaeval("vim.api._vim_id(vim.api._vim_id)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Cannot convert given lua table', - exc_exec([[call luaeval("vim.api._vim_id({1, foo=42})")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Cannot convert given lua type', - exc_exec([[call luaeval("vim.api._vim_id({42, vim.api._vim_id})")]])) - -- Errors in number of arguments - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected 1 argument', - exc_exec([[call luaeval("vim.api._vim_id()")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected 1 argument', - exc_exec([[call luaeval("vim.api._vim_id(1, 2)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected 2 arguments', - exc_exec([[call luaeval("vim.api.vim_set_var(1, 2, 3)")]])) - -- Error in argument types - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected lua string', - exc_exec([[call luaeval("vim.api.vim_set_var(1, 2)")]])) - - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected lua number', - exc_exec([[call luaeval("vim.api.buffer_get_line(0, 'test')")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Number is not integral', - exc_exec([[call luaeval("vim.api.buffer_get_line(0, 1.5)")]])) - - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected lua table', - exc_exec([[call luaeval("vim.api._vim_id_float('test')")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Unexpected type', - exc_exec([[call luaeval("vim.api._vim_id_float({[vim.type_idx]=vim.types.dictionary})")]])) - - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected lua table', - exc_exec([[call luaeval("vim.api._vim_id_array(1)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Unexpected type', - exc_exec([[call luaeval("vim.api._vim_id_array({[vim.type_idx]=vim.types.dictionary})")]])) - - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Expected lua table', - exc_exec([[call luaeval("vim.api._vim_id_dictionary(1)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): Unexpected type', - exc_exec([[call luaeval("vim.api._vim_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.vim_replace_termcodes("", vim, false, nil)')) - eq('', funcs.luaeval('vim.api.vim_replace_termcodes("", 0, 1.5, "test")')) - eq('', funcs.luaeval('vim.api.vim_replace_termcodes("", true, {}, {[vim.type_idx]=vim.types.array})')) - end) - - -- TODO: check buffer/window/etc. -end) -- cgit From 666d85d3ce80c19c9cd2acd156edbf50fd7e8741 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 21 Jan 2017 01:52:19 +0300 Subject: functests: Some more tests --- test/functional/lua/api_spec.lua | 10 ++++++++++ test/functional/lua/luaeval_spec.lua | 7 +++++++ 2 files changed, 17 insertions(+) (limited to 'test') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index 31c855c2c1..f6f65cb741 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -36,6 +36,16 @@ describe('luaeval(vim.api.…)', function() end) end) + it('correctly evaluates API code which calls luaeval', function() + eq(1, funcs.luaeval(([===[vim.api.nvim_eval([==[ + luaeval('vim.api.nvim_eval([=[ + luaeval("vim.api.nvim_eval([[ + luaeval(1) + ]])") + ]=])') + ]==])]===]):gsub('\n', ' '))) + 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"')]])) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 345848cfff..b0169c3d6b 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -241,4 +241,11 @@ describe('luaeval()', function() eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: ERROR', exc_exec([[call luaeval("error('ERROR')")]])) end) + + it('does not leak memory when called with too long line with syntax error', + function() + local s = ('x'):rep(65536) + eq('Vim(call):E5107: Error while creating lua chunk for luaeval(): [string ""]:1: unexpected symbol near \')\'', + exc_exec([[call luaeval("(']] .. s ..[[' + )")]])) + end) end) -- cgit From 140cd0da1d0b10cf19a501696971ca2e20eff75b Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 29 Jan 2017 00:52:48 +0300 Subject: functests: Fix “function has more then 60 upvalues” error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/functional/helpers.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 13a0cff137..a62c05128b 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -570,7 +570,7 @@ local curbufmeths = create_callindex(curbuf) local curwinmeths = create_callindex(curwin) local curtabmeths = create_callindex(curtab) -local M = { +local module = { prepend_argv = prepend_argv, clear = clear, connect = connect, @@ -644,5 +644,5 @@ return function(after_each) check_cores('build/bin/nvim') end) end - return M + return module end -- cgit From 7a5646d594ef4ed97f1969103a1cee32733bfa2d Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 29 Jan 2017 04:11:18 +0300 Subject: functests: Add tests for :lua --- test/functional/lua/commands_spec.lua | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'test') diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 191504bfaa..6a37d1fd1b 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -2,3 +2,56 @@ local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq +local clear = helpers.clear +local meths = helpers.meths +local source = helpers.source +local dedent = helpers.dedent +local exc_exec = helpers.exc_exec +local redir_exec = helpers.redir_exec +local curbufmeths = helpers.curbufmeths + +before_each(clear) + +describe(':lua command', function() + it('works', function() + eq('', redir_exec( + 'lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TEST"})')) + eq({'', 'TEST'}, curbufmeths.get_lines(0, 100, false)) + source(dedent([[ + lua << EOF + vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TSET"}) + EOF]])) + eq({'', 'TSET'}, curbufmeths.get_lines(0, 100, false)) + source(dedent([[ + lua << EOF + vim.api.nvim_buf_set_lines(1, 1, 2, false, {"SETT"})]])) + eq({'', 'SETT'}, curbufmeths.get_lines(0, 100, false)) + source(dedent([[ + lua << EOF + vim.api.nvim_buf_set_lines(1, 1, 2, false, {"ETTS"}) + vim.api.nvim_buf_set_lines(1, 2, 3, false, {"TTSE"}) + vim.api.nvim_buf_set_lines(1, 3, 4, false, {"STTE"}) + EOF]])) + eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false)) + end) + it('throws catchable errors', function() + eq([[Vim(lua):E5104: Error while creating lua chunk: [string ""]:1: unexpected symbol near ')']], + exc_exec('lua ()')) + eq([[Vim(lua):E5105: Error while calling lua chunk: [string ""]:1: TEST]], + exc_exec('lua error("TEST")')) + eq([[Vim(lua):E5105: Error while calling lua chunk: [string ""]:1: Invalid buffer id]], + exc_exec('lua vim.api.nvim_buf_set_lines(-10, 1, 1, false, {"TEST"})')) + eq({''}, curbufmeths.get_lines(0, 100, false)) + end) + it('accepts embedded NLs without heredoc', function() + -- Such code is usually used for `:execute 'lua' {generated_string}`: + -- heredocs do not work in this case. + meths.command([[ + lua + vim.api.nvim_buf_set_lines(1, 1, 2, false, {"ETTS"}) + vim.api.nvim_buf_set_lines(1, 2, 3, false, {"TTSE"}) + vim.api.nvim_buf_set_lines(1, 3, 4, false, {"STTE"}) + ]]) + eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false)) + end) +end) -- cgit From b4e2860c69a4e96fa305b535ce0dbdde37632fe1 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 29 Jan 2017 05:09:54 +0300 Subject: doc,functests: Add documentation Missing: updates to various lists. --- test/functional/lua/commands_spec.lua | 8 ++++++++ test/functional/lua/luaeval_spec.lua | 1 + 2 files changed, 9 insertions(+) (limited to 'test') diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 6a37d1fd1b..c607889edb 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -2,8 +2,10 @@ local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq +local NIL = helpers.NIL local clear = helpers.clear local meths = helpers.meths +local funcs = helpers.funcs local source = helpers.source local dedent = helpers.dedent local exc_exec = helpers.exc_exec @@ -54,4 +56,10 @@ describe(':lua command', function() ]]) eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false)) end) + it('preserves global and not preserves local variables', function() + eq('', redir_exec('lua gvar = 42')) + eq('', redir_exec('lua local lvar = 100500')) + eq(NIL, funcs.luaeval('lvar')) + eq(42, funcs.luaeval('gvar')) + end) end) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index b0169c3d6b..6132d44bee 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -46,6 +46,7 @@ describe('luaeval()', function() funcs.luaeval('{n=1, f=1.5, s="string", l={4, 2}}')) -- Not tested: nil inside containers: behaviour will most likely change. eq(NIL, funcs.luaeval('nil')) + eq({['']=1}, funcs.luaeval('{[""]=1}')) end) end) describe('recursive lua values', function() -- cgit From 9114d9be778b07f4a49edc078f1c159aa51320d8 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 29 Jan 2017 18:40:39 +0300 Subject: executor: Add :luado command --- test/functional/lua/luaeval_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 6132d44bee..5d0180b212 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -36,7 +36,7 @@ describe('luaeval()', function() it('is successfully received', function() local t = {t=true, f=false, --[[n=NIL,]] d={l={'string', 42, 0.42}}} eq(t, funcs.luaeval("_A", t)) - -- Not tested: nil, funcrefs, returned object identity: behaviour will + -- Not tested: nil, funcrefs, returned object identity: behaviour will -- most likely change. end) end) -- cgit From e1bbaca7acf7fc498da49081d069b00aa05506df Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 29 Jan 2017 19:26:22 +0300 Subject: executor,functests: Add tests for :luado, also some fixes Fixes: 1. Allocate space for the NUL byte. 2. Do not exclude last line from range. 3. Remove code for sandbox: it is handled earlier. 4. Fix index in new_line_transformed when converting NULs to NLs. 5. Always allocate new_line_transformed, but save allocated value. --- test/functional/lua/commands_spec.lua | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'test') diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index c607889edb..f1d430b34c 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -63,3 +63,48 @@ describe(':lua command', function() eq(42, funcs.luaeval('gvar')) end) end) + +describe(':luado command', function() + it('works', function() + curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"}) + eq('', redir_exec('luado lines = (lines or {}) lines[#lines + 1] = {linenr, line}')) + eq({'ABC', 'def', 'gHi'}, curbufmeths.get_lines(0, -1, false)) + eq({{1, 'ABC'}, {2, 'def'}, {3, 'gHi'}}, funcs.luaeval('lines')) + + -- Automatic transformation of numbers + eq('', redir_exec('luado return linenr')) + eq({'1', '2', '3'}, curbufmeths.get_lines(0, -1, false)) + + eq('', redir_exec('luado return ("<%02x>"):format(line:byte())')) + eq({'<31>', '<32>', '<33>'}, curbufmeths.get_lines(0, -1, false)) + end) + it('stops processing lines when suddenly out of lines', function() + curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"}) + eq('', redir_exec('2,$luado runs = ((runs or 0) + 1) vim.api.nvim_command("%d")')) + eq({''}, curbufmeths.get_lines(0, -1, false)) + eq(1, funcs.luaeval('runs')) + end) + it('works correctly when changing lines out of range', function() + curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"}) + eq('\nE322: line number out of range: 1 past the end\nE320: Cannot find line 2', + redir_exec('2,$luado vim.api.nvim_command("%d") return linenr')) + eq({''}, curbufmeths.get_lines(0, -1, false)) + end) + it('fails on errors', function() + eq([[Vim(luado):E5109: Error while creating lua chunk: [string ""]:1: unexpected symbol near ')']], + exc_exec('luado ()')) + eq([[Vim(luado):E5111: Error while calling lua function: [string ""]:1: attempt to perform arithmetic on global 'liness' (a nil value)]], + exc_exec('luado return liness + 1')) + end) + it('fails in sandbox when needed', function() + curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"}) + eq('\nE48: Not allowed in sandbox: sandbox luado runs = (runs or 0) + 1', + redir_exec('sandbox luado runs = (runs or 0) + 1')) + eq(NIL, funcs.luaeval('runs')) + end) + it('works with long strings', function() + local s = ('x'):rep(100500) + eq('', redir_exec(('luado return "%s"'):format(s))) + eq({s}, curbufmeths.get_lines(0, -1, false)) + end) +end) -- cgit From 295e7607c472b49e8c0762977e38c4527b746b6f Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 29 Jan 2017 19:32:01 +0300 Subject: executor: Fix some memory leaks --- test/functional/lua/commands_spec.lua | 13 +++++++++++++ test/functional/lua/luaeval_spec.lua | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index f1d430b34c..41a5a8d9e0 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -62,6 +62,15 @@ describe(':lua command', function() eq(NIL, funcs.luaeval('lvar')) eq(42, funcs.luaeval('gvar')) end) + it('works with long strings', function() + local s = ('x'):rep(100500) + + eq('\nE5104: Error while creating lua chunk: [string ""]:1: unfinished string near \'\'', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s})'):format(s))) + eq({''}, curbufmeths.get_lines(0, -1, false)) + + eq('', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s"})'):format(s))) + eq({'', s}, curbufmeths.get_lines(0, -1, false)) + end) end) describe(':luado command', function() @@ -104,6 +113,10 @@ describe(':luado command', function() end) it('works with long strings', function() local s = ('x'):rep(100500) + + eq('\nE5109: Error while creating lua chunk: [string ""]:1: unfinished string near \'\'', redir_exec(('luado return "%s'):format(s))) + eq({''}, curbufmeths.get_lines(0, -1, false)) + eq('', redir_exec(('luado return "%s"'):format(s))) eq({s}, curbufmeths.get_lines(0, -1, false)) end) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 5d0180b212..7973cabae4 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -243,10 +243,11 @@ describe('luaeval()', function() exc_exec([[call luaeval("error('ERROR')")]])) end) - it('does not leak memory when called with too long line with syntax error', + it('does not leak memory when called with too long line', function() local s = ('x'):rep(65536) eq('Vim(call):E5107: Error while creating lua chunk for luaeval(): [string ""]:1: unexpected symbol near \')\'', exc_exec([[call luaeval("(']] .. s ..[[' + )")]])) + eq(s, funcs.luaeval('"' .. s .. '"')) end) end) -- cgit From dcb992ab3759b604c1824913002714a018be0532 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 29 Jan 2017 19:51:55 +0300 Subject: executor: Add :luafile command --- test/functional/lua/commands_spec.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'test') diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 41a5a8d9e0..80fac07f8c 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -9,6 +9,7 @@ local funcs = helpers.funcs local source = helpers.source local dedent = helpers.dedent local exc_exec = helpers.exc_exec +local write_file = helpers.write_file local redir_exec = helpers.redir_exec local curbufmeths = helpers.curbufmeths @@ -121,3 +122,30 @@ describe(':luado command', function() eq({s}, curbufmeths.get_lines(0, -1, false)) end) end) + +describe(':luafile', function() + local fname = 'Xtest-functional-lua-commands-luafile' + + after_each(function() + os.remove(fname) + end) + + it('works', function() + write_file(fname, [[ + vim.api.nvim_buf_set_lines(1, 1, 2, false, {"ETTS"}) + vim.api.nvim_buf_set_lines(1, 2, 3, false, {"TTSE"}) + vim.api.nvim_buf_set_lines(1, 3, 4, false, {"STTE"}) + ]]) + eq('', redir_exec('luafile ' .. fname)) + eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false)) + end) + + it('correctly errors out', function() + write_file(fname, '()') + eq(("Vim(luafile):E5112: Error while creating lua chunk: %s:1: unexpected symbol near ')'"):format(fname), + exc_exec('luafile ' .. fname)) + write_file(fname, 'vimm.api.nvim_buf_set_lines(1, 1, 2, false, {"ETTS"})') + eq(("Vim(luafile):E5113: Error while calling lua chunk: %s:1: attempt to index global 'vimm' (a nil value)"):format(fname), + exc_exec('luafile ' .. fname)) + end) +end) -- cgit From 9fd2bf67aa1db66e3465753d5aaaec342f4ce193 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 29 Jan 2017 23:22:50 +0300 Subject: executor,functests: Add print() tests, some fixes --- test/functional/lua/commands_spec.lua | 13 +++++++ test/functional/lua/luaeval_spec.lua | 2 ++ test/functional/lua/overrides_spec.lua | 65 ++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 test/functional/lua/overrides_spec.lua (limited to 'test') diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 80fac07f8c..017ee55729 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -46,6 +46,10 @@ describe(':lua command', function() exc_exec('lua vim.api.nvim_buf_set_lines(-10, 1, 1, false, {"TEST"})')) eq({''}, curbufmeths.get_lines(0, 100, false)) end) + it('works with NULL errors', function() + eq([=[Vim(lua):E5105: Error while calling lua chunk: [NULL]]=], + exc_exec('lua error(nil)')) + end) it('accepts embedded NLs without heredoc', function() -- Such code is usually used for `:execute 'lua' {generated_string}`: -- heredocs do not work in this case. @@ -106,6 +110,10 @@ describe(':luado command', function() eq([[Vim(luado):E5111: Error while calling lua function: [string ""]:1: attempt to perform arithmetic on global 'liness' (a nil value)]], exc_exec('luado return liness + 1')) end) + it('works with NULL errors', function() + eq([=[Vim(luado):E5111: Error while calling lua function: [NULL]]=], + exc_exec('luado error(nil)')) + end) it('fails in sandbox when needed', function() curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"}) eq('\nE48: Not allowed in sandbox: sandbox luado runs = (runs or 0) + 1', @@ -148,4 +156,9 @@ describe(':luafile', function() eq(("Vim(luafile):E5113: Error while calling lua chunk: %s:1: attempt to index global 'vimm' (a nil value)"):format(fname), exc_exec('luafile ' .. fname)) end) + it('works with NULL errors', function() + write_file(fname, 'error(nil)') + eq([=[Vim(luafile):E5113: Error while calling lua chunk: [NULL]]=], + exc_exec('luafile ' .. fname)) + end) end) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 7973cabae4..6da0001cea 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -241,6 +241,8 @@ describe('luaeval()', function() exc_exec([[call luaeval("vim.xxx_nonexistent_key_xxx()")]])) eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: ERROR', exc_exec([[call luaeval("error('ERROR')")]])) + eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [NULL]', + exc_exec([[call luaeval("error(nil)")]])) end) it('does not leak memory when called with too long line', diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua new file mode 100644 index 0000000000..92167d18dc --- /dev/null +++ b/test/functional/lua/overrides_spec.lua @@ -0,0 +1,65 @@ +-- Test for Vim overrides of lua built-ins +local helpers = require('test.functional.helpers')(after_each) + +local eq = helpers.eq +local NIL = helpers.NIL +local clear = helpers.clear +local funcs = helpers.funcs +local meths = helpers.meths +local command = helpers.command +local write_file = helpers.write_file +local redir_exec = helpers.redir_exec + +local fname = 'Xtest-functional-lua-overrides-luafile' + +before_each(clear) + +after_each(function() + os.remove(fname) +end) + +describe('print', function() + it('returns nothing', function() + eq(NIL, funcs.luaeval('print("abc")')) + eq(0, funcs.luaeval('select("#", print("abc"))')) + end) + it('allows catching printed text with :execute', function() + eq('\nabc', funcs.execute('lua print("abc")')) + eq('\nabc', funcs.execute('luado print("abc")')) + eq('\nabc', funcs.execute('call luaeval("print(\'abc\')")')) + write_file(fname, 'print("abc")') + eq('\nabc', funcs.execute('luafile ' .. fname)) + + eq('\nabc', redir_exec('lua print("abc")')) + eq('\nabc', redir_exec('luado print("abc")')) + eq('\nabc', redir_exec('call luaeval("print(\'abc\')")')) + write_file(fname, 'print("abc")') + eq('\nabc', redir_exec('luafile ' .. fname)) + end) + it('handles errors in __tostring', function() + write_file(fname, [[ + local meta_nilerr = { __tostring = function() error(nil) end } + local meta_abcerr = { __tostring = function() error("abc") end } + local meta_tblout = { __tostring = function() return {"TEST"} end } + v_nilerr = setmetatable({}, meta_nilerr) + v_abcerr = setmetatable({}, meta_abcerr) + v_tblout = setmetatable({}, meta_tblout) + ]]) + eq('', redir_exec('luafile ' .. fname)) + eq('\nE5114: Error while converting print argument #2: [NULL]', + redir_exec('lua print("foo", v_nilerr, "bar")')) + eq('\nE5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc', + redir_exec('lua print("foo", v_abcerr, "bar")')) + eq('\nE5114: Error while converting print argument #2: ', + redir_exec('lua print("foo", v_tblout, "bar")')) + end) + it('prints strings with NULs and NLs correctly', function() + meths.set_option('more', true) + eq('\nabc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT\n', + redir_exec([[lua print("abc \0 def\nghi\0\0\0jkl\nTEST\n\n\nT\n")]])) + eq('\nabc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT^@', + redir_exec([[lua print("abc \0 def\nghi\0\0\0jkl\nTEST\n\n\nT\0")]])) + eq('\nT^@', redir_exec([[lua print("T\0")]])) + eq('\nT\n', redir_exec([[lua print("T\n")]])) + end) +end) -- cgit From d13fdfd4467db8245159d10d96c1f30b24b51565 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 30 Jan 2017 03:30:45 +0300 Subject: functests: Add test for debug.debug --- test/functional/lua/overrides_spec.lua | 111 +++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) (limited to 'test') diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 92167d18dc..60a0589b48 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -1,8 +1,10 @@ -- Test for Vim overrides of lua built-ins local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local eq = helpers.eq local NIL = helpers.NIL +local feed = helpers.feed local clear = helpers.clear local funcs = helpers.funcs local meths = helpers.meths @@ -10,6 +12,8 @@ local command = helpers.command local write_file = helpers.write_file local redir_exec = helpers.redir_exec +local screen + local fname = 'Xtest-functional-lua-overrides-luafile' before_each(clear) @@ -63,3 +67,110 @@ describe('print', function() eq('\nT\n', redir_exec([[lua print("T\n")]])) end) end) + +describe('debug.debug', function() + before_each(function() + screen = Screen.new() + screen:attach() + screen:set_default_attr_ids({ + [0] = {bold=true, foreground=255}, + E = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + cr = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + end) + it('works', function() + write_file(fname, [[ + function Test(a) + print(a) + debug.debug() + print(a * 100) + end + ]]) + eq('', redir_exec('luafile ' .. fname)) + feed(':lua Test()\n') + screen:expect([[ + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + nil | + lua_debug> ^ | + ]]) + feed('print("TEST")\n') + screen:expect([[ + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + nil | + lua_debug> print("TEST") | + TEST | + lua_debug> ^ | + ]]) + feed('') + screen:expect([[ + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + nil | + lua_debug> print("TEST") | + TEST | + | + {E:E5105: Error while calling lua chunk: Xtest-functiona}| + {E:l-lua-overrides-luafile:4: attempt to perform arithme}| + {E:tic on local 'a' (a nil value)} | + Interrupt: {cr:Press ENTER or type command to continue}^ | + ]]) + feed(':lua Test()\n') + screen:expect([[ + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + nil | + lua_debug> ^ | + ]]) + feed('\n') + screen:expect([[ + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + nil | + lua_debug> | + {E:E5105: Error while calling lua chunk: Xtest-functiona}| + {E:l-lua-overrides-luafile:4: attempt to perform arithme}| + {E:tic on local 'a' (a nil value)} | + {cr:Press ENTER or type command to continue}^ | + ]]) + end) +end) -- cgit From a24e94215ed0a4bfe55b6741ab2e9477b278dbb7 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 30 Jan 2017 03:35:45 +0300 Subject: eval,functests: Fix linter errors --- test/functional/lua/overrides_spec.lua | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'test') diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 60a0589b48..c8aee130a7 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -79,14 +79,13 @@ describe('debug.debug', function() }) end) it('works', function() - write_file(fname, [[ + command([[lua function Test(a) print(a) debug.debug() print(a * 100) end ]]) - eq('', redir_exec('luafile ' .. fname)) feed(':lua Test()\n') screen:expect([[ {0:~ }| @@ -133,9 +132,9 @@ describe('debug.debug', function() lua_debug> print("TEST") | TEST | | - {E:E5105: Error while calling lua chunk: Xtest-functiona}| - {E:l-lua-overrides-luafile:4: attempt to perform arithme}| - {E:tic on local 'a' (a nil value)} | + {E:E5105: Error while calling lua chunk: [string ""]:5: attempt to perform arithmetic o}| + {E:n local 'a' (a nil value)} | Interrupt: {cr:Press ENTER or type command to continue}^ | ]]) feed(':lua Test()\n') @@ -167,9 +166,9 @@ describe('debug.debug', function() {0:~ }| nil | lua_debug> | - {E:E5105: Error while calling lua chunk: Xtest-functiona}| - {E:l-lua-overrides-luafile:4: attempt to perform arithme}| - {E:tic on local 'a' (a nil value)} | + {E:E5105: Error while calling lua chunk: [string ""]:5: attempt to perform arithmetic o}| + {E:n local 'a' (a nil value)} | {cr:Press ENTER or type command to continue}^ | ]]) end) -- cgit From a40a969e9a4776f1e274dcf0e59c8f1ec1770ca0 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 8 Apr 2017 20:33:48 +0300 Subject: api: Rename _vim_id functions to nvim__id --- test/functional/lua/api_spec.lua | 108 +++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 54 deletions(-) (limited to 'test') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index f6f65cb741..c74dfb90a0 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -73,84 +73,84 @@ describe('luaeval(vim.api.…)', function() end) it('correctly converts to API objects', function() - eq(1, funcs.luaeval('vim.api._vim_id(1)')) - eq('1', funcs.luaeval('vim.api._vim_id("1")')) - eq({1}, funcs.luaeval('vim.api._vim_id({1})')) - eq({foo=1}, funcs.luaeval('vim.api._vim_id({foo=1})')) - eq(1.5, funcs.luaeval('vim.api._vim_id(1.5)')) - eq(true, funcs.luaeval('vim.api._vim_id(true)')) - eq(false, funcs.luaeval('vim.api._vim_id(false)')) - eq(NIL, funcs.luaeval('vim.api._vim_id(nil)')) - - eq(0, eval([[type(luaeval('vim.api._vim_id(1)'))]])) - eq(1, eval([[type(luaeval('vim.api._vim_id("1")'))]])) - eq(3, eval([[type(luaeval('vim.api._vim_id({1})'))]])) - eq(4, eval([[type(luaeval('vim.api._vim_id({foo=1})'))]])) - eq(5, eval([[type(luaeval('vim.api._vim_id(1.5)'))]])) - eq(6, eval([[type(luaeval('vim.api._vim_id(true)'))]])) - eq(6, eval([[type(luaeval('vim.api._vim_id(false)'))]])) - eq(7, eval([[type(luaeval('vim.api._vim_id(nil)'))]])) - - eq({foo=1, bar={42, {{baz=true}, 5}}}, funcs.luaeval('vim.api._vim_id({foo=1, bar={42, {{baz=true}, 5}}})')) + 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._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=0})"))')) - eq(4, eval([[type(luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.dictionary})'))]])) - eq(3, eval([[type(luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array})'))]])) + 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._vim_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._vim_id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) - eq({foo=2}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) - eq(10, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) - eq({}, funcs.luaeval('vim.api._vim_id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})')) + 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._vim_id_array({[vim.type_idx]=vim.types.array})'))]])) + eq(3, eval([[type(luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array})'))]])) - eq({}, funcs.luaeval('vim.api._vim_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._vim_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._vim_id_array({{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) - eq({10}, funcs.luaeval('vim.api._vim_id_array({{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) - eq({}, funcs.luaeval('vim.api._vim_id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})')) + 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._vim_id_array({})')) - eq(3, eval([[type(luaeval('vim.api._vim_id_array({})'))]])) + 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._vim_id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]])) + eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]])) - eq({}, funcs.luaeval('vim.api._vim_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._vim_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._vim_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._vim_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._vim_id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2}})')) + 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._vim_id_dictionary({})')) - eq(4, eval([[type(luaeval('vim.api._vim_id_dictionary({})'))]])) + 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 while calling lua chunk for luaeval(): [string ""]:1: Cannot convert given lua type', - exc_exec([[call luaeval("vim.api._vim_id(vim.api._vim_id)")]])) + exc_exec([[call luaeval("vim.api.nvim__id(vim.api.nvim__id)")]])) eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Cannot convert given lua table', - exc_exec([[call luaeval("vim.api._vim_id({1, foo=42})")]])) + exc_exec([[call luaeval("vim.api.nvim__id({1, foo=42})")]])) eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Cannot convert given lua type', - exc_exec([[call luaeval("vim.api._vim_id({42, vim.api._vim_id})")]])) + exc_exec([[call luaeval("vim.api.nvim__id({42, vim.api.nvim__id})")]])) -- Errors in number of arguments eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected 1 argument', - exc_exec([[call luaeval("vim.api._vim_id()")]])) + exc_exec([[call luaeval("vim.api.nvim__id()")]])) eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected 1 argument', - exc_exec([[call luaeval("vim.api._vim_id(1, 2)")]])) + exc_exec([[call luaeval("vim.api.nvim__id(1, 2)")]])) eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected 2 arguments', exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2, 3)")]])) -- Error in argument types @@ -163,19 +163,19 @@ describe('luaeval(vim.api.…)', function() exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 1.5, 1, false)")]])) eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected lua table', - exc_exec([[call luaeval("vim.api._vim_id_float('test')")]])) + exc_exec([[call luaeval("vim.api.nvim__id_float('test')")]])) eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Unexpected type', - exc_exec([[call luaeval("vim.api._vim_id_float({[vim.type_idx]=vim.types.dictionary})")]])) + exc_exec([[call luaeval("vim.api.nvim__id_float({[vim.type_idx]=vim.types.dictionary})")]])) eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected lua table', - exc_exec([[call luaeval("vim.api._vim_id_array(1)")]])) + exc_exec([[call luaeval("vim.api.nvim__id_array(1)")]])) eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Unexpected type', - exc_exec([[call luaeval("vim.api._vim_id_array({[vim.type_idx]=vim.types.dictionary})")]])) + exc_exec([[call luaeval("vim.api.nvim__id_array({[vim.type_idx]=vim.types.dictionary})")]])) eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected lua table', - exc_exec([[call luaeval("vim.api._vim_id_dictionary(1)")]])) + exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]])) eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Unexpected type', - exc_exec([[call luaeval("vim.api._vim_id_dictionary({[vim.type_idx]=vim.types.array})")]])) + 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 -- cgit From 9cad5155e3dd44d2b767f0889fdb66231208603d Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 11 Apr 2017 01:18:42 +0300 Subject: functests: Make sure funcs.luaeval receives only one argument --- test/functional/lua/api_spec.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index c74dfb90a0..a064e0f98f 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -37,13 +37,14 @@ describe('luaeval(vim.api.…)', function() end) it('correctly evaluates API code which calls luaeval', function() - eq(1, funcs.luaeval(([===[vim.api.nvim_eval([==[ + local str = (([===[vim.api.nvim_eval([==[ luaeval('vim.api.nvim_eval([=[ luaeval("vim.api.nvim_eval([[ luaeval(1) ]])") ]=])') - ]==])]===]):gsub('\n', ' '))) + ]==])]===]):gsub('\n', ' ')) + eq(1, funcs.luaeval(str)) end) it('correctly converts from API objects', function() -- cgit From add76592d9a690d12e266da1f788e588bb42b919 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 11 Apr 2017 02:24:37 +0300 Subject: functests: Test for “string cannot contain newline” set_lines error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Should make me able to determine whether they are lua bindings that contain a bug or set_lines. --- test/functional/api/buffer_spec.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'test') diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index c3002618b0..2e3b570571 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -10,6 +10,7 @@ local insert = helpers.insert local NIL = helpers.NIL local meth_pcall = helpers.meth_pcall local command = helpers.command +local bufmeths = helpers.bufmeths describe('api/buf', function() before_each(clear) @@ -121,6 +122,15 @@ describe('api/buf', function() local get_lines, set_lines = curbufmeths.get_lines, curbufmeths.set_lines local line_count = curbufmeths.line_count + it('fails correctly when input is not valid', function() + eq(1, curbufmeths.get_number()) + local err, emsg = pcall(bufmeths.set_lines, 1, 1, 2, false, {'b\na'}) + eq(false, err) + local exp_emsg = 'string cannot contain newlines' + -- Expected {filename}:{lnum}: {exp_emsg} + eq(': ' .. exp_emsg, emsg:sub(-#exp_emsg - 2)) + end) + it('has correct line_count when inserting and deleting', function() eq(1, line_count()) set_lines(-1, -1, true, {'line'}) -- cgit From acd9ed8d8397cbab5c7300b06beda4daa053e9e2 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 11 Apr 2017 02:32:13 +0300 Subject: functests: Add another check for the similar transformation Reasoning is majorly the same: check whether lua has bug or API function has bug, but on the other side: previous commit is checking whether similar bug when using API via msgpack RPC, this commit is checking whether another API function used via lua bindings triggers the same bug. Should additionally give a hint about which lua code contains a bug. --- test/functional/lua/api_spec.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index a064e0f98f..7dc7e962fb 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -29,11 +29,17 @@ describe('luaeval(vim.api.…)', function() end) end) describe('with errors', function() - it('transforms API errors into lua errors', function() + it('transforms API errors from nvim_buf_set_lines into lua errors', 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 errors from nvim_win_set_cursor into lua errors', function() + funcs.setline(1, {"abc", "def", "a\nb", "ttt"}) + eq({false, 'Argument "pos" must be a [row, col] array'}, + funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, 1, {1, 2, 3})}')) + end) end) it('correctly evaluates API code which calls luaeval', function() -- cgit From 78082e8d3e54b4bee47d8a6c9ae2530a7e992dc9 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 11 Apr 2017 10:38:57 +0300 Subject: functests: Check whether it is a problem with an array --- test/functional/lua/api_spec.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index 7dc7e962fb..a70e70b2b9 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -29,17 +29,22 @@ describe('luaeval(vim.api.…)', function() end) end) describe('with errors', function() - it('transforms API errors from nvim_buf_set_lines into lua 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 errors from nvim_win_set_cursor into lua errors', function() - funcs.setline(1, {"abc", "def", "a\nb", "ttt"}) + 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, 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, 1, {"b\\na"})}')) + end) end) it('correctly evaluates API code which calls luaeval', function() -- cgit From 5b6d598ca8301682d931539ecd6da6a9fabae569 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 8 May 2017 21:06:23 +0300 Subject: functests: Fix tests --- test/functional/api/window_spec.lua | 7 +++++++ test/functional/lua/api_spec.lua | 7 +++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 6882f50a3e..8a65d3f71e 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -9,6 +9,7 @@ local funcs = helpers.funcs local request = helpers.request local NIL = helpers.NIL local meth_pcall = helpers.meth_pcall +local meths = helpers.meths local command = helpers.command -- check if str is visible at the beginning of some line @@ -55,6 +56,12 @@ describe('api/win', function() eq('typing\n some dumb text', curbuf_contents()) end) + it('does not leak memory when using invalid window ID with invalid pos', + function() + eq({false, 'Invalid window id'}, + meth_pcall(meths.win_set_cursor, 1, {"b\na"})) + end) + it('updates the screen, and also when the window is unfocused', function() insert("prologue") feed('100o') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index b07a7a75e4..b1dc5c07fd 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -37,13 +37,16 @@ describe('luaeval(vim.api.…)', function() 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, 1, {1, 2, 3})}')) + 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, 1, {"b\\na"})}')) + funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {"b\\na"})}')) end) end) -- cgit