diff options
Diffstat (limited to 'test/functional/lua/vim_spec.lua')
-rw-r--r-- | test/functional/lua/vim_spec.lua | 264 |
1 files changed, 224 insertions, 40 deletions
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 2b249b7a69..867f366d06 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') +local nvim_prog = helpers.nvim_prog local funcs = helpers.funcs local meths = helpers.meths local command = helpers.command @@ -22,8 +23,8 @@ local remove_trace = helpers.remove_trace local mkdir_p = helpers.mkdir_p local rmdir = helpers.rmdir local write_file = helpers.write_file -local expect_exit = helpers.expect_exit local poke_eventloop = helpers.poke_eventloop +local assert_alive = helpers.assert_alive describe('lua stdlib', function() before_each(clear) @@ -158,28 +159,32 @@ describe('lua stdlib', function() end) it("vim.str_utfindex/str_byteindex", function() - exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]]) - local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48} - local indicies16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48} - for i,k in pairs(indicies32) do + exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ\000ъ"]]) + local indices32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48,49,51} + local indices16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48,49,51} + for i,k in pairs(indices32) do eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ...)", i), i) end - for i,k in pairs(indicies16) do + for i,k in pairs(indices16) do eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ..., true)", i), i) end + eq("index out of range", pcall_err(exec_lua, "return vim.str_byteindex(_G.test_text, ...)", #indices32 + 1)) + eq("index out of range", pcall_err(exec_lua, "return vim.str_byteindex(_G.test_text, ..., true)", #indices16 + 1)) local i32, i16 = 0, 0 - for k = 0,48 do - if indicies32[i32] < k then + local len = 51 + for k = 0,len do + if indices32[i32] < k then i32 = i32 + 1 end - if indicies16[i16] < k then + if indices16[i16] < k then i16 = i16 + 1 - if indicies16[i16+1] == indicies16[i16] then + if indices16[i16+1] == indices16[i16] then i16 = i16 + 1 end end eq({i32, i16}, exec_lua("return {vim.str_utfindex(_G.test_text, ...)}", k), k) end + eq("index out of range", pcall_err(exec_lua, "return vim.str_utfindex(_G.test_text, ...)", len + 1)) end) it("vim.str_utf_start", function() @@ -414,6 +419,12 @@ describe('lua stdlib', function() return getmetatable(t2) == mt ]])) + ok(exec_lua([[ + local t1 = {a = vim.NIL} + local t2 = vim.deepcopy(t1) + return t2.a == vim.NIL + ]])) + matches('Cannot deepcopy object of type thread', pcall_err(exec_lua, [[ local thread = coroutine.create(function () return 0 end) @@ -425,6 +436,8 @@ describe('lua stdlib', function() it('vim.pesc', function() eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]])) eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) + -- pesc() returns one result. #20751 + eq({'x'}, exec_lua([[return {vim.pesc('x')}]])) -- Validates args. matches('s: expected string, got number', @@ -499,6 +512,8 @@ describe('lua stdlib', function() eq(NIL, exec_lua("return vim.tbl_get({ unindexable = function () end }, 'unindexable', 'missing_key')")) eq(NIL, exec_lua("return vim.tbl_get({}, 'missing_key')")) eq(NIL, exec_lua("return vim.tbl_get({})")) + eq(1, exec_lua("return select('#', vim.tbl_get({}))")) + eq(1, exec_lua("return select('#', vim.tbl_get({ nested = {} }, 'nested', 'missing_key'))")) end) it('vim.tbl_extend', function() @@ -748,6 +763,20 @@ describe('lua stdlib', function() pcall_err(exec_lua, code)) end) + it('vim.spairs', function() + local res = '' + local table = { + ccc=1, + bbb=2, + ddd=3, + aaa=4 + } + for key, _ in vim.spairs(table) do + res = res .. key + end + matches('aaabbbcccddd', res) + end) + it('vim.call, vim.fn', function() eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]])) eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]])) @@ -788,6 +817,11 @@ describe('lua stdlib', function() local x = vim.fn.VarArg(function() return 'foo' end, function() return 'bar' end) return #x == 2 and x[1]() == 'foo' and x[2]() == 'bar' ]])) + + -- Test for #20211 + eq('a (b) c', exec_lua([[ + return vim.fn.substitute('a b c', 'b', function(m) return '(' .. m[1] .. ')' end, 'g') + ]])) end) it('vim.fn should error when calling API function', function() @@ -896,7 +930,7 @@ describe('lua stdlib', function() ]])) -- vim.empty_dict() gives new value each time - -- equality is not overriden (still by ref) + -- equality is not overridden (still by ref) -- non-empty table uses the usual heuristics (ignores the tag) eq({false, {"foo"}, {namey="bar"}}, exec_lua([[ local aa = vim.empty_dict() @@ -1006,11 +1040,11 @@ describe('lua stdlib', function() eq('hi', funcs.luaeval "vim.g.testing") eq(123, funcs.luaeval "vim.g.other") eq(5120.1, funcs.luaeval "vim.g.floaty") - eq(NIL, funcs.luaeval "vim.g.nonexistant") + eq(NIL, funcs.luaeval "vim.g.nonexistent") eq(NIL, funcs.luaeval "vim.g.nullvar") -- lost over RPC, so test locally: eq({false, true}, exec_lua [[ - return {vim.g.nonexistant == vim.NIL, vim.g.nullvar == vim.NIL} + return {vim.g.nonexistent == vim.NIL, vim.g.nullvar == vim.NIL} ]]) eq({hello="world"}, funcs.luaeval "vim.g.to_delete") @@ -1029,6 +1063,7 @@ describe('lua stdlib', function() vim.g.AddCounter = add_counter vim.g.GetCounter = get_counter vim.g.funcs = {add = add_counter, get = get_counter} + vim.g.AddParens = function(s) return '(' .. s .. ')' end ]] eq(0, eval('g:GetCounter()')) @@ -1044,6 +1079,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.g.funcs.get()]])) exec_lua([[vim.api.nvim_get_var('funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]])) + eq('((foo))', eval([['foo'->AddParens()->AddParens()]])) exec_lua [[ local counter = 0 @@ -1052,6 +1088,7 @@ describe('lua stdlib', function() vim.api.nvim_set_var('AddCounter', add_counter) vim.api.nvim_set_var('GetCounter', get_counter) vim.api.nvim_set_var('funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_set_var('AddParens', function(s) return '(' .. s .. ')' end) ]] eq(0, eval('g:GetCounter()')) @@ -1067,6 +1104,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.g.funcs.get()]])) exec_lua([[vim.api.nvim_get_var('funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]])) + eq('((foo))', eval([['foo'->AddParens()->AddParens()]])) exec([[ function Test() @@ -1109,12 +1147,12 @@ describe('lua stdlib', function() eq('bye', funcs.luaeval "vim.b[BUF].testing") eq(123, funcs.luaeval "vim.b.other") eq(5120.1, funcs.luaeval "vim.b.floaty") - eq(NIL, funcs.luaeval "vim.b.nonexistant") - eq(NIL, funcs.luaeval "vim.b[BUF].nonexistant") + eq(NIL, funcs.luaeval "vim.b.nonexistent") + eq(NIL, funcs.luaeval "vim.b[BUF].nonexistent") eq(NIL, funcs.luaeval "vim.b.nullvar") -- lost over RPC, so test locally: eq({false, true}, exec_lua [[ - return {vim.b.nonexistant == vim.NIL, vim.b.nullvar == vim.NIL} + return {vim.b.nonexistent == vim.NIL, vim.b.nullvar == vim.NIL} ]]) matches([[attempt to index .* nil value]], @@ -1133,6 +1171,7 @@ describe('lua stdlib', function() vim.b.AddCounter = add_counter vim.b.GetCounter = get_counter vim.b.funcs = {add = add_counter, get = get_counter} + vim.b.AddParens = function(s) return '(' .. s .. ')' end ]] eq(0, eval('b:GetCounter()')) @@ -1148,6 +1187,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.b.funcs.get()]])) exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]])) exec_lua [[ local counter = 0 @@ -1156,6 +1196,7 @@ describe('lua stdlib', function() vim.api.nvim_buf_set_var(0, 'AddCounter', add_counter) vim.api.nvim_buf_set_var(0, 'GetCounter', get_counter) vim.api.nvim_buf_set_var(0, 'funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_buf_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end) ]] eq(0, eval('b:GetCounter()')) @@ -1171,6 +1212,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.b.funcs.get()]])) exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]])) exec([[ function Test() @@ -1189,7 +1231,7 @@ describe('lua stdlib', function() eq(NIL, funcs.luaeval "vim.b.testing") eq(NIL, funcs.luaeval "vim.b.other") - eq(NIL, funcs.luaeval "vim.b.nonexistant") + eq(NIL, funcs.luaeval "vim.b.nonexistent") end) it('vim.w', function() @@ -1208,8 +1250,8 @@ describe('lua stdlib', function() eq('hi', funcs.luaeval "vim.w.testing") eq('bye', funcs.luaeval "vim.w[WIN].testing") eq(123, funcs.luaeval "vim.w.other") - eq(NIL, funcs.luaeval "vim.w.nonexistant") - eq(NIL, funcs.luaeval "vim.w[WIN].nonexistant") + eq(NIL, funcs.luaeval "vim.w.nonexistent") + eq(NIL, funcs.luaeval "vim.w[WIN].nonexistent") matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.w[WIN][0].testing')) @@ -1227,6 +1269,7 @@ describe('lua stdlib', function() vim.w.AddCounter = add_counter vim.w.GetCounter = get_counter vim.w.funcs = {add = add_counter, get = get_counter} + vim.w.AddParens = function(s) return '(' .. s .. ')' end ]] eq(0, eval('w:GetCounter()')) @@ -1242,6 +1285,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.w.funcs.get()]])) exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]])) exec_lua [[ local counter = 0 @@ -1250,6 +1294,7 @@ describe('lua stdlib', function() vim.api.nvim_win_set_var(0, 'AddCounter', add_counter) vim.api.nvim_win_set_var(0, 'GetCounter', get_counter) vim.api.nvim_win_set_var(0, 'funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_win_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end) ]] eq(0, eval('w:GetCounter()')) @@ -1265,6 +1310,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.w.funcs.get()]])) exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]])) exec([[ function Test() @@ -1283,7 +1329,7 @@ describe('lua stdlib', function() eq(NIL, funcs.luaeval "vim.w.testing") eq(NIL, funcs.luaeval "vim.w.other") - eq(NIL, funcs.luaeval "vim.w.nonexistant") + eq(NIL, funcs.luaeval "vim.w.nonexistent") end) it('vim.t', function() @@ -1295,10 +1341,10 @@ describe('lua stdlib', function() eq('hi', funcs.luaeval "vim.t.testing") eq(123, funcs.luaeval "vim.t.other") - eq(NIL, funcs.luaeval "vim.t.nonexistant") + eq(NIL, funcs.luaeval "vim.t.nonexistent") eq('hi', funcs.luaeval "vim.t[0].testing") eq(123, funcs.luaeval "vim.t[0].other") - eq(NIL, funcs.luaeval "vim.t[0].nonexistant") + eq(NIL, funcs.luaeval "vim.t[0].nonexistent") matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.t[0][0].testing')) @@ -1316,6 +1362,7 @@ describe('lua stdlib', function() vim.t.AddCounter = add_counter vim.t.GetCounter = get_counter vim.t.funcs = {add = add_counter, get = get_counter} + vim.t.AddParens = function(s) return '(' .. s .. ')' end ]] eq(0, eval('t:GetCounter()')) @@ -1331,6 +1378,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.t.funcs.get()]])) exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]])) exec_lua [[ local counter = 0 @@ -1339,6 +1387,7 @@ describe('lua stdlib', function() vim.api.nvim_tabpage_set_var(0, 'AddCounter', add_counter) vim.api.nvim_tabpage_set_var(0, 'GetCounter', get_counter) vim.api.nvim_tabpage_set_var(0, 'funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_tabpage_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end) ]] eq(0, eval('t:GetCounter()')) @@ -1354,6 +1403,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.t.funcs.get()]])) exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]])) exec_lua [[ vim.cmd "tabnew" @@ -1361,15 +1411,27 @@ describe('lua stdlib', function() eq(NIL, funcs.luaeval "vim.t.testing") eq(NIL, funcs.luaeval "vim.t.other") - eq(NIL, funcs.luaeval "vim.t.nonexistant") + eq(NIL, funcs.luaeval "vim.t.nonexistent") end) it('vim.env', function() - exec_lua [[ - vim.fn.setenv("A", 123) - ]] - eq('123', funcs.luaeval "vim.env.A") - eq(true, funcs.luaeval "vim.env.B == nil") + exec_lua([[vim.fn.setenv('A', 123)]]) + eq('123', funcs.luaeval('vim.env.A')) + exec_lua([[vim.env.A = 456]]) + eq('456', funcs.luaeval('vim.env.A')) + exec_lua([[vim.env.A = nil]]) + eq(NIL, funcs.luaeval('vim.env.A')) + + eq(true, funcs.luaeval('vim.env.B == nil')) + + command([[let $HOME = 'foo']]) + eq('foo', funcs.expand('~')) + eq('foo', funcs.luaeval('vim.env.HOME')) + exec_lua([[vim.env.HOME = nil]]) + eq('foo', funcs.expand('~')) + exec_lua([[vim.env.HOME = 'bar']]) + eq('bar', funcs.expand('~')) + eq('bar', funcs.luaeval('vim.env.HOME')) end) it('vim.v', function() @@ -1396,7 +1458,7 @@ describe('lua stdlib', function() ]] eq('', funcs.luaeval "vim.bo.filetype") eq(true, funcs.luaeval "vim.bo[BUF].modifiable") - matches("unknown option 'nosuchopt'$", + matches("no such option: 'nosuchopt'$", pcall_err(exec_lua, 'return vim.bo.nosuchopt')) matches("Expected lua string$", pcall_err(exec_lua, 'return vim.bo[0][0].autoread')) @@ -1417,7 +1479,7 @@ describe('lua stdlib', function() eq(0, funcs.luaeval "vim.wo.cole") eq(0, funcs.luaeval "vim.wo[0].cole") eq(0, funcs.luaeval "vim.wo[1001].cole") - matches("unknown option 'notanopt'$", + matches("no such option: 'notanopt'$", pcall_err(exec_lua, 'return vim.wo.notanopt')) matches("Expected lua string$", pcall_err(exec_lua, 'return vim.wo[0][0].list')) @@ -2141,6 +2203,22 @@ describe('lua stdlib', function() end) end) -- vim.opt + describe('opt_local', function() + it('should be able to append to an array list type option', function() + eq({ "foo,bar,baz,qux" }, exec_lua [[ + local result = {} + + vim.opt.tags = "foo,bar" + vim.opt_local.tags:append("baz") + vim.opt_local.tags:append("qux") + + table.insert(result, vim.bo.tags) + + return result + ]]) + end) + end) + it('vim.cmd', function() exec_lua [[ vim.cmd "autocmd BufNew * ++once lua BUF = vim.fn.expand('<abuf>')" @@ -2173,6 +2251,10 @@ describe('lua stdlib', function() eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1, 8)}]]) eq({}, exec_lua[[return {re1:match_line(0, 1, 1, 7)}]]) eq({0,3}, exec_lua[[return {re1:match_line(0, 1, 0, 7)}]]) + + -- vim.regex() error inside :silent! should not crash. #20546 + command([[silent! lua vim.regex('\\z')]]) + assert_alive() end) it('vim.defer_fn', function() @@ -2185,13 +2267,19 @@ describe('lua stdlib', function() eq(true, exec_lua[[return vim.g.test]]) end) - it('vim.region', function() - insert(helpers.dedent( [[ - text tααt tααt text - text tαxt txtα tex - text tαxt tαxt - ]])) - eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]]) + describe('vim.region', function() + it('charwise', function() + insert(helpers.dedent( [[ + text tααt tααt text + text tαxt txtα tex + text tαxt tαxt + ]])) + eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]]) + end) + it('blockwise', function() + insert([[αα]]) + eq({0,5}, exec_lua[[ return vim.region(0,{0,0},{0,4},'3',true)[0] ]]) + end) end) describe('vim.on_key', function() @@ -2623,6 +2711,46 @@ describe('lua stdlib', function() a.nvim_buf_call(a.nvim_create_buf(false, true), function() vim.cmd "redraw" end) ]] end) + + it('can be nested crazily with hidden buffers', function() + eq(true, exec_lua([[ + local function scratch_buf_call(fn) + local buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_option(buf, 'cindent', true) + return vim.api.nvim_buf_call(buf, function() + return vim.api.nvim_get_current_buf() == buf + and vim.api.nvim_buf_get_option(buf, 'cindent') + and fn() + end) and vim.api.nvim_buf_delete(buf, {}) == nil + end + + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return true + end) + end) + end) + end) + end) + end) + end) + end) + end) + end) + end) + end) + ]])) + end) end) describe('vim.api.nvim_win_call', function() @@ -2721,6 +2849,57 @@ describe('lua stdlib', function() ]] end) end) + + describe('vim.iconv', function() + it('can convert strings', function() + eq('hello', exec_lua[[ + return vim.iconv('hello', 'latin1', 'utf-8') + ]]) + end) + + it('can validate arguments', function() + eq({false, 'Expected at least 3 arguments'}, exec_lua[[ + return {pcall(vim.iconv, 'hello')} + ]]) + + eq({false, 'bad argument #3 to \'?\' (expected string)'}, exec_lua[[ + return {pcall(vim.iconv, 'hello', 'utf-8', true)} + ]]) + end) + + it('can handle bad encodings', function() + eq(NIL, exec_lua[[ + return vim.iconv('hello', 'foo', 'bar') + ]]) + end) + + it('can handle strings with NUL bytes', function() + eq(7, exec_lua[[ + local a = string.char(97, 98, 99, 0, 100, 101, 102) -- abc\0def + return string.len(vim.iconv(a, 'latin1', 'utf-8')) + ]]) + end) + + end) + + describe("vim.defaulttable", function() + it("creates nested table by default", function() + eq({ b = {c = 1 } }, exec_lua[[ + local a = vim.defaulttable() + a.b.c = 1 + return a + ]]) + end) + + it("allows to create default objects", function() + eq({ b = 1 }, exec_lua[[ + local a = vim.defaulttable(function() return 0 end) + a.b = a.b + 1 + return a + ]]) + end) + end) + end) describe('lua: builtin modules', function() @@ -2745,9 +2924,14 @@ describe('lua: builtin modules', function() end) - it('does not work when disabled without runtime', function() - clear{args={'--luamod-dev'}, env={VIMRUNTIME='fixtures/a'}} - expect_exit(exec_lua, [[return vim.tbl_count {x=1,y=2}]]) + it('fails when disabled without runtime', function() + clear() + command("let $VIMRUNTIME='fixtures/a'") + -- Use system([nvim,…]) instead of clear() to avoid stderr noise. #21844 + local out = funcs.system({nvim_prog, '--clean', '--luamod-dev', + [[+call nvim_exec_lua('return vim.tbl_count {x=1,y=2}')]], '+qa!'}):gsub('\r\n', '\n') + eq(1, eval('v:shell_error')) + matches("'vim%.shared' not found", out) end) end) |