diff options
Diffstat (limited to 'test/functional/core/fileio_spec.lua')
-rw-r--r-- | test/functional/core/fileio_spec.lua | 258 |
1 files changed, 149 insertions, 109 deletions
diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index 65f947132e..928cab525c 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -1,4 +1,4 @@ -local luv = require('luv') +local uv = vim.uv local helpers = require('test.functional.helpers')(after_each) local assert_log = helpers.assert_log @@ -9,18 +9,18 @@ local eq = helpers.eq local neq = helpers.neq local ok = helpers.ok local feed = helpers.feed -local funcs = helpers.funcs +local fn = helpers.fn local nvim_prog = helpers.nvim_prog local request = helpers.request local retry = helpers.retry local rmdir = helpers.rmdir local matches = helpers.matches -local meths = helpers.meths +local api = helpers.api local mkdir = helpers.mkdir -local sleep = helpers.sleep +local sleep = vim.uv.sleep local read_file = helpers.read_file -local trim = helpers.trim -local currentdir = helpers.funcs.getcwd +local trim = vim.trim +local currentdir = helpers.fn.getcwd local assert_alive = helpers.assert_alive local check_close = helpers.check_close local expect_exit = helpers.expect_exit @@ -30,10 +30,11 @@ local feed_command = helpers.feed_command local skip = helpers.skip local is_os = helpers.is_os local is_ci = helpers.is_ci +local spawn = helpers.spawn +local set_session = helpers.set_session describe('fileio', function() - before_each(function() - end) + before_each(function() end) after_each(function() check_close() os.remove('Xtest_startup_shada') @@ -49,54 +50,91 @@ describe('fileio', function() rmdir('Xtest_backupdir with spaces') end) - it('fsync() codepaths #8304', function() - clear({ args={ '-i', 'Xtest_startup_shada', - '--cmd', 'set nofsync', - '--cmd', 'set directory=Xtest_startup_swapdir' } }) + local args = { nvim_prog, '--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.tbl_flatten({ args, '--embed', extra_args }) + local screen_nvim = spawn(argv) + set_session(screen_nvim) + local screen = Screen.new(70, 10) + screen:attach() + screen:set_default_attr_ids({ + [1] = { foreground = Screen.colors.NvimDarkGrey4 }, + [2] = { background = Screen.colors.NvimDarkGrey1, foreground = Screen.colors.NvimLightGrey3 }, + [3] = { foreground = Screen.colors.NvimLightCyan }, + }) + return screen + end + + it("fsync() with 'nofsync' #8304", function() + clear({ args = { '--cmd', 'set nofsync directory=Xtest_startup_swapdir' } }) -- These cases ALWAYS force fsync (regardless of 'fsync' option): -- 1. Idle (CursorHold) with modified buffers (+ 'swapfile'). command('write Xtest_startup_file1') - feed('ifoo<esc>h') + feed('Afoo<esc>h') command('write') - eq(0, request('nvim__stats').fsync) -- 'nofsync' is the default. + eq(0, request('nvim__stats').fsync) command('set swapfile') command('set updatetime=1') - feed('izub<esc>h') -- File is 'modified'. - sleep(3) -- Allow 'updatetime' to expire. + feed('Azub<esc>h') -- File is 'modified'. + sleep(3) -- Allow 'updatetime' to expire. retry(3, nil, function() eq(1, request('nvim__stats').fsync) end) - command('set updatetime=9999') + command('set updatetime=100000 updatecount=100000') - -- 2. Exit caused by deadly signal (+ 'swapfile'). - local j = funcs.jobstart({ nvim_prog, '-u', 'NONE', '-i', - 'Xtest_startup_shada', '--headless', - '-c', 'set swapfile', - '-c', 'write Xtest_startup_file2', - '-c', 'put =localtime()', }) - sleep(10) -- Let Nvim start. - funcs.jobstop(j) -- Send deadly signal. - - -- 3. SIGPWR signal. - -- ?? - - -- 4. Explicit :preserve command. + -- 2. Explicit :preserve command. command('preserve') - eq(2, request('nvim__stats').fsync) + -- TODO: should be exactly 2; where is the extra fsync() is coming from? #26404 + ok(request('nvim__stats').fsync == 2 or request('nvim__stats').fsync == 3) - -- 5. Enable 'fsync' option, write file. + -- 3. Enable 'fsync' option, write file. command('set fsync') - feed('ibaz<esc>h') + feed('Abaz<esc>h') command('write') - eq(4, request('nvim__stats').fsync) + -- TODO: should be exactly 4; where is the extra fsync() is coming from? #26404 + ok(request('nvim__stats').fsync == 4 or request('nvim__stats').fsync == 5) + eq('foozubbaz', trim(read_file('Xtest_startup_file1'))) + + -- 4. Exit caused by deadly signal (+ 'swapfile'). + local j = fn.jobstart(vim.tbl_flatten({ args, '--embed' }), { rpc = true }) + fn.rpcrequest( + j, + 'nvim_exec2', + [[ + set nofsync directory=Xtest_startup_swapdir + edit Xtest_startup_file2 + write + put ='fsyncd text' + ]], + {} + ) + eq('Xtest_startup_swapdir', fn.rpcrequest(j, 'nvim_eval', '&directory')) + fn.jobstop(j) -- Send deadly signal. + + local screen = startup() + feed(':recover Xtest_startup_file2<cr>') + screen:expect({ any = [[Using swap file "Xtest_startup_swapdir[/\]Xtest_startup_file2%.swp"]] }) + feed('<cr>') + screen:expect({ any = 'fsyncd text' }) + + -- 5. SIGPWR signal. + -- oldtest: Test_signal_PWR() end) it('backup #9709', function() skip(is_ci('cirrus')) - clear({ args={ '-i', 'Xtest_startup_shada', - '--cmd', 'set directory=Xtest_startup_swapdir' } }) + clear({ + args = { + '-i', + 'Xtest_startup_shada', + '--cmd', + 'set directory=Xtest_startup_swapdir', + }, + }) command('write Xtest_startup_file1') feed('ifoo<esc>') @@ -109,8 +147,8 @@ describe('fileio', function() local foobar_contents = trim(read_file('Xtest_startup_file1')) local bar_contents = trim(read_file('Xtest_startup_file1~')) - eq('foobar', foobar_contents); - eq('foo', bar_contents); + eq('foobar', foobar_contents) + eq('foo', bar_contents) end) it('backup with full path #11214', function() @@ -126,13 +164,16 @@ describe('fileio', function() command('write') -- Backup filename = fullpath, separators replaced with "%". - local backup_file_name = string.gsub(currentdir()..'/Xtest_startup_file1', - is_os('win') and '[:/\\]' or '/', '%%') .. '~' - local foo_contents = trim(read_file('Xtest_backupdir/'..backup_file_name)) + local backup_file_name = string.gsub( + currentdir() .. '/Xtest_startup_file1', + 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')) - eq('foobar', foobar_contents); - eq('foo', foo_contents); + eq('foobar', foobar_contents) + eq('foo', foo_contents) end) it('backup with full path with spaces', function() @@ -148,13 +189,16 @@ describe('fileio', function() command('write') -- Backup filename = fullpath, separators replaced with "%". - local backup_file_name = string.gsub(currentdir()..'/Xtest_startup_file1', - is_os('win') and '[:/\\]' or '/', '%%') .. '~' - local foo_contents = trim(read_file('Xtest_backupdir with spaces/'..backup_file_name)) + local backup_file_name = string.gsub( + currentdir() .. '/Xtest_startup_file1', + is_os('win') and '[:/\\]' or '/', + '%%' + ) .. '~' + local foo_contents = trim(read_file('Xtest_backupdir with spaces/' .. backup_file_name)) local foobar_contents = trim(read_file('Xtest_startup_file1')) - eq('foobar', foobar_contents); - eq('foo', foo_contents); + eq('foobar', foobar_contents) + eq('foo', foo_contents) end) it('backup symlinked files #11349', function() @@ -166,7 +210,7 @@ describe('fileio', function() local backup_file_name = link_file_name .. '~' write_file('Xtest_startup_file1', initial_content, false) - luv.fs_symlink('Xtest_startup_file1', link_file_name) + uv.fs_symlink('Xtest_startup_file1', link_file_name) command('set backup') command('set backupcopy=yes') command('edit ' .. link_file_name) @@ -174,11 +218,10 @@ describe('fileio', function() 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") + 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() @@ -190,7 +233,7 @@ describe('fileio', function() local backup_file_name = backup_dir .. sep .. link_file_name .. '~' write_file('Xtest_startup_file1', initial_content, false) - luv.fs_symlink('Xtest_startup_file1', link_file_name) + uv.fs_symlink('Xtest_startup_file1', link_file_name) mkdir(backup_dir) command('set backup') command('set backupcopy=yes') @@ -200,7 +243,7 @@ describe('fileio', function() 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") + 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) @@ -215,11 +258,11 @@ describe('fileio', function() '', } local fname = 'Xtest_тест.md' - funcs.writefile(text, fname, 's') + fn.writefile(text, fname, 's') table.insert(text, '') - eq(text, funcs.readfile(fname, 'b')) + eq(text, fn.readfile(fname, 'b')) end) - it('read invalid u8 over INT_MAX doesn\'t segfault', function() + it("read invalid u8 over INT_MAX doesn't segfault", function() clear() command('call writefile(0zFFFFFFFF, "Xtest-u8-int-max")') -- This should not segfault @@ -229,34 +272,32 @@ describe('fileio', function() it(':w! does not show "file has been changed" warning', function() clear() - write_file("Xtest-overwrite-forced", 'foobar') + write_file('Xtest-overwrite-forced', 'foobar') command('set nofixendofline') - local screen = Screen.new(40,4) + 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} + [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('set shortmess-=F') - command("e Xtest-overwrite-forced") + command('e Xtest-overwrite-forced') screen:expect([[ ^foobar | - {1:~ }| - {1:~ }| + {1:~ }|*2 "Xtest-overwrite-forced" [noeol] 1L, 6B | ]]) -- Get current unix time. - local cur_unix_time = os.time(os.date("!*t")) + 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") + feed_command('w') screen:expect([[ {2:WARNING: The file has been changed since}| {2: reading it!!!} | @@ -264,20 +305,18 @@ describe('fileio', function() ^ | ]]) - feed("n") - feed("<cr>") + feed('n') + feed('<cr>') screen:expect([[ ^foobar | - {1:~ }| - {1:~ }| + {1:~ }|*2 | ]]) -- Use a screen test because the warning does not set v:errmsg. - command("w!") + command('w!') screen:expect([[ ^foobar | - {1:~ }| - {1:~ }| + {1:~ }|*2 <erwrite-forced" [noeol] 1L, 6B written | ]]) end) @@ -302,13 +341,13 @@ describe('tmpdir', function() -- Tempfiles typically look like: "…/nvim.<user>/xxx/0". -- - "…/nvim.<user>/xxx/" is the per-process tmpdir, not shared with other Nvims. -- - "…/nvim.<user>/" is the tmpdir root, shared by all Nvims (normally). - local tmproot = (funcs.tempname()):match(tmproot_pat) + local tmproot = (fn.tempname()):match(tmproot_pat) ok(tmproot:len() > 4, 'tmproot like "nvim.foo"', tmproot) return tmproot end it('failure modes', function() - clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) + clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = os_tmpdir } }) assert_nolog('tempdir is not a directory', testlog) assert_nolog('tempdir has invalid permissions', testlog) @@ -319,9 +358,9 @@ describe('tmpdir', function() -- "…/nvim.<user>/" is not a directory: expect_exit(command, ':qall!') rmdir(tmproot) - write_file(tmproot, '') -- Not a directory, vim_mktempdir() should skip it. - clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) - matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir(). + write_file(tmproot, '') -- Not a directory, vim_mktempdir() should skip it. + clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = os_tmpdir } }) + matches(tmproot_pat, fn.stdpath('run')) -- Tickle vim_mktempdir(). -- Assert that broken tmpdir root was handled. assert_log('tempdir root not a directory', testlog, 100) @@ -330,9 +369,9 @@ describe('tmpdir', function() os.remove(testlog) os.remove(tmproot) mkdir(tmproot) - funcs.setfperm(tmproot, 'rwxr--r--') -- Invalid permissions, vim_mktempdir() should skip it. - clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) - matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir(). + fn.setfperm(tmproot, 'rwxr--r--') -- Invalid permissions, vim_mktempdir() should skip it. + clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = os_tmpdir } }) + matches(tmproot_pat, fn.stdpath('run')) -- Tickle vim_mktempdir(). -- Assert that broken tmpdir root was handled. assert_log('tempdir root has invalid permissions', testlog, 100) end) @@ -340,53 +379,54 @@ describe('tmpdir', function() it('too long', function() local bigname = ('%s/%s'):format(os_tmpdir, ('x'):rep(666)) mkdir(bigname) - clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=bigname, } }) - matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir(). - local len = (funcs.tempname()):len() + clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = bigname } }) + matches(tmproot_pat, fn.stdpath('run')) -- Tickle vim_mktempdir(). + local len = (fn.tempname()):len() ok(len > 4 and len < 256, '4 < len < 256', tostring(len)) end) it('disappeared #1432', function() - clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) + clear({ env = { NVIM_LOG_FILE = testlog, TMPDIR = os_tmpdir } }) assert_nolog('tempdir disappeared', testlog) local function rm_tmpdir() - local tmpname1 = funcs.tempname() - local tmpdir1 = funcs.fnamemodify(tmpname1, ':h') - eq(funcs.stdpath('run'), tmpdir1) + local tmpname1 = fn.tempname() + local tmpdir1 = fn.fnamemodify(tmpname1, ':h') + eq(fn.stdpath('run'), tmpdir1) rmdir(tmpdir1) retry(nil, 1000, function() - eq(0, funcs.isdirectory(tmpdir1)) + eq(0, fn.isdirectory(tmpdir1)) end) - local tmpname2 = funcs.tempname() - local tmpdir2 = funcs.fnamemodify(tmpname2, ':h') + local tmpname2 = fn.tempname() + local tmpdir2 = fn.fnamemodify(tmpname2, ':h') neq(tmpdir1, tmpdir2) end -- Your antivirus hates you... rm_tmpdir() assert_log('tempdir disappeared', testlog, 100) - funcs.tempname() - funcs.tempname() - funcs.tempname() - eq('', meths.get_vvar('errmsg')) + fn.tempname() + fn.tempname() + fn.tempname() + eq('', api.nvim_get_vvar('errmsg')) rm_tmpdir() - funcs.tempname() - funcs.tempname() - funcs.tempname() - eq('E5431: tempdir disappeared (2 times)', meths.get_vvar('errmsg')) + fn.tempname() + fn.tempname() + fn.tempname() + eq('E5431: tempdir disappeared (2 times)', api.nvim_get_vvar('errmsg')) rm_tmpdir() - eq('E5431: tempdir disappeared (3 times)', meths.get_vvar('errmsg')) + eq('E5431: tempdir disappeared (3 times)', api.nvim_get_vvar('errmsg')) end) it('$NVIM_APPNAME relative path', function() - clear({ env={ - NVIM_APPNAME='a/b', - NVIM_LOG_FILE=testlog, - TMPDIR=os_tmpdir, - } }) - matches([=[.*[/\\]a%%b%.[^/\\]+]=], funcs.tempname()) + clear({ + env = { + NVIM_APPNAME = 'a/b', + NVIM_LOG_FILE = testlog, + TMPDIR = os_tmpdir, + }, + }) + matches([=[.*[/\\]a%%b%.[^/\\]+]=], fn.tempname()) end) - end) |