" Tests for autocommands source shared.vim func s:cleanup_buffers() abort for bnr in range(1, bufnr('$')) if bufloaded(bnr) && bufnr('%') != bnr execute 'bd! ' . bnr endif endfor endfunc func Test_vim_did_enter() call assert_false(v:vim_did_enter) " This script will never reach the main loop, can't check if v:vim_did_enter " becomes one. endfunc if has('timers') func ExitInsertMode(id) call feedkeys("\") endfunc func Test_cursorhold_insert() " Need to move the cursor. call feedkeys("ggG", "xt") let g:triggered = 0 au CursorHoldI * let g:triggered += 1 set updatetime=20 call timer_start(100, 'ExitInsertMode') call feedkeys('a', 'x!') call assert_equal(1, g:triggered) unlet g:triggered au! CursorHoldI set updatetime& endfunc func Test_cursorhold_insert_with_timer_interrupt() if !has('job') return endif " Need to move the cursor. call feedkeys("ggG", "xt") " Confirm the timer invoked in exit_cb of the job doesn't disturb " CursorHoldI event. let g:triggered = 0 au CursorHoldI * let g:triggered += 1 set updatetime=500 call job_start(has('win32') ? 'cmd /c echo:' : 'echo', \ {'exit_cb': {-> timer_start(1000, 'ExitInsertMode')}}) call feedkeys('a', 'x!') call assert_equal(1, g:triggered) unlet g:triggered au! CursorHoldI set updatetime& endfunc func Test_cursorhold_insert_ctrl_x() let g:triggered = 0 au CursorHoldI * let g:triggered += 1 set updatetime=20 call timer_start(100, 'ExitInsertMode') " CursorHoldI does not trigger after CTRL-X call feedkeys("a\", 'x!') call assert_equal(0, g:triggered) unlet g:triggered au! CursorHoldI set updatetime& endfunc endif func Test_bufunload() augroup test_bufunload_group autocmd! autocmd BufUnload * call add(s:li, "bufunload") autocmd BufDelete * call add(s:li, "bufdelete") autocmd BufWipeout * call add(s:li, "bufwipeout") augroup END let s:li=[] new setlocal bufhidden= bunload call assert_equal(["bufunload", "bufdelete"], s:li) let s:li=[] new setlocal bufhidden=delete bunload call assert_equal(["bufunload", "bufdelete"], s:li) let s:li=[] new setlocal bufhidden=unload bwipeout call assert_equal(["bufunload", "bufdelete", "bufwipeout"], s:li) au! test_bufunload_group augroup! test_bufunload_group endfunc " SEGV occurs in older versions. (At least 7.4.2005 or older) func Test_autocmd_bufunload_with_tabnext() tabedit tabfirst augroup test_autocmd_bufunload_with_tabnext_group autocmd! autocmd BufUnload tabnext augroup END quit call assert_equal(2, tabpagenr('$')) autocmd! test_autocmd_bufunload_with_tabnext_group augroup! test_autocmd_bufunload_with_tabnext_group tablast quit endfunc func Test_autocmd_bufwinleave_with_tabfirst() tabedit augroup sample autocmd! autocmd BufWinLeave tabfirst augroup END call setline(1, ['a', 'b', 'c']) edit! a.txt tabclose endfunc " SEGV occurs in older versions. (At least 7.4.2321 or older) func Test_autocmd_bufunload_avoiding_SEGV_01() split aa.txt let lastbuf = bufnr('$') augroup test_autocmd_bufunload autocmd! exe 'autocmd BufUnload ' . (lastbuf + 1) . 'bwipeout!' augroup END " Todo: check for E937 generated first " call assert_fails('edit bb.txt', 'E937:') call assert_fails('edit bb.txt', 'E517:') autocmd! test_autocmd_bufunload augroup! test_autocmd_bufunload bwipe! aa.txt bwipe! bb.txt endfunc " SEGV occurs in older versions. (At least 7.4.2321 or older) func Test_autocmd_bufunload_avoiding_SEGV_02() setlocal buftype=nowrite let lastbuf = bufnr('$') augroup test_autocmd_bufunload autocmd! exe 'autocmd BufUnload ' . (lastbuf + 1) . 'bwipeout!' augroup END normal! i1 call assert_fails('edit a.txt', 'E517:') call feedkeys("\") autocmd! test_autocmd_bufunload augroup! test_autocmd_bufunload bwipe! a.txt endfunc func Test_win_tab_autocmd() let g:record = [] augroup testing au WinNew * call add(g:record, 'WinNew') au WinEnter * call add(g:record, 'WinEnter') au WinLeave * call add(g:record, 'WinLeave') au TabNew * call add(g:record, 'TabNew') au TabClosed * call add(g:record, 'TabClosed') au TabEnter * call add(g:record, 'TabEnter') au TabLeave * call add(g:record, 'TabLeave') augroup END split tabnew close close call assert_equal([ \ 'WinLeave', 'WinNew', 'WinEnter', \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', \ 'WinLeave', 'TabLeave', 'TabClosed', 'WinEnter', 'TabEnter', \ 'WinLeave', 'WinEnter' \ ], g:record) let g:record = [] tabnew somefile tabnext bwipe somefile call assert_equal([ \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', \ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', \ 'TabClosed' \ ], g:record) augroup testing au! augroup END unlet g:record endfunc func s:AddAnAutocmd() augroup vimBarTest au BufReadCmd * echo 'hello' augroup END call assert_equal(3, len(split(execute('au vimBarTest'), "\n"))) endfunc func Test_early_bar() " test that a bar is recognized before the {event} call s:AddAnAutocmd() augroup vimBarTest | au! | augroup END call assert_equal(1, len(split(execute('au vimBarTest'), "\n"))) call s:AddAnAutocmd() augroup vimBarTest| au!| augroup END call assert_equal(1, len(split(execute('au vimBarTest'), "\n"))) " test that a bar is recognized after the {event} call s:AddAnAutocmd() augroup vimBarTest| au!BufReadCmd| augroup END call assert_equal(1, len(split(execute('au vimBarTest'), "\n"))) " test that a bar is recognized after the {group} call s:AddAnAutocmd() au! vimBarTest|echo 'hello' call assert_equal(1, len(split(execute('au vimBarTest'), "\n"))) endfunc func RemoveGroup() autocmd! StartOK augroup! StartOK endfunc func Test_augroup_warning() augroup TheWarning au VimEnter * echo 'entering' augroup END call assert_true(match(execute('au VimEnter'), "TheWarning.*VimEnter") >= 0) redir => res augroup! TheWarning redir END call assert_true(match(res, "W19:") >= 0) call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0) " check "Another" does not take the pace of the deleted entry augroup Another augroup END call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0) augroup! Another " no warning for postpone aucmd delete augroup StartOK au VimEnter * call RemoveGroup() augroup END call assert_true(match(execute('au VimEnter'), "StartOK.*VimEnter") >= 0) redir => res doautocmd VimEnter redir END call assert_true(match(res, "W19:") < 0) au! VimEnter endfunc func Test_BufReadCmdHelp() " This used to cause access to free memory au BufReadCmd * e +h help au! BufReadCmd endfunc func Test_BufReadCmdHelpJump() " This used to cause access to free memory au BufReadCmd * e +h{ " } to fix highlighting call assert_fails('help', 'E434:') au! BufReadCmd endfunc func Test_augroup_deleted() " This caused a crash before E936 was introduced augroup x call assert_fails('augroup! x', 'E936:') au VimEnter * echo augroup end augroup! x call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0) au! VimEnter endfunc " Tests for autocommands on :close command. " This used to be in test13. func Test_three_windows() " Clean up buffers, because in some cases this function fails. call s:cleanup_buffers() " Write three files and open them, each in a window. " Then go to next window, with autocommand that deletes the previous one. " Do this twice, writing the file. e! Xtestje1 call setline(1, 'testje1') w sp Xtestje2 call setline(1, 'testje2') w sp Xtestje3 call setline(1, 'testje3') w wincmd w au WinLeave Xtestje2 bwipe wincmd w call assert_equal('Xtestje1', expand('%')) au WinLeave Xtestje1 bwipe Xtestje3 close call assert_equal('Xtestje1', expand('%')) " Test deleting the buffer on a Unload event. If this goes wrong there " will be the ATTENTION prompt. e Xtestje1 au! au! BufUnload Xtestje1 bwipe call assert_fails('e Xtestje3', 'E937:') call assert_equal('Xtestje3', expand('%')) e Xtestje2 sp Xtestje1 call assert_fails('e', 'E937:') call assert_equal('Xtestje1', expand('%')) " Test changing buffers in a BufWipeout autocommand. If this goes wrong " there are ml_line errors and/or a Crash. au! only e Xanother e Xtestje1 bwipe Xtestje2 bwipe Xtestje3 au BufWipeout Xtestje1 buf Xtestje1 bwipe call assert_equal('Xanother', expand('%')) only help wincmd w 1quit call assert_equal('Xanother', expand('%')) au! enew call delete('Xtestje1') call delete('Xtestje2') call delete('Xtestje3') endfunc func Test_BufEnter() au! BufEnter au Bufenter * let val = val . '+' let g:val = '' split NewFile call assert_equal('+', g:val) bwipe! call assert_equal('++', g:val) " Also get BufEnter when editing a directory call mkdir('Xdir') split Xdir call assert_equal('+++', g:val) " On MS-Windows we can't edit the directory, make sure we wipe the right " buffer. bwipe! Xdir call delete('Xdir', 'd') au! BufEnter endfunc " Closing a window might cause an endless loop " E814 for older Vims func Test_autocmd_bufwipe_in_SessLoadPost() edit Xtest tabnew file Xsomething set noswapfile mksession! let content = ['set nocp noswapfile', \ 'let v:swapchoice="e"', \ 'augroup test_autocmd_sessionload', \ 'autocmd!', \ 'autocmd SessionLoadPost * exe bufnr("Xsomething") . "bw!"', \ 'augroup END', \ '', \ 'func WriteErrors()', \ ' call writefile([execute("messages")], "Xerrors")', \ 'endfunc', \ 'au VimLeave * call WriteErrors()', \ ] call writefile(content, 'Xvimrc') call system(v:progpath. ' -u Xvimrc --not-a-term --noplugins -S Session.vim -c cq') let errors = join(readfile('Xerrors')) call assert_match('E814', errors) set swapfile for file in ['Session.vim', 'Xvimrc', 'Xerrors'] call delete(file) endfor endfunc " SEGV occurs in older versions. func Test_autocmd_bufwipe_in_SessLoadPost2() tabnew set noswapfile mksession! let content = ['set nocp noswapfile', \ 'function! DeleteInactiveBufs()', \ ' tabfirst', \ ' let tabblist = []', \ ' for i in range(1, tabpagenr(''$''))', \ ' call extend(tabblist, tabpagebuflist(i))', \ ' endfor', \ ' for b in range(1, bufnr(''$''))', \ ' if bufexists(b) && buflisted(b) && (index(tabblist, b) == -1 || bufname(b) =~# ''^$'')', \ ' exec ''bwipeout '' . b', \ ' endif', \ ' endfor', \ ' echomsg "SessionLoadPost DONE"', \ 'endfunction', \ 'au SessionLoadPost * call DeleteInactiveBufs()', \ '', \ 'func WriteErrors()', \ ' call writefile([execute("messages")], "Xerrors")', \ 'endfunc', \ 'au VimLeave * call WriteErrors()', \ ] call writefile(content, 'Xvimrc') call system(v:progpath. ' -u Xvimrc --not-a-term --noplugins -S Session.vim -c cq') let errors = join(readfile('Xerrors')) " This probably only ever matches on unix. call assert_notmatch('Caught deadly signal SEGV', errors) call assert_match('SessionLoadPost DONE', errors) set swapfile for file in ['Session.vim', 'Xvimrc', 'Xerrors'] call delete(file) endfor endfunc func Test_empty_doau() doau \| endfunc func s:AutoCommandOptionSet(match) let item = remove(g:options, 0) let expected = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", item[0], item[1], item[2], item[3]) let actual = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", a:match, v:option_old, v:option_new, v:option_type) let g:opt = [expected, actual] "call assert_equal(expected, actual) endfunc func Test_OptionSet() if !has("eval") || !exists("+autochdir") return endif badd test_autocmd.vim call test_override('starting', 1) set nocp au OptionSet * :call s:AutoCommandOptionSet(expand("")) " 1: Setting number option" let g:options=[['number', 0, 1, 'global']] set nu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 2: Setting local number option" let g:options=[['number', 1, 0, 'local']] setlocal nonu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 3: Setting global number option" let g:options=[['number', 1, 0, 'global']] setglobal nonu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 4: Setting local autoindent option" let g:options=[['autoindent', 0, 1, 'local']] setlocal ai call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 5: Setting global autoindent option" let g:options=[['autoindent', 0, 1, 'global']] setglobal ai call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 6: Setting global autoindent option" let g:options=[['autoindent', 1, 0, 'global']] set ai! call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " Should not print anything, use :noa " 7: don't trigger OptionSet" let g:options=[['invalid', 1, 1, 'invalid']] noa set nonu call assert_equal([['invalid', 1, 1, 'invalid']], g:options) call assert_equal(g:opt[0], g:opt[1]) " 8: Setting several global list and number option" let g:options=[['list', 0, 1, 'global'], ['number', 0, 1, 'global']] set list nu call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 9: don't trigger OptionSet" let g:options=[['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']] noa set nolist nonu call assert_equal([['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']], g:options) call assert_equal(g:opt[0], g:opt[1]) " 10: Setting global acd" let g:options=[['autochdir', 0, 1, 'local']] setlocal acd call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 11: Setting global autoread (also sets local value)" let g:options=[['autoread', 0, 1, 'global']] set ar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 12: Setting local autoread" let g:options=[['autoread', 1, 1, 'local']] setlocal ar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 13: Setting global autoread" let g:options=[['autoread', 1, 0, 'global']] setglobal invar call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 14: Setting option backspace through :let" let g:options=[['backspace', '', 'eol,indent,start', 'global']] let &bs="eol,indent,start" call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 15: Setting option backspace through setbufvar()" let g:options=[['backup', 0, 1, 'local']] " try twice, first time, shouldn't trigger because option name is invalid, " second time, it should trigger let bnum = bufnr('%') call assert_fails("call setbufvar(bnum, '&l:bk', 1)", "E355") " should trigger, use correct option name call setbufvar(bnum, '&backup', 1) call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 16: Setting number option using setwinvar" let g:options=[['number', 0, 1, 'local']] call setwinvar(0, '&number', 1) call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 17: Setting key option, shouldn't trigger" let g:options=[['key', 'invalid', 'invalid1', 'invalid']] setlocal key=blah setlocal key= call assert_equal([['key', 'invalid', 'invalid1', 'invalid']], g:options) call assert_equal(g:opt[0], g:opt[1]) " 18: Setting string option" let oldval = &tags let g:options=[['tags', oldval, 'tagpath', 'global']] set tags=tagpath call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " 1l: Resetting string option" let g:options=[['tags', 'tagpath', oldval, 'global']] set tags& call assert_equal([], g:options) call assert_equal(g:opt[0], g:opt[1]) " Cleanup au! OptionSet for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp'] exe printf(":set %s&vim", opt) endfor call test_override('starting', 0) delfunc! AutoCommandOptionSet endfunc func Test_OptionSet_diffmode() call test_override('starting', 1) " 18: Changing an option when entering diff mode new au OptionSet diff :let &l:cul=v:option_new call setline(1, ['buffer 1', 'line2', 'line3', 'line4']) call assert_equal(0, &l:cul) diffthis call assert_equal(1, &l:cul) vnew call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4']) call assert_equal(0, &l:cul) diffthis call assert_equal(1, &l:cul) diffoff call assert_equal(0, &l:cul) call assert_equal(1, getwinvar(2, '&l:cul')) bw! call assert_equal(1, &l:cul) diffoff! call assert_equal(0, &l:cul) call assert_equal(0, getwinvar(1, '&l:cul')) bw! " Cleanup au! OptionSet call test_override('starting', 0) endfunc func Test_OptionSet_diffmode_close() call test_override('starting', 1) " 19: Try to close the current window when entering diff mode " should not segfault new au OptionSet diff close call setline(1, ['buffer 1', 'line2', 'line3', 'line4']) call assert_fails(':diffthis', 'E788') call assert_equal(1, &diff) vnew call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4']) call assert_fails(':diffthis', 'E788') call assert_equal(1, &diff) bw! call assert_fails(':diffoff!', 'E788') bw! " Cleanup au! OptionSet call test_override('starting', 0) "delfunc! AutoCommandOptionSet endfunc func Test_OptionSet_modeline() call test_override('starting', 1) au! OptionSet augroup set_tabstop au OptionSet tabstop call timer_start(1, {-> execute("echo 'Handler called'", "")}) augroup END call writefile(['vim: set ts=7 sw=5 :', 'something'], 'XoptionsetModeline') set modeline let v:errmsg = '' call assert_fails('split XoptionsetModeline', 'E12:') call assert_equal(7, &ts) call assert_equal('', v:errmsg) augroup set_tabstop au! augroup END bwipe! set ts& call delete('XoptionsetModeline') call test_override('starting', 0) endfunc " Test for Bufleave autocommand that deletes the buffer we are about to edit. func Test_BufleaveWithDelete() new | edit Xfile1 augroup test_bufleavewithdelete autocmd! autocmd BufLeave Xfile1 bwipe Xfile2 augroup END call assert_fails('edit Xfile2', 'E143:') call assert_equal('Xfile1', bufname('%')) autocmd! test_bufleavewithdelete BufLeave Xfile1 augroup! test_bufleavewithdelete new bwipe! Xfile1 endfunc " Test for autocommand that changes the buffer list, when doing ":ball". func Test_Acmd_BufAll() enew! %bwipe! call writefile(['Test file Xxx1'], 'Xxx1') call writefile(['Test file Xxx2'], 'Xxx2') call writefile(['Test file Xxx3'], 'Xxx3') " Add three files to the buffer list split Xxx1 close split Xxx2 close split Xxx3 close " Wipe the buffer when the buffer is opened au BufReadPost Xxx2 bwipe call append(0, 'Test file Xxx4') ball call assert_equal(2, winnr('$')) call assert_equal('Xxx1', bufname(winbufnr(winnr('$')))) wincmd t au! BufReadPost %bwipe! call delete('Xxx1') call delete('Xxx2') call delete('Xxx3') enew! | only endfunc " Test for autocommand that changes current buffer on BufEnter event. " Check if modelines are interpreted for the correct buffer. func Test_Acmd_BufEnter() %bwipe! call writefile(['start of test file Xxx1', \ "\this is a test", \ 'end of test file Xxx1'], 'Xxx1') call writefile(['start of test file Xxx2', \ 'vim: set noai :', \ "\this is a test", \ 'end of test file Xxx2'], 'Xxx2') au BufEnter Xxx2 brew set ai modeline modelines=3 edit Xxx1 " edit Xxx2, autocmd will do :brew edit Xxx2 exe "normal G?this is a\" " Append text with autoindent to this file normal othis should be auto-indented call assert_equal("\this should be auto-indented", getline('.')) call assert_equal(3, line('.')) " Remove autocmd and edit Xxx2 again au! BufEnter Xxx2 buf! Xxx2 exe "normal G?this is a\" " append text without autoindent to Xxx normal othis should be in column 1 call assert_equal("this should be in column 1", getline('.')) call assert_equal(4, line('.')) %bwipe! call delete('Xxx1') call delete('Xxx2') set ai&vim modeline&vim modelines&vim endfunc " Test for issue #57 " do not move cursor on when autoindent is set func Test_ai_CTRL_O() enew! set ai let save_fo = &fo set fo+=r exe "normal o# abcdef\2hi\\d0\" exe "normal o# abcdef\2hi\d0\" call assert_equal(['# abc', 'def', 'def'], getline(2, 4)) set ai&vim let &fo = save_fo enew! endfunc " Test for autocommand that deletes the current buffer on BufLeave event. " Also test deleting the last buffer, should give a new, empty buffer. func Test_BufLeave_Wipe() %bwipe! let content = ['start of test file Xxx', \ 'this is a test', \ 'end of test file Xxx'] call writefile(content, 'Xxx1') call writefile(content, 'Xxx2') au BufLeave Xxx2 bwipe edit Xxx1 split Xxx2 " delete buffer Xxx2, we should be back to Xxx1 bwipe call assert_equal('Xxx1', bufname('%')) call assert_equal(1, winnr('$')) " Create an alternate buffer %write! test.out call assert_equal('test.out', bufname('#')) " delete alternate buffer bwipe test.out call assert_equal('Xxx1', bufname('%')) call assert_equal('', bufname('#')) au BufLeave Xxx1 bwipe " delete current buffer, get an empty one bwipe! call assert_equal(1, line('$')) call assert_equal('', bufname('%')) let g:bufinfo = getbufinfo() call assert_equal(1, len(g:bufinfo)) call delete('Xxx1') call delete('Xxx2') call delete('test.out') %bwipe au! BufLeave " check that bufinfo doesn't contain a pointer to freed memory call test_garbagecollect_now() endfunc func Test_QuitPre() edit Xfoo let winid = win_getid(winnr()) split Xbar au! QuitPre * let g:afile = expand('') " Close the other window, should be correct. exe win_id2win(winid) . 'q' call assert_equal('Xfoo', g:afile) unlet g:afile bwipe Xfoo bwipe Xbar endfunc func Test_Cmdline() au! CmdlineChanged : let g:text = getcmdline() let g:text = 0 call feedkeys(":echom 'hello'\", 'xt') call assert_equal("echom 'hello'", g:text) au! CmdlineChanged au! CmdlineChanged : let g:entered = expand('') let g:entered = 0 call feedkeys(":echom 'hello'\", 'xt') call assert_equal(':', g:entered) au! CmdlineChanged au! CmdlineEnter : let g:entered = expand('') au! CmdlineLeave : let g:left = expand('') let g:entered = 0 let g:left = 0 call feedkeys(":echo 'hello'\", 'xt') call assert_equal(':', g:entered) call assert_equal(':', g:left) au! CmdlineEnter au! CmdlineLeave let save_shellslash = &shellslash set noshellslash au! CmdlineEnter / let g:entered = expand('') au! CmdlineLeave / let g:left = expand('') let g:entered = 0 let g:left = 0 new call setline(1, 'hello') call feedkeys("/hello\", 'xt') call assert_equal('/', g:entered) call assert_equal('/', g:left) bwipe! au! CmdlineEnter au! CmdlineLeave let &shellslash = save_shellslash endfunc " Test for BufWritePre autocommand that deletes or unloads the buffer. func Test_BufWritePre() %bwipe au BufWritePre Xxx1 bunload au BufWritePre Xxx2 bwipe call writefile(['start of Xxx1', 'test', 'end of Xxx1'], 'Xxx1') call writefile(['start of Xxx2', 'test', 'end of Xxx2'], 'Xxx2') edit Xtest e! Xxx2 bdel Xtest e Xxx1 " write it, will unload it and give an error msg call assert_fails('w', 'E203') call assert_equal('Xxx2', bufname('%')) edit Xtest e! Xxx2 bwipe Xtest " write it, will delete the buffer and give an error msg call assert_fails('w', 'E203') call assert_equal('Xxx1', bufname('%')) au! BufWritePre call delete('Xxx1') call delete('Xxx2') endfunc " Test for BufUnload autocommand that unloads all the other buffers func Test_bufunload_all() call writefile(['Test file Xxx1'], 'Xxx1')" call writefile(['Test file Xxx2'], 'Xxx2')" let content = [ \ "func UnloadAllBufs()", \ " let i = 1", \ " while i <= bufnr('$')", \ " if i != bufnr('%') && bufloaded(i)", \ " exe i . 'bunload'", \ " endif", \ " let i += 1", \ " endwhile", \ "endfunc", \ "au BufUnload * call UnloadAllBufs()", \ "au VimLeave * call writefile(['Test Finished'], 'Xout')", \ "edit Xxx1", \ "split Xxx2", \ "q"] call writefile(content, 'Xtest') call delete('Xout') call system(v:progpath. ' --clean -N --not-a-term -S Xtest') call assert_true(filereadable('Xout')) call delete('Xxx1') call delete('Xxx2') call delete('Xtest') call delete('Xout') endfunc " Some tests for buffer-local autocommands func Test_buflocal_autocmd() let g:bname = '' edit xx au BufLeave let g:bname = expand("%") " here, autocommand for xx should trigger. " but autocommand shall not apply to buffer named . edit somefile call assert_equal('xx', g:bname) let g:bname = '' " here, autocommand shall be auto-deleted bwipe xx " autocmd should not trigger edit xx call assert_equal('', g:bname) " autocmd should not trigger edit somefile call assert_equal('', g:bname) enew unlet g:bname endfunc " Test for "*Cmd" autocommands func Test_Cmd_Autocmds() call writefile(['start of Xxx', "\tabc2", 'end of Xxx'], 'Xxx') enew! au BufReadCmd XtestA 0r Xxx|$del edit XtestA " will read text of Xxd instead call assert_equal('start of Xxx', getline(1)) au BufWriteCmd XtestA call append(line("$"), "write") write " will append a line to the file call assert_equal('write', getline('$')) call assert_fails('read XtestA', 'E484') " should not read anything call assert_equal('write', getline(4)) " now we have: " 1 start of Xxx " 2 abc2 " 3 end of Xxx " 4 write au FileReadCmd XtestB '[r Xxx 2r XtestB " will read Xxx below line 2 instead call assert_equal('start of Xxx', getline(3)) " now we have: " 1 start of Xxx " 2 abc2 " 3 start of Xxx " 4 abc2 " 5 end of Xxx " 6 end of Xxx " 7 write au FileWriteCmd XtestC '[,']copy $ normal 4GA1 4,5w XtestC " will copy lines 4 and 5 to the end call assert_equal("\tabc21", getline(8)) call assert_fails('r XtestC', 'E484') " should not read anything call assert_equal("end of Xxx", getline(9)) " now we have: " 1 start of Xxx " 2 abc2 " 3 start of Xxx " 4 abc21 " 5 end of Xxx " 6 end of Xxx " 7 write " 8 abc21 " 9 end of Xxx let g:lines = [] au FileAppendCmd XtestD call extend(g:lines, getline(line("'["), line("']"))) w >>XtestD " will add lines to 'lines' call assert_equal(9, len(g:lines)) call assert_fails('$r XtestD', 'E484') " should not read anything call assert_equal(9, line('$')) call assert_equal('end of Xxx', getline('$')) au BufReadCmd XtestE 0r Xxx|$del sp XtestE " split window with test.out call assert_equal('end of Xxx', getline(3)) let g:lines = [] exe "normal 2Goasdf\\\" au BufWriteCmd XtestE call extend(g:lines, getline(0, '$')) wall " will write other window to 'lines' call assert_equal(4, len(g:lines), g:lines) call assert_equal('asdf', g:lines[2]) au! BufReadCmd au! BufWriteCmd au! FileReadCmd au! FileWriteCmd au! FileAppendCmd %bwipe! call delete('Xxx') enew! endfunc func SetChangeMarks(start, end) exe a:start. 'mark [' exe a:end. 'mark ]' endfunc " Verify the effects of autocmds on '[ and '] func Test_change_mark_in_autocmds() edit! Xtest call feedkeys("ia\b\c\d\u", 'xtn') call SetChangeMarks(2, 3) write call assert_equal([1, 4], [line("'["), line("']")]) call SetChangeMarks(2, 3) au BufWritePre * call assert_equal([1, 4], [line("'["), line("']")]) write au! BufWritePre if executable('cat') write XtestFilter write >> XtestFilter call SetChangeMarks(2, 3) " Marks are set to the entire range of the write au FilterWritePre * call assert_equal([1, 4], [line("'["), line("']")]) " '[ is adjusted to just before the line that will receive the filtered " data au FilterReadPre * call assert_equal([4, 4], [line("'["), line("']")]) " The filtered data is read into the buffer, and the source lines are " still present, so the range is after the source lines au FilterReadPost * call assert_equal([5, 12], [line("'["), line("']")]) %!cat XtestFilter " After the filtered data is read, the original lines are deleted call assert_equal([1, 8], [line("'["), line("']")]) au! FilterWritePre,FilterReadPre,FilterReadPost undo call SetChangeMarks(1, 4) au FilterWritePre * call assert_equal([2, 3], [line("'["), line("']")]) au FilterReadPre * call assert_equal([3, 3], [line("'["), line("']")]) au FilterReadPost * call assert_equal([4, 11], [line("'["), line("']")]) 2,3!cat XtestFilter call assert_equal([2, 9], [line("'["), line("']")]) au! FilterWritePre,FilterReadPre,FilterReadPost undo call delete('XtestFilter') endif call SetChangeMarks(1, 4) au FileWritePre * call assert_equal([2, 3], [line("'["), line("']")]) 2,3write Xtest2 au! FileWritePre call SetChangeMarks(2, 3) au FileAppendPre * call assert_equal([1, 4], [line("'["), line("']")]) write >> Xtest2 au! FileAppendPre call SetChangeMarks(1, 4) au FileAppendPre * call assert_equal([2, 3], [line("'["), line("']")]) 2,3write >> Xtest2 au! FileAppendPre call SetChangeMarks(1, 1) au FileReadPre * call assert_equal([3, 1], [line("'["), line("']")]) au FileReadPost * call assert_equal([4, 11], [line("'["), line("']")]) 3read Xtest2 au! FileReadPre,FileReadPost undo call SetChangeMarks(4, 4) " When the line is 0, it's adjusted to 1 au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")]) au FileReadPost * call assert_equal([1, 8], [line("'["), line("']")]) 0read Xtest2 au! FileReadPre,FileReadPost undo call SetChangeMarks(4, 4) " When the line is 0, it's adjusted to 1 au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")]) au FileReadPost * call assert_equal([2, 9], [line("'["), line("']")]) 1read Xtest2 au! FileReadPre,FileReadPost undo bwipe! call delete('Xtest') call delete('Xtest2') endfunc func Test_Filter_noshelltemp() if !executable('cat') return endif enew! call setline(1, ['a', 'b', 'c', 'd']) let shelltemp = &shelltemp set shelltemp let g:filter_au = 0 au FilterWritePre * let g:filter_au += 1 au FilterReadPre * let g:filter_au += 1 au FilterReadPost * let g:filter_au += 1 %!cat call assert_equal(3, g:filter_au) if has('filterpipe') set noshelltemp let g:filter_au = 0 au FilterWritePre * let g:filter_au += 1 au FilterReadPre * let g:filter_au += 1 au FilterReadPost * let g:filter_au += 1 %!cat call assert_equal(0, g:filter_au) endif au! FilterWritePre,FilterReadPre,FilterReadPost let &shelltemp = shelltemp bwipe! endfunc func Test_TextYankPost() enew! call setline(1, ['foo']) let g:event = [] au TextYankPost * let g:event = copy(v:event) call assert_equal({}, v:event) call assert_fails('let v:event = {}', 'E46:') call assert_fails('let v:event.mykey = 0', 'E742:') norm "ayiw call assert_equal( \{'regcontents': ['foo'], 'regname': 'a', 'operator': 'y', 'regtype': 'v'}, \g:event) norm y_ call assert_equal( \{'regcontents': ['foo'], 'regname': '', 'operator': 'y', 'regtype': 'V'}, \g:event) call feedkeys("\y", 'x') call assert_equal( \{'regcontents': ['f'], 'regname': '', 'operator': 'y', 'regtype': "\x161"}, \g:event) norm "xciwbar call assert_equal( \{'regcontents': ['foo'], 'regname': 'x', 'operator': 'c', 'regtype': 'v'}, \g:event) norm "bdiw call assert_equal( \{'regcontents': ['bar'], 'regname': 'b', 'operator': 'd', 'regtype': 'v'}, \g:event) call assert_equal({}, v:event) au! TextYankPost unlet g:event bwipe! endfunc func Test_nocatch_wipe_all_buffers() " Real nasty autocommand: wipe all buffers on any event. au * * bwipe * " Get E93 first? " call assert_fails('next x', 'E93:') call assert_fails('next x', 'E517:') bwipe au! endfunc func Test_nocatch_wipe_dummy_buffer() " Nasty autocommand: wipe buffer on any event. au * x bwipe call assert_fails('lvĀ½ /x', 'E480') au! endfunc function s:Before_test_dirchanged() augroup test_dirchanged autocmd! augroup END let s:li = [] let s:dir_this = getcwd() let s:dir_foo = s:dir_this . '/foo' call mkdir(s:dir_foo) let s:dir_bar = s:dir_this . '/bar' call mkdir(s:dir_bar) endfunc function s:After_test_dirchanged() exe 'cd' s:dir_this call delete(s:dir_foo, 'd') call delete(s:dir_bar, 'd') augroup test_dirchanged autocmd! augroup END endfunc function Test_dirchanged_global() call s:Before_test_dirchanged() autocmd test_dirchanged DirChanged global call add(s:li, "cd:") autocmd test_dirchanged DirChanged global call add(s:li, expand("")) exe 'cd' s:dir_foo call assert_equal(["cd:", s:dir_foo], s:li) exe 'cd' s:dir_foo call assert_equal(["cd:", s:dir_foo], s:li) exe 'lcd' s:dir_bar call assert_equal(["cd:", s:dir_foo], s:li) call s:After_test_dirchanged() endfunc function Test_dirchanged_local() call s:Before_test_dirchanged() autocmd test_dirchanged DirChanged window call add(s:li, "lcd:") autocmd test_dirchanged DirChanged window call add(s:li, expand("")) exe 'cd' s:dir_foo call assert_equal([], s:li) exe 'lcd' s:dir_bar call assert_equal(["lcd:", s:dir_bar], s:li) exe 'lcd' s:dir_bar call assert_equal(["lcd:", s:dir_bar], s:li) call s:After_test_dirchanged() endfunc function Test_dirchanged_auto() if !exists('+autochdir') return endif call s:Before_test_dirchanged() call test_autochdir() autocmd test_dirchanged DirChanged auto call add(s:li, "auto:") autocmd test_dirchanged DirChanged auto call add(s:li, expand("")) set acd exe 'cd ..' call assert_equal([], s:li) exe 'edit ' . s:dir_foo . '/Xfile' call assert_equal(s:dir_foo, getcwd()) call assert_equal(["auto:", s:dir_foo], s:li) set noacd bwipe! call s:After_test_dirchanged() endfunc " Test TextChangedI and TextChangedP func Test_ChangedP() new call setline(1, ['foo', 'bar', 'foobar']) call test_override("char_avail", 1) set complete=. completeopt=menuone func! TextChangedAutocmd(char) let g:autocmd .= a:char endfunc au! TextChanged :call TextChangedAutocmd('N') au! TextChangedI :call TextChangedAutocmd('I') au! TextChangedP :call TextChangedAutocmd('P') call cursor(3, 1) let g:autocmd = '' call feedkeys("o\", 'tnix') call assert_equal('I', g:autocmd) let g:autocmd = '' call feedkeys("Sf", 'tnix') call assert_equal('II', g:autocmd) let g:autocmd = '' call feedkeys("Sf\", 'tnix') call assert_equal('IIP', g:autocmd) let g:autocmd = '' call feedkeys("Sf\\", 'tnix') call assert_equal('IIPP', g:autocmd) let g:autocmd = '' call feedkeys("Sf\\\", 'tnix') call assert_equal('IIPPP', g:autocmd) let g:autocmd = '' call feedkeys("Sf\\\\", 'tnix') call assert_equal('IIPPPP', g:autocmd) call assert_equal(['foo', 'bar', 'foobar', 'foo'], getline(1, '$')) " TODO: how should it handle completeopt=noinsert,noselect? " CleanUp call test_override("char_avail", 0) au! TextChanged au! TextChangedI au! TextChangedP delfu TextChangedAutocmd unlet! g:autocmd set complete&vim completeopt&vim bw! endfunc let g:setline_handled = v:false func SetLineOne() if !g:setline_handled call setline(1, "(x)") let g:setline_handled = v:true endif endfunc func Test_TextChangedI_with_setline() new call test_override('char_avail', 1) autocmd TextChangedI call SetLineOne() call feedkeys("i(\\", 'tx') call assert_equal('(', getline(1)) call assert_equal('x)', getline(2)) undo call assert_equal('', getline(1)) call assert_equal('', getline(2)) call test_override('starting', 0) bwipe! endfunc func Test_Changed_FirstTime() if !has('terminal') || has('gui_running') return endif " Prepare file for TextChanged event. call writefile([''], 'Xchanged.txt') let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3}) call assert_equal('running', term_getstatus(buf)) " Wait for the ruler (in the status line) to be shown. " In ConPTY, there is additional character which is drawn up to the width of " the screen. if has('conpty') call WaitForAssert({-> assert_match('\ assert_match('\ call writefile(['No'], 'Xchanged.txt')\") call term_sendkeys(buf, "\\:qa!\") call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))}) call assert_equal([''], readfile('Xchanged.txt')) " clean up call delete('Xchanged.txt') bwipe! endfunc func Test_autocmd_nested() let g:did_nested = 0 augroup Testing au WinNew * edit somefile au BufNew * let g:did_nested = 1 augroup END split call assert_equal(0, g:did_nested) close bwipe! somefile " old nested argument still works augroup Testing au! au WinNew * nested edit somefile au BufNew * let g:did_nested = 1 augroup END split call assert_equal(1, g:did_nested) close bwipe! somefile " New ++nested argument works augroup Testing au! au WinNew * ++nested edit somefile au BufNew * let g:did_nested = 1 augroup END split call assert_equal(1, g:did_nested) close bwipe! somefile augroup Testing au! augroup END call assert_fails('au WinNew * ++nested ++nested echo bad', 'E983:') call assert_fails('au WinNew * nested nested echo bad', 'E983:') endfunc func Test_autocmd_once() " Without ++once WinNew triggers twice let g:did_split = 0 augroup Testing au WinNew * let g:did_split += 1 augroup END split split call assert_equal(2, g:did_split) call assert_true(exists('#WinNew')) close close " With ++once WinNew triggers once let g:did_split = 0 augroup Testing au! au WinNew * ++once let g:did_split += 1 augroup END split split call assert_equal(1, g:did_split) call assert_false(exists('#WinNew')) close close call assert_fails('au WinNew * ++once ++once echo bad', 'E983:') endfunc " FileChangedShell tested in test_filechanged.vim