summaryrefslogtreecommitdiffstats
path: root/src/testdir/test_autocmd.vim
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/testdir/test_autocmd.vim1418
1 files changed, 1418 insertions, 0 deletions
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
new file mode 100644
index 0000000..71df515
--- /dev/null
+++ b/src/testdir/test_autocmd.vim
@@ -0,0 +1,1418 @@
+" 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("\<Esc>")
+ 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\<C-X>", '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 <buffer> 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 <buffer> 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 <buffer> ' . (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 <buffer> ' . (lastbuf + 1) . 'bwipeout!'
+ augroup END
+
+ normal! i1
+ call assert_fails('edit a.txt', 'E517:')
+ call feedkeys("\<CR>")
+
+ 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("<amatch>"))
+
+ " 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',
+ \ "\<Tab>this is a test",
+ \ 'end of test file Xxx1'], 'Xxx1')
+ call writefile(['start of test file Xxx2',
+ \ 'vim: set noai :',
+ \ "\<Tab>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\<CR>"
+ " Append text with autoindent to this file
+ normal othis should be auto-indented
+ call assert_equal("\<Tab>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\<CR>"
+ " 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 <c-o> when autoindent is set
+func Test_ai_CTRL_O()
+ enew!
+ set ai
+ let save_fo = &fo
+ set fo+=r
+ exe "normal o# abcdef\<Esc>2hi\<CR>\<C-O>d0\<Esc>"
+ exe "normal o# abcdef\<Esc>2hi\<C-O>d0\<Esc>"
+ 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('<afile>')
+ " Close the other window, <afile> 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'\<CR>", 'xt')
+ call assert_equal("echom 'hello'", g:text)
+ au! CmdlineChanged
+
+ au! CmdlineChanged : let g:entered = expand('<afile>')
+ let g:entered = 0
+ call feedkeys(":echom 'hello'\<CR>", 'xt')
+ call assert_equal(':', g:entered)
+ au! CmdlineChanged
+
+ au! CmdlineEnter : let g:entered = expand('<afile>')
+ au! CmdlineLeave : let g:left = expand('<afile>')
+ let g:entered = 0
+ let g:left = 0
+ call feedkeys(":echo 'hello'\<CR>", '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('<afile>')
+ au! CmdlineLeave / let g:left = expand('<afile>')
+ let g:entered = 0
+ let g:left = 0
+ new
+ call setline(1, 'hello')
+ call feedkeys("/hello\<CR>", '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 <buffer> let g:bname = expand("%")
+ " here, autocommand for xx should trigger.
+ " but autocommand shall not apply to buffer named <buffer>.
+ 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\<Esc>\<C-W>\<C-W>"
+ 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\<CR>b\<CR>c\<CR>d\<C-g>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("\<C-V>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("<afile>"))
+ 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("<afile>"))
+ 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("<afile>"))
+ 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 <buffer> :call TextChangedAutocmd('N')
+ au! TextChangedI <buffer> :call TextChangedAutocmd('I')
+ au! TextChangedP <buffer> :call TextChangedAutocmd('P')
+
+ call cursor(3, 1)
+ let g:autocmd = ''
+ call feedkeys("o\<esc>", '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\<C-N>", 'tnix')
+ call assert_equal('IIP', g:autocmd)
+
+ let g:autocmd = ''
+ call feedkeys("Sf\<C-N>\<C-N>", 'tnix')
+ call assert_equal('IIPP', g:autocmd)
+
+ let g:autocmd = ''
+ call feedkeys("Sf\<C-N>\<C-N>\<C-N>", 'tnix')
+ call assert_equal('IIPPP', g:autocmd)
+
+ let g:autocmd = ''
+ call feedkeys("Sf\<C-N>\<C-N>\<C-N>\<C-N>", '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 <buffer> call SetLineOne()
+ call feedkeys("i(\<CR>\<Esc>", '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('\<All.*$', term_getline(buf, 3))})
+ else
+ call WaitForAssert({-> assert_match('\<All$', term_getline(buf, 3))})
+ endif
+ " It's only adding autocmd, so that no event occurs.
+ call term_sendkeys(buf, ":au! TextChanged <buffer> call writefile(['No'], 'Xchanged.txt')\<cr>")
+ call term_sendkeys(buf, "\<C-\\>\<C-N>:qa!\<cr>")
+ call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))})
+ call assert_equal([''], readfile('Xchanged.txt'))
+
+ " clean up
+ call delete('Xchanged.txt')
+ bwipe!
+endfunc
+
+" FileChangedShell tested in test_filechanged.vim