diff options
Diffstat (limited to 'test/functional/core')
-rw-r--r-- | test/functional/core/channels_spec.lua | 9 | ||||
-rw-r--r-- | test/functional/core/exit_spec.lua | 6 | ||||
-rw-r--r-- | test/functional/core/fileio_spec.lua | 132 | ||||
-rw-r--r-- | test/functional/core/job_spec.lua | 49 | ||||
-rw-r--r-- | test/functional/core/log_spec.lua | 9 | ||||
-rw-r--r-- | test/functional/core/main_spec.lua | 6 | ||||
-rw-r--r-- | test/functional/core/path_spec.lua | 18 | ||||
-rw-r--r-- | test/functional/core/remote_spec.lua | 9 | ||||
-rw-r--r-- | test/functional/core/startup_spec.lua | 307 |
9 files changed, 440 insertions, 105 deletions
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua index ca52404d3b..8275575c24 100644 --- a/test/functional/core/channels_spec.lua +++ b/test/functional/core/channels_spec.lua @@ -1,5 +1,4 @@ local helpers = require('test.functional.helpers')(after_each) -local uname = helpers.uname local clear, eq, eval, next_msg, ok, source = helpers.clear, helpers.eq, helpers.eval, helpers.next_msg, helpers.ok, helpers.source local command, funcs, meths = helpers.command, helpers.funcs, helpers.meths @@ -12,6 +11,7 @@ local retry = helpers.retry local expect_twostreams = helpers.expect_twostreams local assert_alive = helpers.assert_alive local pcall_err = helpers.pcall_err +local skip = helpers.skip describe('channels', function() local init = [[ @@ -145,7 +145,7 @@ describe('channels', function() end it('can use stdio channel with pty', function() - if helpers.pending_win32(pending) then return end + skip(is_os('win')) source([[ let g:job_opts = { \ 'on_stdout': function('OnEvent'), @@ -178,8 +178,7 @@ describe('channels', function() command("call chansend(id, 'incomplet\004')") - local is_bsd = not not string.find(uname(), 'bsd') - local bsdlike = is_bsd or is_os('mac') + local bsdlike = is_os('bsd') or is_os('mac') local extra = bsdlike and "^D\008\008" or "" expect_twoline(id, "stdout", "incomplet"..extra, "[1, ['incomplet'], 'stdin']", true) @@ -199,7 +198,7 @@ describe('channels', function() it('stdio channel can use rpc and stderr simultaneously', function() - if helpers.pending_win32(pending) then return end + skip(is_os('win')) source([[ let g:job_opts = { \ 'on_stderr': function('OnEvent'), diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua index 8cad7adfa6..05a69e1992 100644 --- a/test/functional/core/exit_spec.lua +++ b/test/functional/core/exit_spec.lua @@ -89,14 +89,14 @@ describe(':cquit', function() end) it('exits with redir msg for multiple exit codes after :cquit 1 2', function() - test_cq('cquit 1 2', nil, 'Vim(cquit):E488: Trailing characters: 2: cquit 1 2') + test_cq('cquit 1 2', nil, 'nvim_exec(): Vim(cquit):E488: Trailing characters: 2: cquit 1 2') end) it('exits with redir msg for non-number exit code after :cquit X', function() - test_cq('cquit X', nil, 'Vim(cquit):E488: Trailing characters: X: cquit X') + test_cq('cquit X', nil, 'nvim_exec(): Vim(cquit):E488: Trailing characters: X: cquit X') end) it('exits with redir msg for negative exit code after :cquit -1', function() - test_cq('cquit -1', nil, 'Vim(cquit):E488: Trailing characters: -1: cquit -1') + test_cq('cquit -1', nil, 'nvim_exec(): Vim(cquit):E488: Trailing characters: -1: cquit -1') end) end) diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index a4d22685e8..4e9891a4de 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -1,3 +1,4 @@ +local lfs = require('lfs') local helpers = require('test.functional.helpers')(after_each) local assert_log = helpers.assert_log @@ -5,6 +6,7 @@ local assert_nolog = helpers.assert_nolog local clear = helpers.clear local command = helpers.command local eq = helpers.eq +local neq = helpers.neq local ok = helpers.ok local feed = helpers.feed local funcs = helpers.funcs @@ -19,22 +21,28 @@ local read_file = helpers.read_file local tmpname = helpers.tmpname local trim = helpers.trim local currentdir = helpers.funcs.getcwd -local iswin = helpers.iswin local assert_alive = helpers.assert_alive +local check_close = helpers.check_close local expect_exit = helpers.expect_exit local write_file = helpers.write_file +local Screen = require('test.functional.ui.screen') +local feed_command = helpers.feed_command +local skip = helpers.skip +local is_os = helpers.is_os +local is_ci = helpers.is_ci describe('fileio', function() before_each(function() end) after_each(function() - expect_exit(command, ':qall!') + check_close() os.remove('Xtest_startup_shada') os.remove('Xtest_startup_file1') os.remove('Xtest_startup_file1~') os.remove('Xtest_startup_file2') os.remove('Xtest_тест.md') os.remove('Xtest-u8-int-max') + os.remove('Xtest-overwrite-forced') rmdir('Xtest_startup_swapdir') rmdir('Xtest_backupdir') end) @@ -83,6 +91,7 @@ describe('fileio', function() end) it('backup #9709', function() + skip(is_ci('cirrus')) clear({ args={ '-i', 'Xtest_startup_shada', '--cmd', 'set directory=Xtest_startup_swapdir' } }) @@ -102,6 +111,7 @@ describe('fileio', function() end) it('backup with full path #11214', function() + skip(is_ci('cirrus')) clear() mkdir('Xtest_backupdir') command('set backup') @@ -114,7 +124,7 @@ describe('fileio', function() -- Backup filename = fullpath, separators replaced with "%". local backup_file_name = string.gsub(currentdir()..'/Xtest_startup_file1', - iswin() and '[:/\\]' or '/', '%%') .. '~' + is_os('win') and '[:/\\]' or '/', '%%') .. '~' local foo_contents = trim(read_file('Xtest_backupdir/'..backup_file_name)) local foobar_contents = trim(read_file('Xtest_startup_file1')) @@ -122,6 +132,53 @@ describe('fileio', function() eq('foo', foo_contents); end) + it('backup symlinked files #11349', function() + skip(is_ci('cirrus')) + clear() + + local initial_content = 'foo' + local link_file_name = 'Xtest_startup_file2' + local backup_file_name = link_file_name .. '~' + + write_file('Xtest_startup_file1', initial_content, false) + lfs.link('Xtest_startup_file1', link_file_name, true) + command('set backup') + command('set backupcopy=yes') + command('edit ' .. link_file_name) + feed('Abar<esc>') + command('write') + + local backup_raw = read_file(backup_file_name) + neq(nil, backup_raw, "Expected backup file " .. backup_file_name .. "to exist but did not") + eq(initial_content, trim(backup_raw), 'Expected backup to contain original contents') + end) + + + it('backup symlinked files in first available backupdir #11349', function() + skip(is_ci('cirrus')) + clear() + + local initial_content = 'foo' + local backup_dir = 'Xtest_backupdir' + local sep = helpers.get_pathsep() + local link_file_name = 'Xtest_startup_file2' + local backup_file_name = backup_dir .. sep .. link_file_name .. '~' + + write_file('Xtest_startup_file1', initial_content, false) + lfs.link('Xtest_startup_file1', link_file_name, true) + mkdir(backup_dir) + command('set backup') + command('set backupcopy=yes') + command('set backupdir=.__this_does_not_exist__,' .. backup_dir) + command('edit ' .. link_file_name) + feed('Abar<esc>') + command('write') + + local backup_raw = read_file(backup_file_name) + neq(nil, backup_raw, "Expected backup file " .. backup_file_name .. " to exist but did not") + eq(initial_content, trim(backup_raw), 'Expected backup to contain original contents') + end) + it('readfile() on multibyte filename #10586', function() clear() local text = { @@ -144,6 +201,61 @@ describe('fileio', function() command('edit ++enc=utf32 Xtest-u8-int-max') assert_alive() end) + + it(':w! does not show "file has been changed" warning', function() + clear() + write_file("Xtest-overwrite-forced", 'foobar') + command('set nofixendofline') + local screen = Screen.new(40,4) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [3] = {bold = true, foreground = Screen.colors.SeaGreen4} + }) + screen:attach() + command("set shortmess-=F") + + command("e Xtest-overwrite-forced") + screen:expect([[ + ^foobar | + {1:~ }| + {1:~ }| + "Xtest-overwrite-forced" [noeol] 1L, 6B | + ]]) + + -- Get current unix time. + local cur_unix_time = os.time(os.date("!*t")) + local future_time = cur_unix_time + 999999 + -- Set the file's access/update time to be + -- greater than the time at which it was created. + local uv = require("luv") + uv.fs_utime('Xtest-overwrite-forced', future_time, future_time) + -- use async feed_command because nvim basically hangs on the prompt + feed_command("w") + screen:expect([[ + {2:WARNING: The file has been changed since}| + {2: reading it!!!} | + {3:Do you really want to write to it (y/n)^?}| + | + ]]) + + feed("n") + feed("<cr>") + screen:expect([[ + ^foobar | + {1:~ }| + {1:~ }| + | + ]]) + -- Use a screen test because the warning does not set v:errmsg. + command("w!") + screen:expect([[ + ^foobar | + {1:~ }| + {1:~ }| + <erwrite-forced" [noeol] 1L, 6B written | + ]]) + end) end) describe('tmpdir', function() @@ -159,7 +271,7 @@ describe('tmpdir', function() end) after_each(function() - expect_exit(command, ':qall!') + check_close() os.remove(testlog) end) @@ -183,14 +295,10 @@ describe('tmpdir', function() clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=faketmp, } }) matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir(). -- Assert that broken tmpdir root was handled. - retry(nil, 1000, function() - assert_log('tempdir root not a directory', testlog, 100) - end) + assert_log('tempdir root not a directory', testlog, 100) -- "…/nvim.<user>/" has wrong permissions: - if iswin() then - return -- TODO(justinmk): need setfperm/getfperm on Windows. #8244 - end + skip(is_os('win'), 'TODO(justinmk): need setfperm/getfperm on Windows. #8244') os.remove(testlog) os.remove(tmproot) mkdir(tmproot) @@ -198,9 +306,7 @@ describe('tmpdir', function() clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=faketmp, } }) matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir(). -- Assert that broken tmpdir root was handled. - retry(nil, 1000, function() - assert_log('tempdir root has invalid permissions', testlog, 100) - end) + assert_log('tempdir root has invalid permissions', testlog, 100) end) it('too long', function() diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 02ff18bdda..1bae626b98 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -13,7 +13,6 @@ local retry = helpers.retry local meths = helpers.meths local NIL = helpers.NIL local poke_eventloop = helpers.poke_eventloop -local iswin = helpers.iswin local get_pathsep = helpers.get_pathsep local pathroot = helpers.pathroot local exec_lua = helpers.exec_lua @@ -23,6 +22,8 @@ local expect_msg_seq = helpers.expect_msg_seq local pcall_err = helpers.pcall_err local matches = helpers.matches local Screen = require('test.functional.ui.screen') +local skip = helpers.skip +local is_os = helpers.is_os describe('jobs', function() local channel @@ -55,7 +56,7 @@ describe('jobs', function() it('must specify env option as a dict', function() command("let g:job_opts.env = v:true") local _, err = pcall(function() - if iswin() then + if is_os('win') then nvim('command', "let j = jobstart('set', g:job_opts)") else nvim('command', "let j = jobstart('env', g:job_opts)") @@ -68,7 +69,7 @@ describe('jobs', function() nvim('command', "let $VAR = 'abc'") nvim('command', "let $TOTO = 'goodbye world'") nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") - if iswin() then + if is_os('win') then nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]]) else nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]]) @@ -87,12 +88,12 @@ describe('jobs', function() end) it('append environment with pty #env', function() - if helpers.pending_win32(pending) then return end + skip(is_os('win')) nvim('command', "let $VAR = 'abc'") nvim('command', "let $TOTO = 'goodbye world'") nvim('command', "let g:job_opts.pty = v:true") nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") - if iswin() then + if is_os('win') then nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]]) else nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]]) @@ -122,7 +123,7 @@ describe('jobs', function() -- -- Rather than expecting a completely empty environment, ensure that $VAR -- is *not* in the environment but $TOTO is. - if iswin() then + if is_os('win') then nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]]) expect_msg_seq({ {'notification', 'stdout', {0, {'hello world %VAR%', ''}}} @@ -141,7 +142,7 @@ describe('jobs', function() -- Since $Toto is being set in the job, it should take precedence over the -- global $TOTO on Windows nvim('command', "let g:job_opts = {'env': {'Toto': 'def'}, 'stdout_buffered': v:true}") - if iswin() then + if is_os('win') then nvim('command', [[let j = jobstart('set | find /I "toto="', g:job_opts)]]) else nvim('command', [[let j = jobstart('env | grep -i toto=', g:job_opts)]]) @@ -150,7 +151,7 @@ describe('jobs', function() nvim('command', "let g:output = Normalize(g:job_opts.stdout)") local actual = eval('g:output') local expected - if iswin() then + if is_os('win') then -- Toto is normalized to TOTO so we can detect duplicates, and because -- Windows doesn't care about case expected = {'TOTO=def', ''} @@ -164,7 +165,7 @@ describe('jobs', function() it('uses &shell and &shellcmdflag if passed a string', function() nvim('command', "let $VAR = 'abc'") - if iswin() then + if is_os('win') then nvim('command', "let j = jobstart('echo %VAR%', g:job_opts)") else nvim('command', "let j = jobstart('echo $VAR', g:job_opts)") @@ -176,7 +177,7 @@ describe('jobs', function() it('changes to given / directory', function() nvim('command', "let g:job_opts.cwd = '/'") - if iswin() then + if is_os('win') then nvim('command', "let j = jobstart('cd', g:job_opts)") else nvim('command', "let j = jobstart('pwd', g:job_opts)") @@ -191,7 +192,7 @@ describe('jobs', function() local dir = eval("resolve(tempname())"):gsub("/", get_pathsep()) mkdir(dir) nvim('command', "let g:job_opts.cwd = '" .. dir .. "'") - if iswin() then + if is_os('win') then nvim('command', "let j = jobstart('cd', g:job_opts)") else nvim('command', "let j = jobstart('pwd', g:job_opts)") @@ -215,7 +216,7 @@ describe('jobs', function() local dir = eval('resolve(tempname())."-bogus"') local _, err = pcall(function() nvim('command', "let g:job_opts.cwd = '" .. dir .. "'") - if iswin() then + if is_os('win') then nvim('command', "let j = jobstart('cd', g:job_opts)") else nvim('command', "let j = jobstart('pwd', g:job_opts)") @@ -225,7 +226,7 @@ describe('jobs', function() end) it('error on non-executable `cwd`', function() - if iswin() then return end -- N/A for Windows + skip(is_os('win'), 'Not applicable for Windows') local dir = 'Xtest_not_executable_dir' mkdir(dir) @@ -248,7 +249,7 @@ describe('jobs', function() end local executable_jobid = new_job() - local exe = iswin() and './test/functional/fixtures' or './test/functional/fixtures/non_executable.txt' + local exe = is_os('win') and './test/functional/fixtures' or './test/functional/fixtures/non_executable.txt' eq("Vim:E475: Invalid value for argument cmd: '"..exe.."' is not executable", pcall_err(eval, "jobstart(['"..exe.."'])")) eq("", eval("v:errmsg")) @@ -702,7 +703,7 @@ describe('jobs', function() describe('jobwait', function() before_each(function() - if iswin() then + if is_os('win') then helpers.set_shell_powershell() end end) @@ -786,7 +787,7 @@ describe('jobs', function() feed_command('call rpcnotify(g:channel, "ready") | '.. 'call rpcnotify(g:channel, "wait", '.. 'jobwait([jobstart("'.. - (iswin() and 'Start-Sleep 10' or 'sleep 10').. + (is_os('win') and 'Start-Sleep 10' or 'sleep 10').. '; exit 55")]))') eq({'notification', 'ready', {}}, next_msg()) feed('<c-c>') @@ -797,7 +798,7 @@ describe('jobs', function() feed_command('call rpcnotify(g:channel, "ready") | '.. 'call rpcnotify(g:channel, "wait", '.. 'jobwait([jobstart("'.. - (iswin() and 'Start-Sleep 10' or 'sleep 10').. + (is_os('win') and 'Start-Sleep 10' or 'sleep 10').. '; exit 55")], 10000))') eq({'notification', 'ready', {}}, next_msg()) feed('<c-c>') @@ -805,7 +806,7 @@ describe('jobs', function() end) it('can be called recursively', function() - if helpers.pending_win32(pending) then return end -- TODO: Need `cat`. + skip(is_os('win'), "TODO: Need `cat`") source([[ let g:opts = {} let g:counter = 0 @@ -930,7 +931,7 @@ describe('jobs', function() -- ..c.."', '-c', '"..c.."'])") -- Create child with several descendants. - if iswin() then + if is_os('win') then source([[ function! s:formatprocs(pid, prefix) let result = '' @@ -979,13 +980,13 @@ describe('jobs', function() endfunction ]]) end - local sleep_cmd = (iswin() + local sleep_cmd = (is_os('win') and 'ping -n 31 127.0.0.1' or 'sleep 30') local j = eval("jobstart('"..sleep_cmd..' | '..sleep_cmd..' | '..sleep_cmd.."')") local ppid = funcs.jobpid(j) local children - if iswin() then + if is_os('win') then local status, result = pcall(retry, nil, nil, function() children = meths.get_proc_children(ppid) -- On Windows conhost.exe may exist, and @@ -1006,7 +1007,7 @@ describe('jobs', function() -- Assert that nvim_get_proc() sees the children. for _, child_pid in ipairs(children) do local info = meths.get_proc(child_pid) - -- eq((iswin() and 'nvim.exe' or 'nvim'), info.name) + -- eq((is_os('win') and 'nvim.exe' or 'nvim'), info.name) eq(ppid, info.ppid) end -- Kill the root of the tree. @@ -1027,7 +1028,7 @@ describe('jobs', function() end) describe('running tty-test program', function() - if helpers.pending_win32(pending) then return end + if skip(is_os('win')) then return end local function next_chunk() local rv while true do @@ -1124,7 +1125,7 @@ describe("pty process teardown", function() end) it("does not prevent/delay exit. #4798 #4900", function() - if helpers.pending_win32(pending) then return end + skip(is_os('win')) -- Use a nested nvim (in :term) to test without --headless. feed_command(":terminal '"..helpers.nvim_prog .."' -u NONE -i NONE --cmd '"..nvim_set.."' " diff --git a/test/functional/core/log_spec.lua b/test/functional/core/log_spec.lua index 3b1ccd9559..f682df4155 100644 --- a/test/functional/core/log_spec.lua +++ b/test/functional/core/log_spec.lua @@ -6,7 +6,6 @@ local eq = helpers.eq local exec_lua = helpers.exec_lua local expect_exit = helpers.expect_exit local request = helpers.request -local retry = helpers.retry describe('log', function() local testlog = 'Xtest_logging' @@ -40,9 +39,7 @@ describe('log', function() }}) local tid = _G._nvim_test_id - retry(nil, 1000, function() - assert_log(tid..'%.%d+%.%d +server_init:%d+: test log message', testlog, 100) - end) + assert_log(tid..'%.%d+%.%d +server_init:%d+: test log message', testlog, 100) exec_lua([[ local j1 = vim.fn.jobstart({ vim.v.progpath, '-es', '-V1', '+foochild', '+qa!' }, vim.empty_dict()) @@ -50,8 +47,6 @@ describe('log', function() ]]) -- Child Nvim spawned by jobstart() appends "/c" to parent name. - retry(nil, 1000, function() - assert_log('%.%d+%.%d/c +server_init:%d+: test log message', testlog, 100) - end) + assert_log('%.%d+%.%d/c +server_init:%d+: test log message', testlog, 100) end) end) diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua index f6fb859ccc..ab11e14a67 100644 --- a/test/functional/core/main_spec.lua +++ b/test/functional/core/main_spec.lua @@ -9,6 +9,8 @@ local clear = helpers.clear local funcs = helpers.funcs local nvim_prog_abs = helpers.nvim_prog_abs local write_file = helpers.write_file +local is_os = helpers.is_os +local skip = helpers.skip describe('Command-line option', function() describe('-s', function() @@ -49,12 +51,12 @@ describe('Command-line option', function() eq(#('100500\n'), attrs.size) end) it('does not crash after reading from stdin in non-headless mode', function() - if helpers.pending_win32(pending) then return end + skip(is_os('win')) local screen = Screen.new(40, 8) screen:attach() local args = { nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', - '--cmd', 'set noswapfile shortmess+=IFW fileformats=unix', + '--cmd', '"set noswapfile shortmess+=IFW fileformats=unix"', '-s', '-' } diff --git a/test/functional/core/path_spec.lua b/test/functional/core/path_spec.lua index 669bc99136..a786887bbd 100644 --- a/test/functional/core/path_spec.lua +++ b/test/functional/core/path_spec.lua @@ -3,14 +3,16 @@ local clear = helpers.clear local eq = helpers.eq local eval = helpers.eval local command = helpers.command -local iswin = helpers.iswin +local insert = helpers.insert +local feed = helpers.feed +local is_os = helpers.is_os describe('path collapse', function() local targetdir local expected_path local function join_path(...) - local pathsep = (iswin() and '\\' or '/') + local pathsep = (is_os('win') and '\\' or '/') return table.concat({...}, pathsep) end @@ -54,3 +56,15 @@ describe('path collapse', function() eq(expected_path, eval('expand("%:p")')) end) end) + +describe('file search', function() + before_each(clear) + + it('find multibyte file name in line #20517', function() + command('cd test/functional/fixtures') + insert('filename_with_unicode_ααα') + eq('', eval('expand("%")')) + feed('gf') + eq('filename_with_unicode_ααα', eval('expand("%:t")')) + end) +end) diff --git a/test/functional/core/remote_spec.lua b/test/functional/core/remote_spec.lua index d7bd075eb2..846d79abf3 100644 --- a/test/functional/core/remote_spec.lua +++ b/test/functional/core/remote_spec.lua @@ -3,6 +3,7 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local command = helpers.command local eq = helpers.eq +local exec_lua = helpers.exec_lua local expect = helpers.expect local funcs = helpers.funcs local insert = helpers.insert @@ -48,8 +49,8 @@ describe('Remote', function() -- our incoming --remote calls. local client_starter = spawn(new_argv(), false, nil, true) set_session(client_starter) - local client_job_id = funcs.jobstart(client_argv) - eq({ 0 }, funcs.jobwait({client_job_id})) + -- Call jobstart() and jobwait() in the same RPC request to reduce flakiness. + eq({ 0 }, exec_lua([[return vim.fn.jobwait({ vim.fn.jobstart(...) })]], client_argv)) client_starter:close() set_session(server) end @@ -121,8 +122,8 @@ describe('Remote', function() -- the event loop. If the server event loop is blocked, it can't process -- our incoming --remote calls. clear() - local bogus_job_id = funcs.jobstart(bogus_argv) - eq({2}, funcs.jobwait({bogus_job_id})) + -- 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)) 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 4f9df4010e..1be5de6488 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -12,6 +12,7 @@ local eval = helpers.eval local exec_lua = helpers.exec_lua local feed = helpers.feed local funcs = helpers.funcs +local pesc = helpers.pesc local mkdir = helpers.mkdir local mkdir_p = helpers.mkdir_p local nvim_prog = helpers.nvim_prog @@ -20,11 +21,12 @@ local read_file = helpers.read_file local retry = helpers.retry local rmdir = helpers.rmdir local sleep = helpers.sleep -local iswin = helpers.iswin local startswith = helpers.startswith local write_file = helpers.write_file local meths = helpers.meths local alter_slashes = helpers.alter_slashes +local is_os = helpers.is_os +local dedent = helpers.dedent local testfile = 'Xtest_startuptime' after_each(function() @@ -41,10 +43,36 @@ describe('startup', function() it('--startuptime', function() clear({ args = {'--startuptime', testfile}}) - retry(nil, 1000, function() - assert_log('sourcing', testfile, 100) - assert_log("require%('vim%._editor'%)", testfile, 100) - end) + assert_log('sourcing', testfile, 100) + assert_log("require%('vim%._editor'%)", testfile, 100) + end) + + it('-D does not hang #12647', function() + clear() + local screen + screen = Screen.new(60, 7) + screen:attach() + command([[let g:id = termopen('"]]..nvim_prog.. + [[" -u NONE -i NONE --cmd "set noruler" -D')]]) + screen:expect([[ + ^ | + | + Entering Debug mode. Type "cont" to continue. | + nvim_exec() | + cmd: aunmenu * | + > | + | + ]]) + command([[call chansend(g:id, "cont\n")]]) + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + [No Name] | + | + | + ]]) end) end) @@ -57,6 +85,124 @@ describe('startup', function() os.remove('Xtest_startup_ttyout') end) + describe('-l Lua', function() + local function assert_l_out(expected, nvim_args, lua_args, script, input) + local args = { nvim_prog } + vim.list_extend(args, nvim_args or {}) + vim.list_extend(args, { '-l', (script or 'test/functional/fixtures/startup.lua') }) + vim.list_extend(args, lua_args or {}) + local out = funcs.system(args, input):gsub('\r\n', '\n') + return eq(dedent(expected), out) + end + + it('failure modes', function() + -- nvim -l <empty> + matches('nvim%.?e?x?e?: Argument missing after: "%-l"', funcs.system({ nvim_prog, '-l' })) + eq(1, eval('v:shell_error')) + end) + + it('os.exit() sets Nvim exitcode', function() + -- nvim -l foo.lua -arg1 -- a b c + assert_l_out([[ + bufs: + nvim args: 7 + lua args: { "-arg1", "--exitcode", "73", "--arg2", + [0] = "test/functional/fixtures/startup.lua" + }]], + {}, + { '-arg1', "--exitcode", "73", '--arg2' } + ) + eq(73, eval('v:shell_error')) + end) + + it('Lua-error sets Nvim exitcode', function() + eq(0, eval('v:shell_error')) + matches('E5113: .* my pearls!!', + funcs.system({ nvim_prog, '-l', 'test/functional/fixtures/startup-fail.lua' })) + eq(1, eval('v:shell_error')) + matches('E5113: .* %[string "error%("whoa"%)"%]:1: whoa', + funcs.system({ nvim_prog, '-l', '-' }, 'error("whoa")')) + eq(1, eval('v:shell_error')) + end) + + it('executes stdin "-"', function() + assert_l_out('arg0=- args=2 whoa', + nil, + { 'arg1', 'arg 2' }, + '-', + "print(('arg0=%s args=%d %s'):format(_G.arg[0], #_G.arg, 'whoa'))") + assert_l_out('biiig input: 1000042', + nil, + nil, + '-', + ('print("biiig input: "..("%s"):len())'):format(string.rep('x', (1000 * 1000) + 42))) + eq(0, eval('v:shell_error')) + end) + + it('sets _G.arg', function() + -- nvim -l foo.lua [args] + assert_l_out([[ + bufs: + nvim args: 7 + lua args: { "-arg1", "--arg2", "--", "arg3", + [0] = "test/functional/fixtures/startup.lua" + }]], + {}, + { '-arg1', '--arg2', '--', 'arg3' } + ) + eq(0, eval('v:shell_error')) + + -- nvim file1 file2 -l foo.lua -arg1 -- file3 file4 + assert_l_out([[ + bufs: file1 file2 + nvim args: 10 + lua args: { "-arg1", "arg 2", "--", "file3", "file4", + [0] = "test/functional/fixtures/startup.lua" + }]], + { 'file1', 'file2', }, + { '-arg1', 'arg 2', '--', 'file3', 'file4' } + ) + eq(0, eval('v:shell_error')) + + -- nvim -l foo.lua <vim args> + assert_l_out([[ + bufs: + nvim args: 5 + lua args: { "-c", "set wrap?", + [0] = "test/functional/fixtures/startup.lua" + }]], + {}, + { '-c', 'set wrap?' } + ) + eq(0, eval('v:shell_error')) + + -- nvim <vim args> -l foo.lua <vim args> + assert_l_out( + -- luacheck: ignore 611 (Line contains only whitespaces) + [[ + wrap + + bufs: + nvim args: 7 + lua args: { "-c", "set wrap?", + [0] = "test/functional/fixtures/startup.lua" + }]], + { '-c', 'set wrap?' }, + { '-c', 'set wrap?' } + ) + eq(0, eval('v:shell_error')) + end) + + it('disables swapfile/shada/config/plugins', function() + assert_l_out('updatecount=0 shadafile=NONE loadplugins=false scriptnames=1', + nil, + nil, + '-', + [[print(('updatecount=%d shadafile=%s loadplugins=%s scriptnames=%d'):format( + vim.o.updatecount, vim.o.shadafile, tostring(vim.o.loadplugins), math.max(1, #vim.fn.split(vim.fn.execute('scriptnames'),'\n'))))]]) + end) + end) + it('pipe at both ends: has("ttyin")==0 has("ttyout")==0', function() -- system() puts a pipe at both ends. local out = funcs.system({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', @@ -65,6 +211,7 @@ describe('startup', function() '+q' }) eq('0 0', out) end) + it('with --embed: has("ttyin")==0 has("ttyout")==0', function() local screen = Screen.new(25, 3) -- Remote UI connected by --embed. @@ -76,10 +223,11 @@ describe('startup', function() 0 0 | ]]) end) + it('in a TTY: has("ttyin")==1 has("ttyout")==1', function() local screen = Screen.new(25, 4) screen:attach() - if iswin() then + if is_os('win') then command([[set shellcmdflag=/s\ /c shellxquote=\"]]) end -- Running in :terminal @@ -94,8 +242,9 @@ describe('startup', function() | ]]) end) + it('output to pipe: has("ttyin")==1 has("ttyout")==0', function() - if iswin() then + if is_os('win') then command([[set shellcmdflag=/s\ /c shellxquote=\"]]) end -- Running in :terminal @@ -110,8 +259,9 @@ describe('startup', function() read_file('Xtest_startup_ttyout')) end) end) + it('input from pipe: has("ttyin")==0 has("ttyout")==1', function() - if iswin() then + if is_os('win') then command([[set shellcmdflag=/s\ /c shellxquote=\"]]) end -- Running in :terminal @@ -127,10 +277,11 @@ describe('startup', function() read_file('Xtest_startup_ttyout')) end) end) + it('input from pipe (implicit) #7679', function() local screen = Screen.new(25, 4) screen:attach() - if iswin() then + if is_os('win') then command([[set shellcmdflag=/s\ /c shellxquote=\"]]) end -- Running in :terminal @@ -146,6 +297,7 @@ describe('startup', function() | ]]) end) + it('input from pipe + file args #7679', function() eq('ohyeah\r\n0 0 bufs=3', funcs.system({nvim_prog, '-n', '-u', 'NONE', '-i', 'NONE', '--headless', @@ -237,11 +389,11 @@ describe('startup', function() it('-es/-Es disables swapfile, user config #8540', function() for _,arg in ipairs({'-es', '-Es'}) do local out = funcs.system({nvim_prog, arg, - '+set swapfile? updatecount? shada?', + '+set swapfile? updatecount? shadafile?', "+put =execute('scriptnames')", '+%print'}) local line1 = string.match(out, '^.-\n') -- updatecount=0 means swapfile was disabled. - eq(" swapfile updatecount=0 shada=!,'100,<50,s10,h\n", line1) + eq(" swapfile updatecount=0 shadafile=\n", line1) -- Standard plugins were loaded, but not user config. eq('health.vim', string.match(out, 'health.vim')) eq(nil, string.match(out, 'init.vim')) @@ -265,11 +417,13 @@ describe('startup', function() { 'put =mode(1)', 'print', '' })) end) - it('fails on --embed with -es/-Es', function() - matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es', + it('fails on --embed with -es/-Es/-l', function() + matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l', funcs.system({nvim_prog, '--embed', '-es' })) - matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es', + matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l', funcs.system({nvim_prog, '--embed', '-Es' })) + matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l', + funcs.system({nvim_prog, '--embed', '-l', 'foo.lua' })) end) it('does not crash if --embed is given twice', function() @@ -354,7 +508,9 @@ describe('startup', function() local function pack_clear(cmd) -- add packages after config dir in rtp but before config/after - clear{args={'--cmd', 'set packpath=test/functional/fixtures', '--cmd', 'let paths=split(&rtp, ",")', '--cmd', 'let &rtp = paths[0]..",test/functional/fixtures,test/functional/fixtures/middle,"..join(paths[1:],",")', '--cmd', cmd}, env={XDG_CONFIG_HOME='test/functional/fixtures/'}} + clear{args={'--cmd', 'set packpath=test/functional/fixtures', '--cmd', 'let paths=split(&rtp, ",")', '--cmd', 'let &rtp = paths[0]..",test/functional/fixtures,test/functional/fixtures/middle,"..join(paths[1:],",")', '--cmd', cmd}, env={XDG_CONFIG_HOME='test/functional/fixtures/'}, + args_rm={'runtimepath'}, + } end @@ -462,6 +618,19 @@ describe('startup', function() clear{args={'--cmd', 'set packpath^=test/functional/fixtures', '--cmd', [[ lua _G.test_loadorder = {} vim.cmd "runtime! filen.lua" ]]}, env={XDG_CONFIG_HOME='test/functional/fixtures/'}} eq({'ordinary', 'FANCY', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]]) end) + + it('window widths are correct when modelines set &columns with tabpages', function() + write_file('tab1.noft', 'vim: columns=81') + write_file('tab2.noft', 'vim: columns=81') + finally(function() + os.remove('tab1.noft') + os.remove('tab2.noft') + end) + clear({args = {'-p', 'tab1.noft', 'tab2.noft'}}) + eq(81, meths.win_get_width(0)) + command('tabnext') + eq(81, meths.win_get_width(0)) + end) end) describe('sysinit', function() @@ -516,32 +685,6 @@ describe('sysinit', function() eval('printf("loaded %d xdg %d vim %d", g:loaded, get(g:, "xdg", 0), get(g:, "vim", 0))')) end) - it('fixed hang issue with -D (#12647)', function() - local screen - screen = Screen.new(60, 7) - screen:attach() - command([[let g:id = termopen('"]]..nvim_prog.. - [[" -u NONE -i NONE --cmd "set noruler" -D')]]) - screen:expect([[ - ^ | - Entering Debug mode. Type "cont" to continue. | - nvim_exec() | - cmd: aunmenu * | - > | - <" -u NONE -i NONE --cmd "set noruler" -D 1,1 All| - | - ]]) - command([[call chansend(g:id, "cont\n")]]) - screen:expect([[ - ^ | - ~ | - ~ | - [No Name] | - | - <" -u NONE -i NONE --cmd "set noruler" -D 1,0-1 All| - | - ]]) - end) end) describe('user config init', function() @@ -574,7 +717,81 @@ describe('user config init', function() eq(funcs.fnamemodify(init_lua_path, ':p'), eval('$MYVIMRC')) end) - describe 'with explicitly provided config'(function() + describe('with existing .exrc in cwd', function() + local exrc_path = '.exrc' + local xstate = 'Xstate' + + local function setup_exrc_file(filename) + exrc_path = filename + + if string.find(exrc_path, "%.lua$") then + write_file(exrc_path, string.format([[ + vim.g.exrc_file = "%s" + ]], exrc_path)) + else + write_file(exrc_path, string.format([[ + let g:exrc_file = "%s" + ]], exrc_path)) + end + end + + before_each(function() + write_file(init_lua_path, [[ + vim.o.exrc = true + vim.g.exrc_file = '---' + ]]) + mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim')) + end) + + after_each(function() + os.remove(exrc_path) + rmdir(xstate) + end) + + for _, filename in ipairs({ '.exrc', '.nvimrc', '.nvim.lua' }) do + it('loads ' .. filename, function () + setup_exrc_file(filename) + + clear{ args_rm = {'-u'}, env={ XDG_CONFIG_HOME=xconfig, XDG_STATE_HOME=xstate } } + -- The 'exrc' file is not trusted, and the prompt is skipped because there is no UI. + eq('---', eval('g:exrc_file')) + + local screen = Screen.new(50, 8) + screen:attach() + funcs.termopen({nvim_prog}) + screen:expect({ any = pesc('[i]gnore, (v)iew, (d)eny, (a)llow:') }) + -- `i` to enter Terminal mode, `a` to allow + feed('ia') + screen:expect([[ + | + ~ | + ~ | + ~ | + ~ | + [No Name] 0,0-1 All| + | + -- TERMINAL -- | + ]]) + feed(':echo g:exrc_file<CR>') + screen:expect(string.format([[ + | + ~ | + ~ | + ~ | + ~ | + [No Name] 0,0-1 All| + %s%s| + -- TERMINAL -- | + ]], filename, string.rep(' ', 50 - #filename))) + + clear{ args_rm = {'-u'}, env={ XDG_CONFIG_HOME=xconfig, XDG_STATE_HOME=xstate } } + -- The 'exrc' file is now trusted. + eq(filename, eval('g:exrc_file')) + end) + end + end) + + describe('with explicitly provided config', function() local custom_lua_path = table.concat({xhome, 'custom.lua'}, pathsep) before_each(function() write_file(custom_lua_path, [[ @@ -589,7 +806,7 @@ describe('user config init', function() end) end) - describe 'VIMRC also exists'(function() + describe('VIMRC also exists', function() before_each(function() write_file(table.concat({xconfig, 'nvim', 'init.vim'}, pathsep), [[ let g:vim_rc = 1 @@ -635,7 +852,7 @@ describe('runtime:', function() end) it('loads plugin/*.lua from start packages', function() - local plugin_path = table.concat({xconfig, 'nvim', 'pack', 'catagory', + local plugin_path = table.concat({xconfig, 'nvim', 'pack', 'category', 'start', 'test_plugin'}, pathsep) local plugin_folder_path = table.concat({plugin_path, 'plugin'}, pathsep) local plugin_file_path = table.concat({plugin_folder_path, 'plugin.lua'}, @@ -663,7 +880,7 @@ describe('runtime:', function() end) it('loads plugin/*.lua from site packages', function() - local nvimdata = iswin() and "nvim-data" or "nvim" + local nvimdata = is_os('win') and "nvim-data" or "nvim" local plugin_path = table.concat({xdata, nvimdata, 'site', 'pack', 'xa', 'start', 'yb'}, pathsep) local plugin_folder_path = table.concat({plugin_path, 'plugin'}, pathsep) local plugin_after_path = table.concat({plugin_path, 'after', 'plugin'}, pathsep) |