diff options
Diffstat (limited to 'test/functional/autocmd')
| -rw-r--r-- | test/functional/autocmd/autocmd_spec.lua | 26 | ||||
| -rw-r--r-- | test/functional/autocmd/bufenter_spec.lua | 16 | ||||
| -rw-r--r-- | test/functional/autocmd/cmdline_spec.lua | 118 | ||||
| -rw-r--r-- | test/functional/autocmd/dirchanged_spec.lua | 7 | ||||
| -rw-r--r-- | test/functional/autocmd/filetype_spec.lua | 16 | ||||
| -rw-r--r-- | test/functional/autocmd/tabclose_spec.lua | 87 | ||||
| -rw-r--r-- | test/functional/autocmd/tabnewentered_spec.lua | 8 | ||||
| -rw-r--r-- | test/functional/autocmd/termclose_spec.lua | 55 | ||||
| -rw-r--r-- | test/functional/autocmd/textyankpost_spec.lua | 30 |
9 files changed, 312 insertions, 51 deletions
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index c38bd75c69..8ee9462a8d 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -1,9 +1,13 @@ local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local command = helpers.command local eq = helpers.eq local eval = helpers.eval +local clear = helpers.clear +local meths = helpers.meths +local expect = helpers.expect +local command = helpers.command +local exc_exec = helpers.exc_exec +local curbufmeths = helpers.curbufmeths describe('autocmds:', function() before_each(clear) @@ -33,4 +37,22 @@ describe('autocmds:', function() it('v:vim_did_enter is 1 after VimEnter', function() eq(1, eval('v:vim_did_enter')) end) + + describe('BufLeave autocommand', function() + it('can wipe out the buffer created by :edit which triggered autocmd', + function() + meths.set_option('hidden', true) + curbufmeths.set_lines(0, 1, false, { + 'start of test file xx', + 'end of test file xx'}) + + command('autocmd BufLeave * bwipeout yy') + eq('Vim(edit):E143: Autocommands unexpectedly deleted new buffer yy', + exc_exec('edit yy')) + + expect([[ + start of test file xx + end of test file xx]]) + end) + end) end) diff --git a/test/functional/autocmd/bufenter_spec.lua b/test/functional/autocmd/bufenter_spec.lua index ccbcdf5c5e..e14ddb3316 100644 --- a/test/functional/autocmd/bufenter_spec.lua +++ b/test/functional/autocmd/bufenter_spec.lua @@ -4,7 +4,6 @@ local clear = helpers.clear local command = helpers.command local eq = helpers.eq local eval = helpers.eval -local execute = helpers.execute local request = helpers.request local source = helpers.source @@ -28,8 +27,21 @@ describe('autocmd BufEnter', function() endtry endfunction ]]) - execute("call Test()") + command("call Test()") eq(1, eval("exists('g:dir_bufenter')")) -- Did BufEnter for the directory. eq(2, eval("bufnr('%')")) -- Switched to the dir buffer. end) + + it('triggered by ":split normal|:help|:bw"', function() + command("split normal") + command("wincmd j") + command("helptags runtime/doc") + command("help") + command("wincmd L") + command("autocmd BufEnter normal let g:bufentered = 1") + command("bw") + eq(1, eval('bufnr("%")')) -- The cursor is back to the bottom window + eq(0, eval("exists('g:bufentered')")) -- The autocmd hasn't been triggered + end) + end) diff --git a/test/functional/autocmd/cmdline_spec.lua b/test/functional/autocmd/cmdline_spec.lua new file mode 100644 index 0000000000..3f0504d02f --- /dev/null +++ b/test/functional/autocmd/cmdline_spec.lua @@ -0,0 +1,118 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') + +local clear = helpers.clear +local command = helpers.command +local eq = helpers.eq +local expect = helpers.expect +local next_msg = helpers.next_msg +local feed = helpers.feed +local meths = helpers.meths + +describe('cmdline autocommands', function() + local channel + before_each(function() + clear() + channel = meths.get_api_info()[1] + meths.set_var("channel",channel) + command("autocmd CmdlineEnter * call rpcnotify(g:channel, 'CmdlineEnter', v:event)") + command("autocmd CmdlineLeave * call rpcnotify(g:channel, 'CmdlineLeave', v:event)") + command("autocmd CmdWinEnter * call rpcnotify(g:channel, 'CmdWinEnter', v:event)") + command("autocmd CmdWinLeave * call rpcnotify(g:channel, 'CmdWinLeave', v:event)") + end) + + it('works', function() + feed(':') + eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) + feed('redraw<cr>') + eq({'notification', 'CmdlineLeave', + {{cmdtype=':', cmdlevel=1, abort=false}}}, next_msg()) + + feed(':') + eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) + + -- note: feed('bork<c-c>') might not consume 'bork' + -- due to out-of-band interupt handling + feed('bork<esc>') + eq({'notification', 'CmdlineLeave', + {{cmdtype=':', cmdlevel=1, abort=true}}}, next_msg()) + end) + + it('can abort cmdline', function() + command("autocmd CmdlineLeave * let v:event.abort= len(getcmdline())>15") + feed(":put! ='ok'<cr>") + expect([[ + ok + ]]) + + feed(":put! ='blah blah'<cr>") + expect([[ + ok + ]]) + end) + + it('handles errors correctly', function() + clear() + local screen = Screen.new(72, 8) + screen:attach() + 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}, + [4] = {bold = true, reverse = true}, + }) + command("autocmd CmdlineEnter * echoerr 'FAIL'") + command("autocmd CmdlineLeave * echoerr 'very error'") + feed(':') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {4: }| + : | + {2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} | + :^ | + ]]) + feed("put ='lorem ipsum'<cr>") + screen:expect([[ + | + {4: }| + : | + {2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} | + :put ='lorem ipsum' | + {2:E5500: autocmd has thrown an exception: Vim(echoerr):very error} | + | + {3:Press ENTER or type command to continue}^ | + ]]) + + feed('<cr>') + screen:expect([[ + | + ^lorem ipsum | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end) + + it('works with nested cmdline', function() + feed(':') + eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) + feed('<c-r>=') + eq({'notification', 'CmdlineEnter', {{cmdtype='=', cmdlevel=2}}}, next_msg()) + feed('<c-f>') + eq({'notification', 'CmdWinEnter', {{}}}, next_msg()) + feed(':') + eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=3}}}, next_msg()) + feed('<c-c>') + eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=3, abort=true}}}, next_msg()) + feed('<c-c>') + eq({'notification', 'CmdWinLeave', {{}}}, next_msg()) + feed('1+2<cr>') + eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, abort=false}}}, next_msg()) + end) +end) diff --git a/test/functional/autocmd/dirchanged_spec.lua b/test/functional/autocmd/dirchanged_spec.lua index 63cf0bc410..7979e91a4c 100644 --- a/test/functional/autocmd/dirchanged_spec.lua +++ b/test/functional/autocmd/dirchanged_spec.lua @@ -154,4 +154,11 @@ describe('autocmd DirChanged', function() eq('Failed to change directory', string.match(err, ': (.*)')) eq({cwd=dirs[2], scope='global'}, eval('g:ev')) end) + + it('works when local to buffer', function() + command('let g:triggered = 0') + command('autocmd DirChanged <buffer> let g:triggered = 1') + command('cd '..dirs[1]) + eq(1, eval('g:triggered')) + end) end) diff --git a/test/functional/autocmd/filetype_spec.lua b/test/functional/autocmd/filetype_spec.lua new file mode 100644 index 0000000000..e6fa7ab6bb --- /dev/null +++ b/test/functional/autocmd/filetype_spec.lua @@ -0,0 +1,16 @@ +local helpers = require('test.functional.helpers')(after_each) + +local eval = helpers.eval +local clear = helpers.clear +local command = helpers.command + +describe('autocmd FileType', function() + before_each(clear) + + it("is triggered by :help only once", function() + command("let g:foo = 0") + command("autocmd FileType help let g:foo = g:foo + 1") + command("help help") + assert.same(1, eval('g:foo')) + end) +end) diff --git a/test/functional/autocmd/tabclose_spec.lua b/test/functional/autocmd/tabclose_spec.lua index 1431c69589..b7c33dc3d8 100644 --- a/test/functional/autocmd/tabclose_spec.lua +++ b/test/functional/autocmd/tabclose_spec.lua @@ -2,32 +2,67 @@ local helpers = require('test.functional.helpers')(after_each) local clear, nvim, eq = helpers.clear, helpers.nvim, helpers.eq describe('TabClosed', function() - describe('au TabClosed', function() - describe('with * as <afile>', function() - it('matches when closing any tab', function() - clear() - nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()') - repeat - nvim('command', 'tabnew') - until nvim('eval', 'tabpagenr()') == 6 -- current tab is now 6 - eq("\ntabclosed:6:6:5", nvim('command_output', 'tabclose')) -- close last 6, current tab is now 5 - eq("\ntabclosed:5:5:4", nvim('command_output', 'close')) -- close last window on tab, closes tab - eq("\ntabclosed:2:2:3", nvim('command_output', '2tabclose')) -- close tab 2, current tab is now 3 - eq("\ntabclosed:1:1:2\ntabclosed:1:1:1", nvim('command_output', 'tabonly')) -- close tabs 1 and 2 - end) - end) - describe('with NR as <afile>', function() - it('matches when closing a tab whose index is NR', function() - nvim('command', 'au! TabClosed 2 echom "tabclosed:match"') - repeat - nvim('command', 'tabnew') - until nvim('eval', 'tabpagenr()') == 5 -- current tab is now 5 - -- sanity check, we shouldn't match on tabs with numbers other than 2 - eq("\ntabclosed:5:5:4", nvim('command_output', 'tabclose')) - -- close tab page 2, current tab is now 3 - eq("\ntabclosed:2:2:3\ntabclosed:match", nvim('command_output', '2tabclose')) - end) - end) + before_each(clear) + + describe('au TabClosed', function() + describe('with * as <afile>', function() + it('matches when closing any tab', function() + nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()') + repeat + nvim('command', 'tabnew') + until nvim('eval', 'tabpagenr()') == 6 -- current tab is now 6 + eq("tabclosed:6:6:5", nvim('command_output', 'tabclose')) -- close last 6, current tab is now 5 + eq("tabclosed:5:5:4", nvim('command_output', 'close')) -- close last window on tab, closes tab + eq("tabclosed:2:2:3", nvim('command_output', '2tabclose')) -- close tab 2, current tab is now 3 + eq("tabclosed:1:1:2\ntabclosed:1:1:1", nvim('command_output', 'tabonly')) -- close tabs 1 and 2 + end) + + it('is triggered when closing a window via bdelete from another tab', function() + nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()') + nvim('command', '1tabedit Xtestfile') + nvim('command', '1tabedit Xtestfile') + nvim('command', 'normal! 1gt') + eq({1, 3}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) + eq("tabclosed:2:2:1\ntabclosed:2:2:1", nvim('command_output', 'bdelete Xtestfile')) + eq({1, 1}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) + end) + + it('is triggered when closing a window via bdelete from current tab', function() + nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()') + nvim('command', 'file Xtestfile1') + nvim('command', '1tabedit Xtestfile2') + nvim('command', '1tabedit Xtestfile2') + + -- Only one tab is closed, and the alternate file is used for the other. + eq({2, 3}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) + eq("tabclosed:2:2:2", nvim('command_output', 'bdelete Xtestfile2')) + eq('Xtestfile1', nvim('eval', 'bufname("")')) + end) + end) + + describe('with NR as <afile>', function() + it('matches when closing a tab whose index is NR', function() + nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()') + nvim('command', 'au! TabClosed 2 echom "tabclosed:match"') + repeat + nvim('command', 'tabnew') + until nvim('eval', 'tabpagenr()') == 7 -- current tab is now 7 + -- sanity check, we shouldn't match on tabs with numbers other than 2 + eq("tabclosed:7:7:6", nvim('command_output', 'tabclose')) + -- close tab page 2, current tab is now 5 + eq("tabclosed:2:2:5\ntabclosed:match", nvim('command_output', '2tabclose')) + end) + end) + + describe('with close', function() + it('is triggered', function() + nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()') + nvim('command', 'tabedit Xtestfile') + eq({2, 2}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) + eq("tabclosed:2:2:1", nvim('command_output', 'close')) + eq({1, 1}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) + end) end) + end) end) diff --git a/test/functional/autocmd/tabnewentered_spec.lua b/test/functional/autocmd/tabnewentered_spec.lua index bdbe677132..59cac07b34 100644 --- a/test/functional/autocmd/tabnewentered_spec.lua +++ b/test/functional/autocmd/tabnewentered_spec.lua @@ -7,14 +7,14 @@ describe('TabNewEntered', function() it('matches when entering any new tab', function() clear() nvim('command', 'au! TabNewEntered * echom "tabnewentered:".tabpagenr().":".bufnr("")') - eq("\ntabnewentered:2:2", nvim('command_output', 'tabnew')) - eq("\n\"test.x2\" [New File]\ntabnewentered:3:3", nvim('command_output', 'tabnew test.x2')) + eq("tabnewentered:2:2", nvim('command_output', 'tabnew')) + eq("tabnewentered:3:3", nvim('command_output', 'tabnew test.x2')) end) end) describe('with FILE as <afile>', function() it('matches when opening a new tab for FILE', function() nvim('command', 'au! TabNewEntered Xtest-tabnewentered echom "tabnewentered:match"') - eq('\n"Xtest-tabnewentered" [New File]\ntabnewentered:4:4\ntabnewentered:match', + eq('tabnewentered:4:4\ntabnewentered:match', nvim('command_output', 'tabnew Xtest-tabnewentered')) end) end) @@ -24,7 +24,7 @@ describe('TabNewEntered', function() nvim('command', 'au! TabNewEntered * echom "entered"') nvim('command', 'tabnew test.x2') nvim('command', 'split') - eq('\nentered', nvim('command_output', 'execute "normal \\<C-W>T"')) + eq('entered', nvim('command_output', 'execute "normal \\<C-W>T"')) end) end) end) diff --git a/test/functional/autocmd/termclose_spec.lua b/test/functional/autocmd/termclose_spec.lua index d4beab22e4..db4e5379d0 100644 --- a/test/functional/autocmd/termclose_spec.lua +++ b/test/functional/autocmd/termclose_spec.lua @@ -1,11 +1,13 @@ +local luv = require('luv') local helpers = require('test.functional.helpers')(after_each) local clear, command, nvim, nvim_dir = helpers.clear, helpers.command, helpers.nvim, helpers.nvim_dir local eval, eq, retry = helpers.eval, helpers.eq, helpers.retry +local ok = helpers.ok +local iswin = helpers.iswin -if helpers.pending_win32(pending) then return end describe('TermClose event', function() before_each(function() @@ -14,13 +16,62 @@ describe('TermClose event', function() nvim('set_option', 'shellcmdflag', 'EXE') end) - it('triggers when terminal job ends', function() + it('triggers when fast-exiting terminal job stops', function() command('autocmd TermClose * let g:test_termclose = 23') command('terminal') command('call jobstop(b:terminal_job_id)') retry(nil, nil, function() eq(23, eval('g:test_termclose')) end) end) + it('triggers when long-running terminal job gets stopped', function() + nvim('set_option', 'shell', iswin() and 'cmd.exe' or 'sh') + command('autocmd TermClose * let g:test_termclose = 23') + command('terminal') + command('call jobstop(b:terminal_job_id)') + retry(nil, nil, function() eq(23, eval('g:test_termclose')) end) + end) + + it('kills job trapping SIGTERM', function() + if iswin() then return end + nvim('set_option', 'shell', 'sh') + nvim('set_option', 'shellcmdflag', '-c') + command([[ let g:test_job = jobstart('trap "" TERM && echo 1 && sleep 60', { ]] + .. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]] + .. [[ 'on_exit': {-> execute('let g:test_job_exited = 1')}}) ]]) + retry(nil, nil, function() eq(1, eval('get(g:, "test_job_started", 0)')) end) + + luv.update_time() + local start = luv.now() + command('call jobstop(g:test_job)') + retry(nil, nil, function() eq(1, eval('get(g:, "test_job_exited", 0)')) end) + luv.update_time() + local duration = luv.now() - start + -- Nvim begins SIGTERM after KILL_TIMEOUT_MS. + ok(duration >= 2000) + ok(duration <= 4000) -- Epsilon for slow CI + end) + + it('kills PTY job trapping SIGHUP and SIGTERM', function() + if iswin() then return end + nvim('set_option', 'shell', 'sh') + nvim('set_option', 'shellcmdflag', '-c') + command([[ let g:test_job = jobstart('trap "" HUP TERM && echo 1 && sleep 60', { ]] + .. [[ 'pty': 1,]] + .. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]] + .. [[ 'on_exit': {-> execute('let g:test_job_exited = 1')}}) ]]) + retry(nil, nil, function() eq(1, eval('get(g:, "test_job_started", 0)')) end) + + luv.update_time() + local start = luv.now() + command('call jobstop(g:test_job)') + retry(nil, nil, function() eq(1, eval('get(g:, "test_job_exited", 0)')) end) + luv.update_time() + local duration = luv.now() - start + -- Nvim begins SIGKILL after (2 * KILL_TIMEOUT_MS). + ok(duration >= 4000) + ok(duration <= 7000) -- Epsilon for slow CI + end) + it('reports the correct <abuf>', function() command('set hidden') command('autocmd TermClose * let g:abuf = expand("<abuf>")') diff --git a/test/functional/autocmd/textyankpost_spec.lua b/test/functional/autocmd/textyankpost_spec.lua index bd5f1912c5..486a3346b1 100644 --- a/test/functional/autocmd/textyankpost_spec.lua +++ b/test/functional/autocmd/textyankpost_spec.lua @@ -1,6 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) local clear, eval, eq = helpers.clear, helpers.eval, helpers.eq -local feed, execute, expect, command = helpers.feed, helpers.execute, helpers.expect, helpers.command +local feed, command, expect = helpers.feed, helpers.command, helpers.expect local curbufmeths, funcs, neq = helpers.curbufmeths, helpers.funcs, helpers.neq describe('TextYankPost', function() @@ -8,11 +8,11 @@ describe('TextYankPost', function() clear() -- emulate the clipboard so system clipboard isn't affected - execute('let &rtp = "test/functional/fixtures,".&rtp') + command('let &rtp = "test/functional/fixtures,".&rtp') - execute('let g:count = 0') - execute('autocmd TextYankPost * let g:event = copy(v:event)') - execute('autocmd TextYankPost * let g:count += 1') + command('let g:count = 0') + command('autocmd TextYankPost * let g:event = copy(v:event)') + command('autocmd TextYankPost * let g:count += 1') curbufmeths.set_lines(0, -1, true, { 'foo\0bar', @@ -61,27 +61,27 @@ describe('TextYankPost', function() regtype = 'V' }, eval('g:event')) - execute('set debug=msg') + command('set debug=msg') -- the regcontents should not be changed without copy. local status, err = pcall(command,'call extend(g:event.regcontents, ["more text"])') eq(status,false) neq(nil, string.find(err, ':E742:')) -- can't mutate keys inside the autocommand - execute('autocmd! TextYankPost * let v:event.regcontents = 0') + command('autocmd! TextYankPost * let v:event.regcontents = 0') status, err = pcall(command,'normal yy') eq(status,false) neq(nil, string.find(err, ':E46:')) -- can't add keys inside the autocommand - execute('autocmd! TextYankPost * let v:event.mykey = 0') + command('autocmd! TextYankPost * let v:event.mykey = 0') status, err = pcall(command,'normal yy') eq(status,false) neq(nil, string.find(err, ':E742:')) end) it('is not invoked recursively', function() - execute('autocmd TextYankPost * normal "+yy') + command('autocmd TextYankPost * normal "+yy') feed('yy') eq({ operator = 'y', @@ -134,7 +134,7 @@ describe('TextYankPost', function() feed('"_yy') eq(0, eval('g:count')) - execute('delete _') + command('delete _') eq(0, eval('g:count')) end) @@ -155,7 +155,7 @@ describe('TextYankPost', function() regtype = 'V' }, eval('g:event')) - execute("set clipboard=unnamed") + command("set clipboard=unnamed") -- regname still shows the name the user requested feed('yy') @@ -176,7 +176,7 @@ describe('TextYankPost', function() end) it('works with Ex commands', function() - execute('1delete +') + command('1delete +') eq({ operator = 'd', regcontents = { 'foo\nbar' }, @@ -185,7 +185,7 @@ describe('TextYankPost', function() }, eval('g:event')) eq(1, eval('g:count')) - execute('yank') + command('yank') eq({ operator = 'y', regcontents = { 'baz text' }, @@ -194,7 +194,7 @@ describe('TextYankPost', function() }, eval('g:event')) eq(2, eval('g:count')) - execute('normal yw') + command('normal yw') eq({ operator = 'y', regcontents = { 'baz ' }, @@ -203,7 +203,7 @@ describe('TextYankPost', function() }, eval('g:event')) eq(3, eval('g:count')) - execute('normal! dd') + command('normal! dd') eq({ operator = 'd', regcontents = { 'baz text' }, |