neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

test_autocmd.vim (153526B)


      1 " Tests for autocommands
      2 
      3 source shared.vim
      4 source check.vim
      5 source term_util.vim
      6 source screendump.vim
      7 source vim9.vim
      8 source load.vim
      9 
     10 func s:cleanup_buffers() abort
     11  for bnr in range(1, bufnr('$'))
     12    if bufloaded(bnr) && bufnr('%') != bnr
     13      execute 'bd! ' . bnr
     14    endif
     15  endfor
     16 endfunc
     17 
     18 func CleanUpTestAuGroup()
     19  augroup testing
     20    au!
     21  augroup END
     22  augroup! testing
     23 endfunc
     24 
     25 func Test_vim_did_enter()
     26  call assert_false(v:vim_did_enter)
     27 
     28  " This script will never reach the main loop, can't check if v:vim_did_enter
     29  " becomes one.
     30 endfunc
     31 
     32 " Test for the CursorHold autocmd
     33 func Test_CursorHold_autocmd()
     34  CheckRunVimInTerminal
     35  call writefile(['one', 'two', 'three'], 'XoneTwoThree', 'D')
     36  let before =<< trim END
     37    set updatetime=10
     38    au CursorHold * call writefile([line('.')], 'XCHoutput', 'a')
     39  END
     40  call writefile(before, 'XCHinit', 'D')
     41  let buf = RunVimInTerminal('-S XCHinit XoneTwoThree', {})
     42  call term_sendkeys(buf, "G")
     43  call term_wait(buf, 50)
     44  call term_sendkeys(buf, "gg")
     45  call term_wait(buf)
     46  call WaitForAssert({-> assert_equal(['1'], readfile('XCHoutput')[-1:-1])})
     47  call term_sendkeys(buf, "j")
     48  call term_wait(buf)
     49  call WaitForAssert({-> assert_equal(['1', '2'], readfile('XCHoutput')[-2:-1])})
     50  call term_sendkeys(buf, "j")
     51  call term_wait(buf)
     52  call WaitForAssert({-> assert_equal(['1', '2', '3'], readfile('XCHoutput')[-3:-1])})
     53  call StopVimInTerminal(buf)
     54 
     55  call delete('XCHoutput')
     56 endfunc
     57 
     58 if has('timers')
     59 
     60  func ExitInsertMode(id)
     61    call feedkeys("\<Esc>")
     62  endfunc
     63 
     64  func Test_cursorhold_insert()
     65    " depends on timing
     66    let g:test_is_flaky = 1
     67 
     68    " Need to move the cursor.
     69    call feedkeys("ggG", "xt")
     70 
     71    let g:triggered = 0
     72    au CursorHoldI * let g:triggered += 1
     73    set updatetime=20
     74    call timer_start(LoadAdjust(200), 'ExitInsertMode')
     75    call feedkeys('a', 'x!')
     76    call assert_equal(1, g:triggered)
     77    unlet g:triggered
     78    au! CursorHoldI
     79    set updatetime&
     80  endfunc
     81 
     82  func Test_cursorhold_insert_with_timer_interrupt()
     83    CheckFeature job
     84    " Need to move the cursor.
     85    call feedkeys("ggG", "xt")
     86 
     87    " Confirm the timer invoked in exit_cb of the job doesn't disturb
     88    " CursorHoldI event.
     89    let g:triggered = 0
     90    au CursorHoldI * let g:triggered += 1
     91    set updatetime=100
     92    call job_start(has('win32') ? 'cmd /D /c echo:' : 'echo',
     93          \ {'exit_cb': {-> timer_start(200, 'ExitInsertMode')}})
     94    call feedkeys('a', 'x!')
     95    call assert_equal(1, g:triggered)
     96    unlet g:triggered
     97    au! CursorHoldI
     98    set updatetime&
     99  endfunc
    100 
    101  func Test_cursorhold_insert_ctrl_x()
    102    let g:triggered = 0
    103    au CursorHoldI * let g:triggered += 1
    104    set updatetime=20
    105    call timer_start(LoadAdjust(100), 'ExitInsertMode')
    106    " CursorHoldI does not trigger after CTRL-X
    107    call feedkeys("a\<C-X>", 'x!')
    108    call assert_equal(0, g:triggered)
    109    unlet g:triggered
    110    au! CursorHoldI
    111    set updatetime&
    112  endfunc
    113 
    114  func Test_cursorhold_insert_ctrl_g_U()
    115    au CursorHoldI * :
    116    set updatetime=20
    117    new
    118    call timer_start(100, { -> feedkeys("\<Left>foo\<Esc>", 't') })
    119    call feedkeys("i()\<C-g>U", 'tx!')
    120    sleep 200m
    121    call assert_equal('(foo)', getline(1))
    122    undo
    123    call assert_equal('', getline(1))
    124 
    125    bwipe!
    126    au! CursorHoldI
    127    set updatetime&
    128  endfunc
    129 
    130  func Test_OptionSet_modeline()
    131    call Ntest_override('starting', 1)
    132    au! OptionSet
    133    augroup set_tabstop
    134      au OptionSet tabstop call timer_start(1, {-> execute("echo 'Handler called'", "")})
    135    augroup END
    136    call writefile(['vim: set ts=7 sw=5 :', 'something'], 'XoptionsetModeline', 'D')
    137    set modeline
    138    let v:errmsg = ''
    139    call assert_fails('split XoptionsetModeline', 'E12:')
    140    call assert_equal(7, &ts)
    141    call assert_equal('', v:errmsg)
    142 
    143    augroup set_tabstop
    144      au!
    145    augroup END
    146    bwipe!
    147    set ts&
    148    call Ntest_override('starting', 0)
    149  endfunc
    150 
    151 endif "has('timers')
    152 
    153 func Test_bufunload()
    154  augroup test_bufunload_group
    155    autocmd!
    156    autocmd BufUnload * call add(s:li, "bufunload")
    157    autocmd BufDelete * call add(s:li, "bufdelete")
    158    autocmd BufWipeout * call add(s:li, "bufwipeout")
    159  augroup END
    160 
    161  let s:li = []
    162  new
    163  setlocal bufhidden=
    164  bunload
    165  call assert_equal(["bufunload", "bufdelete"], s:li)
    166 
    167  let s:li = []
    168  new
    169  setlocal bufhidden=delete
    170  bunload
    171  call assert_equal(["bufunload", "bufdelete"], s:li)
    172 
    173  let s:li = []
    174  new
    175  setlocal bufhidden=unload
    176  bwipeout
    177  call assert_equal(["bufunload", "bufdelete", "bufwipeout"], s:li)
    178 
    179  au! test_bufunload_group
    180  augroup! test_bufunload_group
    181 endfunc
    182 
    183 " SEGV occurs in older versions.  (At least 7.4.2005 or older)
    184 func Test_autocmd_bufunload_with_tabnext()
    185  tabedit
    186  tabfirst
    187 
    188  augroup test_autocmd_bufunload_with_tabnext_group
    189    autocmd!
    190    autocmd BufUnload <buffer> tabnext
    191  augroup END
    192 
    193  quit
    194  call assert_equal(2, tabpagenr('$'))
    195 
    196  autocmd! test_autocmd_bufunload_with_tabnext_group
    197  augroup! test_autocmd_bufunload_with_tabnext_group
    198  tablast
    199  quit
    200 endfunc
    201 
    202 func Test_argdelete_in_next()
    203  au BufNew,BufEnter,BufLeave,BufWinEnter * argdel
    204  call assert_fails('next a b', 'E1156:')
    205  au! BufNew,BufEnter,BufLeave,BufWinEnter *
    206 endfunc
    207 
    208 func Test_autocmd_bufwinleave_with_tabfirst()
    209  tabedit
    210  augroup sample
    211    autocmd!
    212    autocmd BufWinLeave <buffer> tabfirst
    213  augroup END
    214  call setline(1, ['a', 'b', 'c'])
    215  edit! a.txt
    216  tabclose
    217 endfunc
    218 
    219 " SEGV occurs in older versions.  (At least 7.4.2321 or older)
    220 func Test_autocmd_bufunload_avoiding_SEGV_01()
    221  split aa.txt
    222  let lastbuf = bufnr('$')
    223 
    224  augroup test_autocmd_bufunload
    225    autocmd!
    226    exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!'
    227  augroup END
    228 
    229  call assert_fails('edit bb.txt', 'E937:')
    230 
    231  autocmd! test_autocmd_bufunload
    232  augroup! test_autocmd_bufunload
    233  bwipe! aa.txt
    234  bwipe! bb.txt
    235 endfunc
    236 
    237 " SEGV occurs in older versions.  (At least 7.4.2321 or older)
    238 func Test_autocmd_bufunload_avoiding_SEGV_02()
    239  setlocal buftype=nowrite
    240  let lastbuf = bufnr('$')
    241 
    242  augroup test_autocmd_bufunload
    243    autocmd!
    244    exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!'
    245  augroup END
    246 
    247  normal! i1
    248  call assert_fails('edit a.txt', 'E517:')
    249 
    250  autocmd! test_autocmd_bufunload
    251  augroup! test_autocmd_bufunload
    252  bwipe! a.txt
    253 endfunc
    254 
    255 func Test_autocmd_dummy_wipeout()
    256  " prepare files
    257  call writefile([''], 'Xdummywipetest1.txt', 'D')
    258  call writefile([''], 'Xdummywipetest2.txt', 'D')
    259  augroup test_bufunload_group
    260    autocmd!
    261    autocmd BufUnload * call add(s:li, "bufunload")
    262    autocmd BufDelete * call add(s:li, "bufdelete")
    263    autocmd BufWipeout * call add(s:li, "bufwipeout")
    264  augroup END
    265 
    266  let s:li = []
    267  split Xdummywipetest1.txt
    268  silent! vimgrep /notmatched/ Xdummywipetest*
    269  call assert_equal(["bufunload", "bufwipeout"], s:li)
    270 
    271  bwipeout
    272  au! test_bufunload_group
    273  augroup! test_bufunload_group
    274 endfunc
    275 
    276 func Test_win_tab_autocmd()
    277  let g:record = []
    278 
    279  defer CleanUpTestAuGroup()
    280  augroup testing
    281    au WinNewPre * call add(g:record, 'WinNewPre')
    282    au WinNew * call add(g:record, 'WinNew')
    283    au WinClosed * call add(g:record, 'WinClosed')
    284    au WinEnter * call add(g:record, 'WinEnter')
    285    au WinLeave * call add(g:record, 'WinLeave')
    286    au TabNew * call add(g:record, 'TabNew')
    287    au TabClosed * call add(g:record, 'TabClosed')
    288    au TabEnter * call add(g:record, 'TabEnter')
    289    au TabLeave * call add(g:record, 'TabLeave')
    290  augroup END
    291 
    292  split
    293  tabnew
    294  close
    295  close
    296 
    297  call assert_equal([
    298 \ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter',
    299 \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
    300 \ 'WinLeave', 'TabLeave', 'WinClosed', 'TabClosed', 'WinEnter', 'TabEnter',
    301 \ 'WinLeave', 'WinClosed', 'WinEnter'
    302 \ ], g:record)
    303 
    304  let g:record = []
    305  tabnew somefile
    306  tabnext
    307  bwipe somefile
    308 
    309  call assert_equal([
    310 \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
    311 \ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter',
    312 \ 'WinClosed', 'TabClosed'
    313 \ ], g:record)
    314 
    315  let g:record = []
    316  copen
    317  help
    318  tabnext
    319  vnew
    320 
    321  call assert_equal([
    322 \ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter',
    323 \ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter',
    324 \ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter'
    325 \ ], g:record)
    326 
    327  unlet g:record
    328 endfunc
    329 
    330 func Test_WinNewPre()
    331  " Test that the old window layout can be accessed before a new window is created.
    332  let g:layouts_pre = []
    333  let g:layouts_post = []
    334  augroup testing
    335    au WinNewPre * call add(g:layouts_pre, winlayout())
    336    au WinNew * call add(g:layouts_post, winlayout())
    337  augroup END
    338  defer CleanUpTestAuGroup()
    339  split
    340  call assert_notequal(g:layouts_pre[0], g:layouts_post[0])
    341  split
    342  call assert_equal(g:layouts_pre[1], g:layouts_post[0])
    343  call assert_notequal(g:layouts_pre[1], g:layouts_post[1])
    344  " not triggered for tabnew
    345  tabnew
    346  call assert_equal(2, len(g:layouts_pre))
    347  unlet g:layouts_pre
    348  unlet g:layouts_post
    349 
    350  " Test modifying window layout during WinNewPre throws.
    351  let g:caught = 0
    352  augroup testing
    353    au!
    354    au WinNewPre * split
    355  augroup END
    356  try
    357    vnew
    358  catch
    359    let g:caught += 1
    360  endtry
    361  augroup testing
    362    au!
    363    au WinNewPre * tabnew
    364  augroup END
    365  try
    366    vnew
    367  catch
    368    let g:caught += 1
    369  endtry
    370  augroup testing
    371    au!
    372    au WinNewPre * close
    373  augroup END
    374  try
    375    vnew
    376  catch
    377    let g:caught += 1
    378  endtry
    379  augroup testing
    380    au!
    381    au WinNewPre * tabclose
    382  augroup END
    383  try
    384    vnew
    385  catch
    386    let g:caught += 1
    387  endtry
    388  call assert_equal(4, g:caught)
    389  unlet g:caught
    390 endfunc
    391 
    392 func Test_WinResized()
    393  CheckRunVimInTerminal
    394 
    395  let lines =<< trim END
    396    set scrolloff=0
    397    call setline(1, ['111', '222'])
    398    vnew
    399    call setline(1, ['aaa', 'bbb'])
    400    new
    401    call setline(1, ['foo', 'bar'])
    402 
    403    let g:resized = 0
    404    au WinResized * let g:resized += 1
    405 
    406    func WriteResizedEvent()
    407      call writefile([json_encode(v:event)], 'XresizeEvent')
    408    endfunc
    409    au WinResized * call WriteResizedEvent()
    410  END
    411  call writefile(lines, 'Xtest_winresized', 'D')
    412  let buf = RunVimInTerminal('-S Xtest_winresized', {'rows': 10})
    413 
    414  " redraw now to avoid a redraw after the :echo command
    415  call term_sendkeys(buf, ":redraw!\<CR>")
    416  call TermWait(buf)
    417 
    418  call term_sendkeys(buf, ":echo g:resized\<CR>")
    419  call WaitForAssert({-> assert_match('^0$', term_getline(buf, 10))}, 1000)
    420 
    421  " increase window height, two windows will be reported
    422  call term_sendkeys(buf, "\<C-W>+")
    423  call TermWait(buf)
    424  call term_sendkeys(buf, ":echo g:resized\<CR>")
    425  call WaitForAssert({-> assert_match('^1$', term_getline(buf, 10))}, 1000)
    426 
    427  let event = readfile('XresizeEvent')[0]->json_decode()
    428  call assert_equal({
    429        \ 'windows': [1002, 1001],
    430        \ }, event)
    431 
    432  " increase window width, three windows will be reported
    433  call term_sendkeys(buf, "\<C-W>>")
    434  call TermWait(buf)
    435  call term_sendkeys(buf, ":echo g:resized\<CR>")
    436  call WaitForAssert({-> assert_match('^2$', term_getline(buf, 10))}, 1000)
    437 
    438  let event = readfile('XresizeEvent')[0]->json_decode()
    439  call assert_equal({
    440        \ 'windows': [1002, 1001, 1000],
    441        \ }, event)
    442 
    443  call delete('XresizeEvent')
    444  call StopVimInTerminal(buf)
    445 endfunc
    446 
    447 func Test_WinScrolled()
    448  CheckRunVimInTerminal
    449 
    450  let lines =<< trim END
    451    set nowrap scrolloff=0
    452    for ii in range(1, 18)
    453      call setline(ii, repeat(nr2char(96 + ii), ii * 2))
    454    endfor
    455    let win_id = win_getid()
    456    let g:matched = v:false
    457    func WriteScrollEvent()
    458      call writefile([json_encode(v:event)], 'XscrollEvent')
    459    endfunc
    460    execute 'au WinScrolled' win_id 'let g:matched = v:true'
    461    let g:scrolled = 0
    462    au WinScrolled * let g:scrolled += 1
    463    au WinScrolled * let g:amatch = str2nr(expand('<amatch>'))
    464    au WinScrolled * let g:afile = str2nr(expand('<afile>'))
    465    au WinScrolled * call WriteScrollEvent()
    466  END
    467  call writefile(lines, 'Xtest_winscrolled', 'D')
    468  let buf = RunVimInTerminal('-S Xtest_winscrolled', {'rows': 6})
    469 
    470  call term_sendkeys(buf, ":echo g:scrolled\<CR>")
    471  call WaitForAssert({-> assert_match('^0 ', term_getline(buf, 6))}, 1000)
    472 
    473  " Scroll left/right in Normal mode.
    474  call term_sendkeys(buf, "zlzh:echo g:scrolled\<CR>")
    475  call WaitForAssert({-> assert_match('^2 ', term_getline(buf, 6))}, 1000)
    476 
    477  let event = readfile('XscrollEvent')[0]->json_decode()
    478  call assert_equal({
    479        \ 'all': {'leftcol': 1, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
    480        \ '1000': {'leftcol': -1, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}
    481        \ }, event)
    482 
    483  " Scroll up/down in Normal mode.
    484  call term_sendkeys(buf, "\<c-e>\<c-y>:echo g:scrolled\<CR>")
    485  call WaitForAssert({-> assert_match('^4 ', term_getline(buf, 6))}, 1000)
    486 
    487  let event = readfile('XscrollEvent')[0]->json_decode()
    488  call assert_equal({
    489        \ 'all': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
    490        \ '1000': {'leftcol': 0, 'topline': -1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}
    491        \ }, event)
    492 
    493  " Scroll up/down in Insert mode.
    494  call term_sendkeys(buf, "Mi\<c-x>\<c-e>\<Esc>i\<c-x>\<c-y>\<Esc>")
    495  call term_sendkeys(buf, ":echo g:scrolled\<CR>")
    496  call WaitForAssert({-> assert_match('^6 ', term_getline(buf, 6))}, 1000)
    497 
    498  let event = readfile('XscrollEvent')[0]->json_decode()
    499  call assert_equal({
    500        \ 'all': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
    501        \ '1000': {'leftcol': 0, 'topline': -1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}
    502        \ }, event)
    503 
    504  " Scroll the window horizontally to focus the last letter of the third line
    505  " containing only six characters. Moving to the previous and shorter lines
    506  " should trigger another autocommand as Vim has to make them visible.
    507  call term_sendkeys(buf, "5zl2k")
    508  call term_sendkeys(buf, ":echo g:scrolled\<CR>")
    509  call WaitForAssert({-> assert_match('^8 ', term_getline(buf, 6))}, 1000)
    510 
    511  let event = readfile('XscrollEvent')[0]->json_decode()
    512  call assert_equal({
    513        \ 'all': {'leftcol': 5, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
    514        \ '1000': {'leftcol': -5, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}
    515        \ }, event)
    516 
    517  " Ensure the command was triggered for the specified window ID.
    518  call term_sendkeys(buf, ":echo g:matched\<CR>")
    519  call WaitForAssert({-> assert_match('^v:true ', term_getline(buf, 6))}, 1000)
    520 
    521  " Ensure the expansion of <amatch> and <afile> matches the window ID.
    522  call term_sendkeys(buf, ":echo g:amatch == win_id && g:afile == win_id\<CR>")
    523  call WaitForAssert({-> assert_match('^v:true ', term_getline(buf, 6))}, 1000)
    524 
    525  call delete('XscrollEvent')
    526  call StopVimInTerminal(buf)
    527 endfunc
    528 
    529 func Test_WinScrolled_mouse()
    530  CheckRunVimInTerminal
    531 
    532  let lines =<< trim END
    533    set nowrap scrolloff=0
    534    set mouse=a term=xterm ttymouse=sgr mousetime=200 clipboard=
    535    call setline(1, ['foo']->repeat(32))
    536    split
    537    let g:scrolled = 0
    538    au WinScrolled * let g:scrolled += 1
    539  END
    540  call writefile(lines, 'Xtest_winscrolled_mouse', 'D')
    541  let buf = RunVimInTerminal('-S Xtest_winscrolled_mouse', {'rows': 10})
    542 
    543  " With the upper split focused, send a scroll-down event to the unfocused one.
    544  call test_setmouse(7, 1)
    545  call term_sendkeys(buf, "\<ScrollWheelDown>")
    546  call TermWait(buf)
    547  call term_sendkeys(buf, ":echo g:scrolled\<CR>")
    548  call WaitForAssert({-> assert_match('^1', term_getline(buf, 10))}, 1000)
    549 
    550  " Again, but this time while we're in insert mode.
    551  call term_sendkeys(buf, "i\<ScrollWheelDown>\<Esc>")
    552  call TermWait(buf)
    553  call term_sendkeys(buf, ":echo g:scrolled\<CR>")
    554  call WaitForAssert({-> assert_match('^2', term_getline(buf, 10))}, 1000)
    555 
    556  call StopVimInTerminal(buf)
    557 endfunc
    558 
    559 func Test_WinScrolled_close_curwin()
    560  CheckRunVimInTerminal
    561 
    562  let lines =<< trim END
    563    set nowrap scrolloff=0
    564    call setline(1, ['aaa', 'bbb'])
    565    vsplit
    566    au WinScrolled * close
    567    au VimLeave * call writefile(['123456'], 'Xtestout')
    568  END
    569  call writefile(lines, 'Xtest_winscrolled_close_curwin', 'D')
    570  let buf = RunVimInTerminal('-S Xtest_winscrolled_close_curwin', {'rows': 6})
    571 
    572  " This was using freed memory
    573  call term_sendkeys(buf, "\<C-E>")
    574  call TermWait(buf)
    575  call StopVimInTerminal(buf)
    576 
    577  " check the startup script finished to the end
    578  call assert_equal(['123456'], readfile('Xtestout'))
    579  call delete('Xtestout')
    580 endfunc
    581 
    582 func Test_WinScrolled_once_only()
    583  CheckScreendump
    584  CheckRunVimInTerminal
    585 
    586  let lines =<< trim END
    587      set cmdheight=2
    588      call setline(1, ['aaa', 'bbb'])
    589      let trigger_count = 0
    590      func ShowInfo(id)
    591        echo g:trigger_count g:winid winlayout()
    592      endfunc
    593 
    594      vsplit
    595      split
    596      " use a timer to show the info after a redraw
    597      au WinScrolled * let trigger_count += 1 | let winid = expand('<amatch>') | call timer_start(100, 'ShowInfo')
    598      wincmd j
    599      wincmd l
    600  END
    601  call writefile(lines, 'Xtest_winscrolled_once', 'D')
    602  let buf = RunVimInTerminal('-S Xtest_winscrolled_once', #{rows: 10, cols: 60, statusoff: 2})
    603 
    604  call term_sendkeys(buf, "\<C-E>")
    605  call VerifyScreenDump(buf, 'Test_winscrolled_once_only_1', {})
    606 
    607  call StopVimInTerminal(buf)
    608 endfunc
    609 
    610 " Check that WinScrolled is not triggered immediately when defined and there
    611 " are split windows.
    612 func Test_WinScrolled_not_when_defined()
    613  CheckScreendump
    614  CheckRunVimInTerminal
    615 
    616  let lines =<< trim END
    617      call setline(1, ['aaa', 'bbb'])
    618      echo 'nothing happened'
    619      func ShowTriggered(id)
    620        echo 'triggered'
    621      endfunc
    622  END
    623  call writefile(lines, 'Xtest_winscrolled_not', 'D')
    624  let buf = RunVimInTerminal('-S Xtest_winscrolled_not', #{rows: 10, cols: 60, statusoff: 2})
    625  call term_sendkeys(buf, ":split\<CR>")
    626  call TermWait(buf)
    627  " use a timer to show the message after redrawing
    628  call term_sendkeys(buf, ":au WinScrolled * call timer_start(100, 'ShowTriggered')\<CR>")
    629  call VerifyScreenDump(buf, 'Test_winscrolled_not_when_defined_1', {})
    630 
    631  call term_sendkeys(buf, "\<C-E>")
    632  call VerifyScreenDump(buf, 'Test_winscrolled_not_when_defined_2', {})
    633 
    634  call StopVimInTerminal(buf)
    635 endfunc
    636 
    637 func Test_WinScrolled_long_wrapped()
    638  CheckRunVimInTerminal
    639 
    640  let lines =<< trim END
    641    set scrolloff=0
    642    let height = winheight(0)
    643    let width = winwidth(0)
    644    let g:scrolled = 0
    645    au WinScrolled * let g:scrolled += 1
    646    call setline(1, repeat('foo', height * width))
    647    call cursor(1, height * width)
    648  END
    649  call writefile(lines, 'Xtest_winscrolled_long_wrapped', 'D')
    650  let buf = RunVimInTerminal('-S Xtest_winscrolled_long_wrapped', {'rows': 6})
    651 
    652  call term_sendkeys(buf, ":echo g:scrolled\<CR>")
    653  call WaitForAssert({-> assert_match('^0 ', term_getline(buf, 6))}, 1000)
    654 
    655  call term_sendkeys(buf, 'gj')
    656  call term_sendkeys(buf, ":echo g:scrolled\<CR>")
    657  call WaitForAssert({-> assert_match('^1 ', term_getline(buf, 6))}, 1000)
    658 
    659  call term_sendkeys(buf, '0')
    660  call term_sendkeys(buf, ":echo g:scrolled\<CR>")
    661  call WaitForAssert({-> assert_match('^2 ', term_getline(buf, 6))}, 1000)
    662 
    663  call term_sendkeys(buf, '$')
    664  call term_sendkeys(buf, ":echo g:scrolled\<CR>")
    665  call WaitForAssert({-> assert_match('^3 ', term_getline(buf, 6))}, 1000)
    666 
    667  call StopVimInTerminal(buf)
    668 endfunc
    669 
    670 func Test_WinScrolled_diff()
    671  CheckRunVimInTerminal
    672 
    673  let lines =<< trim END
    674    set diffopt+=foldcolumn:0
    675    call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])
    676    vnew
    677    call setline(1, ['d', 'e', 'f', 'g', 'h', 'i'])
    678    windo diffthis
    679    func WriteScrollEvent()
    680      call writefile([json_encode(v:event)], 'XscrollEvent')
    681    endfunc
    682    au WinScrolled * call WriteScrollEvent()
    683  END
    684  call writefile(lines, 'Xtest_winscrolled_diff', 'D')
    685  let buf = RunVimInTerminal('-S Xtest_winscrolled_diff', {'rows': 8})
    686 
    687  call term_sendkeys(buf, "\<C-E>")
    688  call WaitForAssert({-> assert_match('^d', term_getline(buf, 3))}, 1000)
    689 
    690  let event = readfile('XscrollEvent')[0]->json_decode()
    691  call assert_equal({
    692        \ 'all': {'leftcol': 0, 'topline': 1, 'topfill': 1, 'width': 0, 'height': 0, 'skipcol': 0},
    693        \ '1000': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
    694        \ '1001': {'leftcol': 0, 'topline': 0, 'topfill': -1, 'width': 0, 'height': 0, 'skipcol': 0}
    695        \ }, event)
    696 
    697  call term_sendkeys(buf, "2\<C-E>")
    698  call WaitForAssert({-> assert_match('^f', term_getline(buf, 3))}, 1000)
    699 
    700  let event = readfile('XscrollEvent')[0]->json_decode()
    701  call assert_equal({
    702        \ 'all': {'leftcol': 0, 'topline': 2, 'topfill': 2, 'width': 0, 'height': 0, 'skipcol': 0},
    703        \ '1000': {'leftcol': 0, 'topline': 2, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
    704        \ '1001': {'leftcol': 0, 'topline': 0, 'topfill': -2, 'width': 0, 'height': 0, 'skipcol': 0}
    705        \ }, event)
    706 
    707  call term_sendkeys(buf, "\<C-E>")
    708  call WaitForAssert({-> assert_match('^g', term_getline(buf, 3))}, 1000)
    709 
    710  let event = readfile('XscrollEvent')[0]->json_decode()
    711  call assert_equal({
    712        \ 'all': {'leftcol': 0, 'topline': 2, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
    713        \ '1000': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
    714        \ '1001': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}
    715        \ }, event)
    716 
    717  call term_sendkeys(buf, "2\<C-Y>")
    718  call WaitForAssert({-> assert_match('^e', term_getline(buf, 3))}, 1000)
    719 
    720  let event = readfile('XscrollEvent')[0]->json_decode()
    721  call assert_equal({
    722        \ 'all': {'leftcol': 0, 'topline': 3, 'topfill': 1, 'width': 0, 'height': 0, 'skipcol': 0},
    723        \ '1000': {'leftcol': 0, 'topline': -2, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
    724        \ '1001': {'leftcol': 0, 'topline': -1, 'topfill': 1, 'width': 0, 'height': 0, 'skipcol': 0}
    725        \ }, event)
    726 
    727  call StopVimInTerminal(buf)
    728  call delete('XscrollEvent')
    729 endfunc
    730 
    731 func Test_WinClosed()
    732  " Test that the pattern is matched against the closed window's ID, and both
    733  " <amatch> and <afile> are set to it.
    734  new
    735  let winid = win_getid()
    736  let g:matched = v:false
    737  augroup test-WinClosed
    738    autocmd!
    739    execute 'autocmd WinClosed' winid 'let g:matched = v:true'
    740    autocmd WinClosed * let g:amatch = str2nr(expand('<amatch>'))
    741    autocmd WinClosed * let g:afile = str2nr(expand('<afile>'))
    742  augroup END
    743  close
    744  call assert_true(g:matched)
    745  call assert_equal(winid, g:amatch)
    746  call assert_equal(winid, g:afile)
    747 
    748  " Test that WinClosed is non-recursive.
    749  new
    750  new
    751  call assert_equal(3, winnr('$'))
    752  let g:triggered = 0
    753  augroup test-WinClosed
    754    autocmd!
    755    autocmd WinClosed * let g:triggered += 1
    756    autocmd WinClosed * 2 wincmd c
    757  augroup END
    758  close
    759  call assert_equal(1, winnr('$'))
    760  call assert_equal(1, g:triggered)
    761 
    762  autocmd! test-WinClosed
    763  augroup! test-WinClosed
    764  unlet g:matched
    765  unlet g:amatch
    766  unlet g:afile
    767  unlet g:triggered
    768 endfunc
    769 
    770 func Test_WinClosed_throws()
    771  vnew
    772  let bnr = bufnr()
    773  call assert_equal(1, bufloaded(bnr))
    774  augroup test-WinClosed
    775    autocmd WinClosed * throw 'foo'
    776  augroup END
    777  try
    778    close
    779  catch /.*/
    780  endtry
    781  call assert_equal(0, bufloaded(bnr))
    782 
    783  autocmd! test-WinClosed
    784  augroup! test-WinClosed
    785 endfunc
    786 
    787 func Test_WinClosed_throws_with_tabs()
    788  tabnew
    789  let bnr = bufnr()
    790  call assert_equal(1, bufloaded(bnr))
    791  augroup test-WinClosed
    792    autocmd WinClosed * throw 'foo'
    793  augroup END
    794  try
    795    close
    796  catch /.*/
    797  endtry
    798  call assert_equal(0, bufloaded(bnr))
    799 
    800  autocmd! test-WinClosed
    801  augroup! test-WinClosed
    802 endfunc
    803 
    804 " This used to trigger WinClosed twice for the same window, and the window's
    805 " buffer was NULL in the second autocommand.
    806 func Test_WinClosed_switch_tab()
    807  edit Xa
    808  split Xb
    809  split Xc
    810  tab split
    811  new
    812  augroup test-WinClosed
    813    autocmd WinClosed * tabprev | bwipe!
    814  augroup END
    815  close
    816  " Check that the tabline has been fully removed
    817  call assert_equal([1, 1], win_screenpos(0))
    818 
    819  autocmd! test-WinClosed
    820  augroup! test-WinClosed
    821  %bwipe!
    822 endfunc
    823 
    824 " This used to trigger WinClosed/WinLeave/BufLeave twice for the same window,
    825 " and the window's buffer was NULL in the second autocommand.
    826 func Run_test_BufUnload_close_other(extra_cmd)
    827  let oldtab = tabpagenr()
    828  tabnew Xb1
    829  let g:tab = tabpagenr()
    830  let g:w1 = win_getid()
    831  new Xb2
    832  let g:w2 = win_getid()
    833  let g:log = []
    834  exe a:extra_cmd
    835 
    836  augroup test-BufUnload-close-other
    837    autocmd BufUnload * ++nested ++once bwipe! Xb1
    838    for event in ['WinClosed', 'BufLeave', 'WinLeave', 'TabLeave']
    839      exe $'autocmd {event} * call tabpagebuflist(g:tab)'
    840      exe $'autocmd {event} * let g:log += ["{event}:" .. expand("<afile>")]'
    841    endfor
    842  augroup END
    843 
    844  close
    845  " WinClosed is triggered once for each of the 2 closed windows.
    846  " Others are only triggered once.
    847  call assert_equal(['BufLeave:Xb2', 'WinLeave:Xb2', $'WinClosed:{g:w2}',
    848        \ $'WinClosed:{g:w1}', 'TabLeave:Xb2'], g:log)
    849  call assert_equal(oldtab, tabpagenr())
    850  call assert_equal([0, 0], win_id2tabwin(g:w1))
    851  call assert_equal([0, 0], win_id2tabwin(g:w2))
    852 
    853  unlet g:tab
    854  unlet g:w1
    855  unlet g:w2
    856  unlet g:log
    857  autocmd! test-BufUnload-close-other
    858  augroup! test-BufUnload-close-other
    859  %bwipe!
    860 endfunc
    861 
    862 func Test_BufUnload_close_other()
    863  call Run_test_BufUnload_close_other('')
    864  call Run_test_BufUnload_close_other('setlocal bufhidden=wipe')
    865 endfunc
    866 
    867 func Run_test_BufUnload_tabonly(first_cmd)
    868  exe a:first_cmd
    869  tabnew Xa
    870  setlocal bufhidden=wipe
    871  tabprevious
    872  autocmd BufWinLeave Xa ++once tabnext
    873  autocmd BufUnload Xa ++once tabonly
    874  tabonly
    875 
    876  %bwipe!
    877 endfunc
    878 
    879 func Test_BufUnload_tabonly()
    880  " This used to dereference a NULL curbuf.
    881  call Run_test_BufUnload_tabonly('setlocal bufhidden=hide')
    882  " This used to dereference a NULL firstbuf.
    883  call Run_test_BufUnload_tabonly('setlocal bufhidden=wipe')
    884 endfunc
    885 
    886 func Run_test_BufUnload_tabonly_nested(second_autocmd)
    887  file Xa
    888  tabnew Xb
    889  setlocal bufhidden=wipe
    890  tabnew Xc
    891  setlocal bufhidden=wipe
    892  autocmd BufUnload Xb ++once ++nested bwipe! Xa
    893  exe $'autocmd BufUnload Xa ++once ++nested {a:second_autocmd}'
    894  autocmd BufWinLeave Xc ++once tabnext
    895  tabfirst
    896  2tabclose
    897 
    898  %bwipe!
    899 endfunc
    900 
    901 func Test_BufUnload_tabonly_nested()
    902  " These used to cause heap-use-after-free.
    903  call Run_test_BufUnload_tabonly_nested('tabonly')
    904  call Run_test_BufUnload_tabonly_nested('tabonly | tabprevious')
    905 endfunc
    906 
    907 func s:AddAnAutocmd()
    908  augroup vimBarTest
    909    au BufReadCmd * echo 'hello'
    910  augroup END
    911  call assert_equal(3, len(split(execute('au vimBarTest'), "\n")))
    912 endfunc
    913 
    914 func Test_early_bar()
    915  " test that a bar is recognized before the {event}
    916  call s:AddAnAutocmd()
    917  augroup vimBarTest | au! | let done = 77 | augroup END
    918  call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
    919  call assert_equal(77, done)
    920 
    921  call s:AddAnAutocmd()
    922  augroup vimBarTest| au!| let done = 88 | augroup END
    923  call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
    924  call assert_equal(88, done)
    925 
    926  " test that a bar is recognized after the {event}
    927  call s:AddAnAutocmd()
    928  augroup vimBarTest| au!BufReadCmd| let done = 99 | augroup END
    929  call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
    930  call assert_equal(99, done)
    931 
    932  " test that a bar is recognized after the {group}
    933  call s:AddAnAutocmd()
    934  au! vimBarTest|echo 'hello'
    935  call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
    936 endfunc
    937 
    938 func RemoveGroup()
    939  autocmd! StartOK
    940  augroup! StartOK
    941 endfunc
    942 
    943 func Test_augroup_warning()
    944  augroup TheWarning
    945    au VimEnter * echo 'entering'
    946  augroup END
    947  call assert_match("TheWarning.*VimEnter", execute('au VimEnter'))
    948  redir => res
    949  augroup! TheWarning
    950  redir END
    951  call assert_match("W19:", res)
    952  call assert_match("-Deleted-.*VimEnter", execute('au VimEnter'))
    953 
    954  " check "Another" does not take the pace of the deleted entry
    955  augroup Another
    956  augroup END
    957  call assert_match("-Deleted-.*VimEnter", execute('au VimEnter'))
    958  augroup! Another
    959 
    960  " no warning for postpone aucmd delete
    961  augroup StartOK
    962    au VimEnter * call RemoveGroup()
    963  augroup END
    964  call assert_match("StartOK.*VimEnter", execute('au VimEnter'))
    965  redir => res
    966  doautocmd VimEnter
    967  redir END
    968  call assert_notmatch("W19:", res)
    969  au! VimEnter
    970 
    971  call assert_fails('augroup!', 'E471:')
    972 endfunc
    973 
    974 func Test_BufReadCmdHelp()
    975  " This used to cause access to free memory
    976  au BufReadCmd * e +h
    977  help
    978 
    979  au! BufReadCmd
    980 endfunc
    981 
    982 func Test_BufReadCmdHelpJump()
    983  " This used to cause access to free memory
    984  au BufReadCmd * e +h{
    985  " } to fix highlighting
    986  call assert_fails('help', 'E434:')
    987 
    988  au! BufReadCmd
    989 endfunc
    990 
    991 " BufReadCmd is triggered for a "nofile" buffer. Check all values.
    992 func Test_BufReadCmdNofile()
    993  for val in ['nofile',
    994            \ 'nowrite',
    995            \ 'acwrite',
    996            \ 'quickfix',
    997            \ 'help',
    998            "\ 'terminal',
    999            "\ 'prompt',
   1000            "\ 'popup',
   1001            \ ]
   1002    new somefile
   1003    exe 'set buftype=' .. val
   1004    au BufReadCmd somefile call setline(1, 'triggered')
   1005    edit
   1006    call assert_equal('triggered', getline(1))
   1007 
   1008    au! BufReadCmd
   1009    bwipe!
   1010  endfor
   1011 endfunc
   1012 
   1013 func Test_augroup_deleted()
   1014  " This caused a crash before E936 was introduced
   1015  augroup x
   1016    call assert_fails('augroup! x', 'E936:')
   1017    au VimEnter * echo
   1018  augroup end
   1019  augroup! x
   1020  call assert_match("-Deleted-.*VimEnter", execute('au VimEnter'))
   1021  au! VimEnter
   1022 endfunc
   1023 
   1024 " Tests for autocommands on :close command.
   1025 " This used to be in test13.
   1026 func Test_three_windows()
   1027  " Clean up buffers, because in some cases this function fails.
   1028  call s:cleanup_buffers()
   1029 
   1030  " Write three files and open them, each in a window.
   1031  " Then go to next window, with autocommand that deletes the previous one.
   1032  " Do this twice, writing the file.
   1033  e! Xtestje1
   1034  call setline(1, 'testje1')
   1035  w
   1036  sp Xtestje2
   1037  call setline(1, 'testje2')
   1038  w
   1039  sp Xtestje3
   1040  call setline(1, 'testje3')
   1041  w
   1042  wincmd w
   1043  au WinLeave Xtestje2 bwipe
   1044  wincmd w
   1045  call assert_equal('Xtestje1', expand('%'))
   1046 
   1047  au WinLeave Xtestje1 bwipe Xtestje3
   1048  close
   1049  call assert_equal('Xtestje1', expand('%'))
   1050 
   1051  " Test deleting the buffer on a Unload event.  If this goes wrong there
   1052  " will be the ATTENTION prompt.
   1053  e Xtestje1
   1054  au!
   1055  au! BufUnload Xtestje1 bwipe
   1056  call assert_fails('e Xtestje3', 'E937:')
   1057  call assert_equal('Xtestje3', expand('%'))
   1058 
   1059  e Xtestje2
   1060  sp Xtestje1
   1061  call assert_fails('e', 'E937:')
   1062  call assert_equal('Xtestje1', expand('%'))
   1063 
   1064  " Test changing buffers in a BufWipeout autocommand.  If this goes wrong
   1065  " there are ml_line errors and/or a Crash.
   1066  au!
   1067  only
   1068  e Xanother
   1069  e Xtestje1
   1070  bwipe Xtestje2
   1071  bwipe Xtestje3
   1072  au BufWipeout Xtestje1 buf Xtestje1
   1073  bwipe
   1074  call assert_equal('Xanother', expand('%'))
   1075 
   1076  only
   1077 
   1078  help
   1079  wincmd w
   1080  1quit
   1081  call assert_equal('Xanother', expand('%'))
   1082 
   1083  au!
   1084  enew
   1085  call delete('Xtestje1')
   1086  call delete('Xtestje2')
   1087  call delete('Xtestje3')
   1088 endfunc
   1089 
   1090 func Test_BufEnter()
   1091  au! BufEnter
   1092  au Bufenter * let val = val . '+'
   1093  let g:val = ''
   1094  split NewFile
   1095  call assert_equal('+', g:val)
   1096  bwipe!
   1097  call assert_equal('++', g:val)
   1098 
   1099  " Also get BufEnter when editing a directory
   1100  call mkdir('Xbufenterdir', 'D')
   1101  split Xbufenterdir
   1102  call assert_equal('+++', g:val)
   1103 
   1104  " On MS-Windows we can't edit the directory, make sure we wipe the right
   1105  " buffer.
   1106  bwipe! Xbufenterdir
   1107  au! BufEnter
   1108 
   1109  " Editing a "nofile" buffer doesn't read the file but does trigger BufEnter
   1110  " for historic reasons.  Also test other 'buftype' values.
   1111  for val in ['nofile',
   1112            \ 'nowrite',
   1113            \ 'acwrite',
   1114            \ 'quickfix',
   1115            \ 'help',
   1116            "\ 'terminal',
   1117            "\ 'prompt',
   1118            "\ 'popup',
   1119            \ ]
   1120    new somefile
   1121    exe 'set buftype=' .. val
   1122    au BufEnter somefile call setline(1, 'some text')
   1123    edit
   1124    call assert_equal('some text', getline(1))
   1125    bwipe!
   1126    au! BufEnter
   1127  endfor
   1128 
   1129  new
   1130  new
   1131  autocmd BufEnter * ++once close
   1132  call assert_fails('close', 'E1312:')
   1133 
   1134  au! BufEnter
   1135  only
   1136 endfunc
   1137 
   1138 func Test_autocmd_SessLoadPre()
   1139  tabnew
   1140  set noswapfile
   1141  mksession! Session.vim
   1142 
   1143  call assert_false(exists('g:session_loaded_var'))
   1144 
   1145  let content =<< trim [CODE]
   1146    set nocp noswapfile
   1147 
   1148    func! Assert(cond, msg)
   1149      if !a:cond
   1150        echomsg "ASSERT_FAIL: " .. a:msg
   1151      else
   1152        echomsg "ASSERT_OK: " .. a:msg
   1153      endif
   1154    endfunc
   1155 
   1156    func! OnSessionLoadPre()
   1157      call Assert(!exists('g:session_loaded_var'),
   1158            \ 'SessionLoadPre: var NOT set')
   1159    endfunc
   1160    au SessionLoadPre * call OnSessionLoadPre()
   1161 
   1162    func! OnSessionLoadPost()
   1163      call Assert(exists('g:session_loaded_var'),
   1164            \ 'SessionLoadPost: var IS set')
   1165      echomsg "SessionLoadPost DONE"
   1166    endfunc
   1167    au SessionLoadPost * call OnSessionLoadPost()
   1168 
   1169    func! WriteErrors()
   1170      call writefile([execute("messages")], "XerrorsPost")
   1171    endfunc
   1172    au VimLeave * call WriteErrors()
   1173  [CODE]
   1174 
   1175  call writefile(content, 'Xvimrc', 'D')
   1176 
   1177  call writefile(
   1178        \ ['let g:session_loaded_var = 1'],
   1179        \ 'Sessionx.vim',
   1180        \ 'b'
   1181        \ )
   1182 
   1183  " --- Run child Vim ---
   1184  call system(
   1185        \ GetVimCommand('Xvimrc')
   1186        \ .. ' --headless --noplugins -S Session.vim -c cq'
   1187        \ )
   1188 
   1189  call WaitForAssert({-> assert_true(filereadable('XerrorsPost'))})
   1190 
   1191  let errors = join(readfile('XerrorsPost'), "\n")
   1192  call assert_notmatch('ASSERT_FAIL', errors)
   1193  call assert_match('ASSERT_OK: SessionLoadPre: var NOT set', errors)
   1194  call assert_match('ASSERT_OK: SessionLoadPost: var IS set', errors)
   1195  call assert_match('SessionLoadPost DONE', errors)
   1196 
   1197  set swapfile
   1198  for file in ['Session.vim', 'Sessionx.vim', 'XerrorsPost']
   1199    call delete(file)
   1200  endfor
   1201 endfunc
   1202 
   1203 " Closing a window might cause an endless loop
   1204 " E814 for older Vims
   1205 func Test_autocmd_bufwipe_in_SessLoadPost()
   1206  edit Xtest
   1207  tabnew
   1208  file Xsomething
   1209  set noswapfile
   1210  mksession!
   1211 
   1212  let content =<< trim [CODE]
   1213    set nocp noswapfile
   1214    let v:swapchoice = "e"
   1215    augroup test_autocmd_sessionload
   1216    autocmd!
   1217    autocmd SessionLoadPost * exe bufnr("Xsomething") . "bw!"
   1218    augroup END
   1219 
   1220    func WriteErrors()
   1221      call writefile([execute("messages")], "XerrorsBwipe")
   1222    endfunc
   1223    au VimLeave * call WriteErrors()
   1224  [CODE]
   1225 
   1226  call writefile(content, 'Xvimrc', 'D')
   1227  call system(GetVimCommand('Xvimrc') .. ' --headless --noplugins -S Session.vim -c cq')
   1228  sleep 100m
   1229  let errors = join(readfile('XerrorsBwipe'))
   1230  call assert_match('E814:', errors)
   1231 
   1232  set swapfile
   1233  for file in ['Session.vim', 'XerrorsBwipe']
   1234    call delete(file)
   1235  endfor
   1236 endfunc
   1237 
   1238 " Using :blast and :ball for many events caused a crash, because b_nwindows was
   1239 " not incremented correctly.
   1240 func Test_autocmd_blast_badd()
   1241  let content =<< trim [CODE]
   1242      au BufNew,BufAdd,BufWinEnter,BufEnter,BufLeave,BufWinLeave,BufUnload,VimEnter foo* blast
   1243      edit foo1
   1244      au BufNew,BufAdd,BufWinEnter,BufEnter,BufLeave,BufWinLeave,BufUnload,VimEnter foo* ball
   1245      edit foo2
   1246      call writefile(['OK'], 'XerrorsBlast')
   1247      qall
   1248  [CODE]
   1249 
   1250  call writefile(content, 'XblastBall', 'D')
   1251  call system(GetVimCommand() .. ' --clean -S XblastBall')
   1252  sleep 100m
   1253  call assert_match('OK', readfile('XerrorsBlast')->join())
   1254 
   1255  call delete('XerrorsBlast')
   1256 endfunc
   1257 
   1258 " SEGV occurs in older versions.
   1259 func Test_autocmd_bufwipe_in_SessLoadPost2()
   1260  tabnew
   1261  set noswapfile
   1262  mksession!
   1263 
   1264  let content =<< trim [CODE]
   1265    set nocp noswapfile
   1266    function! DeleteInactiveBufs()
   1267      tabfirst
   1268      let tabblist = []
   1269      for i in range(1, tabpagenr(''$''))
   1270        call extend(tabblist, tabpagebuflist(i))
   1271      endfor
   1272      for b in range(1, bufnr(''$''))
   1273        if bufexists(b) && buflisted(b) && (index(tabblist, b) == -1 || bufname(b) =~# ''^$'')
   1274          exec ''bwipeout '' . b
   1275        endif
   1276      endfor
   1277      echomsg "SessionLoadPost DONE"
   1278    endfunction
   1279    au SessionLoadPost * call DeleteInactiveBufs()
   1280 
   1281    func WriteErrors()
   1282      call writefile([execute("messages")], "XerrorsPost")
   1283    endfunc
   1284    au VimLeave * call WriteErrors()
   1285  [CODE]
   1286 
   1287  call writefile(content, 'Xvimrc', 'D')
   1288  call system(GetVimCommand('Xvimrc') .. ' --headless --noplugins -S Session.vim -c cq')
   1289  sleep 100m
   1290  let errors = join(readfile('XerrorsPost'))
   1291  " This probably only ever matches on unix.
   1292  call assert_notmatch('Caught deadly signal SEGV', errors)
   1293  call assert_match('SessionLoadPost DONE', errors)
   1294 
   1295  set swapfile
   1296  for file in ['Session.vim', 'XerrorsPost']
   1297    call delete(file)
   1298  endfor
   1299 endfunc
   1300 
   1301 func Test_empty_doau()
   1302  doau \|
   1303 endfunc
   1304 
   1305 func s:AutoCommandOptionSet(match)
   1306  let template = "Option: <%s>, OldVal: <%s>, OldValLocal: <%s>, OldValGlobal: <%s>, NewVal: <%s>, Scope: <%s>, Command: <%s>\n"
   1307  let item     = remove(g:options, 0)
   1308  let expected = printf(template, item[0], item[1], item[2], item[3], item[4], item[5], item[6])
   1309  let actual   = printf(template, a:match, v:option_old, v:option_oldlocal, v:option_oldglobal, v:option_new, v:option_type, v:option_command)
   1310  let g:opt    = [expected, actual]
   1311  "call assert_equal(expected, actual)
   1312 endfunc
   1313 
   1314 func Test_OptionSet()
   1315  " Use test/functional/legacy/autocmd_option_spec.lua
   1316  throw 'Skipped: Nvim changed types of OptionSet v: variables'
   1317  CheckOption autochdir
   1318 
   1319  call test_override('starting', 1)
   1320  set nocp
   1321  au OptionSet * :call s:AutoCommandOptionSet(expand("<amatch>"))
   1322 
   1323  " 1: Setting number option"
   1324  let g:options = [['number', 0, 0, 0, 1, 'global', 'set']]
   1325  set nu
   1326  call assert_equal([], g:options)
   1327  call assert_equal(g:opt[0], g:opt[1])
   1328 
   1329  " 2: Setting local number option"
   1330  let g:options = [['number', 1, 1, '', 0, 'local', 'setlocal']]
   1331  setlocal nonu
   1332  call assert_equal([], g:options)
   1333  call assert_equal(g:opt[0], g:opt[1])
   1334 
   1335  " 3: Setting global number option"
   1336  let g:options = [['number', 1, '', 1, 0, 'global', 'setglobal']]
   1337  setglobal nonu
   1338  call assert_equal([], g:options)
   1339  call assert_equal(g:opt[0], g:opt[1])
   1340 
   1341  " 4: Setting local autoindent option"
   1342  let g:options = [['autoindent', 0, 0, '', 1, 'local', 'setlocal']]
   1343  setlocal ai
   1344  call assert_equal([], g:options)
   1345  call assert_equal(g:opt[0], g:opt[1])
   1346 
   1347  " 5: Setting global autoindent option"
   1348  let g:options = [['autoindent', 0, '', 0, 1, 'global', 'setglobal']]
   1349  setglobal ai
   1350  call assert_equal([], g:options)
   1351  call assert_equal(g:opt[0], g:opt[1])
   1352 
   1353  " 6: Setting global autoindent option"
   1354  let g:options = [['autoindent', 1, 1, 1, 0, 'global', 'set']]
   1355  set ai!
   1356  call assert_equal([], g:options)
   1357  call assert_equal(g:opt[0], g:opt[1])
   1358 
   1359  " 6a: Setting global autoindent option"
   1360  let g:options = [['autoindent', 1, 1, 0, 0, 'global', 'set']]
   1361  noa setlocal ai
   1362  noa setglobal noai
   1363  set ai!
   1364  call assert_equal([], g:options)
   1365  call assert_equal(g:opt[0], g:opt[1])
   1366 
   1367  " Should not print anything, use :noa
   1368  " 7: don't trigger OptionSet"
   1369  let g:options = [['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']]
   1370  noa set nonu
   1371  call assert_equal([['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']], g:options)
   1372  call assert_equal(g:opt[0], g:opt[1])
   1373 
   1374  " 8: Setting several global list and number option"
   1375  let g:options = [['list', 0, 0, 0, 1, 'global', 'set'], ['number', 0, 0, 0, 1, 'global', 'set']]
   1376  set list nu
   1377  call assert_equal([], g:options)
   1378  call assert_equal(g:opt[0], g:opt[1])
   1379 
   1380  " 9: don't trigger OptionSet"
   1381  let g:options = [['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid'], ['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']]
   1382  noa set nolist nonu
   1383  call assert_equal([['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid'], ['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']], g:options)
   1384  call assert_equal(g:opt[0], g:opt[1])
   1385 
   1386  " 10: Setting global acd"
   1387  let g:options = [['autochdir', 0, 0, '', 1, 'local', 'setlocal']]
   1388  setlocal acd
   1389  call assert_equal([], g:options)
   1390  call assert_equal(g:opt[0], g:opt[1])
   1391 
   1392  " 11: Setting global autoread (also sets local value)"
   1393  let g:options = [['autoread', 0, 0, 0, 1, 'global', 'set']]
   1394  set ar
   1395  call assert_equal([], g:options)
   1396  call assert_equal(g:opt[0], g:opt[1])
   1397 
   1398  " 12: Setting local autoread"
   1399  let g:options = [['autoread', 1, 1, '', 1, 'local', 'setlocal']]
   1400  setlocal ar
   1401  call assert_equal([], g:options)
   1402  call assert_equal(g:opt[0], g:opt[1])
   1403 
   1404  " 13: Setting global autoread"
   1405  let g:options = [['autoread', 1, '', 1, 0, 'global', 'setglobal']]
   1406  setglobal invar
   1407  call assert_equal([], g:options)
   1408  call assert_equal(g:opt[0], g:opt[1])
   1409 
   1410  " 14: Setting option backspace through :let"
   1411  let g:options = [['backspace', 'indent,eol,start', 'indent,eol,start', 'indent,eol,start', '', 'global', 'set']]
   1412  let &bs = ''
   1413  call assert_equal([], g:options)
   1414  call assert_equal(g:opt[0], g:opt[1])
   1415 
   1416  " 15: Setting option backspace through setbufvar()"
   1417  let g:options = [['backup', 0, 0, '', 1, 'local', 'setlocal']]
   1418  " try twice, first time, shouldn't trigger because option name is invalid,
   1419  " second time, it should trigger
   1420  let bnum = bufnr('%')
   1421  call assert_fails("call setbufvar(bnum, '&l:bk', 1)", 'E355:')
   1422  " should trigger, use correct option name
   1423  call setbufvar(bnum, '&backup', 1)
   1424  call assert_equal([], g:options)
   1425  call assert_equal(g:opt[0], g:opt[1])
   1426 
   1427  " 16: Setting number option using setwinvar"
   1428  let g:options = [['number', 0, 0, '', 1, 'local', 'setlocal']]
   1429  call setwinvar(0, '&number', 1)
   1430  call assert_equal([], g:options)
   1431  call assert_equal(g:opt[0], g:opt[1])
   1432 
   1433  " 17: Setting key option, shouldn't trigger"
   1434  let g:options = [['key', 'invalid', 'invalid1', 'invalid2', 'invalid3', 'invalid4', 'invalid5']]
   1435  setlocal key=blah
   1436  setlocal key=
   1437  call assert_equal([['key', 'invalid', 'invalid1', 'invalid2', 'invalid3', 'invalid4', 'invalid5']], g:options)
   1438  call assert_equal(g:opt[0], g:opt[1])
   1439 
   1440 
   1441  " 18a: Setting string global option"
   1442  let oldval = &backupext
   1443  let g:options = [['backupext', oldval, oldval, oldval, 'foo', 'global', 'set']]
   1444  set backupext=foo
   1445  call assert_equal([], g:options)
   1446  call assert_equal(g:opt[0], g:opt[1])
   1447 
   1448  " 18b: Resetting string global option"
   1449  let g:options = [['backupext', 'foo', 'foo', 'foo', oldval, 'global', 'set']]
   1450  set backupext&
   1451  call assert_equal([], g:options)
   1452  call assert_equal(g:opt[0], g:opt[1])
   1453 
   1454  " 18c: Setting global string global option"
   1455  let g:options = [['backupext', oldval, '', oldval, 'bar', 'global', 'setglobal']]
   1456  setglobal backupext=bar
   1457  call assert_equal([], g:options)
   1458  call assert_equal(g:opt[0], g:opt[1])
   1459 
   1460  " 18d: Setting local string global option"
   1461  " As this is a global option this sets the global value even though
   1462  " :setlocal is used!
   1463  noa set backupext& " Reset global and local value (without triggering autocmd)
   1464  let g:options = [['backupext', oldval, oldval, '', 'baz', 'local', 'setlocal']]
   1465  setlocal backupext=baz
   1466  call assert_equal([], g:options)
   1467  call assert_equal(g:opt[0], g:opt[1])
   1468 
   1469  " 18e: Setting again string global option"
   1470  noa setglobal backupext=ext_global " Reset global and local value (without triggering autocmd)
   1471  noa setlocal backupext=ext_local " Sets the global(!) value!
   1472  let g:options = [['backupext', 'ext_local', 'ext_local', 'ext_local', 'fuu', 'global', 'set']]
   1473  set backupext=fuu
   1474  call assert_equal([], g:options)
   1475  call assert_equal(g:opt[0], g:opt[1])
   1476 
   1477 
   1478  " 19a: Setting string global-local (to buffer) option"
   1479  let oldval = &tags
   1480  let g:options = [['tags', oldval, oldval, oldval, 'tagpath', 'global', 'set']]
   1481  set tags=tagpath
   1482  call assert_equal([], g:options)
   1483  call assert_equal(g:opt[0], g:opt[1])
   1484 
   1485  " 19b: Resetting string global-local (to buffer) option"
   1486  let g:options = [['tags', 'tagpath', 'tagpath', 'tagpath', oldval, 'global', 'set']]
   1487  set tags&
   1488  call assert_equal([], g:options)
   1489  call assert_equal(g:opt[0], g:opt[1])
   1490 
   1491  " 19c: Setting global string global-local (to buffer) option "
   1492  let g:options = [['tags', oldval, '', oldval, 'tagpath1', 'global', 'setglobal']]
   1493  setglobal tags=tagpath1
   1494  call assert_equal([], g:options)
   1495  call assert_equal(g:opt[0], g:opt[1])
   1496 
   1497  " 19d: Setting local string global-local (to buffer) option"
   1498  let g:options = [['tags', 'tagpath1', 'tagpath1', '', 'tagpath2', 'local', 'setlocal']]
   1499  setlocal tags=tagpath2
   1500  call assert_equal([], g:options)
   1501  call assert_equal(g:opt[0], g:opt[1])
   1502 
   1503  " 19e: Setting again string global-local (to buffer) option"
   1504  " Note: v:option_old is the old global value for global-local string options
   1505  " but the old local value for all other kinds of options.
   1506  noa setglobal tags=tag_global " Reset global and local value (without triggering autocmd)
   1507  noa setlocal tags=tag_local
   1508  let g:options = [['tags', 'tag_global', 'tag_local', 'tag_global', 'tagpath', 'global', 'set']]
   1509  set tags=tagpath
   1510  call assert_equal([], g:options)
   1511  call assert_equal(g:opt[0], g:opt[1])
   1512 
   1513  " 19f: Setting string global-local (to buffer) option to an empty string"
   1514  " Note: v:option_old is the old global value for global-local string options
   1515  " but the old local value for all other kinds of options.
   1516  noa set tags=tag_global " Reset global and local value (without triggering autocmd)
   1517  noa setlocal tags= " empty string
   1518  let g:options = [['tags', 'tag_global', '', 'tag_global', 'tagpath', 'global', 'set']]
   1519  set tags=tagpath
   1520  call assert_equal([], g:options)
   1521  call assert_equal(g:opt[0], g:opt[1])
   1522 
   1523 
   1524  " 20a: Setting string local (to buffer) option"
   1525  let oldval = &spelllang
   1526  let g:options = [['spelllang', oldval, oldval, oldval, 'elvish,klingon', 'global', 'set']]
   1527  set spelllang=elvish,klingon
   1528  call assert_equal([], g:options)
   1529  call assert_equal(g:opt[0], g:opt[1])
   1530 
   1531  " 20b: Resetting string local (to buffer) option"
   1532  let g:options = [['spelllang', 'elvish,klingon', 'elvish,klingon', 'elvish,klingon', oldval, 'global', 'set']]
   1533  set spelllang&
   1534  call assert_equal([], g:options)
   1535  call assert_equal(g:opt[0], g:opt[1])
   1536 
   1537  " 20c: Setting global string local (to buffer) option"
   1538  let g:options = [['spelllang', oldval, '', oldval, 'elvish', 'global', 'setglobal']]
   1539  setglobal spelllang=elvish
   1540  call assert_equal([], g:options)
   1541  call assert_equal(g:opt[0], g:opt[1])
   1542 
   1543  " 20d: Setting local string local (to buffer) option"
   1544  noa set spelllang& " Reset global and local value (without triggering autocmd)
   1545  let g:options = [['spelllang', oldval, oldval, '', 'klingon', 'local', 'setlocal']]
   1546  setlocal spelllang=klingon
   1547  call assert_equal([], g:options)
   1548  call assert_equal(g:opt[0], g:opt[1])
   1549 
   1550  " 20e: Setting again string local (to buffer) option"
   1551  " Note: v:option_old is the old global value for global-local string options
   1552  " but the old local value for all other kinds of options.
   1553  noa setglobal spelllang=spellglobal " Reset global and local value (without triggering autocmd)
   1554  noa setlocal spelllang=spelllocal
   1555  let g:options = [['spelllang', 'spelllocal', 'spelllocal', 'spellglobal', 'foo', 'global', 'set']]
   1556  set spelllang=foo
   1557  call assert_equal([], g:options)
   1558  call assert_equal(g:opt[0], g:opt[1])
   1559 
   1560 
   1561  " 21a: Setting string global-local (to window) option"
   1562  let oldval = &statusline
   1563  let g:options = [['statusline', oldval, oldval, oldval, 'foo', 'global', 'set']]
   1564  set statusline=foo
   1565  call assert_equal([], g:options)
   1566  call assert_equal(g:opt[0], g:opt[1])
   1567 
   1568  " 21b: Resetting string global-local (to window) option"
   1569  " Note: v:option_old is the old global value for global-local string options
   1570  " but the old local value for all other kinds of options.
   1571  let g:options = [['statusline', 'foo', 'foo', 'foo', oldval, 'global', 'set']]
   1572  set statusline&
   1573  call assert_equal([], g:options)
   1574  call assert_equal(g:opt[0], g:opt[1])
   1575 
   1576  " 21c: Setting global string global-local (to window) option"
   1577  let g:options = [['statusline', oldval, '', oldval, 'bar', 'global', 'setglobal']]
   1578  setglobal statusline=bar
   1579  call assert_equal([], g:options)
   1580  call assert_equal(g:opt[0], g:opt[1])
   1581 
   1582  " 21d: Setting local string global-local (to window) option"
   1583  noa set statusline& " Reset global and local value (without triggering autocmd)
   1584  let g:options = [['statusline', oldval, oldval, '', 'baz', 'local', 'setlocal']]
   1585  setlocal statusline=baz
   1586  call assert_equal([], g:options)
   1587  call assert_equal(g:opt[0], g:opt[1])
   1588 
   1589  " 21e: Setting again string global-local (to window) option"
   1590  " Note: v:option_old is the old global value for global-local string options
   1591  " but the old local value for all other kinds of options.
   1592  noa setglobal statusline=bar " Reset global and local value (without triggering autocmd)
   1593  noa setlocal statusline=baz
   1594  let g:options = [['statusline', 'bar', 'baz', 'bar', 'foo', 'global', 'set']]
   1595  set statusline=foo
   1596  call assert_equal([], g:options)
   1597  call assert_equal(g:opt[0], g:opt[1])
   1598 
   1599 
   1600  " 22a: Setting string local (to window) option"
   1601  let oldval = &foldignore
   1602  let g:options = [['foldignore', oldval, oldval, oldval, 'fo', 'global', 'set']]
   1603  set foldignore=fo
   1604  call assert_equal([], g:options)
   1605  call assert_equal(g:opt[0], g:opt[1])
   1606 
   1607  " 22b: Resetting string local (to window) option"
   1608  let g:options = [['foldignore', 'fo', 'fo', 'fo', oldval, 'global', 'set']]
   1609  set foldignore&
   1610  call assert_equal([], g:options)
   1611  call assert_equal(g:opt[0], g:opt[1])
   1612 
   1613  " 22c: Setting global string local (to window) option"
   1614  let g:options = [['foldignore', oldval, '', oldval, 'bar', 'global', 'setglobal']]
   1615  setglobal foldignore=bar
   1616  call assert_equal([], g:options)
   1617  call assert_equal(g:opt[0], g:opt[1])
   1618 
   1619  " 22d: Setting local string local (to window) option"
   1620  noa set foldignore& " Reset global and local value (without triggering autocmd)
   1621  let g:options = [['foldignore', oldval, oldval, '', 'baz', 'local', 'setlocal']]
   1622  setlocal foldignore=baz
   1623  call assert_equal([], g:options)
   1624  call assert_equal(g:opt[0], g:opt[1])
   1625 
   1626  " 22e: Setting again string local (to window) option"
   1627  noa setglobal foldignore=glob " Reset global and local value (without triggering autocmd)
   1628  noa setlocal foldignore=loc
   1629  let g:options = [['foldignore', 'loc', 'loc', 'glob', 'fo', 'global', 'set']]
   1630  set foldignore=fo
   1631  call assert_equal([], g:options)
   1632  call assert_equal(g:opt[0], g:opt[1])
   1633 
   1634 
   1635  " 23a: Setting global number global option"
   1636  noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd)
   1637  noa setlocal cmdheight=1 " Sets the global(!) value!
   1638  let g:options = [['cmdheight', '1', '', '1', '2', 'global', 'setglobal']]
   1639  setglobal cmdheight=2
   1640  call assert_equal([], g:options)
   1641  call assert_equal(g:opt[0], g:opt[1])
   1642 
   1643  " 23b: Setting local number global option"
   1644  noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd)
   1645  noa setlocal cmdheight=1 " Sets the global(!) value!
   1646  let g:options = [['cmdheight', '1', '1', '', '2', 'local', 'setlocal']]
   1647  setlocal cmdheight=2
   1648  call assert_equal([], g:options)
   1649  call assert_equal(g:opt[0], g:opt[1])
   1650 
   1651  " 23c: Setting again number global option"
   1652  noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd)
   1653  noa setlocal cmdheight=1 " Sets the global(!) value!
   1654  let g:options = [['cmdheight', '1', '1', '1', '2', 'global', 'set']]
   1655  set cmdheight=2
   1656  call assert_equal([], g:options)
   1657  call assert_equal(g:opt[0], g:opt[1])
   1658 
   1659  " 23d: Setting again number global option"
   1660  noa set cmdheight=8 " Reset global and local value (without triggering autocmd)
   1661  let g:options = [['cmdheight', '8', '8', '8', '2', 'global', 'set']]
   1662  set cmdheight=2
   1663  call assert_equal([], g:options)
   1664  call assert_equal(g:opt[0], g:opt[1])
   1665 
   1666 
   1667  " 24a: Setting global number global-local (to buffer) option"
   1668  noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd)
   1669  noa setlocal undolevels=1
   1670  let g:options = [['undolevels', '8', '', '8', '2', 'global', 'setglobal']]
   1671  setglobal undolevels=2
   1672  call assert_equal([], g:options)
   1673  call assert_equal(g:opt[0], g:opt[1])
   1674 
   1675  " 24b: Setting local number global-local (to buffer) option"
   1676  noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd)
   1677  noa setlocal undolevels=1
   1678  let g:options = [['undolevels', '1', '1', '', '2', 'local', 'setlocal']]
   1679  setlocal undolevels=2
   1680  call assert_equal([], g:options)
   1681  call assert_equal(g:opt[0], g:opt[1])
   1682 
   1683  " 24c: Setting again number global-local (to buffer) option"
   1684  noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd)
   1685  noa setlocal undolevels=1
   1686  let g:options = [['undolevels', '1', '1', '8', '2', 'global', 'set']]
   1687  set undolevels=2
   1688  call assert_equal([], g:options)
   1689  call assert_equal(g:opt[0], g:opt[1])
   1690 
   1691  " 24d: Setting again global number global-local (to buffer) option"
   1692  noa set undolevels=8 " Reset global and local value (without triggering autocmd)
   1693  let g:options = [['undolevels', '8', '8', '8', '2', 'global', 'set']]
   1694  set undolevels=2
   1695  call assert_equal([], g:options)
   1696  call assert_equal(g:opt[0], g:opt[1])
   1697 
   1698 
   1699  " 25a: Setting global number local (to buffer) option"
   1700  noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd)
   1701  noa setlocal wrapmargin=1
   1702  let g:options = [['wrapmargin', '8', '', '8', '2', 'global', 'setglobal']]
   1703  setglobal wrapmargin=2
   1704  call assert_equal([], g:options)
   1705  call assert_equal(g:opt[0], g:opt[1])
   1706 
   1707  " 25b: Setting local number local (to buffer) option"
   1708  noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd)
   1709  noa setlocal wrapmargin=1
   1710  let g:options = [['wrapmargin', '1', '1', '', '2', 'local', 'setlocal']]
   1711  setlocal wrapmargin=2
   1712  call assert_equal([], g:options)
   1713  call assert_equal(g:opt[0], g:opt[1])
   1714 
   1715  " 25c: Setting again number local (to buffer) option"
   1716  noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd)
   1717  noa setlocal wrapmargin=1
   1718  let g:options = [['wrapmargin', '1', '1', '8', '2', 'global', 'set']]
   1719  set wrapmargin=2
   1720  call assert_equal([], g:options)
   1721  call assert_equal(g:opt[0], g:opt[1])
   1722 
   1723  " 25d: Setting again global number local (to buffer) option"
   1724  noa set wrapmargin=8 " Reset global and local value (without triggering autocmd)
   1725  let g:options = [['wrapmargin', '8', '8', '8', '2', 'global', 'set']]
   1726  set wrapmargin=2
   1727  call assert_equal([], g:options)
   1728  call assert_equal(g:opt[0], g:opt[1])
   1729 
   1730 
   1731  " 26: Setting number global-local (to window) option.
   1732  " Such option does currently not exist.
   1733 
   1734 
   1735  " 27a: Setting global number local (to window) option"
   1736  noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd)
   1737  noa setlocal foldcolumn=1
   1738  let g:options = [['foldcolumn', '8', '', '8', '2', 'global', 'setglobal']]
   1739  setglobal foldcolumn=2
   1740  call assert_equal([], g:options)
   1741  call assert_equal(g:opt[0], g:opt[1])
   1742 
   1743  " 27b: Setting local number local (to window) option"
   1744  noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd)
   1745  noa setlocal foldcolumn=1
   1746  let g:options = [['foldcolumn', '1', '1', '', '2', 'local', 'setlocal']]
   1747  setlocal foldcolumn=2
   1748  call assert_equal([], g:options)
   1749  call assert_equal(g:opt[0], g:opt[1])
   1750 
   1751  " 27c: Setting again number local (to window) option"
   1752  noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd)
   1753  noa setlocal foldcolumn=1
   1754  let g:options = [['foldcolumn', '1', '1', '8', '2', 'global', 'set']]
   1755  set foldcolumn=2
   1756  call assert_equal([], g:options)
   1757  call assert_equal(g:opt[0], g:opt[1])
   1758 
   1759  " 27d: Setting again global number local (to window) option"
   1760  noa set foldcolumn=8 " Reset global and local value (without triggering autocmd)
   1761  let g:options = [['foldcolumn', '8', '8', '8', '2', 'global', 'set']]
   1762  set foldcolumn=2
   1763  call assert_equal([], g:options)
   1764  call assert_equal(g:opt[0], g:opt[1])
   1765 
   1766 
   1767  " 28a: Setting global boolean global option"
   1768  noa setglobal nowrapscan " Reset global and local value (without triggering autocmd)
   1769  noa setlocal wrapscan " Sets the global(!) value!
   1770  let g:options = [['wrapscan', '1', '', '1', '0', 'global', 'setglobal']]
   1771  setglobal nowrapscan
   1772  call assert_equal([], g:options)
   1773  call assert_equal(g:opt[0], g:opt[1])
   1774 
   1775  " 28b: Setting local boolean global option"
   1776  noa setglobal nowrapscan " Reset global and local value (without triggering autocmd)
   1777  noa setlocal wrapscan " Sets the global(!) value!
   1778  let g:options = [['wrapscan', '1', '1', '', '0', 'local', 'setlocal']]
   1779  setlocal nowrapscan
   1780  call assert_equal([], g:options)
   1781  call assert_equal(g:opt[0], g:opt[1])
   1782 
   1783  " 28c: Setting again boolean global option"
   1784  noa setglobal nowrapscan " Reset global and local value (without triggering autocmd)
   1785  noa setlocal wrapscan " Sets the global(!) value!
   1786  let g:options = [['wrapscan', '1', '1', '1', '0', 'global', 'set']]
   1787  set nowrapscan
   1788  call assert_equal([], g:options)
   1789  call assert_equal(g:opt[0], g:opt[1])
   1790 
   1791  " 28d: Setting again global boolean global option"
   1792  noa set nowrapscan " Reset global and local value (without triggering autocmd)
   1793  let g:options = [['wrapscan', '0', '0', '0', '1', 'global', 'set']]
   1794  set wrapscan
   1795  call assert_equal([], g:options)
   1796  call assert_equal(g:opt[0], g:opt[1])
   1797 
   1798 
   1799  " 29a: Setting global boolean global-local (to buffer) option"
   1800  noa setglobal noautoread " Reset global and local value (without triggering autocmd)
   1801  noa setlocal autoread
   1802  let g:options = [['autoread', '0', '', '0', '1', 'global', 'setglobal']]
   1803  setglobal autoread
   1804  call assert_equal([], g:options)
   1805  call assert_equal(g:opt[0], g:opt[1])
   1806 
   1807  " 29b: Setting local boolean global-local (to buffer) option"
   1808  noa setglobal noautoread " Reset global and local value (without triggering autocmd)
   1809  noa setlocal autoread
   1810  let g:options = [['autoread', '1', '1', '', '0', 'local', 'setlocal']]
   1811  setlocal noautoread
   1812  call assert_equal([], g:options)
   1813  call assert_equal(g:opt[0], g:opt[1])
   1814 
   1815  " 29c: Setting again boolean global-local (to buffer) option"
   1816  noa setglobal noautoread " Reset global and local value (without triggering autocmd)
   1817  noa setlocal autoread
   1818  let g:options = [['autoread', '1', '1', '0', '1', 'global', 'set']]
   1819  set autoread
   1820  call assert_equal([], g:options)
   1821  call assert_equal(g:opt[0], g:opt[1])
   1822 
   1823  " 29d: Setting again global boolean global-local (to buffer) option"
   1824  noa set noautoread " Reset global and local value (without triggering autocmd)
   1825  let g:options = [['autoread', '0', '0', '0', '1', 'global', 'set']]
   1826  set autoread
   1827  call assert_equal([], g:options)
   1828  call assert_equal(g:opt[0], g:opt[1])
   1829 
   1830 
   1831  " 30a: Setting global boolean local (to buffer) option"
   1832  noa setglobal nocindent " Reset global and local value (without triggering autocmd)
   1833  noa setlocal cindent
   1834  let g:options = [['cindent', '0', '', '0', '1', 'global', 'setglobal']]
   1835  setglobal cindent
   1836  call assert_equal([], g:options)
   1837  call assert_equal(g:opt[0], g:opt[1])
   1838 
   1839  " 30b: Setting local boolean local (to buffer) option"
   1840  noa setglobal nocindent " Reset global and local value (without triggering autocmd)
   1841  noa setlocal cindent
   1842  let g:options = [['cindent', '1', '1', '', '0', 'local', 'setlocal']]
   1843  setlocal nocindent
   1844  call assert_equal([], g:options)
   1845  call assert_equal(g:opt[0], g:opt[1])
   1846 
   1847  " 30c: Setting again boolean local (to buffer) option"
   1848  noa setglobal nocindent " Reset global and local value (without triggering autocmd)
   1849  noa setlocal cindent
   1850  let g:options = [['cindent', '1', '1', '0', '1', 'global', 'set']]
   1851  set cindent
   1852  call assert_equal([], g:options)
   1853  call assert_equal(g:opt[0], g:opt[1])
   1854 
   1855  " 30d: Setting again global boolean local (to buffer) option"
   1856  noa set nocindent " Reset global and local value (without triggering autocmd)
   1857  let g:options = [['cindent', '0', '0', '0', '1', 'global', 'set']]
   1858  set cindent
   1859  call assert_equal([], g:options)
   1860  call assert_equal(g:opt[0], g:opt[1])
   1861 
   1862 
   1863  " 31: Setting boolean global-local (to window) option
   1864  " Currently no such option exists.
   1865 
   1866 
   1867  " 32a: Setting global boolean local (to window) option"
   1868  noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd)
   1869  noa setlocal cursorcolumn
   1870  let g:options = [['cursorcolumn', '0', '', '0', '1', 'global', 'setglobal']]
   1871  setglobal cursorcolumn
   1872  call assert_equal([], g:options)
   1873  call assert_equal(g:opt[0], g:opt[1])
   1874 
   1875  " 32b: Setting local boolean local (to window) option"
   1876  noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd)
   1877  noa setlocal cursorcolumn
   1878  let g:options = [['cursorcolumn', '1', '1', '', '0', 'local', 'setlocal']]
   1879  setlocal nocursorcolumn
   1880  call assert_equal([], g:options)
   1881  call assert_equal(g:opt[0], g:opt[1])
   1882 
   1883  " 32c: Setting again boolean local (to window) option"
   1884  noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd)
   1885  noa setlocal cursorcolumn
   1886  let g:options = [['cursorcolumn', '1', '1', '0', '1', 'global', 'set']]
   1887  set cursorcolumn
   1888  call assert_equal([], g:options)
   1889  call assert_equal(g:opt[0], g:opt[1])
   1890 
   1891  " 32d: Setting again global boolean local (to window) option"
   1892  noa set nocursorcolumn " Reset global and local value (without triggering autocmd)
   1893  let g:options = [['cursorcolumn', '0', '0', '0', '1', 'global', 'set']]
   1894  set cursorcolumn
   1895  call assert_equal([], g:options)
   1896  call assert_equal(g:opt[0], g:opt[1])
   1897 
   1898 
   1899  " 33: Test autocommands when an option value is converted internally.
   1900  noa set backspace=1 " Reset global and local value (without triggering autocmd)
   1901  let g:options = [['backspace', 'indent,eol', 'indent,eol', 'indent,eol', '2', 'global', 'set']]
   1902  set backspace=2
   1903  call assert_equal([], g:options)
   1904  call assert_equal(g:opt[0], g:opt[1])
   1905 
   1906 
   1907  " Cleanup
   1908  au! OptionSet
   1909  " set tags&
   1910  for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp', 'backupext', 'tags', 'spelllang', 'statusline', 'foldignore', 'cmdheight', 'undolevels', 'wrapmargin', 'foldcolumn', 'wrapscan', 'autoread', 'cindent', 'cursorcolumn']
   1911    exe printf(":set %s&vim", opt)
   1912  endfor
   1913  call test_override('starting', 0)
   1914  delfunc! AutoCommandOptionSet
   1915 endfunc
   1916 
   1917 func Test_OptionSet_diffmode()
   1918  call Ntest_override('starting', 1)
   1919  " 18: Changing an option when entering diff mode
   1920  new
   1921  au OptionSet diff :let &l:cul = v:option_new
   1922 
   1923  call setline(1, ['buffer 1', 'line2', 'line3', 'line4'])
   1924  call assert_equal(0, &l:cul)
   1925  diffthis
   1926  call assert_equal(1, &l:cul)
   1927 
   1928  vnew
   1929  call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4'])
   1930  call assert_equal(0, &l:cul)
   1931  diffthis
   1932  call assert_equal(1, &l:cul)
   1933 
   1934  diffoff
   1935  call assert_equal(0, &l:cul)
   1936  call assert_equal(1, getwinvar(2, '&l:cul'))
   1937  bw!
   1938 
   1939  call assert_equal(1, &l:cul)
   1940  diffoff!
   1941  call assert_equal(0, &l:cul)
   1942  call assert_equal(0, getwinvar(1, '&l:cul'))
   1943  bw!
   1944 
   1945  " Cleanup
   1946  au! OptionSet
   1947  call Ntest_override('starting', 0)
   1948 endfunc
   1949 
   1950 func Test_OptionSet_diffmode_close()
   1951  call Ntest_override('starting', 1)
   1952  " 19: Try to close the current window when entering diff mode
   1953  " should not segfault
   1954  new
   1955  au OptionSet diff close
   1956 
   1957  call setline(1, ['buffer 1', 'line2', 'line3', 'line4'])
   1958  call assert_fails(':diffthis', 'E788')
   1959  call assert_equal(1, &diff)
   1960  vnew
   1961  call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4'])
   1962  call assert_fails(':diffthis', 'E788')
   1963  call assert_equal(1, &diff)
   1964  set diffopt-=closeoff
   1965  bw!
   1966  call assert_fails(':diffoff!', 'E788')
   1967  bw!
   1968 
   1969  " Cleanup
   1970  au! OptionSet
   1971  call Ntest_override('starting', 0)
   1972  "delfunc! AutoCommandOptionSet
   1973 endfunc
   1974 
   1975 " Test for Bufleave autocommand that deletes the buffer we are about to edit.
   1976 func Test_BufleaveWithDelete()
   1977  new | edit XbufLeave1
   1978 
   1979  augroup test_bufleavewithdelete
   1980      autocmd!
   1981      autocmd BufLeave XbufLeave1 bwipe XbufLeave2
   1982  augroup END
   1983 
   1984  call assert_fails('edit XbufLeave2', 'E143:')
   1985  call assert_equal('XbufLeave1', bufname('%'))
   1986 
   1987  autocmd! test_bufleavewithdelete BufLeave XbufLeave1
   1988  augroup! test_bufleavewithdelete
   1989 
   1990  new
   1991  bwipe! XbufLeave1
   1992 endfunc
   1993 
   1994 " Test for autocommand that changes the buffer list, when doing ":ball".
   1995 func Test_Acmd_BufAll()
   1996  enew!
   1997  %bwipe!
   1998  call writefile(['Test file Xxx1'], 'Xxx1', 'D')
   1999  call writefile(['Test file Xxx2'], 'Xxx2', 'D')
   2000  call writefile(['Test file Xxx3'], 'Xxx3', 'D')
   2001 
   2002  " Add three files to the buffer list
   2003  split Xxx1
   2004  close
   2005  split Xxx2
   2006  close
   2007  split Xxx3
   2008  close
   2009 
   2010  " Wipe the buffer when the buffer is opened
   2011  au BufReadPost Xxx2 bwipe
   2012 
   2013  call append(0, 'Test file Xxx4')
   2014  ball
   2015 
   2016  call assert_equal(2, winnr('$'))
   2017  call assert_equal('Xxx1', bufname(winbufnr(winnr('$'))))
   2018  wincmd t
   2019 
   2020  au! BufReadPost
   2021  %bwipe!
   2022  enew! | only
   2023 endfunc
   2024 
   2025 " Test for autocommand that changes current buffer on BufEnter event.
   2026 " Check if modelines are interpreted for the correct buffer.
   2027 func Test_Acmd_BufEnter()
   2028  %bwipe!
   2029  call writefile(['start of test file Xxx1',
   2030       \ "\<Tab>this is a test",
   2031       \ 'end of test file Xxx1'], 'Xxx1', 'D')
   2032  call writefile(['start of test file Xxx2',
   2033       \ 'vim: set noai :',
   2034       \ "\<Tab>this is a test",
   2035       \ 'end of test file Xxx2'], 'Xxx2', 'D')
   2036 
   2037  au BufEnter Xxx2 brew
   2038  set ai modeline modelines=3
   2039  edit Xxx1
   2040  " edit Xxx2, autocmd will do :brew
   2041  edit Xxx2
   2042  exe "normal G?this is a\<CR>"
   2043  " Append text with autoindent to this file
   2044  normal othis should be auto-indented
   2045  call assert_equal("\<Tab>this should be auto-indented", getline('.'))
   2046  call assert_equal(3, line('.'))
   2047  " Remove autocmd and edit Xxx2 again
   2048  au! BufEnter Xxx2
   2049  buf! Xxx2
   2050  exe "normal G?this is a\<CR>"
   2051  " append text without autoindent to Xxx
   2052  normal othis should be in column 1
   2053  call assert_equal("this should be in column 1", getline('.'))
   2054  call assert_equal(4, line('.'))
   2055 
   2056  %bwipe!
   2057  set ai&vim modeline&vim modelines&vim
   2058 endfunc
   2059 
   2060 " Test for issue #57
   2061 " do not move cursor on <c-o> when autoindent is set
   2062 func Test_ai_CTRL_O()
   2063  enew!
   2064  set ai
   2065  let save_fo = &fo
   2066  set fo+=r
   2067  exe "normal o# abcdef\<Esc>2hi\<CR>\<C-O>d0\<Esc>"
   2068  exe "normal o# abcdef\<Esc>2hi\<C-O>d0\<Esc>"
   2069  call assert_equal(['# abc', 'def', 'def'], getline(2, 4))
   2070 
   2071  set ai&vim
   2072  let &fo = save_fo
   2073  enew!
   2074 endfunc
   2075 
   2076 " Test for autocommand that deletes the current buffer on BufLeave event.
   2077 " Also test deleting the last buffer, should give a new, empty buffer.
   2078 func Test_BufLeave_Wipe()
   2079  %bwipe!
   2080  let content = ['start of test file Xxx',
   2081       \ 'this is a test',
   2082       \ 'end of test file Xxx']
   2083  call writefile(content, 'Xxx1', 'D')
   2084  call writefile(content, 'Xxx2', 'D')
   2085 
   2086  au BufLeave Xxx2 bwipe
   2087  edit Xxx1
   2088  split Xxx2
   2089  " delete buffer Xxx2, we should be back to Xxx1
   2090  bwipe
   2091  call assert_equal('Xxx1', bufname('%'))
   2092  call assert_equal(1, winnr('$'))
   2093 
   2094  " Create an alternate buffer
   2095  %write! test.out
   2096  call assert_equal('test.out', bufname('#'))
   2097  " delete alternate buffer
   2098  bwipe test.out
   2099  call assert_equal('Xxx1', bufname('%'))
   2100  call assert_equal('', bufname('#'))
   2101 
   2102  au BufLeave Xxx1 bwipe
   2103  " delete current buffer, get an empty one
   2104  bwipe!
   2105  call assert_equal(1, line('$'))
   2106  call assert_equal('', bufname('%'))
   2107  let g:bufinfo = getbufinfo()
   2108  call assert_equal(1, len(g:bufinfo))
   2109 
   2110  call delete('test.out')
   2111  %bwipe
   2112  au! BufLeave
   2113 
   2114  " check that bufinfo doesn't contain a pointer to freed memory
   2115  call test_garbagecollect_now()
   2116 endfunc
   2117 
   2118 func Test_QuitPre()
   2119  edit Xfoo
   2120  let winid = win_getid(winnr())
   2121  split Xbar
   2122  au! QuitPre * let g:afile = expand('<afile>')
   2123  " Close the other window, <afile> should be correct.
   2124  exe win_id2win(winid) . 'q'
   2125  call assert_equal('Xfoo', g:afile)
   2126 
   2127  unlet g:afile
   2128  bwipe Xfoo
   2129  bwipe Xbar
   2130 endfunc
   2131 
   2132 func Test_Cmdline_Trigger()
   2133  autocmd CmdlineLeavePre : let g:log = "CmdlineLeavePre"
   2134  autocmd CmdlineLeave : let g:log2 = "CmdlineLeave"
   2135  new
   2136  let g:log = ''
   2137  let g:log2 = ''
   2138  nnoremap <F1> <Cmd>echo "hello"<CR>
   2139  call feedkeys("\<F1>", 'x')
   2140  call assert_equal('', g:log)
   2141  call assert_equal('', g:log2)
   2142  nunmap <F1>
   2143 
   2144  let g:log = ''
   2145  let g:log2 = ''
   2146  nnoremap <F1> :echo "hello"<CR>
   2147  call feedkeys("\<F1>", 'x')
   2148  call assert_equal('CmdlineLeavePre', g:log)
   2149  call assert_equal('CmdlineLeave', g:log2)
   2150  nunmap <F1>
   2151 
   2152  let g:log = ''
   2153  let g:log2 = ''
   2154  call feedkeys(":\<bs>", "tx")
   2155  call assert_equal('CmdlineLeavePre', g:log)
   2156  call assert_equal('CmdlineLeave', g:log2)
   2157 
   2158  let g:log = ''
   2159  let g:log2 = ''
   2160  split
   2161  call assert_equal('', g:log)
   2162  call feedkeys(":echo hello", "tx")
   2163  call assert_equal('CmdlineLeavePre', g:log)
   2164  call assert_equal('CmdlineLeave', g:log2)
   2165 
   2166  let g:log = ''
   2167  let g:log2 = ''
   2168  close
   2169  call assert_equal('', g:log)
   2170  call feedkeys(":echo hello", "tx")
   2171  call assert_equal('CmdlineLeavePre', g:log)
   2172  call assert_equal('CmdlineLeave', g:log2)
   2173 
   2174  let g:log = ''
   2175  let g:log2 = ''
   2176  tabnew
   2177  call assert_equal('', g:log)
   2178  call feedkeys(":echo hello", "tx")
   2179  call assert_equal('CmdlineLeavePre', g:log)
   2180  call assert_equal('CmdlineLeave', g:log2)
   2181 
   2182  let g:log = ''
   2183  let g:log2 = ''
   2184  split
   2185  call assert_equal('', g:log)
   2186  call feedkeys(":echo hello", "tx")
   2187  call assert_equal('CmdlineLeavePre', g:log)
   2188  call assert_equal('CmdlineLeave', g:log2)
   2189 
   2190  let g:log = ''
   2191  let g:log2 = ''
   2192  tabclose
   2193  call assert_equal('', g:log)
   2194  call feedkeys(":echo hello", "tx")
   2195  call assert_equal('CmdlineLeavePre', g:log)
   2196  call assert_equal('CmdlineLeave', g:log2)
   2197 
   2198  autocmd CmdlineLeavePre * let g:cmdline += [getcmdline()]
   2199 
   2200  for end_keys in ["\<CR>", "\<NL>", "\<kEnter>", "\<C-C>", "\<Esc>",
   2201                 \ "\<C-\>\<C-N>", "\<C-\>\<C-G>"]
   2202    let g:cmdline = []
   2203    let g:log = ''
   2204    let g:log2 = ''
   2205    call assert_equal('', g:log)
   2206    let keys = $':echo "hello"{end_keys}'
   2207    let msg = keytrans(keys)
   2208    call feedkeys(keys, "tx")
   2209    call assert_equal(['echo "hello"'], g:cmdline, msg)
   2210    call assert_equal('CmdlineLeavePre', g:log, msg)
   2211    call assert_equal('CmdlineLeave', g:log2, msg)
   2212  endfor
   2213 
   2214  let g:cmdline = []
   2215  call feedkeys(":let c = input('? ')\<cr>ABCDE\<cr>", "tx")
   2216  call assert_equal(["let c = input('? ')", 'ABCDE'], g:cmdline)
   2217 
   2218  au! CmdlineLeavePre
   2219  unlet! g:cmdline
   2220  unlet! g:log
   2221  unlet! g:log2
   2222  bw!
   2223 endfunc
   2224 
   2225 " Ensure :cabbr does not cause a spurious CmdlineLeavePre.
   2226 func Test_CmdlineLeavePre_cabbr()
   2227  " For unknown reason this fails intermittently on MS-Windows
   2228  CheckNotMSWindows
   2229  CheckFeature terminal
   2230  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3})
   2231  call assert_equal('running', term_getstatus(buf))
   2232  call term_sendkeys(buf, ":let g:a=0\<cr>")
   2233  call term_wait(buf, 50)
   2234  call term_sendkeys(buf, ":cabbr v v\<cr>")
   2235  call term_wait(buf, 50)
   2236  call term_sendkeys(buf, ":command! -nargs=* Foo echo\<cr>")
   2237  call term_wait(buf, 50)
   2238  call term_sendkeys(buf, ":au! CmdlineLeavePre * :let g:a+=1\<cr>")
   2239  call term_wait(buf, 50)
   2240  call term_sendkeys(buf, ":Foo v\<cr>")
   2241  call term_wait(buf, 50)
   2242  call term_sendkeys(buf, ":echo g:a\<cr>")
   2243  call term_wait(buf, 50)
   2244  call WaitForAssert({-> assert_match('^2.*$', term_getline(buf, 3))})
   2245  bwipe!
   2246 endfunc
   2247 
   2248 func Test_Cmdline()
   2249  au! CmdlineChanged : let g:text = getcmdline()
   2250  let g:text = 0
   2251  call feedkeys(":echom 'hello'\<CR>", 'xt')
   2252  call assert_equal("echom 'hello'", g:text)
   2253  au! CmdlineChanged
   2254 
   2255  au! CmdlineChanged : let g:entered = expand('<afile>')
   2256  let g:entered = 0
   2257  call feedkeys(":echom 'hello'\<CR>", 'xt')
   2258  call assert_equal(':', g:entered)
   2259  au! CmdlineChanged
   2260 
   2261  autocmd CmdlineChanged : let g:log += [getcmdline()]
   2262 
   2263  let g:log = []
   2264  cnoremap <F1> <Cmd>call setcmdline('ls')<CR>
   2265  call feedkeys(":\<F1>", 'xt')
   2266  call assert_equal(['ls'], g:log)
   2267  cunmap <F1>
   2268 
   2269  let g:log = []
   2270  call feedkeys(":sign \<Tab>\<Tab>\<C-N>\<C-P>\<S-Tab>\<S-Tab>\<Esc>", 'xt')
   2271  call assert_equal([
   2272        \ 's',
   2273        \ 'si',
   2274        \ 'sig',
   2275        \ 'sign',
   2276        \ 'sign ',
   2277        \ 'sign define',
   2278        \ 'sign jump',
   2279        \ 'sign list',
   2280        \ 'sign jump',
   2281        \ 'sign define',
   2282        \ 'sign ',
   2283        \ ], g:log)
   2284  let g:log = []
   2285  set wildmenu wildoptions+=pum
   2286  call feedkeys(":sign \<S-Tab>\<PageUp>\<kPageUp>\<kPageDown>\<PageDown>\<Esc>", 'xt')
   2287  call assert_equal([
   2288        \ 's',
   2289        \ 'si',
   2290        \ 'sig',
   2291        \ 'sign',
   2292        \ 'sign ',
   2293        \ 'sign unplace',
   2294        \ 'sign jump',
   2295        \ 'sign define',
   2296        \ 'sign undefine',
   2297        \ 'sign unplace',
   2298        \ ], g:log)
   2299  set wildmenu& wildoptions&
   2300 
   2301  let g:log = []
   2302  let @r = 'abc'
   2303  call feedkeys(":0\<C-R>=@r\<CR>1\<C-R>\<C-O>r2\<C-R>\<C-R>r3\<Esc>", 'xt')
   2304  call assert_equal([
   2305        \ '0',
   2306        \ '0a',
   2307        \ '0ab',
   2308        \ '0abc',
   2309        \ '0abc1',
   2310        \ '0abc1abc',
   2311        \ '0abc1abc2',
   2312        \ '0abc1abc2abc',
   2313        \ '0abc1abc2abc3',
   2314        \ ], g:log)
   2315 
   2316  " <Del> should trigger CmdlineChanged
   2317  let g:log = []
   2318  call feedkeys(":foo\<Left>\<Left>\<Del>\<Del>\<Esc>", 'xt')
   2319  call assert_equal([
   2320        \ 'f',
   2321        \ 'fo',
   2322        \ 'foo',
   2323        \ 'fo',
   2324        \ 'f',
   2325        \ ], g:log)
   2326 
   2327  unlet g:log
   2328  au! CmdlineChanged
   2329 
   2330  au! CmdlineEnter : let g:entered = expand('<afile>')
   2331  au! CmdlineLeave : let g:left = expand('<afile>')
   2332  au! CmdlineLeavePre : let g:leftpre = expand('<afile>')
   2333  let g:entered = 0
   2334  let g:left = 0
   2335  let g:leftpre = 0
   2336  call feedkeys(":echo 'hello'\<CR>", 'xt')
   2337  call assert_equal(':', g:entered)
   2338  call assert_equal(':', g:left)
   2339  call assert_equal(':', g:leftpre)
   2340  au! CmdlineEnter
   2341  au! CmdlineLeave
   2342  au! CmdlineLeavePre
   2343 
   2344  let save_shellslash = &shellslash
   2345  " Nvim doesn't allow setting value of a hidden option to non-default value
   2346  if exists('+shellslash')
   2347    set noshellslash
   2348  endif
   2349  au! CmdlineEnter / let g:entered = expand('<afile>')
   2350  au! CmdlineLeave / let g:left = expand('<afile>')
   2351  au! CmdlineLeavePre / let g:leftpre = expand('<afile>')
   2352  let g:entered = 0
   2353  let g:left = 0
   2354  let g:leftpre = 0
   2355  new
   2356  call setline(1, 'hello')
   2357  call feedkeys("/hello\<CR>", 'xt')
   2358  call assert_equal('/', g:entered)
   2359  call assert_equal('/', g:left)
   2360  call assert_equal('/', g:leftpre)
   2361  bwipe!
   2362  au! CmdlineEnter
   2363  au! CmdlineLeave
   2364  au! CmdlineLeavePre
   2365  let &shellslash = save_shellslash
   2366 
   2367  let g:left = "cancelled"
   2368  let g:leftpre = "cancelled"
   2369  au! CmdlineLeave : let g:left = "triggered"
   2370  au! CmdlineLeavePre : let g:leftpre = "triggered"
   2371  call feedkeys(":echo 'hello'\<esc>", 'xt')
   2372  call assert_equal('triggered', g:left)
   2373  call assert_equal('triggered', g:leftpre)
   2374  let g:left = "cancelled"
   2375  let g:leftpre = "cancelled"
   2376  au! CmdlineLeave : let g:left = "triggered"
   2377  call feedkeys(":echo 'hello'\<c-c>", 'xt')
   2378  call assert_equal('triggered', g:left)
   2379  call assert_equal('triggered', g:leftpre)
   2380  au! CmdlineLeave
   2381  au! CmdlineLeavePre
   2382 
   2383  au! CursorMovedC : let g:pos += [getcmdpos()]
   2384  let g:pos = []
   2385  call feedkeys(":foo bar baz\<C-W>\<C-W>\<C-W>\<Esc>", 'xt')
   2386  call assert_equal([2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 9, 5, 1], g:pos)
   2387  let g:pos = []
   2388  call feedkeys(":hello\<C-B>\<Esc>", 'xt')
   2389  call assert_equal([2, 3, 4, 5, 6, 1], g:pos)
   2390  let g:pos = []
   2391  call feedkeys(":hello\<C-U>\<Esc>", 'xt')
   2392  call assert_equal([2, 3, 4, 5, 6, 1], g:pos)
   2393  let g:pos = []
   2394  call feedkeys(":hello\<Left>\<C-R>=''\<CR>\<Left>\<Right>\<Esc>", 'xt')
   2395  call assert_equal([2, 3, 4, 5, 6, 5, 4, 5], g:pos)
   2396  let g:pos = []
   2397  call feedkeys(":12345678\<C-R>=setcmdpos(3)??''\<CR>\<Esc>", 'xt')
   2398  call assert_equal([2, 3, 4, 5, 6, 7, 8, 9, 3], g:pos)
   2399  let g:pos = []
   2400  call feedkeys(":12345678\<C-R>=setcmdpos(3)??''\<CR>\<Left>\<Esc>", 'xt')
   2401  call assert_equal([2, 3, 4, 5, 6, 7, 8, 9, 3, 2], g:pos)
   2402  au! CursorMovedC
   2403 
   2404  " setcmdpos() is no-op inside an autocommand
   2405  au! CursorMovedC : let g:pos += [getcmdpos()] | call setcmdpos(1)
   2406  let g:pos = []
   2407  call feedkeys(":hello\<Left>\<Left>\<Esc>", 'xt')
   2408  call assert_equal([2, 3, 4, 5, 6, 5, 4], g:pos)
   2409  au! CursorMovedC
   2410 
   2411  unlet g:entered
   2412  unlet g:left
   2413  unlet g:pos
   2414 endfunc
   2415 
   2416 " Test for BufWritePre autocommand that deletes or unloads the buffer.
   2417 func Test_BufWritePre()
   2418  %bwipe
   2419  au BufWritePre Xxx1 bunload
   2420  au BufWritePre Xxx2 bwipe
   2421 
   2422  call writefile(['start of Xxx1', 'test', 'end of Xxx1'], 'Xxx1', 'D')
   2423  call writefile(['start of Xxx2', 'test', 'end of Xxx2'], 'Xxx2', 'D')
   2424 
   2425  edit Xtest
   2426  e! Xxx2
   2427  bdel Xtest
   2428  e Xxx1
   2429  " write it, will unload it and give an error msg
   2430  call assert_fails('w', 'E203:')
   2431  call assert_equal('Xxx2', bufname('%'))
   2432  edit Xtest
   2433  e! Xxx2
   2434  bwipe Xtest
   2435  " write it, will delete the buffer and give an error msg
   2436  call assert_fails('w', 'E203:')
   2437  call assert_equal('Xxx1', bufname('%'))
   2438  au! BufWritePre
   2439 endfunc
   2440 
   2441 " Test for BufUnload autocommand that unloads all the other buffers
   2442 func Test_bufunload_all()
   2443  let g:test_is_flaky = 1
   2444  call writefile(['Test file Xxx1'], 'Xxx1', 'D')
   2445  call writefile(['Test file Xxx2'], 'Xxx2', 'D')
   2446 
   2447  let content =<< trim [CODE]
   2448    func UnloadAllBufs()
   2449      let i = 1
   2450      while i <= bufnr('$')
   2451        if i != bufnr('%') && bufloaded(i)
   2452          exe  i . 'bunload'
   2453        endif
   2454        let i += 1
   2455      endwhile
   2456    endfunc
   2457    au BufUnload * call UnloadAllBufs()
   2458    au VimLeave * call writefile(['Test Finished'], 'Xout')
   2459    set nohidden  " Accommodate Nvim default
   2460    edit Xxx1
   2461    split Xxx2
   2462    q
   2463  [CODE]
   2464 
   2465  call writefile(content, 'Xbunloadtest', 'D')
   2466 
   2467  call delete('Xout')
   2468  call system(GetVimCommandClean() .. ' -N --headless -S Xbunloadtest')
   2469  call assert_true(filereadable('Xout'))
   2470 
   2471  call delete('Xout')
   2472 endfunc
   2473 
   2474 " Some tests for buffer-local autocommands
   2475 func Test_buflocal_autocmd()
   2476  let g:bname = ''
   2477  edit xx
   2478  au BufLeave <buffer> let g:bname = expand("%")
   2479  " here, autocommand for xx should trigger.
   2480  " but autocommand shall not apply to buffer named <buffer>.
   2481  edit somefile
   2482  call assert_equal('xx', g:bname)
   2483  let g:bname = ''
   2484  " here, autocommand shall be auto-deleted
   2485  bwipe xx
   2486  " autocmd should not trigger
   2487  edit xx
   2488  call assert_equal('', g:bname)
   2489  " autocmd should not trigger
   2490  edit somefile
   2491  call assert_equal('', g:bname)
   2492  enew
   2493  unlet g:bname
   2494 endfunc
   2495 
   2496 " Test for "*Cmd" autocommands
   2497 func Test_Cmd_Autocmds()
   2498  call writefile(['start of Xxx', "\tabc2", 'end of Xxx'], 'Xxx', 'D')
   2499 
   2500  enew!
   2501  au BufReadCmd XtestA 0r Xxx|$del
   2502  edit XtestA			" will read text of Xxd instead
   2503  call assert_equal('start of Xxx', getline(1))
   2504 
   2505  au BufWriteCmd XtestA call append(line("$"), "write")
   2506  write				" will append a line to the file
   2507  call assert_equal('write', getline('$'))
   2508  call assert_fails('read XtestA', 'E484')	" should not read anything
   2509  call assert_equal('write', getline(4))
   2510 
   2511  " now we have:
   2512  " 1	start of Xxx
   2513  " 2		abc2
   2514  " 3	end of Xxx
   2515  " 4	write
   2516 
   2517  au FileReadCmd XtestB '[r Xxx
   2518  2r XtestB			" will read Xxx below line 2 instead
   2519  call assert_equal('start of Xxx', getline(3))
   2520 
   2521  " now we have:
   2522  " 1	start of Xxx
   2523  " 2		abc2
   2524  " 3	start of Xxx
   2525  " 4		abc2
   2526  " 5	end of Xxx
   2527  " 6	end of Xxx
   2528  " 7	write
   2529 
   2530  au FileWriteCmd XtestC '[,']copy $
   2531  normal 4GA1
   2532  4,5w XtestC			" will copy lines 4 and 5 to the end
   2533  call assert_equal("\tabc21", getline(8))
   2534  call assert_fails('r XtestC', 'E484')	" should not read anything
   2535  call assert_equal("end of Xxx", getline(9))
   2536 
   2537  " now we have:
   2538  " 1	start of Xxx
   2539  " 2		abc2
   2540  " 3	start of Xxx
   2541  " 4		abc21
   2542  " 5	end of Xxx
   2543  " 6	end of Xxx
   2544  " 7	write
   2545  " 8		abc21
   2546  " 9	end of Xxx
   2547 
   2548  let g:lines = []
   2549  au FileAppendCmd XtestD call extend(g:lines, getline(line("'["), line("']")))
   2550  w >>XtestD			" will add lines to 'lines'
   2551  call assert_equal(9, len(g:lines))
   2552  call assert_fails('$r XtestD', 'E484')	" should not read anything
   2553  call assert_equal(9, line('$'))
   2554  call assert_equal('end of Xxx', getline('$'))
   2555 
   2556  au BufReadCmd XtestE 0r Xxx|$del
   2557  sp XtestE			" split window with test.out
   2558  call assert_equal('end of Xxx', getline(3))
   2559 
   2560  let g:lines = []
   2561  exe "normal 2Goasdf\<Esc>\<C-W>\<C-W>"
   2562  au BufWriteCmd XtestE call extend(g:lines, getline(0, '$'))
   2563  wall				" will write other window to 'lines'
   2564  call assert_equal(4, len(g:lines), g:lines)
   2565  call assert_equal("asdf", g:lines[2])
   2566 
   2567  au! BufReadCmd
   2568  au! BufWriteCmd
   2569  au! FileReadCmd
   2570  au! FileWriteCmd
   2571  au! FileAppendCmd
   2572  %bwipe!
   2573  enew!
   2574 endfunc
   2575 
   2576 func s:ReadFile()
   2577  setl noswapfile nomodified
   2578  let filename = resolve(expand("<afile>:p"))
   2579  execute 'read' fnameescape(filename)
   2580  1d_
   2581  exe 'file' fnameescape(filename)
   2582  setl buftype=acwrite
   2583 endfunc
   2584 
   2585 func s:WriteFile()
   2586  let filename = resolve(expand("<afile>:p"))
   2587  setl buftype=
   2588  noautocmd execute 'write' fnameescape(filename)
   2589  setl buftype=acwrite
   2590  setl nomodified
   2591 endfunc
   2592 
   2593 func Test_BufReadCmd()
   2594  autocmd BufReadCmd *.test call s:ReadFile()
   2595  autocmd BufWriteCmd *.test call s:WriteFile()
   2596 
   2597  call writefile(['one', 'two', 'three'], 'Xcmd.test', 'D')
   2598  edit Xcmd.test
   2599  set noruler
   2600  call assert_match('Xcmd.test" line 1 of 3', execute('file'))
   2601  set ruler
   2602  call assert_match('Xcmd.test" 3 lines --33%--', execute('file'))
   2603  normal! Gofour
   2604  write
   2605  call assert_equal(['one', 'two', 'three', 'four'], readfile('Xcmd.test'))
   2606 
   2607  bwipe!
   2608  au! BufReadCmd
   2609  au! BufWriteCmd
   2610 endfunc
   2611 
   2612 func Test_BufWriteCmd()
   2613  autocmd BufWriteCmd Xbufwritecmd let g:written = 1
   2614  new
   2615  file Xbufwritecmd
   2616  set buftype=acwrite
   2617  call mkdir('Xbufwritecmd', 'D')
   2618  write
   2619  " BufWriteCmd should be triggered even if a directory has the same name
   2620  call assert_equal(1, g:written)
   2621  unlet g:written
   2622  au! BufWriteCmd
   2623  bwipe!
   2624 endfunc
   2625 
   2626 func SetChangeMarks(start, end)
   2627  exe a:start .. 'mark ['
   2628  exe a:end .. 'mark ]'
   2629 endfunc
   2630 
   2631 " Verify the effects of autocmds on '[ and ']
   2632 func Test_change_mark_in_autocmds()
   2633  edit! Xtest
   2634  call feedkeys("ia\<CR>b\<CR>c\<CR>d\<C-g>u\<Esc>", 'xtn')
   2635 
   2636  call SetChangeMarks(2, 3)
   2637  write
   2638  call assert_equal([1, 4], [line("'["), line("']")])
   2639 
   2640  call SetChangeMarks(2, 3)
   2641  au BufWritePre * call assert_equal([1, 4], [line("'["), line("']")])
   2642  write
   2643  au! BufWritePre
   2644 
   2645  if has('unix')
   2646    write XtestFilter
   2647    write >> XtestFilter
   2648 
   2649    call SetChangeMarks(2, 3)
   2650    " Marks are set to the entire range of the write
   2651    au FilterWritePre * call assert_equal([1, 4], [line("'["), line("']")])
   2652    " '[ is adjusted to just before the line that will receive the filtered
   2653    " data
   2654    au FilterReadPre * call assert_equal([4, 4], [line("'["), line("']")])
   2655    " The filtered data is read into the buffer, and the source lines are
   2656    " still present, so the range is after the source lines
   2657    au FilterReadPost * call assert_equal([5, 12], [line("'["), line("']")])
   2658    %!cat XtestFilter
   2659    " After the filtered data is read, the original lines are deleted
   2660    call assert_equal([1, 8], [line("'["), line("']")])
   2661    au! FilterWritePre,FilterReadPre,FilterReadPost
   2662    undo
   2663 
   2664    call SetChangeMarks(1, 4)
   2665    au FilterWritePre * call assert_equal([2, 3], [line("'["), line("']")])
   2666    au FilterReadPre * call assert_equal([3, 3], [line("'["), line("']")])
   2667    au FilterReadPost * call assert_equal([4, 11], [line("'["), line("']")])
   2668    2,3!cat XtestFilter
   2669    call assert_equal([2, 9], [line("'["), line("']")])
   2670    au! FilterWritePre,FilterReadPre,FilterReadPost
   2671    undo
   2672 
   2673    call delete('XtestFilter')
   2674  endif
   2675 
   2676  call SetChangeMarks(1, 4)
   2677  au FileWritePre * call assert_equal([2, 3], [line("'["), line("']")])
   2678  2,3write Xtest2
   2679  au! FileWritePre
   2680 
   2681  call SetChangeMarks(2, 3)
   2682  au FileAppendPre * call assert_equal([1, 4], [line("'["), line("']")])
   2683  write >> Xtest2
   2684  au! FileAppendPre
   2685 
   2686  call SetChangeMarks(1, 4)
   2687  au FileAppendPre * call assert_equal([2, 3], [line("'["), line("']")])
   2688  2,3write >> Xtest2
   2689  au! FileAppendPre
   2690 
   2691  call SetChangeMarks(1, 1)
   2692  au FileReadPre * call assert_equal([3, 1], [line("'["), line("']")])
   2693  au FileReadPost * call assert_equal([4, 11], [line("'["), line("']")])
   2694  3read Xtest2
   2695  au! FileReadPre,FileReadPost
   2696  undo
   2697 
   2698  call SetChangeMarks(4, 4)
   2699  " When the line is 0, it's adjusted to 1
   2700  au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")])
   2701  au FileReadPost * call assert_equal([1, 8], [line("'["), line("']")])
   2702  0read Xtest2
   2703  au! FileReadPre,FileReadPost
   2704  undo
   2705 
   2706  call SetChangeMarks(4, 4)
   2707  " When the line is 0, it's adjusted to 1
   2708  au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")])
   2709  au FileReadPost * call assert_equal([2, 9], [line("'["), line("']")])
   2710  1read Xtest2
   2711  au! FileReadPre,FileReadPost
   2712  undo
   2713 
   2714  bwipe!
   2715  call delete('Xtest')
   2716  call delete('Xtest2')
   2717 endfunc
   2718 
   2719 func Test_Filter_noshelltemp()
   2720  CheckExecutable cat
   2721 
   2722  enew!
   2723  call setline(1, ['a', 'b', 'c', 'd'])
   2724 
   2725  let shelltemp = &shelltemp
   2726  set shelltemp
   2727 
   2728  let g:filter_au = 0
   2729  au FilterWritePre * let g:filter_au += 1
   2730  au FilterReadPre * let g:filter_au += 1
   2731  au FilterReadPost * let g:filter_au += 1
   2732  %!cat
   2733  call assert_equal(3, g:filter_au)
   2734 
   2735  if has('filterpipe')
   2736    set noshelltemp
   2737 
   2738    let g:filter_au = 0
   2739    au FilterWritePre * let g:filter_au += 1
   2740    au FilterReadPre * let g:filter_au += 1
   2741    au FilterReadPost * let g:filter_au += 1
   2742    %!cat
   2743    call assert_equal(0, g:filter_au)
   2744  endif
   2745 
   2746  au! FilterWritePre,FilterReadPre,FilterReadPost
   2747  let &shelltemp = shelltemp
   2748  bwipe!
   2749 endfunc
   2750 
   2751 func Test_TextYankPost()
   2752  enew!
   2753  call setline(1, ['foo'])
   2754 
   2755  let g:event = []
   2756  au TextYankPost * let g:event = copy(v:event)
   2757 
   2758  call assert_equal({}, v:event)
   2759  call assert_fails('let v:event = {}', 'E46:')
   2760  call assert_fails('let v:event.mykey = 0', 'E742:')
   2761 
   2762  norm "ayiw
   2763  call assert_equal(
   2764    \{'regcontents': ['foo'], 'inclusive': v:true, 'regname': 'a', 'operator': 'y', 'visual': v:false, 'regtype': 'v'},
   2765    \g:event)
   2766  norm y_
   2767  call assert_equal(
   2768    \{'regcontents': ['foo'], 'inclusive': v:false, 'regname': '',  'operator': 'y', 'visual': v:false, 'regtype': 'V'},
   2769    \g:event)
   2770  norm Vy
   2771  call assert_equal(
   2772    \{'regcontents': ['foo'], 'inclusive': v:true, 'regname': '',  'operator': 'y', 'visual': v:true, 'regtype': 'V'},
   2773    \g:event)
   2774  call feedkeys("\<C-V>y", 'x')
   2775  call assert_equal(
   2776    \{'regcontents': ['f'], 'inclusive': v:true, 'regname': '',  'operator': 'y', 'visual': v:true, 'regtype': "\x161"},
   2777    \g:event)
   2778  norm "xciwbar
   2779  call assert_equal(
   2780    \{'regcontents': ['foo'], 'inclusive': v:true, 'regname': 'x', 'operator': 'c', 'visual': v:false, 'regtype': 'v'},
   2781    \g:event)
   2782  norm "bdiw
   2783  call assert_equal(
   2784    \{'regcontents': ['bar'], 'inclusive': v:true, 'regname': 'b', 'operator': 'd', 'visual': v:false, 'regtype': 'v'},
   2785    \g:event)
   2786 
   2787  call assert_equal({}, v:event)
   2788 
   2789  au! TextYankPost
   2790  unlet g:event
   2791  bwipe!
   2792 endfunc
   2793 
   2794 func Test_autocommand_all_events()
   2795  call assert_fails('au * * bwipe', 'E1155:')
   2796  call assert_fails('au * x bwipe', 'E1155:')
   2797  call assert_fails('au! * x bwipe', 'E1155:')
   2798 endfunc
   2799 
   2800 func Test_autocmd_user()
   2801  au User MyEvent let s:res = [expand("<afile>"), expand("<amatch>")]
   2802  doautocmd User MyEvent
   2803  call assert_equal(['MyEvent', 'MyEvent'], s:res)
   2804  au! User
   2805  unlet s:res
   2806 endfunc
   2807 
   2808 function s:Before_test_dirchanged()
   2809  augroup test_dirchanged
   2810    autocmd!
   2811  augroup END
   2812  let s:li = []
   2813  let s:dir_this = getcwd()
   2814  let s:dir_foo = s:dir_this . '/Xfoo'
   2815  call mkdir(s:dir_foo)
   2816  let s:dir_bar = s:dir_this . '/Xbar'
   2817  call mkdir(s:dir_bar)
   2818 endfunc
   2819 
   2820 function s:After_test_dirchanged()
   2821  call chdir(s:dir_this)
   2822  call delete(s:dir_foo, 'd')
   2823  call delete(s:dir_bar, 'd')
   2824  augroup test_dirchanged
   2825    autocmd!
   2826  augroup END
   2827 endfunc
   2828 
   2829 function Test_dirchanged_global()
   2830  call s:Before_test_dirchanged()
   2831  autocmd test_dirchanged DirChangedPre global call add(s:li, expand("<amatch>") .. " pre cd " .. v:event.directory)
   2832  autocmd test_dirchanged DirChanged global call add(s:li, "cd:")
   2833  autocmd test_dirchanged DirChanged global call add(s:li, expand("<afile>"))
   2834  call chdir(s:dir_foo)
   2835  let expected = ["global pre cd " .. s:dir_foo, "cd:", s:dir_foo]
   2836  call assert_equal(expected, s:li)
   2837  call chdir(s:dir_foo)
   2838  call assert_equal(expected, s:li)
   2839  exe 'lcd ' .. fnameescape(s:dir_bar)
   2840  call assert_equal(expected, s:li)
   2841 
   2842  exe 'cd ' .. s:dir_foo
   2843  exe 'cd ' .. s:dir_bar
   2844  autocmd! test_dirchanged DirChanged global let g:result = expand("<afile>")
   2845  cd -
   2846  call assert_equal(s:dir_foo, substitute(g:result, '\\', '/', 'g'))
   2847 
   2848  call s:After_test_dirchanged()
   2849 endfunc
   2850 
   2851 function Test_dirchanged_local()
   2852  call s:Before_test_dirchanged()
   2853  autocmd test_dirchanged DirChanged window call add(s:li, "lcd:")
   2854  autocmd test_dirchanged DirChanged window call add(s:li, expand("<afile>"))
   2855  call chdir(s:dir_foo)
   2856  call assert_equal([], s:li)
   2857  exe 'lcd ' .. fnameescape(s:dir_bar)
   2858  call assert_equal(["lcd:", s:dir_bar], s:li)
   2859  exe 'lcd ' .. fnameescape(s:dir_bar)
   2860  call assert_equal(["lcd:", s:dir_bar], s:li)
   2861  call s:After_test_dirchanged()
   2862 endfunc
   2863 
   2864 function Test_dirchanged_auto()
   2865  CheckFunction test_autochdir
   2866  CheckOption autochdir
   2867  call s:Before_test_dirchanged()
   2868  call test_autochdir()
   2869  autocmd test_dirchanged DirChangedPre auto call add(s:li, "pre cd " .. v:event.directory)
   2870  autocmd test_dirchanged DirChanged auto call add(s:li, "auto:")
   2871  autocmd test_dirchanged DirChanged auto call add(s:li, expand("<afile>"))
   2872  set acd
   2873  cd ..
   2874  call assert_equal([], s:li)
   2875  exe 'edit ' . s:dir_foo . '/Xautofile'
   2876  call assert_equal(s:dir_foo, getcwd())
   2877  let expected = ["pre cd " .. s:dir_foo, "auto:", s:dir_foo]
   2878  call assert_equal(expected, s:li)
   2879  set noacd
   2880  bwipe!
   2881  call s:After_test_dirchanged()
   2882 endfunc
   2883 
   2884 " Test TextChangedI and TextChangedP
   2885 func Test_ChangedP()
   2886  new
   2887  call setline(1, ['foo', 'bar', 'foobar'])
   2888  call Ntest_override("char_avail", 1)
   2889  set complete=. completeopt=menuone
   2890 
   2891  func! TextChangedAutocmd(char)
   2892    let g:autocmd .= a:char
   2893  endfunc
   2894 
   2895  " TextChanged will not be triggered, only check that it isn't.
   2896  au! TextChanged <buffer> :call TextChangedAutocmd('N')
   2897  au! TextChangedI <buffer> :call TextChangedAutocmd('I')
   2898  au! TextChangedP <buffer> :call TextChangedAutocmd('P')
   2899 
   2900  call cursor(3, 1)
   2901  let g:autocmd = ''
   2902  call feedkeys("o\<esc>", 'tnix')
   2903  call assert_equal('I', g:autocmd)
   2904 
   2905  let g:autocmd = ''
   2906  call feedkeys("Sf", 'tnix')
   2907  call assert_equal('II', g:autocmd)
   2908 
   2909  let g:autocmd = ''
   2910  call feedkeys("Sf\<C-N>", 'tnix')
   2911  call assert_equal('IIP', g:autocmd)
   2912 
   2913  let g:autocmd = ''
   2914  call feedkeys("Sf\<C-N>\<C-N>", 'tnix')
   2915  call assert_equal('IIPP', g:autocmd)
   2916 
   2917  let g:autocmd = ''
   2918  call feedkeys("Sf\<C-N>\<C-N>\<C-N>", 'tnix')
   2919  call assert_equal('IIPPP', g:autocmd)
   2920 
   2921  let g:autocmd = ''
   2922  call feedkeys("Sf\<C-N>\<C-N>\<C-N>\<C-N>", 'tnix')
   2923  call assert_equal('IIPPPP', g:autocmd)
   2924 
   2925  call assert_equal(['foo', 'bar', 'foobar', 'foo'], getline(1, '$'))
   2926  " TODO: how should it handle completeopt=noinsert,noselect?
   2927 
   2928  " CleanUp
   2929  call Ntest_override("char_avail", 0)
   2930  au! TextChanged
   2931  au! TextChangedI
   2932  au! TextChangedP
   2933  delfu TextChangedAutocmd
   2934  unlet! g:autocmd
   2935  set complete&vim completeopt&vim
   2936 
   2937  bw!
   2938 endfunc
   2939 
   2940 let g:setline_handled = v:false
   2941 func SetLineOne()
   2942  if !g:setline_handled
   2943    call setline(1, "(x)")
   2944    let g:setline_handled = v:true
   2945  endif
   2946 endfunc
   2947 
   2948 func Test_TextChangedI_with_setline()
   2949  new
   2950  call Ntest_override('char_avail', 1)
   2951  autocmd TextChangedI <buffer> call SetLineOne()
   2952  call feedkeys("i(\<CR>\<Esc>", 'tx')
   2953  call assert_equal('(', getline(1))
   2954  call assert_equal('x)', getline(2))
   2955  undo
   2956  call assert_equal('', getline(1))
   2957  call assert_equal('', getline(2))
   2958 
   2959  call Ntest_override('char_avail', 0)
   2960  bwipe!
   2961 endfunc
   2962 
   2963 func Test_TextChanged_with_norm()
   2964  " For unknown reason this fails on MS-Windows
   2965  CheckNotMSWindows
   2966  CheckFeature terminal
   2967  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3})
   2968  call assert_equal('running', term_getstatus(buf))
   2969  call term_sendkeys(buf, ":let g:a=0\<cr>")
   2970  call term_wait(buf, 50)
   2971  call term_sendkeys(buf, ":au! TextChanged * :let g:a+=1\<cr>")
   2972  call term_wait(buf, 50)
   2973  call term_sendkeys(buf, ":norm! ia\<cr>")
   2974  call term_wait(buf, 50)
   2975  call term_sendkeys(buf, ":echo g:a\<cr>")
   2976  call term_wait(buf, 50)
   2977  call WaitForAssert({-> assert_match('^1.*$', term_getline(buf, 3))})
   2978  bwipe!
   2979 endfunc
   2980 
   2981 func Test_Changed_FirstTime()
   2982  CheckFeature terminal
   2983  CheckNotGui
   2984  " Starting a terminal to run Vim is always considered flaky.
   2985  let g:test_is_flaky = 1
   2986 
   2987  " Prepare file for TextChanged event.
   2988  call writefile([''], 'Xchanged.txt', 'D')
   2989  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3})
   2990  call assert_equal('running', term_getstatus(buf))
   2991  " Wait for the ruler (in the status line) to be shown.
   2992  " In ConPTY, there is additional character which is drawn up to the width of
   2993  " the screen.
   2994  if has('conpty')
   2995    call WaitForAssert({-> assert_match('\<All.*$', term_getline(buf, 3))})
   2996  else
   2997    call WaitForAssert({-> assert_match('\<All$', term_getline(buf, 3))})
   2998  endif
   2999  " It's only adding autocmd, so that no event occurs.
   3000  call term_sendkeys(buf, ":au! TextChanged <buffer> call writefile(['No'], 'Xchanged.txt')\<cr>")
   3001  call term_sendkeys(buf, "\<C-\\>\<C-N>:qa!\<cr>")
   3002  call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))})
   3003  call assert_equal([''], readfile('Xchanged.txt'))
   3004 
   3005  " clean up
   3006  bwipe!
   3007 endfunc
   3008 
   3009 func Test_autocmd_nested()
   3010  let g:did_nested = 0
   3011  defer CleanUpTestAuGroup()
   3012  augroup testing
   3013    au WinNew * edit somefile
   3014    au BufNew * let g:did_nested = 1
   3015  augroup END
   3016  split
   3017  call assert_equal(0, g:did_nested)
   3018  close
   3019  bwipe! somefile
   3020 
   3021  " old nested argument still works
   3022  augroup testing
   3023    au!
   3024    au WinNew * nested edit somefile
   3025    au BufNew * let g:did_nested = 1
   3026  augroup END
   3027  split
   3028  call assert_equal(1, g:did_nested)
   3029  close
   3030  bwipe! somefile
   3031 
   3032  " New ++nested argument works
   3033  augroup Testing
   3034    au!
   3035    au WinNew * ++nested edit somefile
   3036    au BufNew * let g:did_nested = 1
   3037  augroup END
   3038  split
   3039  call assert_equal(1, g:did_nested)
   3040  close
   3041  bwipe! somefile
   3042 
   3043  augroup Testing
   3044    au!
   3045  augroup END
   3046 
   3047  call assert_fails('au WinNew * ++nested ++nested echo bad', 'E983:')
   3048  call assert_fails('au WinNew * nested nested echo bad', 'E983:')
   3049 endfunc
   3050 
   3051 func Test_autocmd_nested_cursor_invalid()
   3052  set laststatus=0
   3053  copen
   3054  cclose
   3055  call setline(1, ['foo', 'bar', 'baz'])
   3056  3
   3057  augroup nested_inv
   3058    autocmd User foo ++nested copen
   3059    autocmd BufAdd * let &laststatus = 2 - &laststatus
   3060  augroup END
   3061  doautocmd User foo
   3062 
   3063  augroup nested_inv
   3064    au!
   3065  augroup END
   3066  set laststatus&
   3067  cclose
   3068  bwipe!
   3069 endfunc
   3070 
   3071 func Test_autocmd_nested_keeps_cursor_pos()
   3072  enew
   3073  call setline(1, 'foo')
   3074  autocmd User foo ++nested normal! $a
   3075  autocmd InsertLeave * :
   3076  doautocmd User foo
   3077  call assert_equal([0, 1, 3, 0], getpos('.'))
   3078 
   3079  bwipe!
   3080 endfunc
   3081 
   3082 func Test_autocmd_nested_switch_window()
   3083  " run this in a separate Vim so that SafeState works
   3084  CheckRunVimInTerminal
   3085  CheckScreendump
   3086 
   3087  let lines =<< trim END
   3088      vim9script
   3089      ['()']->writefile('Xautofile')
   3090      autocmd VimEnter * ++nested edit Xautofile | split
   3091      autocmd BufReadPost * autocmd SafeState * ++once foldclosed('.')
   3092      autocmd WinEnter * matchadd('ErrorMsg', 'pat')
   3093  END
   3094  call writefile(lines, 'Xautoscript', 'D')
   3095  let buf = RunVimInTerminal('-S Xautoscript', {'rows': 10})
   3096  call VerifyScreenDump(buf, 'Test_autocmd_nested_switch', {})
   3097 
   3098  call StopVimInTerminal(buf)
   3099  call delete('Xautofile')
   3100 endfunc
   3101 
   3102 func Test_autocmd_once()
   3103  " Without ++once WinNew triggers twice
   3104  let g:did_split = 0
   3105  augroup Testing
   3106    au WinNew * let g:did_split += 1
   3107  augroup END
   3108  split
   3109  split
   3110  call assert_equal(2, g:did_split)
   3111  call assert_true(exists('#WinNew'))
   3112  close
   3113  close
   3114 
   3115  " With ++once WinNew triggers once
   3116  let g:did_split = 0
   3117  augroup Testing
   3118    au!
   3119    au WinNew * ++once let g:did_split += 1
   3120  augroup END
   3121  split
   3122  split
   3123  call assert_equal(1, g:did_split)
   3124  call assert_false(exists('#WinNew'))
   3125  close
   3126  close
   3127 
   3128  call assert_fails('au WinNew * ++once ++once echo bad', 'E983:')
   3129 endfunc
   3130 
   3131 func Test_autocmd_bufreadpre()
   3132  new
   3133  let b:bufreadpre = 1
   3134  call append(0, range(100))
   3135  w! XAutocmdBufReadPre.txt
   3136  autocmd BufReadPre <buffer> :let b:bufreadpre += 1
   3137  norm! 50gg
   3138  sp
   3139  norm! 100gg
   3140  wincmd p
   3141  let g:wsv1 = winsaveview()
   3142  wincmd p
   3143  let g:wsv2 = winsaveview()
   3144  " triggers BufReadPre, should not move the cursor in either window
   3145  " The topline may change one line in a large window.
   3146  edit
   3147  call assert_inrange(g:wsv2.topline - 1, g:wsv2.topline + 1, winsaveview().topline)
   3148  call assert_equal(g:wsv2.lnum, winsaveview().lnum)
   3149  call assert_equal(2, b:bufreadpre)
   3150  wincmd p
   3151  call assert_equal(g:wsv1.topline, winsaveview().topline)
   3152  call assert_equal(g:wsv1.lnum, winsaveview().lnum)
   3153  call assert_equal(2, b:bufreadpre)
   3154  " Now set the cursor position in an BufReadPre autocommand
   3155  " (even though the position will be invalid, this should make Vim reset the
   3156  " cursor position in the other window.
   3157  wincmd p
   3158  1 " set cpo+=g
   3159  " won't do anything, but try to set the cursor on an invalid lnum
   3160  autocmd BufReadPre <buffer> :norm! 70gg
   3161  " triggers BufReadPre, should not move the cursor in either window
   3162  e
   3163  call assert_equal(1, winsaveview().topline)
   3164  call assert_equal(1, winsaveview().lnum)
   3165  call assert_equal(3, b:bufreadpre)
   3166  wincmd p
   3167  call assert_equal(g:wsv1.topline, winsaveview().topline)
   3168  call assert_equal(g:wsv1.lnum, winsaveview().lnum)
   3169  call assert_equal(3, b:bufreadpre)
   3170  close
   3171  close
   3172  call delete('XAutocmdBufReadPre.txt')
   3173  set cpo-=g
   3174 endfunc
   3175 
   3176 " FileChangedShell tested in test_filechanged.vim
   3177 
   3178 " Tests for the following autocommands:
   3179 " - FileWritePre	writing a compressed file
   3180 " - FileReadPost	reading a compressed file
   3181 " - BufNewFile		reading a file template
   3182 " - BufReadPre		decompressing the file to be read
   3183 " - FilterReadPre	substituting characters in the temp file
   3184 " - FilterReadPost	substituting characters after filtering
   3185 " - FileReadPre		set options for decompression
   3186 " - FileReadPost	decompress the file
   3187 func Test_ReadWrite_Autocmds()
   3188  " Run this test only on Unix-like systems and if gzip is available
   3189  if !has('unix') || !executable("gzip")
   3190    return
   3191  endif
   3192 
   3193  " Make $GZIP empty, "-v" would cause trouble.
   3194  let $GZIP = ""
   3195 
   3196  " Use a FileChangedShell autocommand to avoid a prompt for 'Xtestfile.gz'
   3197  " being modified outside of Vim (noticed on Solaris).
   3198  au FileChangedShell * echo 'caught FileChangedShell'
   3199 
   3200  " Test for the FileReadPost, FileWritePre and FileWritePost autocmds
   3201  augroup Test1
   3202    au!
   3203    au FileWritePre    *.gz   '[,']!gzip
   3204    au FileWritePost   *.gz   undo
   3205    au FileReadPost    *.gz   '[,']!gzip -d
   3206  augroup END
   3207 
   3208  new
   3209  set bin
   3210  call append(0, [
   3211       \ 'line 2	Abcdefghijklmnopqrstuvwxyz',
   3212       \ 'line 3	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3213       \ 'line 4	Abcdefghijklmnopqrstuvwxyz',
   3214       \ 'line 5	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3215       \ 'line 6	Abcdefghijklmnopqrstuvwxyz',
   3216       \ 'line 7	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3217       \ 'line 8	Abcdefghijklmnopqrstuvwxyz',
   3218       \ 'line 9	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3219       \ 'line 10 Abcdefghijklmnopqrstuvwxyz'
   3220       \ ])
   3221  1,9write! Xtestfile.gz
   3222  enew! | close
   3223 
   3224  new
   3225  " Read and decompress the testfile
   3226  0read Xtestfile.gz
   3227  call assert_equal([
   3228       \ 'line 2	Abcdefghijklmnopqrstuvwxyz',
   3229       \ 'line 3	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3230       \ 'line 4	Abcdefghijklmnopqrstuvwxyz',
   3231       \ 'line 5	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3232       \ 'line 6	Abcdefghijklmnopqrstuvwxyz',
   3233       \ 'line 7	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3234       \ 'line 8	Abcdefghijklmnopqrstuvwxyz',
   3235       \ 'line 9	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3236       \ 'line 10 Abcdefghijklmnopqrstuvwxyz'
   3237       \ ], getline(1, 9))
   3238  enew! | close
   3239 
   3240  augroup Test1
   3241    au!
   3242  augroup END
   3243 
   3244  " Test for the FileAppendPre and FileAppendPost autocmds
   3245  augroup Test2
   3246    au!
   3247    au BufNewFile      *.c    read Xtest.c
   3248    au FileAppendPre   *.out  '[,']s/new/NEW/
   3249    au FileAppendPost  *.out  !cat Xtest.c >> test.out
   3250  augroup END
   3251 
   3252  call writefile(['/*', ' * Here is a new .c file', ' */'], 'Xtest.c', 'D')
   3253  new foo.c			" should load Xtest.c
   3254  call assert_equal(['/*', ' * Here is a new .c file', ' */'], getline(2, 4))
   3255  w! >> test.out		" append it to the output file
   3256 
   3257  let contents = readfile('test.out')
   3258  call assert_equal(' * Here is a NEW .c file', contents[2])
   3259  call assert_equal(' * Here is a new .c file', contents[5])
   3260 
   3261  call delete('test.out')
   3262  enew! | close
   3263  augroup Test2
   3264    au!
   3265  augroup END
   3266 
   3267  " Test for the BufReadPre and BufReadPost autocmds
   3268  augroup Test3
   3269    au!
   3270    " setup autocommands to decompress before reading and re-compress
   3271    " afterwards
   3272    au BufReadPre  *.gz  exe '!gzip -d ' . shellescape(expand("<afile>"))
   3273    au BufReadPre  *.gz  call rename(expand("<afile>:r"), expand("<afile>"))
   3274    au BufReadPost *.gz  call rename(expand("<afile>"), expand("<afile>:r"))
   3275    au BufReadPost *.gz  exe '!gzip ' . shellescape(expand("<afile>:r"))
   3276  augroup END
   3277 
   3278  e! Xtestfile.gz		" Edit compressed file
   3279  call assert_equal([
   3280       \ 'line 2	Abcdefghijklmnopqrstuvwxyz',
   3281       \ 'line 3	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3282       \ 'line 4	Abcdefghijklmnopqrstuvwxyz',
   3283       \ 'line 5	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3284       \ 'line 6	Abcdefghijklmnopqrstuvwxyz',
   3285       \ 'line 7	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3286       \ 'line 8	Abcdefghijklmnopqrstuvwxyz',
   3287       \ 'line 9	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3288       \ 'line 10 Abcdefghijklmnopqrstuvwxyz'
   3289       \ ], getline(1, 9))
   3290 
   3291  w! >> test.out		" Append it to the output file
   3292 
   3293  augroup Test3
   3294    au!
   3295  augroup END
   3296 
   3297  " Test for the FilterReadPre and FilterReadPost autocmds.
   3298  set shelltemp			" need temp files here
   3299  augroup Test4
   3300    au!
   3301    au FilterReadPre   *.out  call rename(expand("<afile>"), expand("<afile>") . ".t")
   3302    au FilterReadPre   *.out  exe 'silent !sed s/e/E/ ' . shellescape(expand("<afile>")) . ".t >" . shellescape(expand("<afile>"))
   3303    au FilterReadPre   *.out  exe 'silent !rm ' . shellescape(expand("<afile>")) . '.t'
   3304    au FilterReadPost  *.out  '[,']s/x/X/g
   3305  augroup END
   3306 
   3307  e! test.out			" Edit the output file
   3308  1,$!cat
   3309  call assert_equal([
   3310       \ 'linE 2	AbcdefghijklmnopqrstuvwXyz',
   3311       \ 'linE 3	XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
   3312       \ 'linE 4	AbcdefghijklmnopqrstuvwXyz',
   3313       \ 'linE 5	XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
   3314       \ 'linE 6	AbcdefghijklmnopqrstuvwXyz',
   3315       \ 'linE 7	XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
   3316       \ 'linE 8	AbcdefghijklmnopqrstuvwXyz',
   3317       \ 'linE 9	XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
   3318       \ 'linE 10 AbcdefghijklmnopqrstuvwXyz'
   3319       \ ], getline(1, 9))
   3320  call assert_equal([
   3321       \ 'line 2	Abcdefghijklmnopqrstuvwxyz',
   3322       \ 'line 3	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3323       \ 'line 4	Abcdefghijklmnopqrstuvwxyz',
   3324       \ 'line 5	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3325       \ 'line 6	Abcdefghijklmnopqrstuvwxyz',
   3326       \ 'line 7	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3327       \ 'line 8	Abcdefghijklmnopqrstuvwxyz',
   3328       \ 'line 9	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3329       \ 'line 10 Abcdefghijklmnopqrstuvwxyz'
   3330       \ ], readfile('test.out'))
   3331 
   3332  augroup Test4
   3333    au!
   3334  augroup END
   3335  set shelltemp&vim
   3336 
   3337  " Test for the FileReadPre and FileReadPost autocmds.
   3338  augroup Test5
   3339    au!
   3340    au FileReadPre *.gz exe 'silent !gzip -d ' . shellescape(expand("<afile>"))
   3341    au FileReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>"))
   3342    au FileReadPost *.gz '[,']s/l/L/
   3343  augroup END
   3344 
   3345  new
   3346  0r Xtestfile.gz		" Read compressed file
   3347  call assert_equal([
   3348       \ 'Line 2	Abcdefghijklmnopqrstuvwxyz',
   3349       \ 'Line 3	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3350       \ 'Line 4	Abcdefghijklmnopqrstuvwxyz',
   3351       \ 'Line 5	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3352       \ 'Line 6	Abcdefghijklmnopqrstuvwxyz',
   3353       \ 'Line 7	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3354       \ 'Line 8	Abcdefghijklmnopqrstuvwxyz',
   3355       \ 'Line 9	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3356       \ 'Line 10 Abcdefghijklmnopqrstuvwxyz'
   3357       \ ], getline(1, 9))
   3358  call assert_equal([
   3359       \ 'line 2	Abcdefghijklmnopqrstuvwxyz',
   3360       \ 'line 3	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3361       \ 'line 4	Abcdefghijklmnopqrstuvwxyz',
   3362       \ 'line 5	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3363       \ 'line 6	Abcdefghijklmnopqrstuvwxyz',
   3364       \ 'line 7	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3365       \ 'line 8	Abcdefghijklmnopqrstuvwxyz',
   3366       \ 'line 9	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
   3367       \ 'line 10 Abcdefghijklmnopqrstuvwxyz'
   3368       \ ], readfile('Xtestfile.gz'))
   3369 
   3370  augroup Test5
   3371    au!
   3372  augroup END
   3373 
   3374  au! FileChangedShell
   3375  call delete('Xtestfile.gz')
   3376  call delete('test.out')
   3377 endfunc
   3378 
   3379 func Test_throw_in_BufWritePre()
   3380  new
   3381  call setline(1, ['one', 'two', 'three'])
   3382  call assert_false(filereadable('Xthefile'))
   3383  augroup throwing
   3384    au BufWritePre X* throw 'do not write'
   3385  augroup END
   3386  try
   3387    w Xthefile
   3388  catch
   3389    let caught = 1
   3390  endtry
   3391  call assert_equal(1, caught)
   3392  call assert_false(filereadable('Xthefile'))
   3393 
   3394  bwipe!
   3395  au! throwing
   3396 endfunc
   3397 
   3398 func Test_autocmd_in_try_block()
   3399  call mkdir('Xintrydir', 'R')
   3400  au BufEnter * let g:fname = expand('%')
   3401  try
   3402    edit Xintrydir/
   3403  endtry
   3404  call assert_match('Xintrydir', g:fname)
   3405 
   3406  unlet g:fname
   3407  au! BufEnter
   3408 endfunc
   3409 
   3410 func Test_autocmd_SafeState()
   3411  CheckRunVimInTerminal
   3412 
   3413  let lines =<< trim END
   3414 let g:safe = 0
   3415 let g:again = ''
   3416 au SafeState * let g:safe += 1
   3417 au SafeStateAgain * let g:again ..= 'x'
   3418 func CallTimer()
   3419   call timer_start(10, {id -> execute('let g:again ..= "t"')})
   3420 endfunc
   3421  END
   3422  call writefile(lines, 'XSafeState', 'D')
   3423  let buf = RunVimInTerminal('-S XSafeState', #{rows: 6})
   3424 
   3425  " Sometimes we loop to handle a K_IGNORE, SafeState may be triggered once or
   3426  " more often.
   3427  call term_sendkeys(buf, ":echo g:safe\<CR>")
   3428  call WaitForAssert({-> assert_match('^\d ', term_getline(buf, 6))}, 1000)
   3429 
   3430  " SafeStateAgain should be invoked at least three times
   3431  call term_sendkeys(buf, ":echo g:again\<CR>")
   3432  call WaitForAssert({-> assert_match('^xxx', term_getline(buf, 6))}, 1000)
   3433 
   3434  call term_sendkeys(buf, ":let g:again = ''\<CR>:call CallTimer()\<CR>")
   3435  call TermWait(buf, 50)
   3436  call term_sendkeys(buf, ":\<CR>")
   3437  call TermWait(buf, 50)
   3438  call term_sendkeys(buf, ":echo g:again\<CR>")
   3439  call WaitForAssert({-> assert_match('xtx', term_getline(buf, 6))}, 1000)
   3440 
   3441  call StopVimInTerminal(buf)
   3442 endfunc
   3443 
   3444 func Test_autocmd_CmdWinEnter()
   3445  CheckRunVimInTerminal
   3446  " There is not cmdwin switch, so
   3447  " test for cmdline_hist
   3448  " (both are available with small builds)
   3449  CheckFeature cmdline_hist
   3450  let lines =<< trim END
   3451    let b:dummy_var = 'This is a dummy'
   3452    autocmd CmdWinEnter * quit
   3453    let winnr = winnr('$')
   3454  END
   3455  let filename = 'XCmdWinEnter'
   3456  call writefile(lines, filename)
   3457  let buf = RunVimInTerminal('-S '.filename, #{rows: 6})
   3458 
   3459  call term_sendkeys(buf, "q:")
   3460  call TermWait(buf)
   3461  call term_sendkeys(buf, ":echo b:dummy_var\<cr>")
   3462  call WaitForAssert({-> assert_match('^This is a dummy', term_getline(buf, 6))}, 2000)
   3463  call term_sendkeys(buf, ":echo &buftype\<cr>")
   3464  call WaitForAssert({-> assert_notmatch('^nofile', term_getline(buf, 6))}, 1000)
   3465  call term_sendkeys(buf, ":echo winnr\<cr>")
   3466  call WaitForAssert({-> assert_match('^1', term_getline(buf, 6))}, 1000)
   3467 
   3468  " clean up
   3469  call StopVimInTerminal(buf)
   3470  call delete(filename)
   3471 endfunc
   3472 
   3473 func Test_autocmd_was_using_freed_memory()
   3474  CheckFeature quickfix
   3475 
   3476  pedit xx
   3477  n x
   3478  augroup winenter
   3479    au WinEnter * if winnr('$') > 2 | quit | endif
   3480  augroup END
   3481  " Nvim needs large 'winwidth' and 'nowinfixwidth' to crash
   3482  set winwidth=99999 nowinfixwidth
   3483  split
   3484 
   3485  augroup winenter
   3486    au! WinEnter
   3487  augroup END
   3488 
   3489  set winwidth& winfixwidth&
   3490  bwipe xx
   3491  bwipe x
   3492  pclose
   3493 endfunc
   3494 
   3495 func Test_BufWrite_lockmarks()
   3496  let g:test_is_flaky = 1
   3497  edit! Xtest
   3498  call setline(1, ['a', 'b', 'c', 'd'])
   3499 
   3500  " :lockmarks preserves the marks
   3501  call SetChangeMarks(2, 3)
   3502  lockmarks write
   3503  call assert_equal([2, 3], [line("'["), line("']")])
   3504 
   3505  " *WritePre autocmds get the correct line range, but lockmarks preserves the
   3506  " original values for the user
   3507  augroup lockmarks
   3508    au!
   3509    au BufWritePre,FilterWritePre * call assert_equal([1, 4], [line("'["), line("']")])
   3510    au FileWritePre * call assert_equal([3, 4], [line("'["), line("']")])
   3511  augroup END
   3512 
   3513  lockmarks write
   3514  call assert_equal([2, 3], [line("'["), line("']")])
   3515 
   3516  if executable('cat')
   3517    lockmarks %!cat
   3518    call assert_equal([2, 3], [line("'["), line("']")])
   3519  endif
   3520 
   3521  lockmarks 3,4write Xtest2
   3522  call assert_equal([2, 3], [line("'["), line("']")])
   3523 
   3524  au! lockmarks
   3525  augroup! lockmarks
   3526  call delete('Xtest')
   3527  call delete('Xtest2')
   3528 endfunc
   3529 
   3530 func Test_FileType_spell()
   3531  if !isdirectory('/tmp')
   3532    throw "Skipped: requires /tmp directory"
   3533  endif
   3534 
   3535  " this was crashing with an invalid free()
   3536  setglobal spellfile=/tmp/en.utf-8.add
   3537  augroup crash
   3538    autocmd!
   3539    autocmd BufNewFile,BufReadPost crashfile setf somefiletype
   3540    autocmd BufNewFile,BufReadPost crashfile set ft=anotherfiletype
   3541    autocmd FileType anotherfiletype setlocal spell
   3542  augroup END
   3543  func! NoCrash() abort
   3544    edit /tmp/crashfile
   3545  endfunc
   3546  call NoCrash()
   3547 
   3548  au! crash
   3549  setglobal spellfile=
   3550 endfunc
   3551 
   3552 " this was wiping out the current buffer and using freed memory
   3553 func Test_SpellFileMissing_bwipe()
   3554  next 0
   3555  au SpellFileMissing 0 bwipe
   3556  call assert_fails('set spell spelllang=0', 'E937:')
   3557 
   3558  au! SpellFileMissing
   3559  set nospell spelllang=en
   3560  bwipe
   3561 endfunc
   3562 
   3563 " Test closing a window or editing another buffer from a FileChangedRO handler
   3564 " in a readonly buffer
   3565 func Test_FileChangedRO_winclose()
   3566  augroup FileChangedROTest
   3567    au!
   3568    autocmd FileChangedRO * quit
   3569  augroup END
   3570  new
   3571  set readonly
   3572  call assert_fails('normal i', 'E788:')
   3573  close
   3574  augroup! FileChangedROTest
   3575 
   3576  augroup FileChangedROTest
   3577    au!
   3578    autocmd FileChangedRO * edit Xrofile
   3579  augroup END
   3580  new
   3581  set readonly
   3582  call assert_fails('normal i', 'E788:')
   3583  close
   3584  augroup! FileChangedROTest
   3585 endfunc
   3586 
   3587 func LogACmd()
   3588  call add(g:logged, line('$'))
   3589 endfunc
   3590 
   3591 func Test_TermChanged()
   3592  throw 'skipped: Nvim does not support TermChanged event'
   3593  CheckNotGui
   3594 
   3595  enew!
   3596  tabnew
   3597  call setline(1, ['a', 'b', 'c', 'd'])
   3598  $
   3599  au TermChanged * call LogACmd()
   3600  let g:logged = []
   3601  let term_save = &term
   3602  set term=xterm
   3603  call assert_equal([1, 4], g:logged)
   3604 
   3605  au! TermChanged
   3606  let &term = term_save
   3607  bwipe!
   3608 endfunc
   3609 
   3610 " Test for FileReadCmd autocmd
   3611 func Test_autocmd_FileReadCmd()
   3612  func ReadFileCmd()
   3613    call append(line('$'), "v:cmdarg = " .. v:cmdarg)
   3614  endfunc
   3615  augroup FileReadCmdTest
   3616    au!
   3617    au FileReadCmd Xtest call ReadFileCmd()
   3618  augroup END
   3619 
   3620  new
   3621  read ++bin Xtest
   3622  read ++nobin Xtest
   3623  read ++edit Xtest
   3624  read ++bad=keep Xtest
   3625  read ++bad=drop Xtest
   3626  read ++bad=- Xtest
   3627  read ++ff=unix Xtest
   3628  read ++ff=dos Xtest
   3629  read ++ff=mac Xtest
   3630  read ++enc=utf-8 Xtest
   3631 
   3632  call assert_equal(['',
   3633        \ 'v:cmdarg =  ++bin',
   3634        \ 'v:cmdarg =  ++nobin',
   3635        \ 'v:cmdarg =  ++edit',
   3636        \ 'v:cmdarg =  ++bad=keep',
   3637        \ 'v:cmdarg =  ++bad=drop',
   3638        \ 'v:cmdarg =  ++bad=-',
   3639        \ 'v:cmdarg =  ++ff=unix',
   3640        \ 'v:cmdarg =  ++ff=dos',
   3641        \ 'v:cmdarg =  ++ff=mac',
   3642        \ 'v:cmdarg =  ++enc=utf-8'], getline(1, '$'))
   3643 
   3644  bwipe!
   3645  augroup FileReadCmdTest
   3646    au!
   3647  augroup END
   3648  delfunc ReadFileCmd
   3649 endfunc
   3650 
   3651 " Test for passing invalid arguments to autocmd
   3652 func Test_autocmd_invalid_args()
   3653  " Additional character after * for event
   3654  call assert_fails('autocmd *a Xinvfile set ff=unix', 'E215:')
   3655  augroup Test
   3656  augroup END
   3657  " Invalid autocmd event
   3658  call assert_fails('autocmd Bufabc Xinvfile set ft=vim', 'E216:')
   3659  " Invalid autocmd event in a autocmd group
   3660  call assert_fails('autocmd Test Bufabc Xinvfile set ft=vim', 'E216:')
   3661  augroup! Test
   3662  " Execute all autocmds
   3663  call assert_fails('doautocmd * BufEnter', 'E217:')
   3664  call assert_fails('augroup! x1a2b3', 'E367:')
   3665  call assert_fails('autocmd BufNew <buffer=999> pwd', 'E680:')
   3666  call assert_fails('autocmd BufNew \) set ff=unix', 'E55:')
   3667 endfunc
   3668 
   3669 " Test for deep nesting of autocmds
   3670 func Test_autocmd_deep_nesting()
   3671  autocmd BufEnter Xdeepfile doautocmd BufEnter Xdeepfile
   3672  call assert_fails('doautocmd BufEnter Xdeepfile', 'E218:')
   3673  autocmd! BufEnter Xdeepfile
   3674 endfunc
   3675 
   3676 " Tests for SigUSR1 autocmd event, which is only available on posix systems.
   3677 func Test_autocmd_sigusr1()
   3678  CheckUnix
   3679 
   3680  let g:sigusr1_passed = 0
   3681  au Signal SIGUSR1 let g:sigusr1_passed = 1
   3682  call system('kill -s usr1 ' . getpid())
   3683  call WaitForAssert({-> assert_true(g:sigusr1_passed)})
   3684 
   3685  au! Signal
   3686  unlet g:sigusr1_passed
   3687 endfunc
   3688 
   3689 " Test for BufReadPre autocmd deleting the file
   3690 func Test_BufReadPre_delfile()
   3691  augroup TestAuCmd
   3692    au!
   3693    autocmd BufReadPre XbufreadPre call delete('XbufreadPre')
   3694  augroup END
   3695  call writefile([], 'XbufreadPre', 'D')
   3696  call assert_fails('new XbufreadPre', 'E200:')
   3697  call assert_equal('XbufreadPre', @%)
   3698  call assert_equal(1, &readonly)
   3699 
   3700  augroup TestAuCmd
   3701    au!
   3702  augroup END
   3703  close!
   3704 endfunc
   3705 
   3706 " Test for BufReadPre autocmd changing the current buffer
   3707 func Test_BufReadPre_changebuf()
   3708  augroup TestAuCmd
   3709    au!
   3710    autocmd BufReadPre Xchangebuf edit Xsomeotherfile
   3711  augroup END
   3712  call writefile([], 'Xchangebuf', 'D')
   3713  call assert_fails('new Xchangebuf', 'E201:')
   3714  call assert_equal('Xsomeotherfile', @%)
   3715  call assert_equal(1, &readonly)
   3716 
   3717  augroup TestAuCmd
   3718    au!
   3719  augroup END
   3720  close!
   3721 endfunc
   3722 
   3723 " Test for BufWipeout autocmd changing the current buffer when reading a file
   3724 " in an empty buffer with 'f' flag in 'cpo'
   3725 func Test_BufDelete_changebuf()
   3726  new
   3727  augroup TestAuCmd
   3728    au!
   3729    autocmd BufWipeout * let bufnr = bufadd('somefile') | exe "b " .. bufnr
   3730  augroup END
   3731  let save_cpo = &cpo
   3732  set cpo+=f
   3733  call assert_fails('r Xfile', ['E812:', 'E484:'])
   3734  call assert_equal('somefile', @%)
   3735  let &cpo = save_cpo
   3736  augroup TestAuCmd
   3737    au!
   3738  augroup END
   3739  close!
   3740 endfunc
   3741 
   3742 " Test for the temporary internal window used to execute autocmds
   3743 func Test_autocmd_window()
   3744  %bw!
   3745  edit one.txt
   3746  tabnew two.txt
   3747  vnew three.txt
   3748  tabnew four.txt
   3749  tabprevious
   3750  let g:blist = []
   3751  augroup aucmd_win_test1
   3752    au!
   3753    au BufEnter * call add(g:blist, [expand('<afile>'),
   3754          \ win_gettype(bufwinnr(expand('<afile>')))])
   3755  augroup END
   3756 
   3757  doautoall BufEnter
   3758  call assert_equal([
   3759        \ ['one.txt', 'autocmd'],
   3760        \ ['two.txt', ''],
   3761        \ ['four.txt', 'autocmd'],
   3762        \ ['three.txt', ''],
   3763        \ ], g:blist)
   3764 
   3765  augroup aucmd_win_test1
   3766    au!
   3767  augroup END
   3768  augroup! aucmd_win_test1
   3769  %bw!
   3770 endfunc
   3771 
   3772 " Test for trying to close the temporary window used for executing an autocmd
   3773 func Test_close_autocmd_window()
   3774  %bw!
   3775  edit one.txt
   3776  tabnew two.txt
   3777  augroup aucmd_win_test2
   3778    au!
   3779    " Nvim makes aucmd_win the last window
   3780    " au BufEnter * if expand('<afile>') == 'one.txt' | 1close | endif
   3781    au BufEnter * if expand('<afile>') == 'one.txt' | close | endif
   3782  augroup END
   3783 
   3784  call assert_fails('doautoall BufEnter', 'E813:')
   3785 
   3786  augroup aucmd_win_test2
   3787    au!
   3788  augroup END
   3789  augroup! aucmd_win_test2
   3790  %bw!
   3791 endfunc
   3792 
   3793 " Test for trying to close the tab that has the temporary window for exeucing
   3794 " an autocmd.
   3795 func Test_close_autocmd_tab()
   3796  edit one.txt
   3797  tabnew two.txt
   3798   augroup aucmd_win_test
   3799    au!
   3800    au BufEnter * if expand('<afile>') == 'one.txt' | tabfirst | tabonly | endif
   3801  augroup END
   3802 
   3803  call assert_fails('doautoall BufEnter', 'E813:')
   3804 
   3805  tabonly
   3806  augroup aucmd_win_test
   3807    au!
   3808  augroup END
   3809  augroup! aucmd_win_test
   3810  %bwipe!
   3811 endfunc
   3812 
   3813 func Test_Visual_doautoall_redraw()
   3814  call setline(1, ['a', 'b'])
   3815  new
   3816  wincmd p
   3817  call feedkeys("G\<C-V>", 'txn')
   3818  autocmd User Explode ++once redraw
   3819  doautoall User Explode
   3820  %bwipe!
   3821 endfunc
   3822 
   3823 func Test_get_Visual_selection_in_curbuf_autocmd()
   3824  call Ntest_override('starting', 1)
   3825  new
   3826  autocmd OptionSet list let b:text = getregion(getpos('.'), getpos('v'))
   3827  call setline(1, 'foo bar baz')
   3828 
   3829  normal! gg0fbvtb
   3830  setlocal list
   3831  call assert_equal(['bar '], b:text)
   3832  exe "normal! \<Esc>"
   3833 
   3834  normal! v0
   3835  call setbufvar('%', '&list', v:false)
   3836  call assert_equal(['foo bar '], b:text)
   3837  exe "normal! \<Esc>"
   3838 
   3839  autocmd! OptionSet list
   3840  bwipe!
   3841  call Ntest_override('starting', 0)
   3842 endfunc
   3843 
   3844 " This was using freed memory.
   3845 func Test_BufNew_arglocal()
   3846  arglocal
   3847  au BufNew * arglocal
   3848  call assert_fails('drop xx', 'E1156:')
   3849 
   3850  au! BufNew
   3851 endfunc
   3852 
   3853 func Test_autocmd_closes_window()
   3854  au BufNew,BufWinLeave * e %e
   3855  file yyy
   3856  au BufNew,BufWinLeave * ball
   3857  n xxx
   3858 
   3859  %bwipe
   3860  au! BufNew
   3861  au! BufWinLeave
   3862 endfunc
   3863 
   3864 func Test_autocmd_quit_psearch()
   3865  sn aa bb
   3866  augroup aucmd_win_test
   3867    au!
   3868    au BufEnter,BufLeave,BufNew,WinEnter,WinLeave,WinNew * if winnr('$') > 1 | q | endif
   3869  augroup END
   3870  ps /
   3871 
   3872  augroup aucmd_win_test
   3873    au!
   3874  augroup END
   3875  new
   3876  pclose
   3877 endfunc
   3878 
   3879 " Fuzzer found some strange combination that caused a crash.
   3880 func Test_autocmd_normal_mess()
   3881  " For unknown reason this hangs on MS-Windows
   3882  CheckNotMSWindows
   3883 
   3884  augroup aucmd_normal_test
   3885    au BufLeave,BufWinLeave,BufHidden,BufUnload,BufDelete,BufWipeout * norm 7q/qc
   3886  augroup END
   3887  " Nvim has removed :open
   3888  " call assert_fails('o4', 'E1159:')
   3889  call assert_fails('e4', 'E1159:')
   3890  silent! H
   3891  call assert_fails('e xx', 'E1159:')
   3892  normal G
   3893 
   3894  augroup aucmd_normal_test
   3895    au!
   3896  augroup END
   3897 endfunc
   3898 
   3899 func Test_autocmd_closing_cmdwin()
   3900  " For unknown reason this hangs on MS-Windows
   3901  CheckNotMSWindows
   3902 
   3903  au BufWinLeave * nested q
   3904  call assert_fails("norm 7q?\n", 'E855:')
   3905 
   3906  au! BufWinLeave
   3907  new
   3908  only
   3909 endfunc
   3910 
   3911 func Test_autocmd_vimgrep()
   3912  augroup aucmd_vimgrep
   3913    au QuickfixCmdPre,BufNew,BufReadCmd * sb
   3914    " Nvim makes aucmd_win the last window
   3915    " au QuickfixCmdPre,BufNew,BufReadCmd * q9
   3916    au QuickfixCmdPre,BufNew,BufReadCmd * exe 'q' .. (winnr('$') - (win_gettype(winnr('$')) == 'autocmd'))
   3917  augroup END
   3918  call assert_fails('lv ?a? foo', 'E926:')
   3919 
   3920  augroup aucmd_vimgrep
   3921    au!
   3922  augroup END
   3923 endfunc
   3924 
   3925 func Test_closing_autocmd_window()
   3926  let lines =<< trim END
   3927      edit Xa.txt
   3928      tabnew Xb.txt
   3929      autocmd BufEnter Xa.txt unhide 1
   3930      doautoall BufEnter
   3931  END
   3932  call CheckScriptFailure(lines, 'E814:')
   3933  au! BufEnter
   3934  bwipe Xa.txt
   3935  bwipe Xb.txt
   3936 endfunc
   3937 
   3938 func Test_switch_window_in_autocmd_window()
   3939  edit Xa.txt
   3940  tabnew Xb.txt
   3941  autocmd BufEnter Xa.txt wincmd w
   3942  doautoall BufEnter
   3943  au! BufEnter
   3944  bwipe Xa.txt
   3945  call assert_false(bufexists('Xa.txt'))
   3946  bwipe Xb.txt
   3947  call assert_false(bufexists('Xb.txt'))
   3948 endfunc
   3949 
   3950 " Test that using the autocommand window doesn't change current directory.
   3951 func Test_autocmd_window_cwd()
   3952  let saveddir = getcwd()
   3953  call mkdir('Xcwd/a/b/c/d', 'pR')
   3954 
   3955  new Xa.txt
   3956  tabnew
   3957  new Xb.txt
   3958 
   3959  tabprev
   3960  cd Xcwd
   3961  call assert_match('/Xcwd$', getcwd())
   3962  call assert_match('\[global\] .*/Xcwd$', trim(execute('verbose pwd')))
   3963 
   3964  autocmd BufEnter Xb.txt lcd ./a/b/c/d
   3965  doautoall BufEnter
   3966  au! BufEnter
   3967  call assert_match('/Xcwd$', getcwd())
   3968  call assert_match('\[global\] .*/Xcwd$', trim(execute('verbose pwd')))
   3969 
   3970  tabnext
   3971  cd ./a
   3972  tcd ./b
   3973  lcd ./c
   3974  call assert_match('/Xcwd/a/b/c$', getcwd())
   3975  call assert_match('\[window\] .*/Xcwd/a/b/c$', trim(execute('verbose pwd')))
   3976 
   3977  autocmd BufEnter Xa.txt call assert_match('Xcwd/a/b/c$', getcwd())
   3978  doautoall BufEnter
   3979  au! BufEnter
   3980  call assert_match('/Xcwd/a/b/c$', getcwd())
   3981  call assert_match('\[window\] .*/Xcwd/a/b/c$', trim(execute('verbose pwd')))
   3982  bwipe!
   3983  call assert_match('/Xcwd/a/b$', getcwd())
   3984  call assert_match('\[tabpage\] .*/Xcwd/a/b$', trim(execute('verbose pwd')))
   3985  bwipe!
   3986  call assert_match('/Xcwd/a$', getcwd())
   3987  call assert_match('\[global\] .*/Xcwd/a$', trim(execute('verbose pwd')))
   3988  bwipe!
   3989 
   3990  call chdir(saveddir)
   3991 endfunc
   3992 
   3993 func Test_bufwipeout_changes_window()
   3994  " This should not crash, but we don't have any expectations about what
   3995  " happens, changing window in BufWipeout has unpredictable results.
   3996  tabedit
   3997  let g:window_id = win_getid()
   3998  topleft new
   3999  setlocal bufhidden=wipe
   4000  autocmd BufWipeout <buffer> call win_gotoid(g:window_id)
   4001  tabprevious
   4002  +tabclose
   4003 
   4004  unlet g:window_id
   4005  au! BufWipeout
   4006  %bwipe!
   4007 endfunc
   4008 
   4009 func Test_autocmd_prevent_buf_wipe()
   4010  " Xa must be the first buffer so that win_close_othertab() puts it in
   4011  " another window, which causes wiping the buffer to fail.
   4012  %bwipe!
   4013 
   4014  file Xa
   4015  call setline(1, 'foo')
   4016  setlocal bufhidden=wipe
   4017  tabnew Xb
   4018  setlocal bufhidden=wipe
   4019  autocmd BufUnload Xa ++once ++nested tabonly
   4020  autocmd BufWinLeave Xb ++once tabnext
   4021  tabfirst
   4022 
   4023  edit! Xc
   4024  call assert_equal('Xc', bufname('%'))
   4025  tabnext
   4026  call assert_equal('Xa', bufname('%'))
   4027  call assert_equal("\n\"Xa\" --No lines in buffer--", execute('file'))
   4028 
   4029  %bwipe!
   4030 endfunc
   4031 
   4032 func Test_v_event_readonly()
   4033  autocmd CompleteChanged * let v:event.width = 0
   4034  call assert_fails("normal! i\<C-X>\<C-V>", 'E46:')
   4035  au! CompleteChanged
   4036 
   4037  autocmd DirChangedPre * let v:event.directory = ''
   4038  call assert_fails('cd .', 'E46:')
   4039  au! DirChangedPre
   4040 
   4041  autocmd ModeChanged * let v:event.new_mode = ''
   4042  call assert_fails('normal! cc', 'E46:')
   4043  au! ModeChanged
   4044 
   4045  autocmd TextYankPost * let v:event.operator = ''
   4046  call assert_fails('normal! yy', 'E46:')
   4047  au! TextYankPost
   4048 endfunc
   4049 
   4050 " Test for ModeChanged pattern
   4051 func Test_mode_changes()
   4052  let g:index = 0
   4053  let g:mode_seq = ['n', 'i', 'n', 'v', 'V', 'i', 'ix', 'i', 'ic', 'i', 'n', 'no', 'noV', 'n', 'V', 'v', 's', 'n']
   4054  func! TestMode()
   4055    call assert_equal(g:mode_seq[g:index], get(v:event, "old_mode"))
   4056    call assert_equal(g:mode_seq[g:index + 1], get(v:event, "new_mode"))
   4057    call assert_equal(mode(1), get(v:event, "new_mode"))
   4058    let g:index += 1
   4059  endfunc
   4060 
   4061  au ModeChanged * :call TestMode()
   4062  let g:n_to_any = 0
   4063  au ModeChanged n:* let g:n_to_any += 1
   4064  call feedkeys("i\<esc>vVca\<CR>\<C-X>\<C-L>\<esc>ggdV\<MouseMove>G", 'tnix')
   4065 
   4066  let g:V_to_v = 0
   4067  au ModeChanged V:v let g:V_to_v += 1
   4068  call feedkeys("Vv\<C-G>\<esc>", 'tnix')
   4069  call assert_equal(len(filter(g:mode_seq[1:], {idx, val -> val == 'n'})), g:n_to_any)
   4070  call assert_equal(1, g:V_to_v)
   4071  call assert_equal(len(g:mode_seq) - 1, g:index)
   4072 
   4073  let g:n_to_i = 0
   4074  au ModeChanged n:i let g:n_to_i += 1
   4075  let g:n_to_niI = 0
   4076  au ModeChanged i:niI let g:n_to_niI += 1
   4077  let g:niI_to_i = 0
   4078  au ModeChanged niI:i let g:niI_to_i += 1
   4079  let g:nany_to_i = 0
   4080  au ModeChanged n*:i let g:nany_to_i += 1
   4081  let g:i_to_n = 0
   4082  au ModeChanged i:n let g:i_to_n += 1
   4083  let g:nori_to_any = 0
   4084  au ModeChanged [ni]:* let g:nori_to_any += 1
   4085  let g:i_to_any = 0
   4086  au ModeChanged i:* let g:i_to_any += 1
   4087  let g:index = 0
   4088  let g:mode_seq = ['n', 'i', 'niI', 'i', 'n']
   4089  call feedkeys("a\<C-O>l\<esc>", 'tnix')
   4090  call assert_equal(len(g:mode_seq) - 1, g:index)
   4091  call assert_equal(1, g:n_to_i)
   4092  call assert_equal(1, g:n_to_niI)
   4093  call assert_equal(1, g:niI_to_i)
   4094  call assert_equal(2, g:nany_to_i)
   4095  call assert_equal(1, g:i_to_n)
   4096  call assert_equal(2, g:i_to_any)
   4097  call assert_equal(3, g:nori_to_any)
   4098 
   4099  if has('terminal')
   4100    let g:mode_seq += ['c', 'n', 't', 'nt', 'c', 'nt', 'n']
   4101    call feedkeys(":term\<CR>\<C-W>N:bd!\<CR>", 'tnix')
   4102    call assert_equal(len(g:mode_seq) - 1, g:index)
   4103    call assert_equal(1, g:n_to_i)
   4104    call assert_equal(1, g:n_to_niI)
   4105    call assert_equal(1, g:niI_to_i)
   4106    call assert_equal(2, g:nany_to_i)
   4107    call assert_equal(1, g:i_to_n)
   4108    call assert_equal(2, g:i_to_any)
   4109    call assert_equal(5, g:nori_to_any)
   4110  endif
   4111 
   4112  let g:n_to_c = 0
   4113  au ModeChanged n:c let g:n_to_c += 1
   4114  let g:c_to_n = 0
   4115  au ModeChanged c:n let g:c_to_n += 1
   4116  let g:mode_seq += ['c', 'n', 'c', 'n']
   4117  call feedkeys("q:\<C-C>\<Esc>", 'tnix')
   4118  call assert_equal(len(g:mode_seq) - 1, g:index)
   4119  call assert_equal(2, g:n_to_c)
   4120  call assert_equal(2, g:c_to_n)
   4121 
   4122  let g:n_to_v = 0
   4123  au ModeChanged n:v let g:n_to_v += 1
   4124  let g:v_to_n = 0
   4125  au ModeChanged v:n let g:v_to_n += 1
   4126  let g:mode_seq += ['v', 'n']
   4127  call feedkeys("v\<C-C>", 'tnix')
   4128  call assert_equal(len(g:mode_seq) - 1, g:index)
   4129  call assert_equal(1, g:n_to_v)
   4130  call assert_equal(1, g:v_to_n)
   4131 
   4132  let g:mode_seq += ['c', 'cr', 'c', 'cr', 'n']
   4133  call feedkeys(":\<Insert>\<Insert>\<Insert>\<CR>", 'tnix')
   4134  call assert_equal(len(g:mode_seq) - 1, g:index)
   4135 
   4136  au! ModeChanged
   4137  delfunc TestMode
   4138  unlet! g:mode_seq
   4139  unlet! g:index
   4140  unlet! g:n_to_any
   4141  unlet! g:V_to_v
   4142  unlet! g:n_to_i
   4143  unlet! g:n_to_niI
   4144  unlet! g:niI_to_i
   4145  unlet! g:nany_to_i
   4146  unlet! g:i_to_n
   4147  unlet! g:nori_to_any
   4148  unlet! g:i_to_any
   4149  unlet! g:n_to_c
   4150  unlet! g:c_to_n
   4151  unlet! g:n_to_v
   4152  unlet! g:v_to_n
   4153 endfunc
   4154 
   4155 func Test_recursive_ModeChanged()
   4156  au! ModeChanged * norm 0u
   4157  sil! norm 
   4158  au! ModeChanged
   4159 endfunc
   4160 
   4161 func Test_ModeChanged_starts_visual()
   4162  " This was triggering ModeChanged before setting VIsual, causing a crash.
   4163  au! ModeChanged * norm 0u
   4164  sil! norm 
   4165 
   4166  au! ModeChanged
   4167 endfunc
   4168 
   4169 func Test_noname_autocmd()
   4170  augroup test_noname_autocmd_group
   4171    autocmd!
   4172    autocmd BufEnter * call add(s:li, ["BufEnter", expand("<afile>")])
   4173    autocmd BufDelete * call add(s:li, ["BufDelete", expand("<afile>")])
   4174    autocmd BufLeave * call add(s:li, ["BufLeave", expand("<afile>")])
   4175    autocmd BufUnload * call add(s:li, ["BufUnload", expand("<afile>")])
   4176    autocmd BufWipeout * call add(s:li, ["BufWipeout", expand("<afile>")])
   4177  augroup END
   4178 
   4179  let s:li = []
   4180  edit foo
   4181  call assert_equal([['BufUnload', ''], ['BufDelete', ''], ['BufWipeout', ''], ['BufEnter', 'foo']], s:li)
   4182 
   4183  au! test_noname_autocmd_group
   4184  augroup! test_noname_autocmd_group
   4185 endfunc
   4186 
   4187 func Test_autocmd_split_dummy()
   4188  " Autocommand trying to split a window containing a dummy buffer.
   4189  auto BufReadPre * exe "sbuf " .. expand("<abuf>")
   4190  " Avoid the "W11" prompt
   4191  au FileChangedShell * let v:fcs_choice = 'reload'
   4192  func Xautocmd_changelist()
   4193    cal writefile(['Xtestfile2:4:4'], 'Xerr')
   4194    edit Xerr
   4195    lex 'Xtestfile2:4:4'
   4196  endfunc
   4197  call Xautocmd_changelist()
   4198  " Should get E86, but it doesn't always happen (timing?)
   4199  silent! call Xautocmd_changelist()
   4200 
   4201  au! BufReadPre
   4202  au! FileChangedShell
   4203  delfunc Xautocmd_changelist
   4204  bwipe! Xerr
   4205  call delete('Xerr')
   4206 endfunc
   4207 
   4208 " This was crashing because there was only one window to execute autocommands
   4209 " in.
   4210 func Test_autocmd_nested_setbufvar()
   4211  CheckFeature python3
   4212 
   4213  set hidden
   4214  edit Xaaa
   4215  edit Xbbb
   4216  call setline(1, 'bar')
   4217  enew
   4218  au BufWriteCmd Xbbb ++nested call setbufvar('Xaaa', '&ft', 'foo') | bw! Xaaa
   4219  au FileType foo call py3eval('vim.current.buffer.options["cindent"]')
   4220  wall
   4221 
   4222  au! BufWriteCmd
   4223  au! FileType foo
   4224  set nohidden
   4225  call delete('Xaaa')
   4226  call delete('Xbbb')
   4227  %bwipe!
   4228 endfunc
   4229 
   4230 func SetupVimTest_shm()
   4231  let g:bwe = []
   4232  let g:brp = []
   4233  set shortmess-=l
   4234  messages clear
   4235 
   4236  let dirname='XVimTestSHM'
   4237  call mkdir(dirname, 'R')
   4238  call writefile(['test'], dirname .. '/1')
   4239  call writefile(['test'], dirname .. '/2')
   4240  call writefile(['test'], dirname .. '/3')
   4241 
   4242  augroup test
   4243      autocmd!
   4244      autocmd BufWinEnter * call add(g:bwe, $'BufWinEnter: {expand('<amatch>')}')
   4245      autocmd BufReadPost * call add(g:brp,  $'BufReadPost: {expand('<amatch>')}')
   4246  augroup END
   4247 
   4248  call setqflist([
   4249        \  {'filename': dirname .. '/1', 'lnum': 1, 'col': 1, 'text': 'test', 'vcol': 0},
   4250        \  {'filename': dirname .. '/2', 'lnum': 1, 'col': 1, 'text': 'test', 'vcol': 0},
   4251        \  {'filename': dirname .. '/3', 'lnum': 1, 'col': 1, 'text': 'test', 'vcol': 0}
   4252        \  ])
   4253  cdo! substitute/test/TEST
   4254 
   4255  " clean up
   4256  noa enew!
   4257  set shortmess&vim
   4258  augroup test
   4259      autocmd!
   4260  augroup END
   4261  augroup! test
   4262 endfunc
   4263 
   4264 func Test_autocmd_shortmess()
   4265  CheckNotMSWindows
   4266 
   4267  call SetupVimTest_shm()
   4268  let output = execute(':mess')->split('\n')
   4269 
   4270  let info = copy(output)->filter({idx, val -> val =~# '\d of 3'} )
   4271  let bytes = copy(output)->filter({idx, val -> val =~# 'bytes'} )
   4272 
   4273  " We test the following here:
   4274  " BufReadPost should have been triggered 3 times, once per file
   4275  " BufWinEnter should have been triggered 3 times, once per file
   4276  " FileInfoMessage should have been shown 3 times, regardless of shm option
   4277  " "(x of 3)" message from :cnext has been shown 3 times
   4278 
   4279  call assert_equal(3, g:brp->len())
   4280  call assert_equal(3, g:bwe->len())
   4281  call assert_equal(3, info->len())
   4282  call assert_equal(3, bytes->len())
   4283 
   4284  delfunc SetupVimTest_shm
   4285 endfunc
   4286 
   4287 func Test_autocmd_invalidates_undo_on_textchanged()
   4288  CheckRunVimInTerminal
   4289  let script =<< trim END
   4290    set hidden
   4291    " create quickfix list (at least 2 lines to move line)
   4292    vimgrep /u/j %
   4293 
   4294    " enter quickfix window
   4295    cwindow
   4296 
   4297    " set modifiable
   4298    setlocal modifiable
   4299 
   4300    " set autocmd to clear quickfix list
   4301 
   4302    autocmd! TextChanged <buffer> call setqflist([])
   4303    " move line
   4304    move+1
   4305  END
   4306  call writefile(script, 'XTest_autocmd_invalidates_undo_on_textchanged', 'D')
   4307  let buf = RunVimInTerminal('XTest_autocmd_invalidates_undo_on_textchanged', {'rows': 20})
   4308  call term_sendkeys(buf, ":so %\<cr>")
   4309  call term_sendkeys(buf, "G")
   4310  call WaitForAssert({-> assert_match('^XTest_autocmd_invalidates_undo_on_textchanged\s*$', term_getline(buf, 20))}, 1000)
   4311 
   4312  call StopVimInTerminal(buf)
   4313 endfunc
   4314 
   4315 func Test_autocmd_creates_new_window_on_bufleave()
   4316  e a.txt
   4317  e b.txt
   4318  setlocal bufhidden=wipe
   4319  autocmd BufLeave <buffer> diffsplit c.txt
   4320  bn
   4321  call assert_equal(1, winnr('$'))
   4322  call assert_equal('a.txt', bufname('%'))
   4323  bw a.txt
   4324  bw c.txt
   4325 endfunc
   4326 
   4327 " Ensure `expected` was just recently written as a Vim session
   4328 func s:assert_session_path(expected)
   4329  call assert_equal(a:expected, v:this_session)
   4330 endfunc
   4331 
   4332 " Check for `expected` after a session is written to-disk.
   4333 func s:watch_for_session_path(expected)
   4334  execute 'autocmd SessionWritePost * ++once execute "call s:assert_session_path(\"'
   4335        \ . a:expected
   4336        \ . '\")"'
   4337 endfunc
   4338 
   4339 " Ensure v:this_session gets the full session path, if explicitly stated
   4340 func Test_explicit_session_absolute_path()
   4341  %bwipeout!
   4342 
   4343  let directory = getcwd()
   4344 
   4345  let v:this_session = ""
   4346  let name = "some_file.vim"
   4347  let expected = fnamemodify(name, ":p")
   4348  call s:watch_for_session_path(expected)
   4349  execute "mksession! " .. expected
   4350 
   4351  call delete(expected)
   4352 endfunc
   4353 
   4354 " Ensure v:this_session gets the full session path, if explicitly stated
   4355 func Test_explicit_session_relative_path()
   4356  %bwipeout!
   4357 
   4358  let directory = getcwd()
   4359 
   4360  let v:this_session = ""
   4361  let name = "some_file.vim"
   4362  let expected = fnamemodify(name, ":p")
   4363  call s:watch_for_session_path(expected)
   4364  execute "mksession! " .. name
   4365 
   4366  call delete(expected)
   4367 endfunc
   4368 
   4369 " Ensure v:this_session gets the full session path, if not specified
   4370 func Test_implicit_session()
   4371  %bwipeout!
   4372 
   4373  let directory = getcwd()
   4374 
   4375  let v:this_session = ""
   4376  let expected = fnamemodify("Session.vim", ":p")
   4377  call s:watch_for_session_path(expected)
   4378  mksession!
   4379 
   4380  call delete(expected)
   4381 endfunc
   4382 
   4383 " Test TextChangedI and TextChanged
   4384 func Test_Changed_ChangedI()
   4385  " Run this test in a terminal because it requires running the main loop.
   4386  " Don't use CheckRunVimInTerminal as that will skip the test on Windows.
   4387  CheckFeature terminal
   4388  CheckNotGui
   4389  " Starting a terminal to run Vim is always considered flaky.
   4390  let g:test_is_flaky = 1
   4391 
   4392  call writefile(['one', 'two', 'three'], 'XTextChangedI2', 'D')
   4393  let before =<< trim END
   4394      set ttimeout ttimeoutlen=10
   4395      let [g:autocmd_n, g:autocmd_i] = ['','']
   4396 
   4397      func TextChangedAutocmd(char)
   4398        let g:autocmd_{tolower(a:char)} = a:char .. b:changedtick
   4399        call writefile([$'{g:autocmd_n},{g:autocmd_i}'], 'XTextChangedI3')
   4400      endfunc
   4401 
   4402      au TextChanged  <buffer> :call TextChangedAutocmd('N')
   4403      au TextChangedI <buffer> :call TextChangedAutocmd('I')
   4404 
   4405      nnoremap <CR> o<Esc>
   4406      autocmd SafeState * ++once call writefile([''], 'XTextChangedI3')
   4407  END
   4408 
   4409  call writefile(before, 'Xinit', 'D')
   4410  let buf = term_start(
   4411        \ GetVimCommandCleanTerm() .. '-n -S Xinit XTextChangedI2',
   4412        \ {'term_rows': 10})
   4413  call assert_equal('running', term_getstatus(buf))
   4414  call WaitForAssert({-> assert_true(filereadable('XTextChangedI3'))})
   4415  defer delete('XTextChangedI3')
   4416  call WaitForAssert({-> assert_equal([''], readfile('XTextChangedI3'))})
   4417 
   4418  " TextChanged should trigger if a mapping enters and leaves Insert mode.
   4419  call term_sendkeys(buf, "\<CR>")
   4420  call WaitForAssert({-> assert_equal('N4,', readfile('XTextChangedI3')->join("\n"))})
   4421 
   4422  call term_sendkeys(buf, "i")
   4423  call WaitForAssert({-> assert_match('^-- INSERT --', term_getline(buf, 10))})
   4424  call WaitForAssert({-> assert_equal('N4,', readfile('XTextChangedI3')->join("\n"))})
   4425  " TextChangedI should trigger if change is done in Insert mode.
   4426  call term_sendkeys(buf, "f")
   4427  call WaitForAssert({-> assert_equal('N4,I5', readfile('XTextChangedI3')->join("\n"))})
   4428  call term_sendkeys(buf, "o")
   4429  call WaitForAssert({-> assert_equal('N4,I6', readfile('XTextChangedI3')->join("\n"))})
   4430  call term_sendkeys(buf, "o")
   4431  call WaitForAssert({-> assert_equal('N4,I7', readfile('XTextChangedI3')->join("\n"))})
   4432  " TextChanged shouldn't trigger when leaving Insert mode and TextChangedI
   4433  " has been triggered.
   4434  call term_sendkeys(buf, "\<Esc>")
   4435  call WaitForAssert({-> assert_notmatch('^-- INSERT --', term_getline(buf, 10))})
   4436  call WaitForAssert({-> assert_equal('N4,I7', readfile('XTextChangedI3')->join("\n"))})
   4437 
   4438  " TextChanged should trigger if change is done in Normal mode.
   4439  call term_sendkeys(buf, "yyp")
   4440  call WaitForAssert({-> assert_equal('N8,I7', readfile('XTextChangedI3')->join("\n"))})
   4441 
   4442  " TextChangedI shouldn't trigger if change isn't done in Insert mode.
   4443  call term_sendkeys(buf, "i")
   4444  call WaitForAssert({-> assert_match('^-- INSERT --', term_getline(buf, 10))})
   4445  call WaitForAssert({-> assert_equal('N8,I7', readfile('XTextChangedI3')->join("\n"))})
   4446  call term_sendkeys(buf, "\<Esc>")
   4447  call WaitForAssert({-> assert_notmatch('^-- INSERT --', term_getline(buf, 10))})
   4448  call WaitForAssert({-> assert_equal('N8,I7', readfile('XTextChangedI3')->join("\n"))})
   4449 
   4450  " TextChangedI should trigger if change is a mix of Normal and Insert modes.
   4451  func! s:validate_mixed_textchangedi(buf, keys)
   4452    let buf = a:buf
   4453    call term_sendkeys(buf, "ifoo")
   4454    call WaitForAssert({-> assert_match('^-- INSERT --', term_getline(buf, 10))})
   4455    call term_sendkeys(buf, "\<Esc>")
   4456    call WaitForAssert({-> assert_notmatch('^-- INSERT --', term_getline(buf, 10))})
   4457    call term_sendkeys(buf, ":let [g:autocmd_n, g:autocmd_i] = ['', '']\<CR>")
   4458    call writefile([], 'XTextChangedI3')
   4459    call term_sendkeys(buf, a:keys)
   4460    call WaitForAssert({-> assert_match('^-- INSERT --', term_getline(buf, 10))})
   4461    call WaitForAssert({-> assert_match('^,I\d\+', readfile('XTextChangedI3')->join("\n"))})
   4462    call term_sendkeys(buf, "\<Esc>")
   4463    call WaitForAssert({-> assert_notmatch('^-- INSERT --', term_getline(buf, 10))})
   4464    call WaitForAssert({-> assert_match('^,I\d\+', readfile('XTextChangedI3')->join("\n"))})
   4465  endfunc
   4466 
   4467  call s:validate_mixed_textchangedi(buf, "o")
   4468  call s:validate_mixed_textchangedi(buf, "O")
   4469  call s:validate_mixed_textchangedi(buf, "ciw")
   4470  call s:validate_mixed_textchangedi(buf, "cc")
   4471  call s:validate_mixed_textchangedi(buf, "C")
   4472  call s:validate_mixed_textchangedi(buf, "s")
   4473  call s:validate_mixed_textchangedi(buf, "S")
   4474 
   4475  " clean up
   4476  bwipe!
   4477 endfunc
   4478 
   4479 " Test that filetype detection still works when SwapExists autocommand sets
   4480 " filetype in another buffer.
   4481 func Test_SwapExists_set_other_buf_filetype()
   4482  let lines =<< trim END
   4483    set nocompatible directory=.
   4484    filetype on
   4485 
   4486    let g:buf = bufnr()
   4487    new
   4488 
   4489    func SwapExists()
   4490      let v:swapchoice = 'o'
   4491      call setbufvar(g:buf, '&filetype', 'text')
   4492    endfunc
   4493 
   4494    func SafeState()
   4495      edit <script>
   4496      redir! > XftSwapExists.out
   4497        set readonly? filetype?
   4498      redir END
   4499      qall!
   4500    endfunc
   4501 
   4502    autocmd SwapExists * ++nested call SwapExists()
   4503    autocmd SafeState * ++nested ++once call SafeState()
   4504  END
   4505  call writefile(lines, 'XftSwapExists.vim', 'D')
   4506 
   4507  new XftSwapExists.vim
   4508  if RunVim('', '', ' -S XftSwapExists.vim')
   4509    call assert_equal(
   4510          \ ['', '  readonly', '  filetype=vim'],
   4511          \ readfile('XftSwapExists.out'))
   4512    call delete('XftSwapExists.out')
   4513  endif
   4514 
   4515  bwipe!
   4516 endfunc
   4517 
   4518 " Test that file is not marked as modified when SwapExists autocommand sets
   4519 " 'modified' in another buffer.
   4520 func Test_SwapExists_set_other_buf_modified()
   4521  let lines =<< trim END
   4522    set nocompatible directory=.
   4523 
   4524    let g:buf = bufnr()
   4525    new
   4526 
   4527    func SwapExists()
   4528      let v:swapchoice = 'o'
   4529      call setbufvar(g:buf, '&modified', 1)
   4530    endfunc
   4531 
   4532    func SafeState()
   4533      edit <script>
   4534      redir! > XmodSwapExists.out
   4535        set readonly? modified?
   4536      redir END
   4537      qall!
   4538    endfunc
   4539 
   4540    autocmd SwapExists * ++nested call SwapExists()
   4541    autocmd SafeState * ++nested ++once call SafeState()
   4542  END
   4543  call writefile(lines, 'XmodSwapExists.vim', 'D')
   4544 
   4545  new XmodSwapExists.vim
   4546  if RunVim('', '', ' -S XmodSwapExists.vim')
   4547    call assert_equal(
   4548          \ ['', '  readonly', 'nomodified'],
   4549          \ readfile('XmodSwapExists.out'))
   4550    call delete('XmodSwapExists.out')
   4551  endif
   4552 
   4553  bwipe!
   4554 endfunc
   4555 
   4556 func Test_BufEnter_botline()
   4557  set hidden
   4558  call writefile(range(10), 'Xxx1', 'D')
   4559  call writefile(range(20), 'Xxx2', 'D')
   4560  edit Xxx1
   4561  edit Xxx2
   4562  au BufEnter Xxx1 call assert_true(line('w$') > 1)
   4563  edit Xxx1
   4564 
   4565  bwipe! Xxx1
   4566  bwipe! Xxx2
   4567  au! BufEnter Xxx1
   4568  set hidden&vim
   4569 endfunc
   4570 
   4571 " those commands caused null pointer access, see #15464
   4572 func Test_WinNewPre_crash()
   4573  defer CleanUpTestAuGroup()
   4574  let _cmdheight=&cmdheight
   4575  augroup testing
   4576    au!
   4577    autocmd WinNewPre * redraw
   4578  augroup END
   4579  tabnew
   4580  tabclose
   4581  augroup testing
   4582    au!
   4583    autocmd WinNewPre * wincmd t
   4584  augroup END
   4585  tabnew
   4586  tabclose
   4587  augroup testing
   4588    au!
   4589    autocmd WinNewPre * wincmd b
   4590  augroup END
   4591  tabnew
   4592  tabclose
   4593  augroup testing
   4594    au!
   4595    autocmd WinNewPre * set cmdheight+=1
   4596  augroup END
   4597  tabnew
   4598  tabclose
   4599  let &cmdheight=_cmdheight
   4600 endfunc
   4601 
   4602 
   4603 " This was using freed memory
   4604 func Test_autocmd_BufWinLeave_with_vsp()
   4605  new
   4606  let fname = 'XXXBufWinLeaveUAF.txt'
   4607  let dummy = 'XXXDummy.txt'
   4608  call writefile([], fname)
   4609  call writefile([], dummy)
   4610  defer delete(fname)
   4611  defer delete(dummy)
   4612  exe "e " fname
   4613  vsp
   4614  augroup testing
   4615    exe 'au BufWinLeave' fname 'e' dummy
   4616          \ '| call assert_fails(''vsp' fname ''', ''E1546:'')'
   4617  augroup END
   4618  bw
   4619  call CleanUpTestAuGroup()
   4620  exe "bw! " .. dummy
   4621 endfunc
   4622 
   4623 func Test_OptionSet_cmdheight()
   4624  set mouse=a laststatus=2
   4625  au OptionSet cmdheight :let &l:ch = v:option_new
   4626 
   4627  resize -1
   4628  call assert_equal(2, &l:ch)
   4629  resize +1
   4630  call assert_equal(1, &l:ch)
   4631 
   4632  call Ntest_setmouse(&lines - 1, 1)
   4633  call feedkeys("\<LeftMouse>", 'xt')
   4634  call Ntest_setmouse(&lines - 2, 1)
   4635  call feedkeys("\<LeftDrag>", 'xt')
   4636  call assert_equal(2, &l:ch)
   4637  call feedkeys("\<LeftRelease>", 'xt')
   4638 
   4639  tabnew | resize +1
   4640  call assert_equal(1, &l:ch)
   4641  tabfirst
   4642  call assert_equal(2, &l:ch)
   4643 
   4644  tabonly
   4645  set cmdheight& mouse& laststatus&
   4646 endfunc
   4647 
   4648 func Test_eventignorewin()
   4649  defer CleanUpTestAuGroup()
   4650  augroup testing
   4651    au WinEnter * :call add(g:evs, ["WinEnter", expand("<afile>")])
   4652    au WinLeave * :call add(g:evs, ["WinLeave", expand("<afile>")])
   4653    au BufWinEnter * :call add(g:evs, ["BufWinEnter", expand("<afile>")])
   4654  augroup END
   4655 
   4656  let g:evs = []
   4657  set eventignorewin=WinLeave,WinEnter
   4658  split foo
   4659  call assert_equal([['BufWinEnter', 'foo']], g:evs)
   4660  set eventignorewin=all
   4661  edit bar
   4662  call assert_equal([['BufWinEnter', 'foo']], g:evs)
   4663  set eventignorewin=
   4664  wincmd w
   4665  call assert_equal([['BufWinEnter', 'foo'], ['WinLeave', 'bar']], g:evs)
   4666 
   4667  only!
   4668  %bwipe!
   4669  set eventignorewin&
   4670  unlet g:evs
   4671 endfunc
   4672 
   4673 func Test_WinScrolled_Resized_eiw()
   4674  CheckRunVimInTerminal
   4675 
   4676  let lines =<< trim END
   4677    call setline(1, ['foo']->repeat(32))
   4678    set eventignorewin=WinScrolled,WinResized
   4679    split
   4680    let [g:afile,g:resized,g:scrolled] = ['none',0,0]
   4681    au WinScrolled * let [g:afile,g:scrolled] = [expand('<afile>'),g:scrolled+1]
   4682    au WinResized * let [g:afile,g:resized] = [expand('<afile>'),g:resized+1]
   4683  END
   4684  call writefile(lines, 'Xtest_winscrolled_eiw', 'D')
   4685  let buf = RunVimInTerminal('-S Xtest_winscrolled_eiw', {'rows': 10})
   4686 
   4687  " Both windows are ignoring resize events
   4688  call term_sendkeys(buf, "\<C-W>-")
   4689  call TermWait(buf)
   4690  call term_sendkeys(buf, ":echo g:afile g:resized g:scrolled\<CR>")
   4691  call WaitForAssert({-> assert_equal('none 0 0', term_getline(buf, 10))}, 1000)
   4692 
   4693  " And scroll events
   4694  call term_sendkeys(buf, "Ggg")
   4695  call TermWait(buf)
   4696  call term_sendkeys(buf, ":echo g:afile g:resized g:scrolled\<CR>")
   4697  call WaitForAssert({-> assert_equal('none 0 0', term_getline(buf, 10))}, 1000)
   4698 
   4699  " Un-ignore events in second window, make first window current and resize
   4700  call term_sendkeys(buf, ":set eventignorewin=\<CR>\<C-W>w\<C-W>+")
   4701  call TermWait(buf)
   4702  call term_sendkeys(buf, ":echo win_getid() g:afile g:resized g:scrolled\<CR>")
   4703  call WaitForAssert({-> assert_equal('1000 1001 1 1', term_getline(buf, 10))}, 1000)
   4704 
   4705  call StopVimInTerminal(buf)
   4706 endfunc
   4707 
   4708 " Test that TabClosedPre and TabClosed are triggered when closing a tab.
   4709 func Test_autocmd_TabClosedPre()
   4710  augroup testing
   4711    au TabClosedPre * call add(g:tabpagenr_pre, t:testvar)
   4712    au TabClosed * call add(g:tabpagenr_post, t:testvar)
   4713  augroup END
   4714 
   4715  " Test 'tabclose' triggering
   4716  let g:tabpagenr_pre = []
   4717  let g:tabpagenr_post = []
   4718  let t:testvar = 1
   4719  tabnew
   4720  let t:testvar = 2
   4721  tabnew
   4722  let t:testvar = 3
   4723  tabnew
   4724  let t:testvar = 4
   4725  tabnext
   4726  tabclose
   4727  tabclose
   4728  tabclose
   4729  call assert_equal([1, 2, 3], g:tabpagenr_pre)
   4730  call assert_equal([2, 3, 4], g:tabpagenr_post)
   4731 
   4732  " Test 'tabclose {count}' triggering
   4733  let g:tabpagenr_pre = []
   4734  let g:tabpagenr_post = []
   4735  let t:testvar = 1
   4736  tabnew
   4737  let t:testvar = 2
   4738  tabnew
   4739  let t:testvar = 3
   4740  tabclose 2
   4741  tabclose 2
   4742  call assert_equal([2, 3], g:tabpagenr_pre)
   4743  call assert_equal([3, 1], g:tabpagenr_post)
   4744 
   4745  " Test 'tabonly' triggering
   4746  let g:tabpagenr_pre = []
   4747  let g:tabpagenr_post = []
   4748  let t:testvar = 1
   4749  tabnew
   4750  let t:testvar = 2
   4751  tabonly
   4752  call assert_equal([1], g:tabpagenr_pre)
   4753  call assert_equal([2], g:tabpagenr_post)
   4754 
   4755  " Test 'q' and 'close' triggering (closing the last window in a tab)
   4756  let g:tabpagenr_pre = []
   4757  let g:tabpagenr_post = []
   4758  split
   4759  let t:testvar = 1
   4760  tabnew
   4761  let t:testvar = 2
   4762  split
   4763  vsplit
   4764  tabnew
   4765  let t:testvar = 3
   4766  tabnext
   4767  only
   4768  quit
   4769  quit
   4770  close
   4771  close
   4772  call assert_equal([1, 2], g:tabpagenr_pre)
   4773  call assert_equal([2, 3], g:tabpagenr_post)
   4774 
   4775  " Test failing to close tab page
   4776  let g:tabpagenr_pre = []
   4777  let g:tabpagenr_post = []
   4778  let t:testvar = 1
   4779  call setline(1, 'foo')
   4780  setlocal bufhidden=wipe
   4781  tabnew
   4782  let t:testvar = 2
   4783  tabnew
   4784  let t:testvar = 3
   4785  call setline(1, 'bar')
   4786  setlocal bufhidden=wipe
   4787  tabnew
   4788  let t:testvar = 4
   4789  call setline(1, 'baz')
   4790  setlocal bufhidden=wipe
   4791  new
   4792  call assert_fails('tabclose', 'E445:')
   4793  call assert_equal([4], g:tabpagenr_pre)
   4794  call assert_equal([], g:tabpagenr_post)
   4795  " :tabclose! after failed :tabclose should trigger TabClosedPre again.
   4796  tabclose!
   4797  call assert_equal([4, 4], g:tabpagenr_pre)
   4798  call assert_equal([3], g:tabpagenr_post)
   4799  call assert_fails('tabclose', 'E37:')
   4800  call assert_equal([4, 4, 3], g:tabpagenr_pre)
   4801  call assert_equal([3], g:tabpagenr_post)
   4802  " The same for :close! if the tab page only has one window.
   4803  close!
   4804  call assert_equal([4, 4, 3, 3], g:tabpagenr_pre)
   4805  call assert_equal([3, 2], g:tabpagenr_post)
   4806  " Also test with :close! after failed :tabonly.
   4807  call assert_fails('tabonly', 'E37:')
   4808  call assert_equal([4, 4, 3, 3, 1], g:tabpagenr_pre)
   4809  call assert_equal([3, 2], g:tabpagenr_post)
   4810  tabprevious | close!
   4811  call assert_equal([4, 4, 3, 3, 1, 1], g:tabpagenr_pre)
   4812  call assert_equal([3, 2, 2], g:tabpagenr_post)
   4813  %bwipe!
   4814 
   4815  " Test closing another tab page in BufWinLeave
   4816  let g:tabpagenr_pre = []
   4817  let g:tabpagenr_post = []
   4818  split
   4819  let t:testvar = 1
   4820  tabnew
   4821  let t:testvar = 2
   4822  tabnew Xsomebuf
   4823  let t:testvar = 3
   4824  new
   4825  autocmd BufWinLeave Xsomebuf ++once ++nested tabclose 1
   4826  tabclose
   4827  " TabClosedPre should not be triggered for tab page 3 twice.
   4828  call assert_equal([3, 1], g:tabpagenr_pre)
   4829  " When tab page 1 was closed, tab page 3 was still the current tab page.
   4830  call assert_equal([3, 2], g:tabpagenr_post)
   4831  %bwipe!
   4832 
   4833  func ClearAutocmdAndCreateTabs()
   4834    au! TabClosedPre
   4835    bw!
   4836    e Z
   4837    tabonly
   4838    tabnew A
   4839    tabnew B
   4840    tabnew C
   4841  endfunc
   4842 
   4843  func GetTabs()
   4844    redir => tabsout
   4845      tabs
   4846    redir END
   4847    let tabsout = substitute(tabsout, '\n', '', 'g')
   4848    let tabsout = substitute(tabsout, 'Tab page ', '', 'g')
   4849    let tabsout = substitute(tabsout, '#', '', 'g')  " Nvim: remove '#'
   4850    let tabsout = substitute(tabsout, ' ', '', 'g')
   4851    return tabsout
   4852  endfunc
   4853 
   4854  call CleanUpTestAuGroup()
   4855 
   4856  " Close tab in TabClosedPre autocmd
   4857  call ClearAutocmdAndCreateTabs()
   4858  au TabClosedPre * tabclose
   4859  call assert_fails('tabclose', 'E1312:')
   4860  call ClearAutocmdAndCreateTabs()
   4861  au TabClosedPre * tabclose
   4862  call assert_fails('tabclose 2', 'E1312:')
   4863  call ClearAutocmdAndCreateTabs()
   4864  au TabClosedPre * tabclose 1
   4865  call assert_fails('tabclose', 'E1312:')
   4866 
   4867  " Close other (all) tabs in TabClosedPre autocmd
   4868  call ClearAutocmdAndCreateTabs()
   4869  au TabClosedPre * tabonly
   4870  call assert_fails('tabclose', 'E1312:')
   4871  call ClearAutocmdAndCreateTabs()
   4872  au TabClosedPre * tabonly
   4873  call assert_fails('tabclose 2', 'E1312:')
   4874  call ClearAutocmdAndCreateTabs()
   4875  au TabClosedPre * tabclose 4
   4876  call assert_fails('tabclose 2', 'E1312:')
   4877 
   4878  " Open new tabs in TabClosedPre autocmd
   4879  call ClearAutocmdAndCreateTabs()
   4880  au TabClosedPre * tabnew D
   4881  call assert_fails('tabclose', 'E1312:')
   4882  call ClearAutocmdAndCreateTabs()
   4883  au TabClosedPre * tabnew D
   4884  call assert_fails('tabclose 1', 'E1312:')
   4885 
   4886  " Moving the tab page in TabClosedPre autocmd
   4887  call ClearAutocmdAndCreateTabs()
   4888  au TabClosedPre * tabmove 0
   4889  tabclose
   4890  call assert_equal('1>Z2A3B', GetTabs())
   4891  call ClearAutocmdAndCreateTabs()
   4892  au TabClosedPre * tabmove 0
   4893  tabclose 1
   4894  call assert_equal('1A2B3>C', GetTabs())
   4895  tabonly
   4896  call assert_equal('1>C', GetTabs())
   4897 
   4898  " Switching tab page in TabClosedPre autocmd
   4899  call ClearAutocmdAndCreateTabs()
   4900  au TabClosedPre * tabnext | e Y
   4901  tabclose
   4902  call assert_equal('1Y2A3>B', GetTabs())
   4903  call ClearAutocmdAndCreateTabs()
   4904  au TabClosedPre * tabnext | e Y
   4905  tabclose 1
   4906  call assert_equal('1Y2B3>C', GetTabs())
   4907  tabonly
   4908  call assert_equal('1>Y', GetTabs())
   4909 
   4910  " Create new windows in TabClosedPre autocmd
   4911  call ClearAutocmdAndCreateTabs()
   4912  au TabClosedPre * split | e X| vsplit | e Y | split | e Z
   4913  call assert_fails('tabclose', 'E242:')
   4914  call ClearAutocmdAndCreateTabs()
   4915  au TabClosedPre * new X | new Y | new Z
   4916  call assert_fails('tabclose 1', 'E242:')
   4917 
   4918  " Test directly closing the tab page with ':tabclose'
   4919  au!
   4920  tabonly
   4921  bw!
   4922  e Z
   4923  au TabClosedPre * mksession!
   4924  tabnew A
   4925  sp
   4926  tabclose
   4927  source Session.vim
   4928  call assert_equal('1Z2>AA', GetTabs())
   4929 
   4930  " Test directly closing the tab page with ':tabonly'
   4931  " Z is closed before A. Hence A overwrites the session.
   4932  au!
   4933  tabonly
   4934  bw!
   4935  e Z
   4936  au TabClosedPre * mksession!
   4937  tabnew A
   4938  tabnew B
   4939  tabonly
   4940  source Session.vim
   4941  call assert_equal('1>A2B', GetTabs())
   4942 
   4943  " Clean up
   4944  call delete('Session.vim')
   4945  au!
   4946  only
   4947  tabonly
   4948  bw!
   4949  delfunc ClearAutocmdAndCreateTabs
   4950  delfunc GetTabs
   4951 endfunc
   4952 
   4953 " This used to cause heap-use-after-free.
   4954 func Run_test_TabClosedPre_wipe_buffer(split_cmds)
   4955  file Xa
   4956  exe a:split_cmds
   4957  autocmd TabClosedPre * ++once tabnext | bwipe! Xa
   4958  " Closing window inside TabClosedPre is not allowed.
   4959  call assert_fails('tabonly', 'E1312:')
   4960 
   4961  %bwipe!
   4962 endfunc
   4963 
   4964 func Test_TabClosedPre_wipe_buffer()
   4965  " Test with Xa only in other tab pages.
   4966  call Run_test_TabClosedPre_wipe_buffer('split | tab split | tabnew Xb')
   4967  " Test with Xa in both current and other tab pages.
   4968  call Run_test_TabClosedPre_wipe_buffer('split | tab split | new Xb')
   4969 endfunc
   4970 
   4971 func Test_TabClosedPre_mouse()
   4972  func MyTabline()
   4973    let cnt = tabpagenr('$')
   4974    return range(1, cnt)->mapnew({_, n -> $'%{n}X|Close{n}|%X'})->join('')
   4975  endfunc
   4976 
   4977  let save_mouse = &mouse
   4978  if has('gui')
   4979    set guioptions-=e
   4980  endif
   4981  set mouse=a tabline=%!MyTabline()
   4982 
   4983  func OpenTwoTabPages()
   4984    %bwipe!
   4985    file Xa | split | split
   4986    let g:Xa_bufnr = bufnr()
   4987    tabnew Xb | split
   4988    let g:Xb_bufnr = bufnr()
   4989    redraw!
   4990    call assert_match('^|Close1||Close2| *$', Screenline(1))
   4991    call assert_equal(2, tabpagenr('$'))
   4992  endfunc
   4993 
   4994  autocmd! TabClosedPre
   4995  call OpenTwoTabPages()
   4996  let g:autocmd_bufnrs = []
   4997  autocmd TabClosedPre * let g:autocmd_bufnrs += [tabpagebuflist()]
   4998  call Ntest_setmouse(1, 2)
   4999  call feedkeys("\<LeftMouse>\<LeftRelease>", 'tx')
   5000  call assert_equal(1, tabpagenr('$'))
   5001  call assert_equal([[g:Xa_bufnr]->repeat(3)], g:autocmd_bufnrs)
   5002  call assert_equal([g:Xb_bufnr]->repeat(2), tabpagebuflist())
   5003 
   5004  call OpenTwoTabPages()
   5005  let g:autocmd_bufnrs = []
   5006  autocmd TabClosedPre * call feedkeys("\<LeftRelease>\<LeftMouse>", 'tx')
   5007  call Ntest_setmouse(1, 2)
   5008  " Closing tab page inside TabClosedPre is not allowed.
   5009  call assert_fails('call feedkeys("\<LeftMouse>", "tx")', 'E1312:')
   5010  call feedkeys("\<LeftRelease>", 'tx')
   5011 
   5012  autocmd! TabClosedPre
   5013  call OpenTwoTabPages()
   5014  let g:autocmd_bufnrs = []
   5015  autocmd TabClosedPre * let g:autocmd_bufnrs += [tabpagebuflist()]
   5016  call Ntest_setmouse(1, 10)
   5017  call feedkeys("\<LeftMouse>\<LeftRelease>", 'tx')
   5018  call assert_equal(1, tabpagenr('$'))
   5019  call assert_equal([[g:Xb_bufnr]->repeat(2)], g:autocmd_bufnrs)
   5020  call assert_equal([g:Xa_bufnr]->repeat(3), tabpagebuflist())
   5021 
   5022  call OpenTwoTabPages()
   5023  let g:autocmd_bufnrs = []
   5024  autocmd TabClosedPre * call feedkeys("\<LeftRelease>\<LeftMouse>", 'tx')
   5025  call Ntest_setmouse(1, 10)
   5026  " Closing tab page inside TabClosedPre is not allowed.
   5027  call assert_fails('call feedkeys("\<LeftMouse>", "tx")', 'E1312:')
   5028  call feedkeys("\<LeftRelease>", 'tx')
   5029 
   5030  autocmd! TabClosedPre
   5031  %bwipe!
   5032  unlet g:Xa_bufnr g:Xb_bufnr g:autocmd_bufnrs
   5033  let &mouse = save_mouse
   5034  set tabline& guioptions&
   5035  delfunc MyTabline
   5036  delfunc OpenTwoTabPages
   5037 endfunc
   5038 
   5039 func Test_eventignorewin_non_current()
   5040  defer CleanUpTestAuGroup()
   5041  let s:triggered = ''
   5042  augroup testing
   5043    " Will set <abuf> to the buffer of the closing window.
   5044    autocmd WinClosed * let s:triggered = 'WinClosed'
   5045  augroup END
   5046  let initial_win = win_getid()
   5047 
   5048  new
   5049  let new_buf = bufnr()
   5050  " Only set for one of the windows into the new buffer.
   5051  setlocal eventignorewin=all
   5052  split
   5053  setlocal eventignorewin=
   5054  let close_winnr = winnr()
   5055 
   5056  " Return to the window where the buffer is non-current. WinClosed should
   5057  " trigger as not all windows into new_buf have 'eventignorewin' set for it.
   5058  call win_gotoid(initial_win)
   5059  call assert_notequal(new_buf, bufnr())
   5060  execute close_winnr 'close'
   5061  call assert_equal('WinClosed', s:triggered)
   5062 
   5063  wincmd w
   5064  call assert_equal(new_buf, bufnr())
   5065  tab split
   5066  setlocal eventignorewin=
   5067  let close_winnr = win_getid()
   5068 
   5069  " Ensure that new_buf's window in the other tabpage with 'eventignorewin'
   5070  " unset allows WinClosed to run when new_buf is non-current.
   5071  call win_gotoid(initial_win)
   5072  call assert_notequal(new_buf, bufnr())
   5073  let s:triggered = ''
   5074  only!
   5075  call assert_equal('WinClosed', s:triggered)
   5076  call assert_equal(1, win_findbuf(new_buf)->len())
   5077 
   5078  " Create an only window to new_buf with 'eventignorewin' set.
   5079  tabonly!
   5080  execute new_buf 'sbuffer'
   5081  setlocal eventignorewin=all
   5082  wincmd p
   5083  call assert_equal(1, win_findbuf(new_buf)->len())
   5084  call assert_notequal(new_buf, bufnr())
   5085 
   5086  " Closing a window unrelated to new_buf should not block WinClosed.
   5087  split
   5088  let s:triggered = ''
   5089  close
   5090  call assert_equal('WinClosed', s:triggered)
   5091  call assert_equal(1, win_findbuf(new_buf)->len())
   5092 
   5093  " Check WinClosed is blocked when we close the only window to new_buf (that
   5094  " has 'eventignorewin' set) while new_buf is non-current.
   5095  call assert_notequal(new_buf, bufnr())
   5096  let s:triggered = ''
   5097  only!
   5098  call assert_equal('', s:triggered)
   5099  call assert_equal(0, win_findbuf(new_buf)->len())
   5100 
   5101  augroup testing
   5102    autocmd!
   5103    autocmd BufNew * ++once let s:triggered = 'BufNew'
   5104  augroup END
   5105 
   5106  " Buffer not shown in a window, 'eventignorewin' should not block (and
   5107  " can't even be set for it anyway in this case).
   5108  badd foo
   5109  call assert_equal('BufNew', s:triggered)
   5110 
   5111  unlet! s:triggered
   5112  %bw!
   5113 endfunc
   5114 
   5115 func Test_reuse_curbuf_leak()
   5116  new bar
   5117  let s:bar_buf = bufnr()
   5118  augroup testing
   5119    autocmd!
   5120    autocmd BufDelete * ++once let s:triggered = 1 | execute s:bar_buf 'buffer'
   5121  augroup END
   5122  enew
   5123  let empty_buf = bufnr()
   5124 
   5125  " Old curbuf should be reused, firing BufDelete. As BufDelete changes curbuf,
   5126  " reusing the buffer would fail and leak the ffname.
   5127  edit foo
   5128  call assert_equal(1, s:triggered)
   5129  " Wasn't reused because the buffer changed, but buffer "foo" is still created.
   5130  call assert_equal(1, bufexists(empty_buf))
   5131  call assert_notequal(empty_buf, bufnr())
   5132  call assert_equal('foo', bufname())
   5133  call assert_equal('bar', bufname(s:bar_buf))
   5134 
   5135  unlet! s:bar_buf s:triggered
   5136  call CleanUpTestAuGroup()
   5137  %bw!
   5138 endfunc
   5139 
   5140 func Test_reuse_curbuf_switch()
   5141  edit asdf
   5142  let s:asdf_win = win_getid()
   5143  new
   5144  let other_buf = bufnr()
   5145  let other_win = win_getid()
   5146  augroup testing
   5147    autocmd!
   5148    autocmd BufUnload * ++once let s:triggered = 1
   5149          \| call assert_fails('split', 'E1159:')
   5150          \| call win_gotoid(s:asdf_win)
   5151  augroup END
   5152 
   5153  " Check BufUnload changing curbuf does not cause buflist_new to create a new
   5154  " buffer while leaving "other_buf" unloaded in a window.
   5155  enew
   5156  call assert_equal(1, s:triggered)
   5157  call assert_equal(other_buf, bufnr())
   5158  call assert_equal(other_win, win_getid())
   5159  call assert_equal(1, win_findbuf(other_buf)->len())
   5160  call assert_equal(1, bufloaded(other_buf))
   5161 
   5162  unlet! s:asdf_win s:triggered
   5163  call CleanUpTestAuGroup()
   5164  %bw!
   5165 endfunc
   5166 
   5167 func Test_eventignore_subtract()
   5168  set eventignore=all,-WinEnter
   5169  augroup testing
   5170    autocmd!
   5171    autocmd WinEnter * ++once let s:triggered = 1
   5172  augroup END
   5173 
   5174  new
   5175  call assert_equal(1, s:triggered)
   5176 
   5177  set eventignore&
   5178  unlet! s:triggered
   5179  call CleanUpTestAuGroup()
   5180  %bw!
   5181 endfunc
   5182 
   5183 func Test_win_tabclose_autocmd()
   5184 
   5185  defer CleanUpTestAuGroup()
   5186  new
   5187  augroup testing
   5188    au WinClosed * wincmd p
   5189  augroup END
   5190 
   5191  tabnew
   5192  new
   5193  new
   5194 
   5195  call assert_equal(2, tabpagenr('$'))
   5196  try
   5197    tabclose
   5198  catch
   5199    " should not happen
   5200    call assert_report("closing tabpage failed")
   5201  endtry
   5202  call assert_equal(1, tabpagenr('$'))
   5203  bw!
   5204 endfunc
   5205 
   5206 " vim: shiftwidth=2 sts=2 expandtab