xref: /vim-8.2.3635/src/testdir/test_autocmd.vim (revision fc65cabb)
1" Tests for autocommands
2
3source shared.vim
4
5func! s:cleanup_buffers() abort
6  for bnr in range(1, bufnr('$'))
7    if bufloaded(bnr) && bufnr('%') != bnr
8      execute 'bd! ' . bnr
9    endif
10  endfor
11endfunc
12
13func Test_vim_did_enter()
14  call assert_false(v:vim_did_enter)
15
16  " This script will never reach the main loop, can't check if v:vim_did_enter
17  " becomes one.
18endfunc
19
20if has('timers')
21  func ExitInsertMode(id)
22    call feedkeys("\<Esc>")
23  endfunc
24
25  func Test_cursorhold_insert()
26    " Need to move the cursor.
27    call feedkeys("ggG", "xt")
28
29    let g:triggered = 0
30    au CursorHoldI * let g:triggered += 1
31    set updatetime=20
32    call timer_start(100, 'ExitInsertMode')
33    call feedkeys('a', 'x!')
34    call assert_equal(1, g:triggered)
35    au! CursorHoldI
36    set updatetime&
37  endfunc
38
39  func Test_cursorhold_insert_ctrl_x()
40    let g:triggered = 0
41    au CursorHoldI * let g:triggered += 1
42    set updatetime=20
43    call timer_start(100, 'ExitInsertMode')
44    " CursorHoldI does not trigger after CTRL-X
45    call feedkeys("a\<C-X>", 'x!')
46    call assert_equal(0, g:triggered)
47    au! CursorHoldI
48    set updatetime&
49  endfunc
50endif
51
52func Test_bufunload()
53  augroup test_bufunload_group
54    autocmd!
55    autocmd BufUnload * call add(s:li, "bufunload")
56    autocmd BufDelete * call add(s:li, "bufdelete")
57    autocmd BufWipeout * call add(s:li, "bufwipeout")
58  augroup END
59
60  let s:li=[]
61  new
62  setlocal bufhidden=
63  bunload
64  call assert_equal(["bufunload", "bufdelete"], s:li)
65
66  let s:li=[]
67  new
68  setlocal bufhidden=delete
69  bunload
70  call assert_equal(["bufunload", "bufdelete"], s:li)
71
72  let s:li=[]
73  new
74  setlocal bufhidden=unload
75  bwipeout
76  call assert_equal(["bufunload", "bufdelete", "bufwipeout"], s:li)
77
78  au! test_bufunload_group
79  augroup! test_bufunload_group
80endfunc
81
82" SEGV occurs in older versions.  (At least 7.4.2005 or older)
83func Test_autocmd_bufunload_with_tabnext()
84  tabedit
85  tabfirst
86
87  augroup test_autocmd_bufunload_with_tabnext_group
88    autocmd!
89    autocmd BufUnload <buffer> tabnext
90  augroup END
91
92  quit
93  call assert_equal(2, tabpagenr('$'))
94
95  autocmd! test_autocmd_bufunload_with_tabnext_group
96  augroup! test_autocmd_bufunload_with_tabnext_group
97  tablast
98  quit
99endfunc
100
101func Test_autocmd_bufwinleave_with_tabfirst()
102  tabedit
103  augroup sample
104    autocmd!
105    autocmd BufWinLeave <buffer> tabfirst
106  augroup END
107  call setline(1, ['a', 'b', 'c'])
108  edit! a.txt
109  tabclose
110endfunc
111
112" SEGV occurs in older versions.  (At least 7.4.2321 or older)
113func Test_autocmd_bufunload_avoiding_SEGV_01()
114  split aa.txt
115  let lastbuf = bufnr('$')
116
117  augroup test_autocmd_bufunload
118    autocmd!
119    exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!'
120  augroup END
121
122  " Todo: check for E937 generated first
123  " call assert_fails('edit bb.txt', 'E937:')
124  call assert_fails('edit bb.txt', 'E517:')
125
126  autocmd! test_autocmd_bufunload
127  augroup! test_autocmd_bufunload
128  bwipe! aa.txt
129  bwipe! bb.txt
130endfunc
131
132" SEGV occurs in older versions.  (At least 7.4.2321 or older)
133func Test_autocmd_bufunload_avoiding_SEGV_02()
134  setlocal buftype=nowrite
135  let lastbuf = bufnr('$')
136
137  augroup test_autocmd_bufunload
138    autocmd!
139    exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!'
140  augroup END
141
142  normal! i1
143  call assert_fails('edit a.txt', 'E517:')
144  call feedkeys("\<CR>")
145
146  autocmd! test_autocmd_bufunload
147  augroup! test_autocmd_bufunload
148  bwipe! a.txt
149endfunc
150
151func Test_win_tab_autocmd()
152  let g:record = []
153
154  augroup testing
155    au WinNew * call add(g:record, 'WinNew')
156    au WinEnter * call add(g:record, 'WinEnter')
157    au WinLeave * call add(g:record, 'WinLeave')
158    au TabNew * call add(g:record, 'TabNew')
159    au TabClosed * call add(g:record, 'TabClosed')
160    au TabEnter * call add(g:record, 'TabEnter')
161    au TabLeave * call add(g:record, 'TabLeave')
162  augroup END
163
164  split
165  tabnew
166  close
167  close
168
169  call assert_equal([
170	\ 'WinLeave', 'WinNew', 'WinEnter',
171	\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
172	\ 'WinLeave', 'TabLeave', 'TabClosed', 'WinEnter', 'TabEnter',
173	\ 'WinLeave', 'WinEnter'
174	\ ], g:record)
175
176  let g:record = []
177  tabnew somefile
178  tabnext
179  bwipe somefile
180
181  call assert_equal([
182	\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
183	\ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter',
184	\ 'TabClosed'
185	\ ], g:record)
186
187  augroup testing
188    au!
189  augroup END
190  unlet g:record
191endfunc
192
193func s:AddAnAutocmd()
194  augroup vimBarTest
195    au BufReadCmd * echo 'hello'
196  augroup END
197  call assert_equal(3, len(split(execute('au vimBarTest'), "\n")))
198endfunc
199
200func Test_early_bar()
201  " test that a bar is recognized before the {event}
202  call s:AddAnAutocmd()
203  augroup vimBarTest | au! | augroup END
204  call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
205
206  call s:AddAnAutocmd()
207  augroup vimBarTest| au!| augroup END
208  call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
209
210  " test that a bar is recognized after the {event}
211  call s:AddAnAutocmd()
212  augroup vimBarTest| au!BufReadCmd| augroup END
213  call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
214
215  " test that a bar is recognized after the {group}
216  call s:AddAnAutocmd()
217  au! vimBarTest|echo 'hello'
218  call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
219endfunc
220
221func RemoveGroup()
222  autocmd! StartOK
223  augroup! StartOK
224endfunc
225
226func Test_augroup_warning()
227  augroup TheWarning
228    au VimEnter * echo 'entering'
229  augroup END
230  call assert_true(match(execute('au VimEnter'), "TheWarning.*VimEnter") >= 0)
231  redir => res
232  augroup! TheWarning
233  redir END
234  call assert_true(match(res, "W19:") >= 0)
235  call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
236
237  " check "Another" does not take the pace of the deleted entry
238  augroup Another
239  augroup END
240  call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
241  augroup! Another
242
243  " no warning for postpone aucmd delete
244  augroup StartOK
245    au VimEnter * call RemoveGroup()
246  augroup END
247  call assert_true(match(execute('au VimEnter'), "StartOK.*VimEnter") >= 0)
248  redir => res
249  doautocmd VimEnter
250  redir END
251  call assert_true(match(res, "W19:") < 0)
252  au! VimEnter
253endfunc
254
255func Test_BufReadCmdHelp()
256  " This used to cause access to free memory
257  au BufReadCmd * e +h
258  help
259
260  au! BufReadCmd
261endfunc
262
263func Test_BufReadCmdHelpJump()
264  " This used to cause access to free memory
265  au BufReadCmd * e +h{
266  " } to fix highlighting
267  call assert_fails('help', 'E434:')
268
269  au! BufReadCmd
270endfunc
271
272func Test_augroup_deleted()
273  " This caused a crash before E936 was introduced
274  augroup x
275    call assert_fails('augroup! x', 'E936:')
276    au VimEnter * echo
277  augroup end
278  augroup! x
279  call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
280  au! VimEnter
281endfunc
282
283" Tests for autocommands on :close command.
284" This used to be in test13.
285func Test_three_windows()
286  " Clean up buffers, because in some cases this function fails.
287  call s:cleanup_buffers()
288
289  " Write three files and open them, each in a window.
290  " Then go to next window, with autocommand that deletes the previous one.
291  " Do this twice, writing the file.
292  e! Xtestje1
293  call setline(1, 'testje1')
294  w
295  sp Xtestje2
296  call setline(1, 'testje2')
297  w
298  sp Xtestje3
299  call setline(1, 'testje3')
300  w
301  wincmd w
302  au WinLeave Xtestje2 bwipe
303  wincmd w
304  call assert_equal('Xtestje1', expand('%'))
305
306  au WinLeave Xtestje1 bwipe Xtestje3
307  close
308  call assert_equal('Xtestje1', expand('%'))
309
310  " Test deleting the buffer on a Unload event.  If this goes wrong there
311  " will be the ATTENTION prompt.
312  e Xtestje1
313  au!
314  au! BufUnload Xtestje1 bwipe
315  call assert_fails('e Xtestje3', 'E937:')
316  call assert_equal('Xtestje3', expand('%'))
317
318  e Xtestje2
319  sp Xtestje1
320  call assert_fails('e', 'E937:')
321  call assert_equal('Xtestje1', expand('%'))
322
323  " Test changing buffers in a BufWipeout autocommand.  If this goes wrong
324  " there are ml_line errors and/or a Crash.
325  au!
326  only
327  e Xanother
328  e Xtestje1
329  bwipe Xtestje2
330  bwipe Xtestje3
331  au BufWipeout Xtestje1 buf Xtestje1
332  bwipe
333  call assert_equal('Xanother', expand('%'))
334
335  only
336  help
337  wincmd w
338  1quit
339  call assert_equal('Xanother', expand('%'))
340
341  au!
342  enew
343  call delete('Xtestje1')
344  call delete('Xtestje2')
345  call delete('Xtestje3')
346endfunc
347
348func Test_BufEnter()
349  au! BufEnter
350  au Bufenter * let val = val . '+'
351  let g:val = ''
352  split NewFile
353  call assert_equal('+', g:val)
354  bwipe!
355  call assert_equal('++', g:val)
356
357  " Also get BufEnter when editing a directory
358  call mkdir('Xdir')
359  split Xdir
360  call assert_equal('+++', g:val)
361
362  " On MS-Windows we can't edit the directory, make sure we wipe the right
363  " buffer.
364  bwipe! Xdir
365
366  call delete('Xdir', 'd')
367  au! BufEnter
368endfunc
369
370" Closing a window might cause an endless loop
371" E814 for older Vims
372func Test_autocmd_bufwipe_in_SessLoadPost()
373  edit Xtest
374  tabnew
375  file Xsomething
376  set noswapfile
377  mksession!
378
379  let content = ['set nocp noswapfile',
380        \ 'let v:swapchoice="e"',
381        \ 'augroup test_autocmd_sessionload',
382        \ 'autocmd!',
383        \ 'autocmd SessionLoadPost * exe bufnr("Xsomething") . "bw!"',
384        \ 'augroup END',
385	\ '',
386	\ 'func WriteErrors()',
387	\ '  call writefile([execute("messages")], "Xerrors")',
388	\ 'endfunc',
389	\ 'au VimLeave * call WriteErrors()',
390        \ ]
391  call writefile(content, 'Xvimrc')
392  call system(v:progpath. ' -u Xvimrc --not-a-term --noplugins -S Session.vim -c cq')
393  let errors = join(readfile('Xerrors'))
394  call assert_match('E814', errors)
395
396  set swapfile
397  for file in ['Session.vim', 'Xvimrc', 'Xerrors']
398    call delete(file)
399  endfor
400endfunc
401
402" SEGV occurs in older versions.
403func Test_autocmd_bufwipe_in_SessLoadPost2()
404  tabnew
405  set noswapfile
406  mksession!
407
408  let content = ['set nocp noswapfile',
409      \ 'function! DeleteInactiveBufs()',
410      \ '  tabfirst',
411      \ '  let tabblist = []',
412      \ '  for i in range(1, tabpagenr(''$''))',
413      \ '    call extend(tabblist, tabpagebuflist(i))',
414      \ '  endfor',
415      \ '  for b in range(1, bufnr(''$''))',
416      \ '    if bufexists(b) && buflisted(b) && (index(tabblist, b) == -1 || bufname(b) =~# ''^$'')',
417      \ '      exec ''bwipeout '' . b',
418      \ '    endif',
419      \ '  endfor',
420      \ '  echomsg "SessionLoadPost DONE"',
421      \ 'endfunction',
422      \ 'au SessionLoadPost * call DeleteInactiveBufs()',
423      \ '',
424      \ 'func WriteErrors()',
425      \ '  call writefile([execute("messages")], "Xerrors")',
426      \ 'endfunc',
427      \ 'au VimLeave * call WriteErrors()',
428      \ ]
429  call writefile(content, 'Xvimrc')
430  call system(v:progpath. ' -u Xvimrc --not-a-term --noplugins -S Session.vim -c cq')
431  let errors = join(readfile('Xerrors'))
432  " This probably only ever matches on unix.
433  call assert_notmatch('Caught deadly signal SEGV', errors)
434  call assert_match('SessionLoadPost DONE', errors)
435
436  set swapfile
437  for file in ['Session.vim', 'Xvimrc', 'Xerrors']
438    call delete(file)
439  endfor
440endfunc
441
442func Test_empty_doau()
443  doau \|
444endfunc
445
446func s:AutoCommandOptionSet(match)
447  let item     = remove(g:options, 0)
448  let expected = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", item[0], item[1], item[2], item[3])
449  let actual   = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", a:match, v:option_old, v:option_new, v:option_type)
450  let g:opt    = [expected, actual]
451  "call assert_equal(expected, actual)
452endfunc
453
454func Test_OptionSet()
455  if !has("eval") || !has("autocmd") || !exists("+autochdir")
456    return
457  endif
458
459  badd test_autocmd.vim
460
461  call test_override('starting', 1)
462  set nocp
463  au OptionSet * :call s:AutoCommandOptionSet(expand("<amatch>"))
464
465  " 1: Setting number option"
466  let g:options=[['number', 0, 1, 'global']]
467  set nu
468  call assert_equal([], g:options)
469  call assert_equal(g:opt[0], g:opt[1])
470
471  " 2: Setting local number option"
472  let g:options=[['number', 1, 0, 'local']]
473  setlocal nonu
474  call assert_equal([], g:options)
475  call assert_equal(g:opt[0], g:opt[1])
476
477  " 3: Setting global number option"
478  let g:options=[['number', 1, 0, 'global']]
479  setglobal nonu
480  call assert_equal([], g:options)
481  call assert_equal(g:opt[0], g:opt[1])
482
483  " 4: Setting local autoindent option"
484  let g:options=[['autoindent', 0, 1, 'local']]
485  setlocal ai
486  call assert_equal([], g:options)
487  call assert_equal(g:opt[0], g:opt[1])
488
489  " 5: Setting global autoindent option"
490  let g:options=[['autoindent', 0, 1, 'global']]
491  setglobal ai
492  call assert_equal([], g:options)
493  call assert_equal(g:opt[0], g:opt[1])
494
495  " 6: Setting global autoindent option"
496  let g:options=[['autoindent', 1, 0, 'global']]
497  set ai!
498  call assert_equal([], g:options)
499  call assert_equal(g:opt[0], g:opt[1])
500
501  " Should not print anything, use :noa
502  " 7: don't trigger OptionSet"
503  let g:options=[['invalid', 1, 1, 'invalid']]
504  noa set nonu
505  call assert_equal([['invalid', 1, 1, 'invalid']], g:options)
506  call assert_equal(g:opt[0], g:opt[1])
507
508  " 8: Setting several global list and number option"
509  let g:options=[['list', 0, 1, 'global'], ['number', 0, 1, 'global']]
510  set list nu
511  call assert_equal([], g:options)
512  call assert_equal(g:opt[0], g:opt[1])
513
514  " 9: don't trigger OptionSet"
515  let g:options=[['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']]
516  noa set nolist nonu
517  call assert_equal([['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']], g:options)
518  call assert_equal(g:opt[0], g:opt[1])
519
520  " 10: Setting global acd"
521  let g:options=[['autochdir', 0, 1, 'local']]
522  setlocal acd
523  call assert_equal([], g:options)
524  call assert_equal(g:opt[0], g:opt[1])
525
526  " 11: Setting global autoread (also sets local value)"
527  let g:options=[['autoread', 0, 1, 'global']]
528  set ar
529  call assert_equal([], g:options)
530  call assert_equal(g:opt[0], g:opt[1])
531
532  " 12: Setting local autoread"
533  let g:options=[['autoread', 1, 1, 'local']]
534  setlocal ar
535  call assert_equal([], g:options)
536  call assert_equal(g:opt[0], g:opt[1])
537
538  " 13: Setting global autoread"
539  let g:options=[['autoread', 1, 0, 'global']]
540  setglobal invar
541  call assert_equal([], g:options)
542  call assert_equal(g:opt[0], g:opt[1])
543
544  " 14: Setting option backspace through :let"
545  let g:options=[['backspace', '', 'eol,indent,start', 'global']]
546  let &bs="eol,indent,start"
547  call assert_equal([], g:options)
548  call assert_equal(g:opt[0], g:opt[1])
549
550  " 15: Setting option backspace through setbufvar()"
551  let g:options=[['backup', 0, 1, 'local']]
552  " try twice, first time, shouldn't trigger because option name is invalid,
553  " second time, it should trigger
554  let bnum = bufnr('%')
555  call assert_fails("call setbufvar(bnum, '&l:bk', 1)", "E355")
556  " should trigger, use correct option name
557  call setbufvar(bnum, '&backup', 1)
558  call assert_equal([], g:options)
559  call assert_equal(g:opt[0], g:opt[1])
560
561  " 16: Setting number option using setwinvar"
562  let g:options=[['number', 0, 1, 'local']]
563  call setwinvar(0, '&number', 1)
564  call assert_equal([], g:options)
565  call assert_equal(g:opt[0], g:opt[1])
566
567  " 17: Setting key option, shouldn't trigger"
568  let g:options=[['key', 'invalid', 'invalid1', 'invalid']]
569  setlocal key=blah
570  setlocal key=
571  call assert_equal([['key', 'invalid', 'invalid1', 'invalid']], g:options)
572  call assert_equal(g:opt[0], g:opt[1])
573
574  " 18: Setting string option"
575  let oldval = &tags
576  let g:options=[['tags', oldval, 'tagpath', 'global']]
577  set tags=tagpath
578  call assert_equal([], g:options)
579  call assert_equal(g:opt[0], g:opt[1])
580
581  " 1l: Resetting string option"
582  let g:options=[['tags', 'tagpath', oldval, 'global']]
583  set tags&
584  call assert_equal([], g:options)
585  call assert_equal(g:opt[0], g:opt[1])
586
587  " Cleanup
588  au! OptionSet
589  for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp']
590    exe printf(":set %s&vim", opt)
591  endfor
592  call test_override('starting', 0)
593  delfunc! AutoCommandOptionSet
594endfunc
595
596func Test_OptionSet_diffmode()
597  call test_override('starting', 1)
598  " 18: Changing an option when enetering diff mode
599  new
600  au OptionSet diff :let &l:cul=v:option_new
601
602  call setline(1, ['buffer 1', 'line2', 'line3', 'line4'])
603  call assert_equal(0, &l:cul)
604  diffthis
605  call assert_equal(1, &l:cul)
606
607  vnew
608  call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4'])
609  call assert_equal(0, &l:cul)
610  diffthis
611  call assert_equal(1, &l:cul)
612
613  diffoff
614  call assert_equal(0, &l:cul)
615  call assert_equal(1, getwinvar(2, '&l:cul'))
616  bw!
617
618  call assert_equal(1, &l:cul)
619  diffoff!
620  call assert_equal(0, &l:cul)
621  call assert_equal(0, getwinvar(1, '&l:cul'))
622  bw!
623
624  " Cleanup
625  au! OptionSet
626  call test_override('starting', 0)
627endfunc
628
629func Test_OptionSet_diffmode_close()
630  call test_override('starting', 1)
631  " 19: Try to close the current window when entering diff mode
632  " should not segfault
633  new
634  au OptionSet diff close
635
636  call setline(1, ['buffer 1', 'line2', 'line3', 'line4'])
637  call assert_fails(':diffthis', 'E788')
638  call assert_equal(1, &diff)
639  vnew
640  call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4'])
641  call assert_fails(':diffthis', 'E788')
642  call assert_equal(1, &diff)
643  bw!
644  call assert_fails(':diffoff!', 'E788')
645  bw!
646
647  " Cleanup
648  au! OptionSet
649  call test_override('starting', 0)
650  "delfunc! AutoCommandOptionSet
651endfunc
652
653" Test for Bufleave autocommand that deletes the buffer we are about to edit.
654func Test_BufleaveWithDelete()
655  new | edit Xfile1
656
657  augroup test_bufleavewithdelete
658      autocmd!
659      autocmd BufLeave Xfile1 bwipe Xfile2
660  augroup END
661
662  call assert_fails('edit Xfile2', 'E143:')
663  call assert_equal('Xfile1', bufname('%'))
664
665  autocmd! test_bufleavewithdelete BufLeave Xfile1
666  augroup! test_bufleavewithdelete
667
668  new
669  bwipe! Xfile1
670endfunc
671
672" Test for autocommand that changes the buffer list, when doing ":ball".
673func Test_Acmd_BufAll()
674  enew!
675  %bwipe!
676  call writefile(['Test file Xxx1'], 'Xxx1')
677  call writefile(['Test file Xxx2'], 'Xxx2')
678  call writefile(['Test file Xxx3'], 'Xxx3')
679
680  " Add three files to the buffer list
681  split Xxx1
682  close
683  split Xxx2
684  close
685  split Xxx3
686  close
687
688  " Wipe the buffer when the buffer is opened
689  au BufReadPost Xxx2 bwipe
690
691  call append(0, 'Test file Xxx4')
692  ball
693
694  call assert_equal(2, winnr('$'))
695  call assert_equal('Xxx1', bufname(winbufnr(winnr('$'))))
696  wincmd t
697
698  au! BufReadPost
699  %bwipe!
700  call delete('Xxx1')
701  call delete('Xxx2')
702  call delete('Xxx3')
703  enew! | only
704endfunc
705
706" Test for autocommand that changes current buffer on BufEnter event.
707" Check if modelines are interpreted for the correct buffer.
708func Test_Acmd_BufEnter()
709  %bwipe!
710  call writefile(['start of test file Xxx1',
711	      \ "\<Tab>this is a test",
712	      \ 'end of test file Xxx1'], 'Xxx1')
713  call writefile(['start of test file Xxx2',
714	      \ 'vim: set noai :',
715	      \ "\<Tab>this is a test",
716	      \ 'end of test file Xxx2'], 'Xxx2')
717
718  au BufEnter Xxx2 brew
719  set ai modeline modelines=3
720  edit Xxx1
721  " edit Xxx2, autocmd will do :brew
722  edit Xxx2
723  exe "normal G?this is a\<CR>"
724  " Append text with autoindent to this file
725  normal othis should be auto-indented
726  call assert_equal("\<Tab>this should be auto-indented", getline('.'))
727  call assert_equal(3, line('.'))
728  " Remove autocmd and edit Xxx2 again
729  au! BufEnter Xxx2
730  buf! Xxx2
731  exe "normal G?this is a\<CR>"
732  " append text without autoindent to Xxx
733  normal othis should be in column 1
734  call assert_equal("this should be in column 1", getline('.'))
735  call assert_equal(4, line('.'))
736
737  %bwipe!
738  call delete('Xxx1')
739  call delete('Xxx2')
740  set ai&vim modeline&vim modelines&vim
741endfunc
742
743" Test for issue #57
744" do not move cursor on <c-o> when autoindent is set
745func Test_ai_CTRL_O()
746  enew!
747  set ai
748  let save_fo = &fo
749  set fo+=r
750  exe "normal o# abcdef\<Esc>2hi\<CR>\<C-O>d0\<Esc>"
751  exe "normal o# abcdef\<Esc>2hi\<C-O>d0\<Esc>"
752  call assert_equal(['# abc', 'def', 'def'], getline(2, 4))
753
754  set ai&vim
755  let &fo = save_fo
756  enew!
757endfunc
758
759" Test for autocommand that deletes the current buffer on BufLeave event.
760" Also test deleting the last buffer, should give a new, empty buffer.
761func Test_BufLeave_Wipe()
762  %bwipe!
763  let content = ['start of test file Xxx',
764	      \ 'this is a test',
765	      \ 'end of test file Xxx']
766  call writefile(content, 'Xxx1')
767  call writefile(content, 'Xxx2')
768
769  au BufLeave Xxx2 bwipe
770  edit Xxx1
771  split Xxx2
772  " delete buffer Xxx2, we should be back to Xxx1
773  bwipe
774  call assert_equal('Xxx1', bufname('%'))
775  call assert_equal(1, winnr('$'))
776
777  " Create an alternate buffer
778  %write! test.out
779  call assert_equal('test.out', bufname('#'))
780  " delete alternate buffer
781  bwipe test.out
782  call assert_equal('Xxx1', bufname('%'))
783  call assert_equal('', bufname('#'))
784
785  au BufLeave Xxx1 bwipe
786  " delete current buffer, get an empty one
787  bwipe!
788  call assert_equal(1, line('$'))
789  call assert_equal('', bufname('%'))
790  let g:bufinfo = getbufinfo()
791  call assert_equal(1, len(g:bufinfo))
792
793  call delete('Xxx1')
794  call delete('Xxx2')
795  call delete('test.out')
796  %bwipe
797  au! BufLeave
798
799  " check that bufinfo doesn't contain a pointer to freed memory
800  call test_garbagecollect_now()
801endfunc
802
803func Test_QuitPre()
804  edit Xfoo
805  let winid = win_getid(winnr())
806  split Xbar
807  au! QuitPre * let g:afile = expand('<afile>')
808  " Close the other window, <afile> should be correct.
809  exe win_id2win(winid) . 'q'
810  call assert_equal('Xfoo', g:afile)
811
812  unlet g:afile
813  bwipe Xfoo
814  bwipe Xbar
815endfunc
816
817func Test_Cmdline()
818  au! CmdlineChanged : let g:text = getcmdline()
819  let g:text = 0
820  call feedkeys(":echom 'hello'\<CR>", 'xt')
821  call assert_equal("echom 'hello'", g:text)
822  au! CmdlineChanged
823
824  au! CmdlineChanged : let g:entered = expand('<afile>')
825  let g:entered = 0
826  call feedkeys(":echom 'hello'\<CR>", 'xt')
827  call assert_equal(':', g:entered)
828  au! CmdlineChanged
829
830  au! CmdlineEnter : let g:entered = expand('<afile>')
831  au! CmdlineLeave : let g:left = expand('<afile>')
832  let g:entered = 0
833  let g:left = 0
834  call feedkeys(":echo 'hello'\<CR>", 'xt')
835  call assert_equal(':', g:entered)
836  call assert_equal(':', g:left)
837  au! CmdlineEnter
838  au! CmdlineLeave
839
840  let save_shellslash = &shellslash
841  set noshellslash
842  au! CmdlineEnter / let g:entered = expand('<afile>')
843  au! CmdlineLeave / let g:left = expand('<afile>')
844  let g:entered = 0
845  let g:left = 0
846  new
847  call setline(1, 'hello')
848  call feedkeys("/hello\<CR>", 'xt')
849  call assert_equal('/', g:entered)
850  call assert_equal('/', g:left)
851  bwipe!
852  au! CmdlineEnter
853  au! CmdlineLeave
854  let &shellslash = save_shellslash
855endfunc
856
857" Test for BufWritePre autocommand that deletes or unloads the buffer.
858func Test_BufWritePre()
859  %bwipe
860  au BufWritePre Xxx1 bunload
861  au BufWritePre Xxx2 bwipe
862
863  call writefile(['start of Xxx1', 'test', 'end of Xxx1'], 'Xxx1')
864  call writefile(['start of Xxx2', 'test', 'end of Xxx2'], 'Xxx2')
865
866  edit Xtest
867  e! Xxx2
868  bdel Xtest
869  e Xxx1
870  " write it, will unload it and give an error msg
871  call assert_fails('w', 'E203')
872  call assert_equal('Xxx2', bufname('%'))
873  edit Xtest
874  e! Xxx2
875  bwipe Xtest
876  " write it, will delete the buffer and give an error msg
877  call assert_fails('w', 'E203')
878  call assert_equal('Xxx1', bufname('%'))
879  au! BufWritePre
880  call delete('Xxx1')
881  call delete('Xxx2')
882endfunc
883
884" Test for BufUnload autocommand that unloads all the other buffers
885func Test_bufunload_all()
886  call writefile(['Test file Xxx1'], 'Xxx1')"
887  call writefile(['Test file Xxx2'], 'Xxx2')"
888
889  let content = [
890	      \ "func UnloadAllBufs()",
891	      \ "  let i = 1",
892	      \ "  while i <= bufnr('$')",
893	      \ "    if i != bufnr('%') && bufloaded(i)",
894	      \ "      exe  i . 'bunload'",
895	      \ "    endif",
896	      \ "    let i += 1",
897	      \ "  endwhile",
898	      \ "endfunc",
899	      \ "au BufUnload * call UnloadAllBufs()",
900	      \ "au VimLeave * call writefile(['Test Finished'], 'Xout')",
901	      \ "edit Xxx1",
902	      \ "split Xxx2",
903	      \ "q"]
904  call writefile(content, 'Xtest')
905
906  call delete('Xout')
907  call system(v:progpath. ' --clean -N --not-a-term -S Xtest')
908  call assert_true(filereadable('Xout'))
909
910  call delete('Xxx1')
911  call delete('Xxx2')
912  call delete('Xtest')
913  call delete('Xout')
914endfunc
915
916" Some tests for buffer-local autocommands
917func Test_buflocal_autocmd()
918  let g:bname = ''
919  edit xx
920  au BufLeave <buffer> let g:bname = expand("%")
921  " here, autocommand for xx should trigger.
922  " but autocommand shall not apply to buffer named <buffer>.
923  edit somefile
924  call assert_equal('xx', g:bname)
925  let g:bname = ''
926  " here, autocommand shall be auto-deleted
927  bwipe xx
928  " autocmd should not trigger
929  edit xx
930  call assert_equal('', g:bname)
931  " autocmd should not trigger
932  edit somefile
933  call assert_equal('', g:bname)
934  enew
935  unlet g:bname
936endfunc
937
938" Test for "*Cmd" autocommands
939func Test_Cmd_Autocmds()
940  call writefile(['start of Xxx', "\tabc2", 'end of Xxx'], 'Xxx')
941
942  enew!
943  au BufReadCmd XtestA 0r Xxx|$del
944  edit XtestA			" will read text of Xxd instead
945  call assert_equal('start of Xxx', getline(1))
946
947  au BufWriteCmd XtestA call append(line("$"), "write")
948  write				" will append a line to the file
949  call assert_equal('write', getline('$'))
950  call assert_fails('read XtestA', 'E484')	" should not read anything
951  call assert_equal('write', getline(4))
952
953  " now we have:
954  " 1	start of Xxx
955  " 2		abc2
956  " 3	end of Xxx
957  " 4	write
958
959  au FileReadCmd XtestB '[r Xxx
960  2r XtestB			" will read Xxx below line 2 instead
961  call assert_equal('start of Xxx', getline(3))
962
963  " now we have:
964  " 1	start of Xxx
965  " 2		abc2
966  " 3	start of Xxx
967  " 4		abc2
968  " 5	end of Xxx
969  " 6	end of Xxx
970  " 7	write
971
972  au FileWriteCmd XtestC '[,']copy $
973  normal 4GA1
974  4,5w XtestC			" will copy lines 4 and 5 to the end
975  call assert_equal("\tabc21", getline(8))
976  call assert_fails('r XtestC', 'E484')	" should not read anything
977  call assert_equal("end of Xxx", getline(9))
978
979  " now we have:
980  " 1	start of Xxx
981  " 2		abc2
982  " 3	start of Xxx
983  " 4		abc21
984  " 5	end of Xxx
985  " 6	end of Xxx
986  " 7	write
987  " 8		abc21
988  " 9	end of Xxx
989
990  let g:lines = []
991  au FileAppendCmd XtestD call extend(g:lines, getline(line("'["), line("']")))
992  w >>XtestD			" will add lines to 'lines'
993  call assert_equal(9, len(g:lines))
994  call assert_fails('$r XtestD', 'E484')	" should not read anything
995  call assert_equal(9, line('$'))
996  call assert_equal('end of Xxx', getline('$'))
997
998  au BufReadCmd XtestE 0r Xxx|$del
999  sp XtestE			" split window with test.out
1000  call assert_equal('end of Xxx', getline(3))
1001
1002  let g:lines = []
1003  exe "normal 2Goasdf\<Esc>\<C-W>\<C-W>"
1004  au BufWriteCmd XtestE call extend(g:lines, getline(0, '$'))
1005  wall				" will write other window to 'lines'
1006  call assert_equal(4, len(g:lines), g:lines)
1007  call assert_equal('asdf', g:lines[2])
1008
1009  au! BufReadCmd
1010  au! BufWriteCmd
1011  au! FileReadCmd
1012  au! FileWriteCmd
1013  au! FileAppendCmd
1014  %bwipe!
1015  call delete('Xxx')
1016  enew!
1017endfunc
1018
1019func SetChangeMarks(start, end)
1020  exe a:start. 'mark ['
1021  exe a:end. 'mark ]'
1022endfunc
1023
1024" Verify the effects of autocmds on '[ and ']
1025func Test_change_mark_in_autocmds()
1026  edit! Xtest
1027  call feedkeys("ia\<CR>b\<CR>c\<CR>d\<C-g>u", 'xtn')
1028
1029  call SetChangeMarks(2, 3)
1030  write
1031  call assert_equal([1, 4], [line("'["), line("']")])
1032
1033  call SetChangeMarks(2, 3)
1034  au BufWritePre * call assert_equal([1, 4], [line("'["), line("']")])
1035  write
1036  au! BufWritePre
1037
1038  if executable('cat')
1039    write XtestFilter
1040    write >> XtestFilter
1041
1042    call SetChangeMarks(2, 3)
1043    " Marks are set to the entire range of the write
1044    au FilterWritePre * call assert_equal([1, 4], [line("'["), line("']")])
1045    " '[ is adjusted to just before the line that will receive the filtered
1046    " data
1047    au FilterReadPre * call assert_equal([4, 4], [line("'["), line("']")])
1048    " The filtered data is read into the buffer, and the source lines are
1049    " still present, so the range is after the source lines
1050    au FilterReadPost * call assert_equal([5, 12], [line("'["), line("']")])
1051    %!cat XtestFilter
1052    " After the filtered data is read, the original lines are deleted
1053    call assert_equal([1, 8], [line("'["), line("']")])
1054    au! FilterWritePre,FilterReadPre,FilterReadPost
1055    undo
1056
1057    call SetChangeMarks(1, 4)
1058    au FilterWritePre * call assert_equal([2, 3], [line("'["), line("']")])
1059    au FilterReadPre * call assert_equal([3, 3], [line("'["), line("']")])
1060    au FilterReadPost * call assert_equal([4, 11], [line("'["), line("']")])
1061    2,3!cat XtestFilter
1062    call assert_equal([2, 9], [line("'["), line("']")])
1063    au! FilterWritePre,FilterReadPre,FilterReadPost
1064    undo
1065
1066    call delete('XtestFilter')
1067  endif
1068
1069  call SetChangeMarks(1, 4)
1070  au FileWritePre * call assert_equal([2, 3], [line("'["), line("']")])
1071  2,3write Xtest2
1072  au! FileWritePre
1073
1074  call SetChangeMarks(2, 3)
1075  au FileAppendPre * call assert_equal([1, 4], [line("'["), line("']")])
1076  write >> Xtest2
1077  au! FileAppendPre
1078
1079  call SetChangeMarks(1, 4)
1080  au FileAppendPre * call assert_equal([2, 3], [line("'["), line("']")])
1081  2,3write >> Xtest2
1082  au! FileAppendPre
1083
1084  call SetChangeMarks(1, 1)
1085  au FileReadPre * call assert_equal([3, 1], [line("'["), line("']")])
1086  au FileReadPost * call assert_equal([4, 11], [line("'["), line("']")])
1087  3read Xtest2
1088  au! FileReadPre,FileReadPost
1089  undo
1090
1091  call SetChangeMarks(4, 4)
1092  " When the line is 0, it's adjusted to 1
1093  au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")])
1094  au FileReadPost * call assert_equal([1, 8], [line("'["), line("']")])
1095  0read Xtest2
1096  au! FileReadPre,FileReadPost
1097  undo
1098
1099  call SetChangeMarks(4, 4)
1100  " When the line is 0, it's adjusted to 1
1101  au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")])
1102  au FileReadPost * call assert_equal([2, 9], [line("'["), line("']")])
1103  1read Xtest2
1104  au! FileReadPre,FileReadPost
1105  undo
1106
1107  bwipe!
1108  call delete('Xtest')
1109  call delete('Xtest2')
1110endfunc
1111
1112func Test_Filter_noshelltemp()
1113  if !executable('cat')
1114    return
1115  endif
1116
1117  enew!
1118  call setline(1, ['a', 'b', 'c', 'd'])
1119
1120  let shelltemp = &shelltemp
1121  set shelltemp
1122
1123  let g:filter_au = 0
1124  au FilterWritePre * let g:filter_au += 1
1125  au FilterReadPre * let g:filter_au += 1
1126  au FilterReadPost * let g:filter_au += 1
1127  %!cat
1128  call assert_equal(3, g:filter_au)
1129
1130  if has('filterpipe')
1131    set noshelltemp
1132
1133    let g:filter_au = 0
1134    au FilterWritePre * let g:filter_au += 1
1135    au FilterReadPre * let g:filter_au += 1
1136    au FilterReadPost * let g:filter_au += 1
1137    %!cat
1138    call assert_equal(0, g:filter_au)
1139  endif
1140
1141  au! FilterWritePre,FilterReadPre,FilterReadPost
1142  let &shelltemp = shelltemp
1143  bwipe!
1144endfunc
1145
1146func Test_TextYankPost()
1147  enew!
1148  call setline(1, ['foo'])
1149
1150  let g:event = []
1151  au TextYankPost * let g:event = copy(v:event)
1152
1153  call assert_equal({}, v:event)
1154  call assert_fails('let v:event = {}', 'E46:')
1155  call assert_fails('let v:event.mykey = 0', 'E742:')
1156
1157  norm "ayiw
1158  call assert_equal(
1159    \{'regcontents': ['foo'], 'regname': 'a', 'operator': 'y', 'regtype': 'v'},
1160    \g:event)
1161  norm y_
1162  call assert_equal(
1163    \{'regcontents': ['foo'], 'regname': '',  'operator': 'y', 'regtype': 'V'},
1164    \g:event)
1165  call feedkeys("\<C-V>y", 'x')
1166  call assert_equal(
1167    \{'regcontents': ['f'], 'regname': '',  'operator': 'y', 'regtype': "\x161"},
1168    \g:event)
1169  norm "xciwbar
1170  call assert_equal(
1171    \{'regcontents': ['foo'], 'regname': 'x', 'operator': 'c', 'regtype': 'v'},
1172    \g:event)
1173  norm "bdiw
1174  call assert_equal(
1175    \{'regcontents': ['bar'], 'regname': 'b', 'operator': 'd', 'regtype': 'v'},
1176    \g:event)
1177
1178  call assert_equal({}, v:event)
1179
1180  au! TextYankPost
1181  unlet g:event
1182  bwipe!
1183endfunc
1184
1185func Test_nocatch_wipe_all_buffers()
1186  " Real nasty autocommand: wipe all buffers on any event.
1187  au * * bwipe *
1188  " Get E93 first?
1189  " call assert_fails('next x', 'E93:')
1190  call assert_fails('next x', 'E517:')
1191  bwipe
1192  au!
1193endfunc
1194
1195func Test_nocatch_wipe_dummy_buffer()
1196  " Nasty autocommand: wipe buffer on any event.
1197  au * x bwipe
1198  call assert_fails('lv½ /x', 'E480')
1199  au!
1200endfunc
1201
1202function s:Before_test_dirchanged()
1203  augroup test_dirchanged
1204    autocmd!
1205  augroup END
1206  let s:li = []
1207  let s:dir_this = getcwd()
1208  let s:dir_other = s:dir_this . '/foo'
1209  call mkdir(s:dir_other)
1210endfunc
1211
1212function s:After_test_dirchanged()
1213  exe 'cd' s:dir_this
1214  call delete(s:dir_other, 'd')
1215  augroup test_dirchanged
1216    autocmd!
1217  augroup END
1218endfunc
1219
1220function Test_dirchanged_global()
1221  call s:Before_test_dirchanged()
1222  autocmd test_dirchanged DirChanged global call add(s:li, "cd:")
1223  autocmd test_dirchanged DirChanged global call add(s:li, expand("<afile>"))
1224  exe 'cd' s:dir_other
1225  call assert_equal(["cd:", s:dir_other], s:li)
1226  exe 'lcd' s:dir_other
1227  call assert_equal(["cd:", s:dir_other], s:li)
1228  call s:After_test_dirchanged()
1229endfunc
1230
1231function Test_dirchanged_local()
1232  call s:Before_test_dirchanged()
1233  autocmd test_dirchanged DirChanged window call add(s:li, "lcd:")
1234  autocmd test_dirchanged DirChanged window call add(s:li, expand("<afile>"))
1235  exe 'cd' s:dir_other
1236  call assert_equal([], s:li)
1237  exe 'lcd' s:dir_other
1238  call assert_equal(["lcd:", s:dir_other], s:li)
1239  call s:After_test_dirchanged()
1240endfunc
1241
1242function Test_dirchanged_auto()
1243  if !exists('+autochdir')
1244    return
1245  endif
1246  call s:Before_test_dirchanged()
1247  call test_autochdir()
1248  autocmd test_dirchanged DirChanged auto call add(s:li, "auto:")
1249  autocmd test_dirchanged DirChanged auto call add(s:li, expand("<afile>"))
1250  set acd
1251  exe 'cd ..'
1252  call assert_equal([], s:li)
1253  exe 'edit ' . s:dir_other . '/Xfile'
1254  call assert_equal(s:dir_other, getcwd())
1255  call assert_equal(["auto:", s:dir_other], s:li)
1256  set noacd
1257  bwipe!
1258  call s:After_test_dirchanged()
1259endfunc
1260
1261" Test TextChangedI and TextChangedP
1262func Test_ChangedP()
1263  new
1264  call setline(1, ['foo', 'bar', 'foobar'])
1265  call test_override("char_avail", 1)
1266  set complete=. completeopt=menuone
1267
1268  func! TextChangedAutocmd(char)
1269    let g:autocmd .= a:char
1270  endfunc
1271
1272  au! TextChanged <buffer> :call TextChangedAutocmd('N')
1273  au! TextChangedI <buffer> :call TextChangedAutocmd('I')
1274  au! TextChangedP <buffer> :call TextChangedAutocmd('P')
1275
1276  call cursor(3, 1)
1277  let g:autocmd = ''
1278  call feedkeys("o\<esc>", 'tnix')
1279  call assert_equal('I', g:autocmd)
1280
1281  let g:autocmd = ''
1282  call feedkeys("Sf", 'tnix')
1283  call assert_equal('II', g:autocmd)
1284
1285  let g:autocmd = ''
1286  call feedkeys("Sf\<C-N>", 'tnix')
1287  call assert_equal('IIP', g:autocmd)
1288
1289  let g:autocmd = ''
1290  call feedkeys("Sf\<C-N>\<C-N>", 'tnix')
1291  call assert_equal('IIPP', g:autocmd)
1292
1293  let g:autocmd = ''
1294  call feedkeys("Sf\<C-N>\<C-N>\<C-N>", 'tnix')
1295  call assert_equal('IIPPP', g:autocmd)
1296
1297  let g:autocmd = ''
1298  call feedkeys("Sf\<C-N>\<C-N>\<C-N>\<C-N>", 'tnix')
1299  call assert_equal('IIPPPP', g:autocmd)
1300
1301  call assert_equal(['foo', 'bar', 'foobar', 'foo'], getline(1, '$'))
1302  " TODO: how should it handle completeopt=noinsert,noselect?
1303
1304  " CleanUp
1305  call test_override("char_avail", 0)
1306  au! TextChanged
1307  au! TextChangedI
1308  au! TextChangedP
1309  delfu TextChangedAutocmd
1310  unlet! g:autocmd
1311  set complete&vim completeopt&vim
1312
1313  bw!
1314endfunc
1315
1316let g:setline_handled = v:false
1317func! SetLineOne()
1318  if !g:setline_handled
1319    call setline(1, "(x)")
1320    let g:setline_handled = v:true
1321  endif
1322endfunc
1323
1324func Test_TextChangedI_with_setline()
1325  new
1326  call test_override('char_avail', 1)
1327  autocmd TextChangedI <buffer> call SetLineOne()
1328  call feedkeys("i(\<CR>\<Esc>", 'tx')
1329  call assert_equal('(', getline(1))
1330  call assert_equal('x)', getline(2))
1331  undo
1332  call assert_equal('', getline(1))
1333  call assert_equal('', getline(2))
1334
1335  call test_override('starting', 0)
1336  bwipe!
1337endfunc
1338
1339func Test_Changed_FirstTime()
1340  if !has('terminal') || has('gui_running')
1341    return
1342  endif
1343  " Prepare file for TextChanged event.
1344  call writefile([''], 'Xchanged.txt')
1345  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3})
1346  call assert_equal('running', term_getstatus(buf))
1347  " Wait for the ruler (in the status line) to be shown.
1348  call WaitForAssert({-> assert_match('\<All$', term_getline(buf, 3))})
1349  " It's only adding autocmd, so that no event occurs.
1350  call term_sendkeys(buf, ":au! TextChanged <buffer> call writefile(['No'], 'Xchanged.txt')\<cr>")
1351  call term_sendkeys(buf, "\<C-\\>\<C-N>:qa!\<cr>")
1352  call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))})
1353  call assert_equal([''], readfile('Xchanged.txt'))
1354
1355  " clean up
1356  call delete('Xchanged.txt')
1357  bwipe!
1358endfunc
1359