diff options
Diffstat (limited to 'test/functional')
33 files changed, 779 insertions, 293 deletions
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index a16c6a88e3..fabd9be6d6 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -651,6 +651,11 @@ describe('nvim_create_user_command', function() api.nvim_set_current_buf(bufnr) command('Hello') assert_alive() + eq( + 'Invalid buffer id: 1234', + pcall_err(api.nvim_buf_create_user_command, 1234, 'Hello', '', {}) + ) + assert_alive() end) it('can use a Lua complete function', function() @@ -771,5 +776,9 @@ describe('nvim_del_user_command', function() command('Hello') api.nvim_buf_del_user_command(0, 'Hello') matches('Not an editor command: Hello', pcall_err(command, 'Hello')) + eq('Invalid command (not found): Hello', pcall_err(api.nvim_buf_del_user_command, 0, 'Hello')) + eq('Invalid command (not found): Bye', pcall_err(api.nvim_buf_del_user_command, 0, 'Bye')) + eq('Invalid buffer id: 1234', pcall_err(api.nvim_buf_del_user_command, 1234, 'Hello')) + assert_alive() end) end) diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index bdd340f6c6..c022ba28de 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -9,7 +9,6 @@ local nvim_prog, command, fn = n.nvim_prog, n.command, n.fn local source, next_msg = n.source, n.next_msg local ok = t.ok local api = n.api -local spawn, merge_args = n.spawn, n.merge_args local set_session = n.set_session local pcall_err = t.pcall_err local assert_alive = n.assert_alive @@ -281,10 +280,9 @@ describe('server -> client', function() end) describe('connecting to another (peer) nvim', function() - local nvim_argv = merge_args(n.nvim_argv, { '--headless' }) local function connect_test(server, mode, address) local serverpid = fn.getpid() - local client = spawn(nvim_argv, false, nil, true) + local client = n.new_session(true) set_session(client) local clientpid = fn.getpid() @@ -312,7 +310,7 @@ describe('server -> client', function() end it('via named pipe', function() - local server = spawn(nvim_argv) + local server = n.new_session(false) set_session(server) local address = fn.serverlist()[1] local first = string.sub(address, 1, 1) @@ -321,7 +319,7 @@ describe('server -> client', function() end) it('via ipv4 address', function() - local server = spawn(nvim_argv) + local server = n.new_session(false) set_session(server) local status, address = pcall(fn.serverstart, '127.0.0.1:') if not status then @@ -332,7 +330,7 @@ describe('server -> client', function() end) it('via ipv6 address', function() - local server = spawn(nvim_argv) + local server = n.new_session(false) set_session(server) local status, address = pcall(fn.serverstart, '::1:') if not status then @@ -343,7 +341,7 @@ describe('server -> client', function() end) it('via hostname', function() - local server = spawn(nvim_argv) + local server = n.new_session(false) set_session(server) local address = fn.serverstart('localhost:') eq('localhost:', string.sub(address, 1, 10)) @@ -351,10 +349,10 @@ describe('server -> client', function() end) it('does not crash on receiving UI events', function() - local server = spawn(nvim_argv) + local server = n.new_session(false) set_session(server) local address = fn.serverlist()[1] - local client = spawn(nvim_argv, false, nil, true) + local client = n.new_session(true) set_session(client) local id = fn.sockconnect('pipe', address, { rpc = true }) diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua index dee13d19ae..7b10eb05ef 100644 --- a/test/functional/core/channels_spec.lua +++ b/test/functional/core/channels_spec.lua @@ -5,7 +5,6 @@ local clear, eq, eval, next_msg, ok, source = n.clear, t.eq, n.eval, n.next_msg, local command, fn, api = n.command, n.fn, n.api local matches = t.matches local sleep = vim.uv.sleep -local spawn, nvim_argv = n.spawn, n.nvim_argv local get_session, set_session = n.get_session, n.set_session local nvim_prog = n.nvim_prog local is_os = t.is_os @@ -33,10 +32,10 @@ describe('channels', function() end) pending('can connect to socket', function() - local server = spawn(nvim_argv, nil, nil, true) + local server = n.new_session(true) set_session(server) local address = fn.serverlist()[1] - local client = spawn(nvim_argv, nil, nil, true) + local client = n.new_session(true) set_session(client) source(init) @@ -63,7 +62,7 @@ describe('channels', function() it('dont crash due to garbage in rpc #23781', function() local client = get_session() - local server = spawn(nvim_argv, nil, nil, true) + local server = n.new_session(true) set_session(server) local address = fn.serverlist()[1] set_session(client) diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua index 34c3eedbd2..65f6bc28a6 100644 --- a/test/functional/core/exit_spec.lua +++ b/test/functional/core/exit_spec.lua @@ -8,8 +8,6 @@ local feed = n.feed local eval = n.eval local eq = t.eq local run = n.run -local fn = n.fn -local nvim_prog = n.nvim_prog local pcall_err = t.pcall_err local exec_capture = n.exec_capture local poke_eventloop = n.poke_eventloop @@ -69,8 +67,8 @@ describe(':cquit', function() poke_eventloop() assert_alive() else - fn.system({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', '--cmd', cmdline }) - eq(exit_code, eval('v:shell_error')) + local p = n.spawn_wait('--cmd', cmdline) + eq(exit_code, p.status) end end diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index cf9715f848..b1a8e21762 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -31,7 +31,6 @@ local feed_command = n.feed_command local skip = t.skip local is_os = t.is_os local is_ci = t.is_ci -local spawn = n.spawn local set_session = n.set_session describe('fileio', function() @@ -51,12 +50,11 @@ describe('fileio', function() rmdir('Xtest_backupdir with spaces') end) - local args = { nvim_prog, '--clean', '--cmd', 'set nofsync directory=Xtest_startup_swapdir' } + local args = { '--clean', '--cmd', 'set nofsync directory=Xtest_startup_swapdir' } --- Starts a new nvim session and returns an attached screen. - local function startup(extra_args) - extra_args = extra_args or {} - local argv = vim.iter({ args, '--embed', extra_args }):flatten():totable() - local screen_nvim = spawn(argv) + local function startup() + local argv = vim.iter({ args, '--embed' }):flatten():totable() + local screen_nvim = n.new_session(false, { args = argv, merge = false }) set_session(screen_nvim) local screen = Screen.new(70, 10) screen:set_default_attr_ids({ @@ -100,7 +98,8 @@ describe('fileio', function() eq('foozubbaz', trim(read_file('Xtest_startup_file1'))) -- 4. Exit caused by deadly signal (+ 'swapfile'). - local j = fn.jobstart(vim.iter({ args, '--embed' }):flatten():totable(), { rpc = true }) + local j = + fn.jobstart(vim.iter({ nvim_prog, args, '--embed' }):flatten():totable(), { rpc = true }) fn.rpcrequest( j, 'nvim_exec2', diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua index ce4ba1905f..6add49ceae 100644 --- a/test/functional/core/main_spec.lua +++ b/test/functional/core/main_spec.lua @@ -9,7 +9,6 @@ local feed = n.feed local eval = n.eval local clear = n.clear local fn = n.fn -local nvim_prog_abs = n.nvim_prog_abs local write_file = t.write_file local is_os = t.is_os local skip = t.skip @@ -35,7 +34,7 @@ describe('command-line option', function() it('treats - as stdin', function() eq(nil, uv.fs_stat(fname)) fn.system({ - nvim_prog_abs(), + n.nvim_prog, '-u', 'NONE', '-i', @@ -56,41 +55,29 @@ describe('command-line option', function() eq(nil, uv.fs_stat(fname)) eq(true, not not dollar_fname:find('%$%w+')) write_file(dollar_fname, ':call setline(1, "100500")\n:wqall!\n') - fn.system({ - nvim_prog_abs(), - '-u', - 'NONE', - '-i', - 'NONE', - '--headless', + local p = n.spawn_wait( '--cmd', 'set noswapfile shortmess+=IFW fileformats=unix', '-s', dollar_fname, - fname, - }) - eq(0, eval('v:shell_error')) + fname + ) + eq(0, p.status) local attrs = uv.fs_stat(fname) eq(#'100500\n', attrs.size) end) - it('does not crash when run completion in ex mode', function() - fn.system({ - nvim_prog_abs(), - '--clean', - '-e', - '-s', - '--cmd', - 'exe "norm! i\\<C-X>\\<C-V>"', - }) - eq(0, eval('v:shell_error')) + it('does not crash when run completion in Ex mode', function() + local p = + n.spawn_wait('--clean', '-e', '-s', '--cmd', 'exe "norm! i\\<C-X>\\<C-V>"', '--cmd', 'qa!') + eq(0, p.status) end) it('does not crash after reading from stdin in non-headless mode', function() skip(is_os('win')) local screen = Screen.new(40, 8) local args = { - nvim_prog_abs(), + n.nvim_prog, '-u', 'NONE', '-i', @@ -138,51 +125,40 @@ describe('command-line option', function() ]=] end) - it('errors out when trying to use nonexistent file with -s', function() + it('fails when trying to use nonexistent file with -s', function() + local p = n.spawn_wait( + '--cmd', + 'set noswapfile shortmess+=IFW fileformats=unix', + '--cmd', + 'language C', + '-s', + nonexistent_fname + ) eq( 'Cannot open for reading: "' .. nonexistent_fname .. '": no such file or directory\n', - fn.system({ - nvim_prog_abs(), - '-u', - 'NONE', - '-i', - 'NONE', - '--headless', - '--cmd', - 'set noswapfile shortmess+=IFW fileformats=unix', - '--cmd', - 'language C', - '-s', - nonexistent_fname, - }) + --- TODO(justinmk): using `p.output` because Nvim emits CRLF even on non-Win. Emit LF instead? + p:output() ) - eq(2, eval('v:shell_error')) + eq(2, p.status) end) it('errors out when trying to use -s twice', function() write_file(fname, ':call setline(1, "1")\n:wqall!\n') write_file(dollar_fname, ':call setline(1, "2")\n:wqall!\n') - eq( - 'Attempt to open script file again: "-s ' .. dollar_fname .. '"\n', - fn.system({ - nvim_prog_abs(), - '-u', - 'NONE', - '-i', - 'NONE', - '--headless', - '--cmd', - 'set noswapfile shortmess+=IFW fileformats=unix', - '--cmd', - 'language C', - '-s', - fname, - '-s', - dollar_fname, - fname_2, - }) + local p = n.spawn_wait( + '--cmd', + 'set noswapfile shortmess+=IFW fileformats=unix', + '--cmd', + 'language C', + '-s', + fname, + '-s', + dollar_fname, + fname_2 ) - eq(2, eval('v:shell_error')) + --- TODO(justinmk): using `p.output` because Nvim emits CRLF even on non-Win. Emit LF instead? + eq('Attempt to open script file again: "-s ' .. dollar_fname .. '"\n', p:output()) + eq(2, p.status) eq(nil, uv.fs_stat(fname_2)) end) end) @@ -190,8 +166,8 @@ describe('command-line option', function() it('nvim -v, :version', function() matches('Run ":verbose version"', fn.execute(':version')) matches('fall%-back for %$VIM: .*Run :checkhealth', fn.execute(':verbose version')) - matches('Run "nvim %-V1 %-v"', fn.system({ nvim_prog_abs(), '-v' })) - matches('fall%-back for %$VIM: .*Run :checkhealth', fn.system({ nvim_prog_abs(), '-V1', '-v' })) + matches('Run "nvim %-V1 %-v"', n.spawn_wait('-v').stdout) + matches('fall%-back for %$VIM: .*Run :checkhealth', n.spawn_wait('-V1', '-v').stdout) end) if is_os('win') then @@ -205,7 +181,7 @@ describe('command-line option', function() eq( 'some text', fn.system({ - nvim_prog_abs(), + n.nvim_prog, '-es', '+%print', '+q', diff --git a/test/functional/core/remote_spec.lua b/test/functional/core/remote_spec.lua index 6cc28ddeef..1cfa0535f6 100644 --- a/test/functional/core/remote_spec.lua +++ b/test/functional/core/remote_spec.lua @@ -10,10 +10,8 @@ local expect = n.expect local fn = n.fn local insert = n.insert local nvim_prog = n.nvim_prog -local new_argv = n.new_argv local neq = t.neq local set_session = n.set_session -local spawn = n.spawn local tmpname = t.tmpname local write_file = t.write_file @@ -32,8 +30,7 @@ describe('Remote', function() describe('connect to server and', function() local server before_each(function() - server = spawn(new_argv(), true) - set_session(server) + server = n.clear() end) after_each(function() @@ -49,7 +46,7 @@ describe('Remote', function() -- to wait for the remote instance to exit and calling jobwait blocks -- the event loop. If the server event loop is blocked, it can't process -- our incoming --remote calls. - local client_starter = spawn(new_argv(), false, nil, true) + local client_starter = n.new_session(true) set_session(client_starter) -- Call jobstart() and jobwait() in the same RPC request to reduce flakiness. eq( @@ -144,15 +141,8 @@ describe('Remote', function() describe('exits with error on', function() local function run_and_check_exit_code(...) - local bogus_argv = new_argv(...) - - -- Create an nvim instance just to run the remote-invoking nvim. We want - -- to wait for the remote instance to exit and calling jobwait blocks - -- the event loop. If the server event loop is blocked, it can't process - -- our incoming --remote calls. - clear() - -- Call jobstart() and jobwait() in the same RPC request to reduce flakiness. - eq({ 2 }, exec_lua([[return vim.fn.jobwait({ vim.fn.jobstart(...) })]], bogus_argv)) + local p = n.spawn_wait { args = { ... } } + eq(2, p.status) end it('bogus subcommand', function() run_and_check_exit_code('--remote-bogus') diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index 76b0755441..8ecd3dca97 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -77,22 +77,9 @@ describe('startup', function() end) it('--startuptime does not crash on error #31125', function() - eq( - "E484: Can't open file .", - fn.system({ - nvim_prog, - '-u', - 'NONE', - '-i', - 'NONE', - '--headless', - '--startuptime', - '.', - '-c', - '42cquit', - }) - ) - eq(42, api.nvim_get_vvar('shell_error')) + local p = n.spawn_wait('--startuptime', '.', '-c', '42cquit') + eq("E484: Can't open file .", p.stderr) + eq(42, p.status) end) it('-D does not hang #12647', function() @@ -149,13 +136,18 @@ describe('startup', function() vim.list_extend(args, { '-l', (script or 'test/functional/fixtures/startup.lua') }) vim.list_extend(args, lua_args or {}) local out = fn.system(args, input):gsub('\r\n', '\n') - return eq(dedent(expected), out) + if type(expected) == 'function' then + return expected(out) + else + return eq(dedent(expected), out) + end end it('failure modes', function() -- nvim -l <empty> - matches('nvim%.?e?x?e?: Argument missing after: "%-l"', fn.system({ nvim_prog, '-l' })) - eq(1, eval('v:shell_error')) + local proc = n.spawn_wait('-l') + matches('nvim%.?e?x?e?: Argument missing after: "%-l"', proc.stderr) + eq(1, proc.status) end) it('os.exit() sets Nvim exitcode', function() @@ -182,13 +174,13 @@ describe('startup', function() end) it('Lua-error sets Nvim exitcode', function() + local proc = n.spawn_wait('-l', 'test/functional/fixtures/startup-fail.lua') + matches('E5113: .* my pearls!!', proc:output()) + eq(0, proc.signal) + eq(1, proc.status) + eq(0, eval('v:shell_error')) matches( - 'E5113: .* my pearls!!', - fn.system({ nvim_prog, '-l', 'test/functional/fixtures/startup-fail.lua' }) - ) - eq(1, eval('v:shell_error')) - matches( 'E5113: .* %[string "error%("whoa"%)"%]:1: whoa', fn.system({ nvim_prog, '-l', '-' }, 'error("whoa")') ) @@ -295,14 +287,30 @@ describe('startup', function() eq(0, eval('v:shell_error')) end) - it('disables swapfile/shada/config/plugins', function() + it('disables swapfile/shada/config/plugins unless overridden', function() + local script = [[print(('updatecount=%d shadafile=%s loadplugins=%s scripts=%d'):format( + vim.o.updatecount, vim.o.shadafile, tostring(vim.o.loadplugins), math.max(1, #vim.fn.getscriptinfo())))]] + finally(function() + os.remove('Xtest_shada') + end) + assert_l_out( 'updatecount=0 shadafile=NONE loadplugins=false scripts=1\n', nil, nil, '-', - [[print(('updatecount=%d shadafile=%s loadplugins=%s scripts=%d'):format( - vim.o.updatecount, vim.o.shadafile, tostring(vim.o.loadplugins), math.max(1, #vim.fn.getscriptinfo())))]] + script + ) + + -- User can override. + assert_l_out( + function(out) + return matches('updatecount=99 shadafile=Xtest_shada loadplugins=true scripts=2%d\n', out) + end, + { '+set updatecount=99', '-i', 'Xtest_shada', '+set loadplugins', '-u', 'NORC' }, + nil, + '-', + script ) end) end) @@ -585,19 +593,21 @@ describe('startup', function() eq(' encoding=utf-8\n', fn.system({ nvim_prog, '-n', '-es' }, { 'set encoding', '' })) end) - it('-es/-Es disables swapfile, user config #8540', function() + it('-es/-Es disables swapfile/shada/config #8540', function() for _, arg in ipairs({ '-es', '-Es' }) do local out = fn.system({ nvim_prog, arg, - '+set swapfile? updatecount? shadafile?', + '+set updatecount? shadafile? loadplugins?', '+put =map(getscriptinfo(), {-> v:val.name})', '+%print', }) local line1 = string.match(out, '^.-\n') -- updatecount=0 means swapfile was disabled. - eq(' swapfile updatecount=0 shadafile=\n', line1) - -- Standard plugins were loaded, but not user config. + eq(' updatecount=0 shadafile=NONE loadplugins\n', line1) + -- Standard plugins were loaded, but not user config. #31878 + local nrlines = #vim.split(out, '\n') + ok(nrlines > 20, '>20', nrlines) ok(string.find(out, 'man.lua') ~= nil) ok(string.find(out, 'init.vim') == nil) end @@ -606,15 +616,15 @@ describe('startup', function() it('fails on --embed with -es/-Es/-l', function() matches( 'nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l', - fn.system({ nvim_prog, '--embed', '-es' }) + n.spawn_wait('--embed', '-es').stderr ) matches( 'nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l', - fn.system({ nvim_prog, '--embed', '-Es' }) + n.spawn_wait('--embed', '-Es').stderr ) matches( 'nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l', - fn.system({ nvim_prog, '--embed', '-l', 'foo.lua' }) + n.spawn_wait('--embed', '-l', 'foo.lua').stderr ) end) @@ -698,20 +708,8 @@ describe('startup', function() end) it('get command line arguments from v:argv', function() - local out = fn.system({ - nvim_prog, - '-u', - 'NONE', - '-i', - 'NONE', - '--headless', - '--cmd', - nvim_set, - '-c', - [[echo v:argv[-1:] len(v:argv) > 1]], - '+q', - }) - eq("['+q'] 1", out) + local p = n.spawn_wait('--cmd', nvim_set, '-c', [[echo v:argv[-1:] len(v:argv) > 1]], '+q') + eq("['+q'] 1", p.stderr) end) end) diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index c20d925713..7c68de272b 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -10,6 +10,7 @@ local fn = n.fn local command = n.command local api = n.api local poke_eventloop = n.poke_eventloop +local exec_lua = n.exec_lua describe('completion', function() local screen @@ -1326,4 +1327,29 @@ describe('completion', function() ]], }) end) + + describe('nvim__complete_set', function() + it("fails when 'completeopt' does not include popup", function() + exec_lua([[ + function _G.omni_test(findstart, base) + if findstart == 1 then + return vim.fn.col('.') - 1 + end + return { { word = 'one' } } + end + vim.api.nvim_create_autocmd('CompleteChanged', { + callback = function() + local ok, err = pcall(vim.api.nvim__complete_set, 0, { info = '1info' }) + if not ok then + vim.g.err_msg = err + end + end, + }) + vim.opt.completeopt = 'menu,menuone' + vim.opt.omnifunc = 'v:lua.omni_test' + ]]) + feed('S<C-X><C-O>') + eq('completeopt option does not include popup', api.nvim_get_var('err_msg')) + end) + end) end) diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua index 08f7663075..d1f598a9d8 100644 --- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua +++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua @@ -12,12 +12,10 @@ local fn = n.fn local nvim_prog = n.nvim_prog local ok = t.ok local rmdir = n.rmdir -local new_argv = n.new_argv local new_pipename = n.new_pipename local pesc = vim.pesc local os_kill = n.os_kill local set_session = n.set_session -local spawn = n.spawn local async_meths = n.async_meths local expect_msg_seq = n.expect_msg_seq local pcall_err = t.pcall_err @@ -56,7 +54,7 @@ describe("preserve and (R)ecover with custom 'directory'", function() local nvim0 before_each(function() - nvim0 = spawn(new_argv()) + nvim0 = n.new_session(false) set_session(nvim0) rmdir(swapdir) mkdir(swapdir) @@ -76,7 +74,8 @@ describe("preserve and (R)ecover with custom 'directory'", function() local function test_recover(swappath1) -- Start another Nvim instance. - local nvim2 = spawn({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed' }, true) + local nvim2 = + n.new_session(false, { args = { '-u', 'NONE', '-i', 'NONE', '--embed' }, merge = false }) set_session(nvim2) exec(init) @@ -141,7 +140,7 @@ describe('swapfile detection', function() set swapfile fileformat=unix nomodified undolevels=-1 nohidden ]] before_each(function() - nvim0 = spawn(new_argv()) + nvim0 = n.new_session(false) set_session(nvim0) rmdir(swapdir) mkdir(swapdir) @@ -168,7 +167,8 @@ describe('swapfile detection', function() command('preserve') -- Start another Nvim instance. - local nvim2 = spawn({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed' }, true, nil, true) + local nvim2 = + n.new_session(true, { args = { '-u', 'NONE', '-i', 'NONE', '--embed' }, merge = false }) set_session(nvim2) local screen2 = Screen.new(256, 40) screen2._default_attr_ids = nil @@ -251,7 +251,7 @@ describe('swapfile detection', function() command('preserve') -- Make sure the swap file exists. local nvimpid = fn.getpid() - local nvim1 = spawn(new_argv(), true, nil, true) + local nvim1 = n.new_session(true) set_session(nvim1) local screen = Screen.new(75, 18) exec(init) @@ -273,7 +273,7 @@ describe('swapfile detection', function() [1] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg }) - local nvim1 = spawn(new_argv(), true, nil, true) + local nvim1 = n.new_session(true) set_session(nvim1) screen:attach() exec(init) @@ -292,7 +292,7 @@ describe('swapfile detection', function() ]]) nvim1:close() - local nvim2 = spawn(new_argv(), true, nil, true) + local nvim2 = n.new_session(true) set_session(nvim2) screen:attach() exec(init) diff --git a/test/functional/ex_cmds/wundo_spec.lua b/test/functional/ex_cmds/wundo_spec.lua index 2299f33f06..9b81c6d06d 100644 --- a/test/functional/ex_cmds/wundo_spec.lua +++ b/test/functional/ex_cmds/wundo_spec.lua @@ -5,8 +5,6 @@ local n = require('test.functional.testnvim')() local command = n.command local clear = n.clear local eval = n.eval -local spawn = n.spawn -local nvim_prog = n.nvim_prog local set_session = n.set_session describe(':wundo', function() @@ -24,15 +22,11 @@ end) describe('u_* functions', function() it('safely fail on new, non-empty buffer', function() - local session = spawn({ - nvim_prog, - '-u', - 'NONE', - '-i', - 'NONE', - '--embed', - '-c', - 'set undodir=. undofile', + local session = n.new_session(false, { + args = { + '-c', + 'set undodir=. undofile', + }, }) set_session(session) command('echo "True"') -- Should not error out due to crashed Neovim diff --git a/test/functional/func/memoize_spec.lua b/test/functional/func/memoize_spec.lua new file mode 100644 index 0000000000..ca518ab88d --- /dev/null +++ b/test/functional/func/memoize_spec.lua @@ -0,0 +1,142 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() +local clear = n.clear +local exec_lua = n.exec_lua +local eq = t.eq + +describe('vim.func._memoize', function() + before_each(clear) + + it('caches function results based on their parameters', function() + exec_lua([[ + _G.count = 0 + + local adder = vim.func._memoize('concat', function(arg1, arg2) + _G.count = _G.count + 1 + return arg1 + arg2 + end) + + collectgarbage('stop') + adder(3, -4) + adder(3, -4) + adder(3, -4) + adder(3, -4) + adder(3, -4) + collectgarbage('restart') + ]]) + + eq(1, exec_lua([[return _G.count]])) + end) + + it('caches function results using a weak table by default', function() + exec_lua([[ + _G.count = 0 + + local adder = vim.func._memoize('concat-2', function(arg1, arg2) + _G.count = _G.count + 1 + return arg1 + arg2 + end) + + adder(3, -4) + collectgarbage() + adder(3, -4) + collectgarbage() + adder(3, -4) + ]]) + + eq(3, exec_lua([[return _G.count]])) + end) + + it('can cache using a strong table', function() + exec_lua([[ + _G.count = 0 + + local adder = vim.func._memoize('concat-2', function(arg1, arg2) + _G.count = _G.count + 1 + return arg1 + arg2 + end, false) + + adder(3, -4) + collectgarbage() + adder(3, -4) + collectgarbage() + adder(3, -4) + ]]) + + eq(1, exec_lua([[return _G.count]])) + end) + + it('can clear a single cache entry', function() + exec_lua([[ + _G.count = 0 + + local adder = vim.func._memoize(function(arg1, arg2) + return tostring(arg1) .. '%%' .. tostring(arg2) + end, function(arg1, arg2) + _G.count = _G.count + 1 + return arg1 + arg2 + end) + + collectgarbage('stop') + adder(3, -4) + adder(3, -4) + adder(3, -4) + adder(3, -4) + adder(3, -4) + adder:clear(3, -4) + adder(3, -4) + collectgarbage('restart') + ]]) + + eq(2, exec_lua([[return _G.count]])) + end) + + it('can clear the entire cache', function() + exec_lua([[ + _G.count = 0 + + local adder = vim.func._memoize(function(arg1, arg2) + return tostring(arg1) .. '%%' .. tostring(arg2) + end, function(arg1, arg2) + _G.count = _G.count + 1 + return arg1 + arg2 + end) + + collectgarbage('stop') + adder(1, 2) + adder(3, -4) + adder(1, 2) + adder(3, -4) + adder(1, 2) + adder(3, -4) + adder:clear() + adder(1, 2) + adder(3, -4) + collectgarbage('restart') + ]]) + + eq(4, exec_lua([[return _G.count]])) + end) + + it('can cache functions that return nil', function() + exec_lua([[ + _G.count = 0 + + local adder = vim.func._memoize('concat', function(arg1, arg2) + _G.count = _G.count + 1 + return nil + end) + + collectgarbage('stop') + adder(1, 2) + adder(1, 2) + adder(1, 2) + adder(1, 2) + adder:clear() + adder(1, 2) + collectgarbage('restart') + ]]) + + eq(2, exec_lua([[return _G.count]])) + end) +end) diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua index 3addcb957c..819b40323a 100644 --- a/test/functional/legacy/cmdline_spec.lua +++ b/test/functional/legacy/cmdline_spec.lua @@ -159,6 +159,50 @@ describe('cmdline', function() endfunc ]]) + feed(':resize -3<CR>') + screen:expect([[ + ^ | + {1:~ }|*2 + {3:[No Name] }| + |*4 + ]]) + + -- :resize now also changes 'cmdheight' accordingly + feed(':set cmdheight+=1<CR>') + screen:expect([[ + ^ | + {1:~ }| + {3:[No Name] }| + |*5 + ]]) + + -- using more space moves the status line up + feed(':set cmdheight+=1<CR>') + screen:expect([[ + ^ | + {3:[No Name] }| + |*6 + ]]) + + -- reducing cmdheight moves status line down + feed(':set cmdheight-=3<CR>') + screen:expect([[ + ^ | + {1:~ }|*3 + {3:[No Name] }| + |*3 + ]]) + + -- reducing window size and then setting cmdheight + feed(':resize -1<CR>') + feed(':set cmdheight=1<CR>') + screen:expect([[ + ^ | + {1:~ }|*5 + {3:[No Name] }| + | + ]]) + -- setting 'cmdheight' works after outputting two messages feed(':call EchoTwo()') screen:expect([[ @@ -185,6 +229,16 @@ describe('cmdline', function() bar | {6:Press ENTER or type command to continue}^ | ]]) + + -- window commands do not reduce 'cmdheight' to value lower than :set by user + feed('<CR>:wincmd _<CR>') + screen:expect([[ + ^ | + {1:~ }|*4 + {3:[No Name] }| + :wincmd _ | + | + ]]) end) -- oldtest: Test_cmdheight_tabline() diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua index adf75c2836..db5e3f6857 100644 --- a/test/functional/legacy/messages_spec.lua +++ b/test/functional/legacy/messages_spec.lua @@ -82,7 +82,7 @@ describe('messages', function() NoSuchFil^e | three | {1:~ }|*5 - from DebugSilent visual | + | {9:E447: Can't find file "NoSuchFile" in path} | ]]) end) diff --git a/test/functional/legacy/window_cmd_spec.lua b/test/functional/legacy/window_cmd_spec.lua index b58bf0bf43..fac982354c 100644 --- a/test/functional/legacy/window_cmd_spec.lua +++ b/test/functional/legacy/window_cmd_spec.lua @@ -299,7 +299,7 @@ describe('splitkeep', function() c | {1:~ }| {3:[No Name] }| - | + :call win_move_statusline(win, 1) | ]]) end) diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index 1c6ff5ac6d..218f9bbc46 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -340,6 +340,9 @@ describe('vim.fs', function() end) describe('normalize()', function() + -- local function vim.fs.normalize(path, opts) + -- return exec_lua([[return vim.fs.vim.fs.normalize(...)]], path, opts) + -- end it('removes trailing /', function() eq('/home/user', vim.fs.normalize('/home/user/')) end) @@ -373,6 +376,29 @@ describe('vim.fs', function() eq('/foo/bar', vim.fs.normalize('/foo//bar////', posix_opts)) end) + it('normalizes drive letter', function() + eq('C:/', vim.fs.normalize('C:/', win_opts)) + eq('C:/', vim.fs.normalize('c:/', win_opts)) + eq('D:/', vim.fs.normalize('d:/', win_opts)) + eq('C:', vim.fs.normalize('C:', win_opts)) + eq('C:', vim.fs.normalize('c:', win_opts)) + eq('D:', vim.fs.normalize('d:', win_opts)) + eq('C:/foo/test', vim.fs.normalize('C:/foo/test/', win_opts)) + eq('C:/foo/test', vim.fs.normalize('c:/foo/test/', win_opts)) + eq('D:foo/test', vim.fs.normalize('D:foo/test/', win_opts)) + eq('D:foo/test', vim.fs.normalize('d:foo/test/', win_opts)) + end) + + it('does not change case on paths, see #31833', function() + eq('TEST', vim.fs.normalize('TEST', win_opts)) + eq('test', vim.fs.normalize('test', win_opts)) + eq('C:/FOO/test', vim.fs.normalize('C:/FOO/test', win_opts)) + eq('C:/foo/test', vim.fs.normalize('C:/foo/test', win_opts)) + eq('//SERVER/SHARE/FOO/BAR', vim.fs.normalize('//SERVER/SHARE/FOO/BAR', win_opts)) + eq('//server/share/foo/bar', vim.fs.normalize('//server/share/foo/bar', win_opts)) + eq('C:/FOO/test', vim.fs.normalize('c:/FOO/test', win_opts)) + end) + it('allows backslashes on unix-based os', function() eq('/home/user/hello\\world', vim.fs.normalize('/home/user/hello\\world', posix_opts)) end) diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index 27640d6066..af6b2ceac3 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -106,20 +106,15 @@ describe('vim.ui_attach', function() end) it('does not crash on exit', function() - fn.system({ - n.nvim_prog, - '-u', - 'NONE', - '-i', - 'NONE', + local p = n.spawn_wait( '--cmd', [[ lua ns = vim.api.nvim_create_namespace 'testspace' ]], '--cmd', [[ lua vim.ui_attach(ns, {ext_popupmenu=true}, function() end) ]], '--cmd', - 'quitall!', - }) - eq(0, n.eval('v:shell_error')) + 'quitall!' + ) + eq(0, p.status) end) it('can receive accurate message kinds even if they are history', function() diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index e7f47ef4e9..a82279e775 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -14,7 +14,6 @@ local api = n.api local command = n.command local clear = n.clear local exc_exec = n.exc_exec -local exec_lua = n.exec_lua local eval = n.eval local eq = t.eq local ok = t.ok @@ -929,17 +928,12 @@ describe('stdpath()', function() assert_alive() -- Check for crash. #8393 -- Check that Nvim rejects invalid APPNAMEs - -- Call jobstart() and jobwait() in the same RPC request to reduce flakiness. local function test_appname(testAppname, expected_exitcode) - local lua_code = string.format( - [[ - local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '--listen', 'x', '+qall!' }, { env = { NVIM_APPNAME = %q } }) - return vim.fn.jobwait({ child }, %d)[1] - ]], - testAppname, - 3000 - ) - eq(expected_exitcode, exec_lua(lua_code)) + local p = n.spawn_wait({ + args = { '--listen', 'x', '+qall!' }, + env = { NVIM_APPNAME = testAppname }, + }) + eq(expected_exitcode, p.status) end -- Invalid appnames: test_appname('a/../b', 1) diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index 753da64522..406b5c3c16 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -66,6 +66,18 @@ describe(':checkhealth', function() eq({}, getcompletion('', 'checkhealth')) assert_alive() end) + + it('vim.g.health', function() + clear() + command("let g:health = {'style':'float'}") + command('checkhealth lsp') + eq( + 'editor', + exec_lua([[ + return vim.api.nvim_win_get_config(0).relative + ]]) + ) + end) end) describe('vim.health', function() diff --git a/test/functional/plugin/lsp/utils_spec.lua b/test/functional/plugin/lsp/utils_spec.lua index ce6e6b2535..1e3e759e0b 100644 --- a/test/functional/plugin/lsp/utils_spec.lua +++ b/test/functional/plugin/lsp/utils_spec.lua @@ -301,4 +301,32 @@ describe('vim.lsp.util', function() end) end) end) + + it('open_floating_preview zindex greater than current window', function() + local screen = Screen.new() + exec_lua(function() + vim.api.nvim_open_win(0, true, { + relative = 'editor', + border = 'single', + height = 11, + width = 51, + row = 2, + col = 2, + }) + vim.keymap.set('n', 'K', function() + vim.lsp.util.open_floating_preview({ 'foo' }, '', { border = 'single' }) + end, {}) + end) + feed('K') + screen:expect([[ + ┌───────────────────────────────────────────────────┐| + │{4:^ }│| + │┌───┐{11: }│| + ││{4:foo}│{11: }│| + │└───┘{11: }│| + │{11:~ }│|*7 + └───────────────────────────────────────────────────┘| + | + ]]) + end) end) diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua index d680f0b83b..837978dee1 100644 --- a/test/functional/shada/marks_spec.lua +++ b/test/functional/shada/marks_spec.lua @@ -218,7 +218,7 @@ describe('ShaDa support code', function() -- -c temporary sets lnum to zero to make `+/pat` work, so calling setpcmark() -- during -c used to add item with zero lnum to jump list. it('does not create incorrect file for non-existent buffers when writing from -c', function() - local argv = n.new_argv { + local p = n.spawn_wait { args_rm = { '-i', '--embed', -- no --embed @@ -232,12 +232,13 @@ describe('ShaDa support code', function() 'qall', }, } - eq('', fn.system(argv)) + eq('', p:output()) + eq(0, p.status) eq(0, exc_exec('rshada')) end) it('does not create incorrect file for non-existent buffers opened from -c', function() - local argv = n.new_argv { + local p = n.spawn_wait { args_rm = { '-i', '--embed', -- no --embed @@ -251,7 +252,8 @@ describe('ShaDa support code', function() 'autocmd VimEnter * qall', }, } - eq('', fn.system(argv)) + eq('', p:output()) + eq(0, p.status) eq(0, exc_exec('rshada')) end) diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua index 5debdc6c77..78fe19b984 100644 --- a/test/functional/shada/shada_spec.lua +++ b/test/functional/shada/shada_spec.lua @@ -6,8 +6,7 @@ local uv = vim.uv local paths = t.paths local api, nvim_command, fn, eq = n.api, n.command, n.fn, t.eq -local write_file, spawn, set_session, nvim_prog, exc_exec = - t.write_file, n.spawn, n.set_session, n.nvim_prog, n.exc_exec +local write_file, set_session, exc_exec = t.write_file, n.set_session, n.exc_exec local is_os = t.is_os local skip = t.skip @@ -254,7 +253,7 @@ describe('ShaDa support code', function() it('does not crash when ShaDa file directory is not writable', function() skip(is_os('win')) - fn.mkdir(dirname, '', 0) + fn.mkdir(dirname, '', '0') eq(0, fn.filewritable(dirname)) reset { shadafile = dirshada, args = { '--cmd', 'set shada=' } } api.nvim_set_option_value('shada', "'10", {}) @@ -270,10 +269,10 @@ end) describe('ShaDa support code', function() it('does not write NONE file', function() - local session = spawn( - { nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', '--headless', '--cmd', 'qall' }, - true - ) + local session = n.new_session(false, { + merge = false, + args = { '-u', 'NONE', '-i', 'NONE', '--embed', '--headless', '--cmd', 'qall' }, + }) session:close() eq(nil, uv.fs_stat('NONE')) eq(nil, uv.fs_stat('NONE.tmp.a')) @@ -281,7 +280,10 @@ describe('ShaDa support code', function() it('does not read NONE file', function() write_file('NONE', '\005\001\015\131\161na\162rX\194\162rc\145\196\001-') - local session = spawn({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', '--headless' }, true) + local session = n.new_session( + false, + { merge = false, args = { '-u', 'NONE', '-i', 'NONE', '--embed', '--headless' } } + ) set_session(session) eq('', fn.getreg('a')) session:close() diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index b6de687af9..cc807ba555 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -435,6 +435,19 @@ describe(':terminal buffer', function() ]]) end) + it('handles unprintable chars', function() + local screen = Screen.new(50, 7) + feed 'i' + local chan = api.nvim_open_term(0, {}) + api.nvim_chan_send(chan, '\239\187\191') -- '\xef\xbb\xbf' + screen:expect([[ + {18:<feff>}^ | + |*5 + {5:-- TERMINAL --} | + ]]) + eq('\239\187\191', api.nvim_get_current_line()) + end) + it("handles bell respecting 'belloff' and 'visualbell'", function() local screen = Screen.new(50, 7) local chan = api.nvim_open_term(0, {}) diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua index c43d139f70..0afbd010f7 100644 --- a/test/functional/terminal/highlight_spec.lua +++ b/test/functional/terminal/highlight_spec.lua @@ -6,7 +6,6 @@ local tt = require('test.functional.testterm') local feed, clear = n.feed, n.clear local api = n.api local testprg, command = n.testprg, n.command -local nvim_prog_abs = n.nvim_prog_abs local fn = n.fn local nvim_set = n.nvim_set local is_os = t.is_os @@ -151,7 +150,7 @@ it(':terminal highlight has lower precedence than editor #9964', function() }) -- Child nvim process in :terminal (with cterm colors). fn.jobstart({ - nvim_prog_abs(), + n.nvim_prog, '-n', '-u', 'NORC', diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index f9145f9b63..3624a7bc2b 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -26,7 +26,6 @@ local api = n.api local is_ci = t.is_ci local is_os = t.is_os local new_pipename = n.new_pipename -local spawn_argv = n.spawn_argv local set_session = n.set_session local write_file = t.write_file local eval = n.eval @@ -3320,8 +3319,8 @@ describe('TUI as a client', function() end) it('connects to remote instance (with its own TUI)', function() - local server_super = spawn_argv(false) -- equivalent to clear() - local client_super = spawn_argv(true) + local server_super = n.new_session(false) + local client_super = n.new_session(true) set_session(server_super) local server_pipe = new_pipename() @@ -3395,8 +3394,8 @@ describe('TUI as a client', function() end) it('connects to remote instance (--headless)', function() - local server = spawn_argv(false) -- equivalent to clear() - local client_super = spawn_argv(true, { env = { NVIM_LOG_FILE = testlog } }) + local server = n.new_session(false) + local client_super = n.new_session(true, { env = { NVIM_LOG_FILE = testlog } }) set_session(server) local server_pipe = api.nvim_get_vvar('servername') @@ -3462,8 +3461,8 @@ describe('TUI as a client', function() end) local function test_remote_tui_quit(status) - local server_super = spawn_argv(false) -- equivalent to clear() - local client_super = spawn_argv(true) + local server_super = n.new_session(false) + local client_super = n.new_session(true) set_session(server_super) local server_pipe = new_pipename() diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 675ad9e3d7..59cb593cf7 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -4,7 +4,7 @@ local t = require('test.testutil') local Session = require('test.client.session') local uv_stream = require('test.client.uv_stream') local SocketStream = uv_stream.SocketStream -local ChildProcessStream = uv_stream.ChildProcessStream +local ProcStream = uv_stream.ProcStream local check_cores = t.check_cores local check_logs = t.check_logs @@ -318,24 +318,14 @@ function M.stop() assert(session):stop() end -function M.nvim_prog_abs() - -- system(['build/bin/nvim']) does not work for whatever reason. It must - -- be executable searched in $PATH or something starting with / or ./. - if M.nvim_prog:match('[/\\]') then - return M.request('nvim_call_function', 'fnamemodify', { M.nvim_prog, ':p' }) - else - return M.nvim_prog - end -end - -- Use for commands which expect nvim to quit. -- The first argument can also be a timeout. function M.expect_exit(fn_or_timeout, ...) local eof_err_msg = 'EOF was received from Nvim. Likely the Nvim process crashed.' if type(fn_or_timeout) == 'function' then - eq(eof_err_msg, t.pcall_err(fn_or_timeout, ...)) + t.matches(eof_err_msg, t.pcall_err(fn_or_timeout, ...)) else - eq( + t.matches( eof_err_msg, t.pcall_err(function(timeout, fn, ...) fn(...) @@ -465,22 +455,6 @@ function M.check_close() session = nil end ---- @param argv string[] ---- @param merge boolean? ---- @param env string[]? ---- @param keep boolean? ---- @param io_extra uv.uv_pipe_t? used for stdin_fd, see :help ui-option ---- @return test.Session -function M.spawn(argv, merge, env, keep, io_extra) - if not keep then - M.check_close() - end - - local child_stream = - ChildProcessStream.spawn(merge and M.merge_args(prepend_argv, argv) or argv, env, io_extra) - return Session.new(child_stream) -end - -- Creates a new Session connected by domain socket (named pipe) or TCP. function M.connect(file_or_address) local addr, port = string.match(file_or_address, '(.*):(%d+)') @@ -489,61 +463,112 @@ function M.connect(file_or_address) return Session.new(stream) end --- Starts (and returns) a new global Nvim session. --- --- Parameters are interpreted as startup args, OR a map with these keys: --- args: List: Args appended to the default `nvim_argv` set. --- args_rm: List: Args removed from the default set. All cases are --- removed, e.g. args_rm={'--cmd'} removes all cases of "--cmd" --- (and its value) from the default set. --- env: Map: Defines the environment of the new session. --- --- Example: --- clear('-e') --- clear{args={'-e'}, args_rm={'-i'}, env={TERM=term}} +--- Starts a new, global Nvim session and clears the current one. +--- +--- Note: Use `new_session()` to start a session without replacing the current one. +--- +--- Parameters are interpreted as startup args, OR a map with these keys: +--- - args: List: Args appended to the default `nvim_argv` set. +--- - args_rm: List: Args removed from the default set. All cases are +--- removed, e.g. args_rm={'--cmd'} removes all cases of "--cmd" +--- (and its value) from the default set. +--- - env: Map: Defines the environment of the new session. +--- +--- Example: +--- ``` +--- clear('-e') +--- clear{args={'-e'}, args_rm={'-i'}, env={TERM=term}} +--- ``` +--- +--- @param ... string Nvim CLI args +--- @return test.Session +--- @overload fun(opts: test.session.Opts): test.Session function M.clear(...) - M.set_session(M.spawn_argv(false, ...)) + M.set_session(M.new_session(false, ...)) return M.get_session() end ---- same params as clear, but does returns the session instead ---- of replacing the default session +--- Starts a new Nvim process with the given args and returns a msgpack-RPC session. +--- +--- Does not replace the current global session, unlike `clear()`. +--- +--- @param keep boolean (default: false) Don't close the current global session. +--- @param ... string Nvim CLI args (or see overload) --- @return test.Session -function M.spawn_argv(keep, ...) - local argv, env, io_extra = M.new_argv(...) - return M.spawn(argv, nil, env, keep, io_extra) +--- @overload fun(keep: boolean, opts: test.session.Opts): test.Session +function M.new_session(keep, ...) + if not keep then + M.check_close() + end + + local argv, env, io_extra = M._new_argv(...) + + local proc = ProcStream.spawn(argv, env, io_extra) + return Session.new(proc) end ---- @class test.new_argv.Opts +--- Starts a (non-RPC, `--headless --listen "Tx"`) Nvim process, waits for exit, and returns result. +--- +--- @param ... string Nvim CLI args, or `test.session.Opts` table. +--- @return test.ProcStream +--- @overload fun(opts: test.session.Opts): test.ProcStream +function M.spawn_wait(...) + local opts = type(...) == 'string' and { args = { ... } } or ... + opts.args_rm = opts.args_rm and opts.args_rm or {} + table.insert(opts.args_rm, '--embed') + local argv, env, io_extra = M._new_argv(opts) + local proc = ProcStream.spawn(argv, env, io_extra) + proc.collect_text = true + proc:read_start() + proc:wait() + proc:close() + return proc +end + +--- @class test.session.Opts +--- Nvim CLI args --- @field args? string[] +--- Remove these args from the default `nvim_argv` args set. Ignored if `merge=false`. --- @field args_rm? string[] +--- (default: true) Merge `args` with the default set. Else use only the provided `args`. +--- @field merge? boolean +--- Environment variables --- @field env? table<string,string> +--- Used for stdin_fd, see `:help ui-option` --- @field io_extra? uv.uv_pipe_t ---- Builds an argument list for use in clear(). +--- @private --- ---- @see clear() for parameters. ---- @param ... string +--- Builds an argument list for use in `new_session()`, `clear()`, and `spawn_wait()`. +--- +--- @param ... string Nvim CLI args, or `test.session.Opts` table. --- @return string[] --- @return string[]? --- @return uv.uv_pipe_t? -function M.new_argv(...) - local args = { unpack(M.nvim_argv) } - table.insert(args, '--headless') - if _G._nvim_test_id then - -- Set the server name to the test-id for logging. #8519 - table.insert(args, '--listen') - table.insert(args, _G._nvim_test_id) +--- @overload fun(opts: test.session.Opts): string[], string[]?, uv.uv_pipe_t? +function M._new_argv(...) + --- @type test.session.Opts|string + local opts = select(1, ...) + local merge = type(opts) ~= 'table' and true or opts.merge ~= false + + local args = merge and { unpack(M.nvim_argv) } or { M.nvim_prog } + if merge then + table.insert(args, '--headless') + if _G._nvim_test_id then + -- Set the server name to the test-id for logging. #8519 + table.insert(args, '--listen') + table.insert(args, _G._nvim_test_id) + end end + local new_args --- @type string[] local io_extra --- @type uv.uv_pipe_t? - local env --- @type string[]? - --- @type test.new_argv.Opts|string - local opts = select(1, ...) + local env --- @type string[]? List of "key=value" env vars. + if type(opts) ~= 'table' then new_args = { ... } else - args = remove_args(args, opts.args_rm) + args = merge and remove_args(args, opts.args_rm) or args if opts.env then local env_opt = {} --- @type table<string,string> for k, v in pairs(opts.env) do diff --git a/test/functional/treesitter/fold_spec.lua b/test/functional/treesitter/fold_spec.lua index e38e58ff92..9f7fdf529f 100644 --- a/test/functional/treesitter/fold_spec.lua +++ b/test/functional/treesitter/fold_spec.lua @@ -5,6 +5,7 @@ local Screen = require('test.functional.ui.screen') local clear = n.clear local eq = t.eq local insert = n.insert +local write_file = t.write_file local exec_lua = n.exec_lua local command = n.command local feed = n.feed @@ -767,4 +768,78 @@ t2]]) ]], } end) + + it("doesn't call get_parser too often when parser is not available", function() + -- spy on vim.treesitter.get_parser() to keep track of how many times it is called + exec_lua(function() + _G.count = 0 + vim.treesitter.get_parser = (function(wrapped) + return function(...) + _G.count = _G.count + 1 + return wrapped(...) + end + end)(vim.treesitter.get_parser) + end) + + insert(test_text) + command [[ + set filetype=some_filetype_without_treesitter_parser + set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1 foldlevel=0 + ]] + + -- foldexpr will return '0' for all lines + local levels = get_fold_levels() ---@type integer[] + eq(19, #levels) + for lnum, level in ipairs(levels) do + eq('0', level, string.format("foldlevel[%d] == %s; expected '0'", lnum, level)) + end + + eq( + 1, + exec_lua [[ return _G.count ]], + 'count should not be as high as the # of lines; actually only once for the buffer.' + ) + end) + + it('can detect a new parser and refresh folds accordingly', function() + write_file('test_fold_file.txt', test_text) + command [[ + e test_fold_file.txt + set filetype=some_filetype_without_treesitter_parser + set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1 foldlevel=0 + ]] + + -- foldexpr will return '0' for all lines + local levels = get_fold_levels() ---@type integer[] + eq(19, #levels) + for lnum, level in ipairs(levels) do + eq('0', level, string.format("foldlevel[%d] == %s; expected '0'", lnum, level)) + end + + -- reload buffer as c filetype to simulate new parser being found + feed('GA// vim: ft=c<Esc>') + command([[w | e]]) + + eq({ + [1] = '>1', + [2] = '1', + [3] = '1', + [4] = '1', + [5] = '>2', + [6] = '2', + [7] = '2', + [8] = '1', + [9] = '1', + [10] = '>2', + [11] = '2', + [12] = '2', + [13] = '2', + [14] = '2', + [15] = '>3', + [16] = '3', + [17] = '3', + [18] = '2', + [19] = '1', + }, get_fold_levels()) + end) end) diff --git a/test/functional/treesitter/inspect_tree_spec.lua b/test/functional/treesitter/inspect_tree_spec.lua index 1f7d15cc96..47f3421cfe 100644 --- a/test/functional/treesitter/inspect_tree_spec.lua +++ b/test/functional/treesitter/inspect_tree_spec.lua @@ -120,14 +120,17 @@ describe('vim.treesitter.inspect_tree', function() end) it('updates source and tree buffer windows and closes them correctly', function() + local name = t.tmpname() + n.command('edit ' .. name) insert([[ print() ]]) + n.command('set filetype=lua | write') -- setup two windows for the source buffer exec_lua(function() _G.source_win = vim.api.nvim_get_current_win() - vim.api.nvim_open_win(0, false, { + _G.source_win2 = vim.api.nvim_open_win(0, false, { win = 0, split = 'left', }) @@ -135,40 +138,44 @@ describe('vim.treesitter.inspect_tree', function() -- setup three windows for the tree buffer exec_lua(function() - vim.treesitter.start(0, 'lua') vim.treesitter.inspect_tree() _G.tree_win = vim.api.nvim_get_current_win() - _G.tree_win_copy_1 = vim.api.nvim_open_win(0, false, { + _G.tree_win2 = vim.api.nvim_open_win(0, false, { win = 0, split = 'left', }) - _G.tree_win_copy_2 = vim.api.nvim_open_win(0, false, { + _G.tree_win3 = vim.api.nvim_open_win(0, false, { win = 0, split = 'left', }) end) - -- close original source window - exec_lua('vim.api.nvim_win_close(source_win, false)') + -- close original source window without closing tree views + exec_lua('vim.api.nvim_set_current_win(source_win)') + feed(':quit<CR>') + eq('', n.api.nvim_get_vvar('errmsg')) + eq(true, exec_lua('return vim.api.nvim_win_is_valid(tree_win)')) + eq(true, exec_lua('return vim.api.nvim_win_is_valid(tree_win2)')) + eq(true, exec_lua('return vim.api.nvim_win_is_valid(tree_win3)')) -- navigates correctly to the remaining source buffer window + exec_lua('vim.api.nvim_set_current_win(tree_win)') feed('<CR>') eq('', n.api.nvim_get_vvar('errmsg')) + eq(true, exec_lua('return vim.api.nvim_get_current_win() == source_win2')) -- close original tree window exec_lua(function() - vim.api.nvim_set_current_win(_G.tree_win_copy_1) + vim.api.nvim_set_current_win(_G.tree_win2) vim.api.nvim_win_close(_G.tree_win, false) end) -- navigates correctly to the remaining source buffer window feed('<CR>') eq('', n.api.nvim_get_vvar('errmsg')) + eq(true, exec_lua('return vim.api.nvim_get_current_win() == source_win2')) -- close source buffer window and all remaining tree windows - t.pcall_err(exec_lua, 'vim.api.nvim_win_close(0, false)') - - eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_1)')) - eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_2)')) + n.expect_exit(n.command, 'quit') end) end) diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua index 634f8af83d..6e21ed1d99 100644 --- a/test/functional/treesitter/query_spec.lua +++ b/test/functional/treesitter/query_spec.lua @@ -835,9 +835,9 @@ void ui_refresh(void) local result = exec_lua(function() local query0 = vim.treesitter.query.parse('c', query) - local match_preds = query0.match_preds + local match_preds = query0._match_predicates local called = 0 - function query0:match_preds(...) + function query0:_match_predicates(...) called = called + 1 return match_preds(self, ...) end diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 93ea2b9186..a2722a4139 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -1038,6 +1038,18 @@ describe('cmdline redraw', function() ]], } end) + + it('silent prompt', function() + command([[nmap <silent> T :call confirm("Save changes?", "&Yes\n&No\n&Cancel")<CR>]]) + feed('T') + screen:expect([[ + | + {3: }| + | + {6:Save changes?} | + {6:[Y]es, (N)o, (C)ancel: }^ | + ]]) + end) end) describe('statusline is redrawn on entering cmdline', function() diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 1e51652c4f..77ffc475b0 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -1121,7 +1121,7 @@ stack traceback: ]], messages = { { - content = { { 'wildmenu wildmode' } }, + content = { { 'wildmenu wildmode\n' } }, history = false, kind = 'wildlist', }, @@ -1335,6 +1335,21 @@ stack traceback: feed('i') n.assert_alive() end) + + it(':digraph contains newlines', function() + command('digraph') + screen:expect({ + condition = function() + local nl = 0 + eq('list_cmd', screen.messages[1].kind) + for _, chunk in ipairs(screen.messages[1].content) do + nl = nl + (chunk[2]:find('\n') and 1 or 0) + end + eq(682, nl) + screen.messages = {} + end, + }) + end) end) describe('ui/builtin messages', function() diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index d1228d3607..60d59190ce 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1680,7 +1680,7 @@ describe('builtin popupmenu', function() end) end - describe('floating window preview #popup', function() + describe('floating window preview popup', function() it('pum popup preview', function() --row must > 10 screen:try_resize(40, 11) @@ -1693,14 +1693,29 @@ describe('builtin popupmenu', function() endfunc set omnifunc=Omni_test set completeopt=menu,popup - funct Set_info() let comp_info = complete_info() if comp_info['selected'] == 2 call nvim__complete_set(comp_info['selected'], {"info": "3info"}) endif endfunc - autocmd CompleteChanged * call Set_info() + funct TsHl() + let comp_info = complete_info() + if get(comp_info, 'previewbufnr', 0) > 0 + call v:lua.vim.treesitter.start(comp_info['preview_bufnr'], 'markdown') + endif + if comp_info['selected'] == 0 + call nvim__complete_set(comp_info['selected'], {"info": "```lua\nfunction test()\n print('foo')\nend\n```"}) + endif + endfunc + augroup Group + au! + autocmd CompleteChanged * :call Set_info() + augroup END + funct TestTs() + autocmd! Group + autocmd CompleteChanged * call TsHl() + endfunc ]]) feed('Gi<C-x><C-o>') --floating preview in right @@ -2004,6 +2019,90 @@ describe('builtin popupmenu', function() ]], } end + feed('<C-E><Esc>') + + -- works when scroll with treesitter highlight + command('call TestTs()') + feed('S<C-x><C-o>') + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:----------------------------------------]|*10 + [3:----------------------------------------]| + ## grid 2 + one^ | + {1:~ }|*9 + ## grid 3 + {2:-- }{5:match 1 of 3} | + ## grid 5 + {s:one }| + {n:two }| + {n:looooooooooooooong }| + ## grid 9 + {n:```lua }| + {n:function test()}| + {n: print('foo') }| + {n:end }| + {n:``` }| + {n: }| + ]], + float_pos = { + [5] = { -1, 'NW', 2, 1, 0, false, 100 }, + [9] = { 1005, 'NW', 1, 1, 19, false, 50 }, + }, + win_viewport = { + [2] = { + win = 1000, + topline = 0, + botline = 2, + curline = 0, + curcol = 3, + linecount = 1, + sum_scroll_delta = 0, + }, + [9] = { + win = 1005, + topline = 0, + botline = 6, + curline = 0, + curcol = 0, + linecount = 5, + sum_scroll_delta = 0, + }, + }, + win_viewport_margins = { + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000, + }, + [9] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1005, + }, + }, + }) + else + screen:expect({ + grid = [[ + one^ | + {s:one }{n:```lua }{1: }| + {n:two function test()}{1: }| + {n:looooooooooooooong print('foo') }{1: }| + {1:~ }{n:end }{1: }| + {1:~ }{n:``` }{1: }| + {1:~ }{n: }{1: }| + {1:~ }|*3 + {2:-- }{5:match 1 of 3} | + ]], + }) + end end) end) diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 666d98c3b2..295c40b9b6 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -2,7 +2,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local spawn, set_session, clear = n.spawn, n.set_session, n.clear +local set_session, clear = n.set_session, n.clear local feed, command = n.feed, n.command local exec = n.exec local insert = n.insert @@ -26,7 +26,7 @@ describe('screen', function() } before_each(function() - local screen_nvim = spawn(nvim_argv) + local screen_nvim = n.new_session(false, { args = nvim_argv, merge = false }) set_session(screen_nvim) screen = Screen.new() end) @@ -766,7 +766,7 @@ describe('Screen default colors', function() 'colorscheme vim', '--embed', } - local screen_nvim = spawn(nvim_argv) + local screen_nvim = n.new_session(false, { args = nvim_argv, merge = false }) set_session(screen_nvim) screen = Screen.new(53, 14, { rgb = true, ext_termcolors = termcolors or nil }) end |