diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:31:31 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:31:31 +0000 |
commit | 9243becbedbb6a1592208051f8fa2b090dcc5e7d (patch) | |
tree | 607c2a862ec3f4399b8766383f6f8e04c4aa43b4 /test/functional/vimscript | |
parent | 9e40b6e9e1bc67f2d856adb837ee64dd0e25b717 (diff) | |
parent | 3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff) | |
download | rneovim-usermarks.tar.gz rneovim-usermarks.tar.bz2 rneovim-usermarks.zip |
Merge remote-tracking branch 'upstream/master' into usermarksusermarks
Diffstat (limited to 'test/functional/vimscript')
20 files changed, 366 insertions, 83 deletions
diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua index 8ca245f61a..c032ac3030 100644 --- a/test/functional/vimscript/api_functions_spec.lua +++ b/test/functional/vimscript/api_functions_spec.lua @@ -5,6 +5,7 @@ local neq, eq, command = helpers.neq, helpers.eq, helpers.command local clear, curbufmeths = helpers.clear, helpers.curbufmeths local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval local insert, pcall_err = helpers.insert, helpers.pcall_err +local matches = helpers.matches local meths = helpers.meths describe('eval-API', function() @@ -49,7 +50,7 @@ describe('eval-API', function() it('cannot change texts if textlocked', function() command("autocmd TextYankPost <buffer> ++once call nvim_buf_set_lines(0, 0, -1, v:false, [])") - eq('Vim(call):E5555: API call: E565: Not allowed to change text or change window', + matches('Vim%(call%):E5555: API call: E565: Not allowed to change text or change window$', pcall_err(command, "normal! yy")) end) diff --git a/test/functional/vimscript/container_functions_spec.lua b/test/functional/vimscript/container_functions_spec.lua index 04a3248c49..5bef3fce05 100644 --- a/test/functional/vimscript/container_functions_spec.lua +++ b/test/functional/vimscript/container_functions_spec.lua @@ -8,7 +8,7 @@ local clear = helpers.clear before_each(clear) describe('extend()', function() - it('suceeds to extend list with itself', function() + it('succeeds to extend list with itself', function() meths.set_var('l', {1, {}}) eq({1, {}, 1, {}}, eval('extend(l, l)')) eq({1, {}, 1, {}}, meths.get_var('l')) diff --git a/test/functional/vimscript/ctx_functions_spec.lua b/test/functional/vimscript/ctx_functions_spec.lua index d92a81c55b..5ee84a6d13 100644 --- a/test/functional/vimscript/ctx_functions_spec.lua +++ b/test/functional/vimscript/ctx_functions_spec.lua @@ -173,9 +173,9 @@ describe('context functions', function() call('SaveSFuncs') call('DeleteSFuncs') - eq('Vim(call):E117: Unknown function: s:greet', + eq('function Greet, line 1: Vim(call):E117: Unknown function: s:greet', pcall_err(command, [[call Greet('World')]])) - eq('Vim(call):E117: Unknown function: s:greet_all', + eq('function GreetAll, line 1: Vim(call):E117: Unknown function: s:greet_all', pcall_err(command, [[call GreetAll('World', 'One', 'Two', 'Three')]])) call('RestoreFuncs') @@ -287,9 +287,11 @@ describe('context functions', function() local with_jumps = { ['jumps'] = eval(([[ - filter(map(getjumplist()[0], 'filter( - { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum }, - { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)') + filter(map(add( + getjumplist()[0], { 'bufnr': bufnr('%'), 'lnum': getcurpos()[1] }), + 'filter( + { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum }, + { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)') ]]):gsub('\n', '')) } diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua index 0c2ca8de78..a8a901042b 100644 --- a/test/functional/vimscript/eval_spec.lua +++ b/test/functional/vimscript/eval_spec.lua @@ -10,16 +10,22 @@ -- test/functional/vimscript/functions_spec.lua local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local lfs = require('lfs') local clear = helpers.clear local eq = helpers.eq local exc_exec = helpers.exc_exec +local exec_lua = helpers.exec_lua +local exec_capture = helpers.exec_capture local eval = helpers.eval local command = helpers.command local write_file = helpers.write_file local meths = helpers.meths local sleep = helpers.sleep +local matches = helpers.matches +local pcall_err = helpers.pcall_err +local assert_alive = helpers.assert_alive local poke_eventloop = helpers.poke_eventloop local feed = helpers.feed @@ -65,13 +71,13 @@ describe("backtick expansion", function() end) it("with default 'shell'", function() - if helpers.iswin() then + if helpers.is_os('win') then command(":silent args `dir /b *2`") else command(":silent args `echo ***2`") end eq({ "file2", }, eval("argv()")) - if helpers.iswin() then + if helpers.is_os('win') then command(":silent args `dir /s/b *4`") eq({ "subdir\\file4", }, eval("map(argv(), 'fnamemodify(v:val, \":.\")')")) else @@ -144,3 +150,73 @@ describe('List support code', function() end end) end) + +describe("uncaught exception", function() + before_each(clear) + after_each(function() + os.remove('throw1.vim') + os.remove('throw2.vim') + os.remove('throw3.vim') + end) + + it('is not forgotten #13490', function() + command('autocmd BufWinEnter * throw "i am error"') + eq('i am error', exc_exec('try | new | endtry')) + + -- Like Vim, throwing here aborts the processing of the script, but does not stop :runtime! + -- from processing the others. + -- Only the first thrown exception should be rethrown from the :try below, though. + for i = 1, 3 do + write_file('throw' .. i .. '.vim', ([[ + let result ..= '%d' + throw 'throw%d' + let result ..= 'X' + ]]):format(i, i)) + end + command('set runtimepath+=. | let result = ""') + eq('throw1', exc_exec('try | runtime! throw*.vim | endtry')) + eq('123', eval('result')) + end) +end) + +describe('listing functions using :function', function() + before_each(clear) + + it('works for lambda functions with <lambda> #20466', function() + command('let A = {-> 1}') + local num = exec_capture('echo A'):match("function%('<lambda>(%d+)'%)") + eq(([[ + function <lambda>%s(...) +1 return 1 + endfunction]]):format(num), exec_capture(('function <lambda>%s'):format(num))) + end) + + -- FIXME: If the same function is deleted, the crash still happens. #20790 + it('does not crash if another function is deleted while listing', function() + local screen = Screen.new(80, 24) + screen:attach() + matches('Vim%(function%):E454: function list was modified', pcall_err(exec_lua, [=[ + vim.cmd([[ + func Func1() + endfunc + func Func2() + endfunc + func Func3() + endfunc + ]]) + + local ns = vim.api.nvim_create_namespace('test') + + vim.ui_attach(ns, { ext_messages = true }, function(event, _, content) + if event == 'msg_show' and content[1][2] == 'function Func1()' then + vim.cmd('delfunc Func3') + end + end) + + vim.cmd('function') + + vim.ui_detach(ns) + ]=])) + assert_alive() + end) +end) diff --git a/test/functional/vimscript/executable_spec.lua b/test/functional/vimscript/executable_spec.lua index b4162b2336..43e4a29e1a 100644 --- a/test/functional/vimscript/executable_spec.lua +++ b/test/functional/vimscript/executable_spec.lua @@ -1,15 +1,16 @@ local helpers = require('test.functional.helpers')(after_each) -local eq, clear, call, iswin, write_file, command = - helpers.eq, helpers.clear, helpers.call, helpers.iswin, helpers.write_file, +local eq, clear, call, write_file, command = + helpers.eq, helpers.clear, helpers.call, helpers.write_file, helpers.command local exc_exec = helpers.exc_exec local eval = helpers.eval +local is_os = helpers.is_os describe('executable()', function() before_each(clear) it('returns 1 for commands in $PATH', function() - local exe = iswin() and 'ping' or 'ls' + local exe = is_os('win') and 'ping' or 'ls' eq(1, call('executable', exe)) command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') eq(1, call('executable', 'null')) @@ -17,7 +18,7 @@ describe('executable()', function() eq(1, call('executable', 'false')) end) - if iswin() then + if is_os('win') then it('exepath respects shellslash', function() command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') eq([[test\functional\fixtures\bin\null.CMD]], call('fnamemodify', call('exepath', 'null'), ':.')) @@ -34,11 +35,13 @@ describe('executable()', function() it('fails for invalid values', function() for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do - eq('Vim(call):E928: String required', exc_exec('call executable('..input..')')) + eq('Vim(call):E1174: String required for argument 1', + exc_exec('call executable('..input..')')) end command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do - eq('Vim(call):E928: String required', exc_exec('call executable('..input..')')) + eq('Vim(call):E1174: String required for argument 1', + exc_exec('call executable('..input..')')) end end) @@ -54,8 +57,8 @@ describe('executable()', function() -- Some executable in build/bin/, *not* in $PATH nor CWD. local sibling_exe = 'printargs-test' -- Windows: siblings are in Nvim's "pseudo-$PATH". - local expected = iswin() and 1 or 0 - if iswin() then + local expected = is_os('win') and 1 or 0 + if is_os('win') then eq('arg1=lemon;arg2=sky;arg3=tree;', call('system', sibling_exe..' lemon sky tree')) end @@ -67,7 +70,7 @@ describe('executable()', function() clear() write_file('Xtest_not_executable', 'non-executable file') write_file('Xtest_executable', 'executable file (exec-bit set)') - if not iswin() then -- N/A for Windows. + if not is_os('win') then -- N/A for Windows. call('system', {'chmod', '-x', 'Xtest_not_executable'}) call('system', {'chmod', '+x', 'Xtest_executable'}) end @@ -88,14 +91,17 @@ describe('executable()', function() end) it('set, qualified as a path', function() - local expected = iswin() and 0 or 1 + local expected = is_os('win') and 0 or 1 eq(expected, call('executable', './Xtest_executable')) end) end) end) describe('executable() (Windows)', function() - if not iswin() then return end -- N/A for Unix. + if not is_os('win') then + pending('N/A for non-windows') + return + end local exts = {'bat', 'exe', 'com', 'cmd'} setup(function() diff --git a/test/functional/vimscript/execute_spec.lua b/test/functional/vimscript/execute_spec.lua index a733b098f5..5fe3d787cb 100644 --- a/test/functional/vimscript/execute_spec.lua +++ b/test/functional/vimscript/execute_spec.lua @@ -8,7 +8,7 @@ local funcs = helpers.funcs local Screen = require('test.functional.ui.screen') local command = helpers.command local feed = helpers.feed -local iswin = helpers.iswin +local is_os = helpers.is_os describe('execute()', function() before_each(clear) @@ -265,7 +265,7 @@ describe('execute()', function() -- This deviates from vim behavior, but is consistent -- with how nvim currently displays the output. it('captures shell-command output', function() - local win_lf = iswin() and '\13' or '' + local win_lf = is_os('win') and '\13' or '' eq('\n:!echo foo\r\n\nfoo'..win_lf..'\n', funcs.execute('!echo foo')) end) diff --git a/test/functional/vimscript/exepath_spec.lua b/test/functional/vimscript/exepath_spec.lua index bbca954511..056f67e0ad 100644 --- a/test/functional/vimscript/exepath_spec.lua +++ b/test/functional/vimscript/exepath_spec.lua @@ -1,19 +1,20 @@ local helpers = require('test.functional.helpers')(after_each) -local eq, clear, call, iswin = - helpers.eq, helpers.clear, helpers.call, helpers.iswin +local eq, clear, call = + helpers.eq, helpers.clear, helpers.call local command = helpers.command local exc_exec = helpers.exc_exec local matches = helpers.matches +local is_os = helpers.is_os describe('exepath()', function() before_each(clear) it('returns 1 for commands in $PATH', function() - local exe = iswin() and 'ping' or 'ls' - local ext_pat = iswin() and '%.EXE$' or '$' + local exe = is_os('win') and 'ping' or 'ls' + local ext_pat = is_os('win') and '%.EXE$' or '$' matches(exe .. ext_pat, call('exepath', exe)) command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') - ext_pat = iswin() and '%.CMD$' or '$' + ext_pat = is_os('win') and '%.CMD$' or '$' matches('null' .. ext_pat, call('exepath', 'null')) matches('true' .. ext_pat, call('exepath', 'true')) matches('false' .. ext_pat, call('exepath', 'false')) @@ -21,16 +22,16 @@ describe('exepath()', function() it('fails for invalid values', function() for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do - eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')')) + eq('Vim(call):E1174: String required for argument 1', exc_exec('call exepath('..input..')')) end - eq('Vim(call):E1142: Non-empty string required', exc_exec('call exepath("")')) + eq('Vim(call):E1175: Non-empty string required for argument 1', exc_exec('call exepath("")')) command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do - eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')')) + eq('Vim(call):E1174: String required for argument 1', exc_exec('call exepath('..input..')')) end end) - if iswin() then + if is_os('win') then it('append extension if omitted', function() local filename = 'cmd' local pathext = '.exe' diff --git a/test/functional/vimscript/fnamemodify_spec.lua b/test/functional/vimscript/fnamemodify_spec.lua index d54a6db417..c3ecdd853c 100644 --- a/test/functional/vimscript/fnamemodify_spec.lua +++ b/test/functional/vimscript/fnamemodify_spec.lua @@ -1,12 +1,12 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eq = helpers.eq -local iswin = helpers.iswin local fnamemodify = helpers.funcs.fnamemodify local getcwd = helpers.funcs.getcwd local command = helpers.command local write_file = helpers.write_file local alter_slashes = helpers.alter_slashes +local is_os = helpers.is_os local function eq_slashconvert(expected, got) eq(alter_slashes(expected), alter_slashes(got)) @@ -27,7 +27,7 @@ describe('fnamemodify()', function() local root = helpers.pathroot() eq(root, fnamemodify([[/]], ':p:h')) eq(root, fnamemodify([[/]], ':p')) - if iswin() then + if is_os('win') then eq(root, fnamemodify([[\]], ':p:h')) eq(root, fnamemodify([[\]], ':p')) command('set shellslash') @@ -114,7 +114,7 @@ describe('fnamemodify()', function() it('handles shell escape', function() local expected - if iswin() then + if is_os('win') then -- we expand with double-quotes on Windows expected = [["hello there! quote ' newline]] .. '\n' .. [["]] else diff --git a/test/functional/vimscript/functions_spec.lua b/test/functional/vimscript/functions_spec.lua index 20c1400030..09b3334989 100644 --- a/test/functional/vimscript/functions_spec.lua +++ b/test/functional/vimscript/functions_spec.lua @@ -9,12 +9,12 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eval = helpers.eval -local iswin = helpers.iswin local matches = helpers.matches +local is_os = helpers.is_os before_each(clear) it('windowsversion()', function() clear() - matches(iswin() and '^%d+%.%d+$' or '^$', eval('windowsversion()')) + matches(is_os('win') and '^%d+%.%d+$' or '^$', eval('windowsversion()')) end) diff --git a/test/functional/vimscript/has_spec.lua b/test/functional/vimscript/has_spec.lua index 4d9b226434..2e26d603b3 100644 --- a/test/functional/vimscript/has_spec.lua +++ b/test/functional/vimscript/has_spec.lua @@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq local clear = helpers.clear local funcs = helpers.funcs -local iswin = helpers.iswin +local is_os = helpers.is_os describe('has()', function() before_each(clear) @@ -51,7 +51,7 @@ describe('has()', function() end) it('"unnamedplus"', function() - if (not iswin()) and funcs.has("clipboard") == 1 then + if (not is_os('win')) and funcs.has("clipboard") == 1 then eq(1, funcs.has("unnamedplus")) else eq(0, funcs.has("unnamedplus")) diff --git a/test/functional/vimscript/hostname_spec.lua b/test/functional/vimscript/hostname_spec.lua index 6112cf64e3..7d4baa7213 100644 --- a/test/functional/vimscript/hostname_spec.lua +++ b/test/functional/vimscript/hostname_spec.lua @@ -3,7 +3,7 @@ local eq = helpers.eq local ok = helpers.ok local call = helpers.call local clear = helpers.clear -local iswin = helpers.iswin +local is_os = helpers.is_os describe('hostname()', function() before_each(clear) @@ -13,8 +13,8 @@ describe('hostname()', function() ok(string.len(actual) > 0) if call('executable', 'hostname') == 1 then local expected = string.gsub(call('system', 'hostname'), '[\n\r]', '') - eq((iswin() and expected:upper() or expected), - (iswin() and actual:upper() or actual)) + eq((is_os('win') and expected:upper() or expected), + (is_os('win') and actual:upper() or actual)) end end) end) diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua index 554d15e550..f50b39c2c5 100644 --- a/test/functional/vimscript/input_spec.lua +++ b/test/functional/vimscript/input_spec.lua @@ -8,7 +8,8 @@ local clear = helpers.clear local source = helpers.source local command = helpers.command local exc_exec = helpers.exc_exec -local nvim_async = helpers.nvim_async +local pcall_err = helpers.pcall_err +local async_meths = helpers.async_meths local NIL = helpers.NIL local screen @@ -449,6 +450,78 @@ describe('inputdialog()', function() end) describe('confirm()', function() + -- oldtest: Test_confirm() + it('works', function() + meths.set_option('more', false) -- Avoid hit-enter prompt + meths.set_option('laststatus', 2) + -- screen:expect() calls are needed to avoid feeding input too early + screen:expect({any = '%[No Name%]'}) + + async_meths.command([[let a = confirm('Press O to proceed')]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('o') + screen:expect({any = '%[No Name%]'}) + eq(1, meths.get_var('a')) + + async_meths.command([[let a = 'Are you sure?'->confirm("&Yes\n&No")]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('y') + screen:expect({any = '%[No Name%]'}) + eq(1, meths.get_var('a')) + + async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('n') + screen:expect({any = '%[No Name%]'}) + eq(2, meths.get_var('a')) + + -- Not possible to match Vim's CTRL-C test here as CTRL-C always sets got_int in Nvim. + + -- confirm() should return 0 when pressing ESC. + async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('<Esc>') + screen:expect({any = '%[No Name%]'}) + eq(0, meths.get_var('a')) + + -- Default choice is returned when pressing <CR>. + async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('<CR>') + screen:expect({any = '%[No Name%]'}) + eq(1, meths.get_var('a')) + + async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No", 2)]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('<CR>') + screen:expect({any = '%[No Name%]'}) + eq(2, meths.get_var('a')) + + async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No", 0)]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('<CR>') + screen:expect({any = '%[No Name%]'}) + eq(0, meths.get_var('a')) + + -- Test with the {type} 4th argument + for _, type in ipairs({'Error', 'Question', 'Info', 'Warning', 'Generic'}) do + async_meths.command(([[let a = confirm('Are you sure?', "&Yes\n&No", 1, '%s')]]):format(type)) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('y') + screen:expect({any = '%[No Name%]'}) + eq(1, meths.get_var('a')) + end + + eq('Vim(call):E730: using List as a String', + pcall_err(command, 'call confirm([])')) + eq('Vim(call):E730: using List as a String', + pcall_err(command, 'call confirm("Are you sure?", [])')) + eq('Vim(call):E745: Using a List as a Number', + pcall_err(command, 'call confirm("Are you sure?", "&Yes\n&No\n", [])')) + eq('Vim(call):E730: using List as a String', + pcall_err(command, 'call confirm("Are you sure?", "&Yes\n&No\n", 0, [])')) + end) + it("shows dialog even if :silent #8788", function() command("autocmd BufNewFile * call confirm('test')") @@ -483,7 +556,7 @@ describe('confirm()', function() feed(':call nvim_command("edit x")<cr>') check_and_clear(':call nvim_command("edit |\n') - nvim_async('command', 'edit x') + async_meths.command('edit x') check_and_clear(' |\n') end) end) diff --git a/test/functional/vimscript/json_functions_spec.lua b/test/functional/vimscript/json_functions_spec.lua index 5d1597f53d..70d0934756 100644 --- a/test/functional/vimscript/json_functions_spec.lua +++ b/test/functional/vimscript/json_functions_spec.lua @@ -343,7 +343,7 @@ describe('json_decode() function', function() exc_exec('call json_decode("\\t\\"abc\\\\u0000")')) end) - it('fails to parse unknown escape sequnces', function() + it('fails to parse unknown escape sequences', function() eq('Vim(call):E474: Unknown escape sequence: \\a"', exc_exec('call json_decode("\\t\\"\\\\a\\"")')) end) diff --git a/test/functional/vimscript/map_functions_spec.lua b/test/functional/vimscript/map_functions_spec.lua index aa64006de0..ba1b4d7a76 100644 --- a/test/functional/vimscript/map_functions_spec.lua +++ b/test/functional/vimscript/map_functions_spec.lua @@ -3,6 +3,8 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eq = helpers.eq local eval = helpers.eval +local exec = helpers.exec +local exec_lua = helpers.exec_lua local expect = helpers.expect local feed = helpers.feed local funcs = helpers.funcs @@ -10,6 +12,8 @@ local meths = helpers.meths local nvim = helpers.nvim local source = helpers.source local command = helpers.command +local exec_capture = helpers.exec_capture +local pcall_err = helpers.pcall_err describe('maparg()', function() before_each(clear) @@ -172,14 +176,12 @@ describe('mapset()', function() it('can restore mapping description from the dict returned by maparg()', function() meths.set_keymap('n', 'lhs', 'rhs', {desc = 'map description'}) - eq('\nn lhs rhs\n map description', - helpers.exec_capture("nmap lhs")) + eq('\nn lhs rhs\n map description', exec_capture("nmap lhs")) local mapargs = funcs.maparg('lhs', 'n', false, true) - meths.del_keymap('n', 'lhs') - eq('\nNo mapping found', helpers.exec_capture("nmap lhs")) + meths.set_keymap('n', 'lhs', 'rhs', {desc = 'MAP DESCRIPTION'}) + eq('\nn lhs rhs\n MAP DESCRIPTION', exec_capture("nmap lhs")) funcs.mapset('n', false, mapargs) - eq('\nn lhs rhs\n map description', - helpers.exec_capture("nmap lhs")) + eq('\nn lhs rhs\n map description', exec_capture("nmap lhs")) end) it('can restore "replace_keycodes" from the dict returned by maparg()', function() @@ -194,4 +196,59 @@ describe('mapset()', function() feed('foo') expect('<<lt><') end) + + it('replaces an abbreviation of the same lhs #20320', function() + command('inoreabbr foo bar') + eq('\ni foo * bar', exec_capture('iabbr foo')) + feed('ifoo ') + expect('bar ') + local mapargs = funcs.maparg('foo', 'i', true, true) + command('inoreabbr foo BAR') + eq('\ni foo * BAR', exec_capture('iabbr foo')) + feed('foo ') + expect('bar BAR ') + funcs.mapset('i', true, mapargs) + eq('\ni foo * bar', exec_capture('iabbr foo')) + feed('foo<Esc>') + expect('bar BAR bar') + end) + + it('can restore Lua callback from the dict returned by maparg()', function() + eq(0, exec_lua([[ + GlobalCount = 0 + vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + return GlobalCount + ]])) + feed('asdf') + eq(1, exec_lua([[return GlobalCount]])) + + exec_lua([[ + _G.saved_asdf_map = vim.fn.maparg('asdf', 'n', false, true) + vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 10 end }) + ]]) + feed('asdf') + eq(11, exec_lua([[return GlobalCount]])) + + exec_lua([[vim.fn.mapset('n', false, _G.saved_asdf_map)]]) + feed('asdf') + eq(12, exec_lua([[return GlobalCount]])) + + exec([[ + let g:saved_asdf_map = maparg('asdf', 'n', v:false, v:true) + lua vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 10 end }) + ]]) + feed('asdf') + eq(22, exec_lua([[return GlobalCount]])) + + command([[call mapset('n', v:false, g:saved_asdf_map)]]) + feed('asdf') + eq(23, exec_lua([[return GlobalCount]])) + end) + + it('does not leak memory if lhs is missing', function() + eq('Vim:E460: entries missing in mapset() dict argument', + pcall_err(exec_lua, [[vim.fn.mapset('n', false, {rhs = 'foo'})]])) + eq('Vim:E460: entries missing in mapset() dict argument', + pcall_err(exec_lua, [[vim.fn.mapset('n', false, {callback = function() end})]])) + end) end) diff --git a/test/functional/vimscript/msgpack_functions_spec.lua b/test/functional/vimscript/msgpack_functions_spec.lua index cab67d77e4..de5a721efe 100644 --- a/test/functional/vimscript/msgpack_functions_spec.lua +++ b/test/functional/vimscript/msgpack_functions_spec.lua @@ -5,7 +5,7 @@ local eval, eq = helpers.eval, helpers.eq local command = helpers.command local nvim = helpers.nvim local exc_exec = helpers.exc_exec -local iswin = helpers.iswin +local is_os = helpers.is_os describe('msgpack*() functions', function() before_each(clear) @@ -467,7 +467,7 @@ describe('msgpackparse() function', function() eval(cmd) eval(cmd) -- do it again (try to force segfault) local api_info = eval(cmd) -- do it again - if iswin() then + if is_os('win') then helpers.assert_alive() pending('msgpackparse() has a bug on windows') return diff --git a/test/functional/vimscript/null_spec.lua b/test/functional/vimscript/null_spec.lua index 2451da983e..1153baac46 100644 --- a/test/functional/vimscript/null_spec.lua +++ b/test/functional/vimscript/null_spec.lua @@ -69,7 +69,7 @@ describe('NULL', function() null_expr_test('can be splice-indexed', 'L[:]', 0, {}) null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0) null_test('is accepted by :for', 'for x in L|throw x|endfor', 0) - null_expr_test('does not crash append()', 'append(1, L)', 0, 0, function() + null_expr_test('does not crash append()', 'append(0, L)', 0, 0, function() eq({''}, curbufmeths.get_lines(0, -1, false)) end) null_expr_test('does not crash setline()', 'setline(1, L)', 0, 0, function() diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/vimscript/server_spec.lua index 6e95459630..c89a0c4e93 100644 --- a/test/functional/vimscript/server_spec.lua +++ b/test/functional/vimscript/server_spec.lua @@ -1,11 +1,14 @@ local helpers = require('test.functional.helpers')(after_each) +local assert_log = helpers.assert_log local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval local clear, funcs, meths = helpers.clear, helpers.funcs, helpers.meths -local iswin = helpers.iswin local ok = helpers.ok local matches = helpers.matches local pcall_err = helpers.pcall_err local mkdir = helpers.mkdir +local is_os = helpers.is_os + +local testlog = 'Xtest-server-log' local function clear_serverlist() for _, server in pairs(funcs.serverlist()) do @@ -14,12 +17,16 @@ local function clear_serverlist() end describe('server', function() + after_each(function() + os.remove(testlog) + end) + it('serverstart() stores sockets in $XDG_RUNTIME_DIR', function() local dir = 'Xtest_xdg_run' mkdir(dir) clear({ env={ XDG_RUNTIME_DIR=dir } }) matches(dir, funcs.stdpath('run')) - if not iswin() then + if not is_os('win') then matches(dir, funcs.serverstart()) end end) @@ -65,7 +72,7 @@ describe('server', function() eq('', meths.get_vvar('servername')) -- v:servername and $NVIM take the next available server. - local servername = (iswin() and [[\\.\pipe\Xtest-functional-server-pipe]] + local servername = (is_os('win') and [[\\.\pipe\Xtest-functional-server-pipe]] or './Xtest-functional-server-socket') funcs.serverstart(servername) eq(servername, meths.get_vvar('servername')) @@ -74,13 +81,20 @@ describe('server', function() end) it('serverstop() returns false for invalid input', function() - clear() + clear{env={ + NVIM_LOG_FILE=testlog, + NVIM_LISTEN_ADDRESS='.', + }} eq(0, eval("serverstop('')")) eq(0, eval("serverstop('bogus-socket-name')")) + assert_log('Not listening on bogus%-socket%-name', testlog, 10) end) it('parses endpoints', function() - clear() + clear{env={ + NVIM_LOG_FILE=testlog, + NVIM_LISTEN_ADDRESS='.', + }} clear_serverlist() eq({}, funcs.serverlist()) @@ -104,6 +118,7 @@ describe('server', function() if status then table.insert(expected, v4) pcall(funcs.serverstart, v4) -- exists already; ignore + assert_log('Failed to start server: address already in use: 127%.0%.0%.1', testlog, 10) end local v6 = '::1:12345' @@ -111,6 +126,7 @@ describe('server', function() if status then table.insert(expected, v6) pcall(funcs.serverstart, v6) -- exists already; ignore + assert_log('Failed to start server: address already in use: ::1', testlog, 10) end eq(expected, funcs.serverlist()) clear_serverlist() @@ -130,7 +146,7 @@ describe('server', function() local n = eval('len(serverlist())') -- Add some servers. - local servs = (iswin() + local servs = (is_os('win') and { [[\\.\pipe\Xtest-pipe0934]], [[\\.\pipe\Xtest-pipe4324]] } or { [[./Xtest-pipe0934]], [[./Xtest-pipe4324]] }) for _, s in ipairs(servs) do @@ -164,7 +180,7 @@ describe('startup --listen', function() end) it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function() - local addr = (iswin() and [[\\.\pipe\Xtest-listen-pipe]] + local addr = (is_os('win') and [[\\.\pipe\Xtest-listen-pipe]] or './Xtest-listen-pipe') clear({ env={ NVIM_LISTEN_ADDRESS='./Xtest-env-pipe' }, args={ '--listen', addr } }) diff --git a/test/functional/vimscript/system_spec.lua b/test/functional/vimscript/system_spec.lua index a778e2f435..7ada1c4bea 100644 --- a/test/functional/vimscript/system_spec.lua +++ b/test/functional/vimscript/system_spec.lua @@ -1,3 +1,5 @@ +-- Tests for system() and :! shell. + local helpers = require('test.functional.helpers')(after_each) local assert_alive = helpers.assert_alive @@ -9,9 +11,9 @@ local command = helpers.command local insert = helpers.insert local expect = helpers.expect local exc_exec = helpers.exc_exec -local iswin = helpers.iswin local os_kill = helpers.os_kill local pcall_err = helpers.pcall_err +local is_os = helpers.is_os local Screen = require('test.functional.ui.screen') @@ -85,7 +87,7 @@ describe('system()', function() end) it('does NOT run in shell', function() - if iswin() then + if is_os('win') then eq("%PATH%\n", eval("system(['powershell', '-NoProfile', '-NoLogo', '-ExecutionPolicy', 'RemoteSigned', '-Command', 'Write-Output', '%PATH%'])")) else eq("* $PATH %PATH%\n", eval("system(['echo', '*', '$PATH', '%PATH%'])")) @@ -94,7 +96,7 @@ describe('system()', function() end) it('sets v:shell_error', function() - if iswin() then + if is_os('win') then eval([[system("cmd.exe /c exit")]]) eq(0, eval('v:shell_error')) eval([[system("cmd.exe /c exit 1")]]) @@ -123,7 +125,7 @@ describe('system()', function() screen:attach() end) - if iswin() then + if is_os('win') then local function test_more() eq('root = true', eval([[get(split(system('"more" ".editorconfig"'), "\n"), 0, '')]])) end @@ -184,7 +186,7 @@ describe('system()', function() -- * on Windows, expected to default to Western European enc -- * on Linux, expected to default to UTF8 command([[let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ']]) - eq(iswin() and '??\n' or 'ああ\n', eval([[system('Write-Output "ああ"')]])) + eq(is_os('win') and '??\n' or 'ああ\n', eval([[system('Write-Output "ああ"')]])) end) it('`echo` and waits for its return', function() @@ -213,7 +215,7 @@ describe('system()', function() screen:try_resize(72, 14) feed(':4verbose echo system("echo hi")<cr>') - if iswin() then + if is_os('win') then screen:expect{any=[[Executing command: "'fake_shell' 'cmdflag' '"echo hi"'"]]} else screen:expect{any=[[Executing command: "'fake_shell' 'cmdflag' 'echo hi'"]]} @@ -243,7 +245,7 @@ describe('system()', function() end) it('`yes` interrupted with CTRL-C', function() - feed(':call system("' .. (iswin() + feed(':call system("' .. (is_os('win') and 'for /L %I in (1,0,2) do @echo y' or 'yes') .. '")<cr>') screen:expect([[ @@ -260,7 +262,7 @@ describe('system()', function() ~ | ~ | ~ | -]] .. (iswin() +]] .. (is_os('win') and [[ :call system("for /L %I in (1,0,2) do @echo y") |]] or [[ @@ -286,7 +288,7 @@ describe('system()', function() it('`yes` interrupted with mapped CTRL-C', function() command('nnoremap <C-C> i') - feed(':call system("' .. (iswin() + feed(':call system("' .. (is_os('win') and 'for /L %I in (1,0,2) do @echo y' or 'yes') .. '")<cr>') screen:expect([[ @@ -303,7 +305,7 @@ describe('system()', function() ~ | ~ | ~ | -]] .. (iswin() +]] .. (is_os('win') and [[ :call system("for /L %I in (1,0,2) do @echo y") |]] or [[ @@ -330,7 +332,7 @@ describe('system()', function() describe('passing no input', function() it('returns the program output', function() - if iswin() then + if is_os('win') then eq("echoed\n", eval('system("echo echoed")')) else eq("echoed", eval('system("echo -n echoed")')) @@ -438,7 +440,7 @@ describe('systemlist()', function() before_each(clear) it('sets v:shell_error', function() - if iswin() then + if is_os('win') then eval([[systemlist("cmd.exe /c exit")]]) eq(0, eval('v:shell_error')) eval([[systemlist("cmd.exe /c exit 1")]]) @@ -617,12 +619,12 @@ describe('systemlist()', function() return end helpers.set_shell_powershell() - eq({iswin() and 'あ\r' or 'あ'}, eval([[systemlist('Write-Output あ')]])) + eq({is_os('win') and 'あ\r' or 'あ'}, eval([[systemlist('Write-Output あ')]])) -- Sanity test w/ default encoding -- * on Windows, expected to default to Western European enc -- * on Linux, expected to default to UTF8 command([[let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ']]) - eq({iswin() and '?\r' or 'あ'}, eval([[systemlist('Write-Output あ')]])) + eq({is_os('win') and '?\r' or 'あ'}, eval([[systemlist('Write-Output あ')]])) end) end) @@ -639,15 +641,15 @@ describe('shell :!', function() 1 4 2]]) - if iswin() then + if is_os('win') then feed(':4verbose %!sort /R<cr>') screen:expect{ - any=[[Executing command: .?Start%-Process sort %-ArgumentList "/R" %-RedirectStandardInput .* %-RedirectStandardOutput .* %-NoNewWindow %-Wait]] + any=[[Executing command: .?& { Get%-Content .* | & sort /R } 2>&1 | Out%-File %-Encoding UTF8 .*; exit $LastExitCode"]] } else feed(':4verbose %!sort -r<cr>') screen:expect{ - any=[[Executing command: .?Start%-Process sort %-ArgumentList "%-r" %-RedirectStandardInput .* %-RedirectStandardOutput .* %-NoNewWindow %-Wait]] + any=[[Executing command: .?& { Get%-Content .* | & sort %-r } 2>&1 | Out%-File %-Encoding UTF8 .*; exit $LastExitCode"]] } end feed('<CR>') @@ -660,4 +662,33 @@ describe('shell :!', function() 1]]) end end) + + it(':{range}! without redirecting to buffer', function() + local screen = Screen.new(500, 10) + screen:attach() + insert([[ + 3 + 1 + 4 + 2]]) + feed(':4verbose %w !sort<cr>') + if is_os('win') then + screen:expect{ + any=[[Executing command: .?sort %< .*]] + } + else + screen:expect{ + any=[[Executing command: .?%(sort%) %< .*]] + + } + end + feed('<CR>') + helpers.set_shell_powershell(true) + feed(':4verbose %w !sort<cr>') + screen:expect{ + any=[[Executing command: .?& { Get%-Content .* | & sort }]] + } + feed('<CR>') + helpers.expect_exit(command, 'qall!') + end) end) diff --git a/test/functional/vimscript/timer_spec.lua b/test/functional/vimscript/timer_spec.lua index 5463cfb234..1818a71ea2 100644 --- a/test/functional/vimscript/timer_spec.lua +++ b/test/functional/vimscript/timer_spec.lua @@ -131,34 +131,34 @@ describe('timers', function() nvim_async("command", "call timer_start("..load_adjust(100)..", 'AddItem', {'repeat': -1})") screen:expect([[ - ITEM 1 | + ^ITEM 1 | ITEM 2 | {1:~ }| {1:~ }| {1:~ }| - ^ | + | ]]) nvim_async("command", "let g:cont = 1") screen:expect([[ - ITEM 1 | + ^ITEM 1 | ITEM 2 | ITEM 3 | {1:~ }| {1:~ }| - ^ | + | ]]) feed("3") eq(51, eval("g:c2")) - screen:expect([[ + screen:expect{grid=[[ ^ITEM 1 | ITEM 2 | ITEM 3 | {1:~ }| {1:~ }| | - ]]) + ]], unchanged=true} end) it('can be stopped', function() diff --git a/test/functional/vimscript/writefile_spec.lua b/test/functional/vimscript/writefile_spec.lua index 5f693249a9..8c8da9dc88 100644 --- a/test/functional/vimscript/writefile_spec.lua +++ b/test/functional/vimscript/writefile_spec.lua @@ -111,6 +111,26 @@ describe('writefile()', function() pcall_err(command, ('call writefile([42], %s)'):format(ddname_tail))) end) + it('writefile(..., "p") creates missing parent directories', function() + os.remove(dname) + eq(nil, read_file(dfname)) + eq(0, funcs.writefile({'abc', 'def', 'ghi'}, dfname, 'p')) + eq('abc\ndef\nghi\n', read_file(dfname)) + os.remove(dfname) + os.remove(dname) + eq(nil, read_file(dfname)) + eq(0, funcs.writefile({'\na\nb\n'}, dfname, 'pb')) + eq('\0a\0b\0', read_file(dfname)) + os.remove(dfname) + os.remove(dname) + eq('Vim(call):E32: No file name', + pcall_err(command, ('call writefile([], "%s", "p")'):format(dfname .. '.d/'))) + eq(('Vim(call):E482: Can\'t open file ./ for writing: illegal operation on a directory'), + pcall_err(command, 'call writefile([], "./", "p")')) + eq(('Vim(call):E482: Can\'t open file . for writing: illegal operation on a directory'), + pcall_err(command, 'call writefile([], ".", "p")')) + end) + it('errors out with invalid arguments', function() write_file(fname, 'TEST') eq('Vim(call):E119: Not enough arguments for function: writefile', |