1" Test for the quickfix commands.
2
3source check.vim
4CheckFeature quickfix
5
6source screendump.vim
7
8set encoding=utf-8
9
10func s:setup_commands(cchar)
11  if a:cchar == 'c'
12    command! -nargs=* -bang Xlist <mods>clist<bang> <args>
13    command! -nargs=* Xgetexpr <mods>cgetexpr <args>
14    command! -nargs=* Xaddexpr <mods>caddexpr <args>
15    command! -nargs=* -count Xolder <mods><count>colder <args>
16    command! -nargs=* Xnewer <mods>cnewer <args>
17    command! -nargs=* Xopen <mods> copen <args>
18    command! -nargs=* Xwindow <mods>cwindow <args>
19    command! -nargs=* Xbottom <mods>cbottom <args>
20    command! -nargs=* Xclose <mods>cclose <args>
21    command! -nargs=* -bang Xfile <mods>cfile<bang> <args>
22    command! -nargs=* Xgetfile <mods>cgetfile <args>
23    command! -nargs=* Xaddfile <mods>caddfile <args>
24    command! -nargs=* -bang Xbuffer <mods>cbuffer<bang> <args>
25    command! -nargs=* Xgetbuffer <mods>cgetbuffer <args>
26    command! -nargs=* Xaddbuffer <mods>caddbuffer <args>
27    command! -nargs=* Xrewind <mods>crewind <args>
28    command! -count -nargs=* -bang Xnext <mods><count>cnext<bang> <args>
29    command! -count -nargs=* -bang Xprev <mods><count>cprev<bang> <args>
30    command! -nargs=* -bang Xfirst <mods>cfirst<bang> <args>
31    command! -nargs=* -bang Xlast <mods>clast<bang> <args>
32    command! -count -nargs=* -bang Xnfile <mods><count>cnfile<bang> <args>
33    command! -nargs=* -bang Xpfile <mods>cpfile<bang> <args>
34    command! -nargs=* Xexpr <mods>cexpr <args>
35    command! -count -nargs=* Xvimgrep <mods> <count>vimgrep <args>
36    command! -nargs=* Xvimgrepadd <mods> vimgrepadd <args>
37    command! -nargs=* Xgrep <mods> grep <args>
38    command! -nargs=* Xgrepadd <mods> grepadd <args>
39    command! -nargs=* Xhelpgrep helpgrep <args>
40    command! -nargs=0 -count Xcc <count>cc
41    command! -count=1 -nargs=0 Xbelow <mods><count>cbelow
42    command! -count=1 -nargs=0 Xabove <mods><count>cabove
43    command! -count=1 -nargs=0 Xbefore <mods><count>cbefore
44    command! -count=1 -nargs=0 Xafter <mods><count>cafter
45    let g:Xgetlist = function('getqflist')
46    let g:Xsetlist = function('setqflist')
47    call setqflist([], 'f')
48  else
49    command! -nargs=* -bang Xlist <mods>llist<bang> <args>
50    command! -nargs=* Xgetexpr <mods>lgetexpr <args>
51    command! -nargs=* Xaddexpr <mods>laddexpr <args>
52    command! -nargs=* -count Xolder <mods><count>lolder <args>
53    command! -nargs=* Xnewer <mods>lnewer <args>
54    command! -nargs=* Xopen <mods> lopen <args>
55    command! -nargs=* Xwindow <mods>lwindow <args>
56    command! -nargs=* Xbottom <mods>lbottom <args>
57    command! -nargs=* Xclose <mods>lclose <args>
58    command! -nargs=* -bang Xfile <mods>lfile<bang> <args>
59    command! -nargs=* Xgetfile <mods>lgetfile <args>
60    command! -nargs=* Xaddfile <mods>laddfile <args>
61    command! -nargs=* -bang Xbuffer <mods>lbuffer<bang> <args>
62    command! -nargs=* Xgetbuffer <mods>lgetbuffer <args>
63    command! -nargs=* Xaddbuffer <mods>laddbuffer <args>
64    command! -nargs=* Xrewind <mods>lrewind <args>
65    command! -count -nargs=* -bang Xnext <mods><count>lnext<bang> <args>
66    command! -count -nargs=* -bang Xprev <mods><count>lprev<bang> <args>
67    command! -nargs=* -bang Xfirst <mods>lfirst<bang> <args>
68    command! -nargs=* -bang Xlast <mods>llast<bang> <args>
69    command! -count -nargs=* -bang Xnfile <mods><count>lnfile<bang> <args>
70    command! -nargs=* -bang Xpfile <mods>lpfile<bang> <args>
71    command! -nargs=* Xexpr <mods>lexpr <args>
72    command! -count -nargs=* Xvimgrep <mods> <count>lvimgrep <args>
73    command! -nargs=* Xvimgrepadd <mods> lvimgrepadd <args>
74    command! -nargs=* Xgrep <mods> lgrep <args>
75    command! -nargs=* Xgrepadd <mods> lgrepadd <args>
76    command! -nargs=* Xhelpgrep lhelpgrep <args>
77    command! -nargs=0 -count Xcc <count>ll
78    command! -count=1 -nargs=0 Xbelow <mods><count>lbelow
79    command! -count=1 -nargs=0 Xabove <mods><count>labove
80    command! -count=1 -nargs=0 Xbefore <mods><count>lbefore
81    command! -count=1 -nargs=0 Xafter <mods><count>lafter
82    let g:Xgetlist = function('getloclist', [0])
83    let g:Xsetlist = function('setloclist', [0])
84    call setloclist(0, [], 'f')
85  endif
86endfunc
87
88" Tests for the :clist and :llist commands
89func XlistTests(cchar)
90  call s:setup_commands(a:cchar)
91
92  if a:cchar == 'l'
93      call assert_fails('llist', 'E776:')
94  endif
95  " With an empty list, command should return error
96  Xgetexpr []
97  silent! Xlist
98  call assert_true(v:errmsg ==# 'E42: No Errors')
99
100  " Populate the list and then try
101  Xgetexpr ['non-error 1', 'Xtestfile1:1:3:Line1',
102		  \ 'non-error 2', 'Xtestfile2:2:2:Line2',
103		  \ 'non-error| 3', 'Xtestfile3:3:1:Line3']
104
105  " List only valid entries
106  let l = split(execute('Xlist', ''), "\n")
107  call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
108		   \ ' 4 Xtestfile2:2 col 2: Line2',
109		   \ ' 6 Xtestfile3:3 col 1: Line3'], l)
110
111  " List all the entries
112  let l = split(execute('Xlist!', ''), "\n")
113  call assert_equal([' 1: non-error 1', ' 2 Xtestfile1:1 col 3: Line1',
114		   \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2',
115		   \ ' 5: non-error| 3', ' 6 Xtestfile3:3 col 1: Line3'], l)
116
117  " List a range of errors
118  let l = split(execute('Xlist 3,6', ''), "\n")
119  call assert_equal([' 4 Xtestfile2:2 col 2: Line2',
120		   \ ' 6 Xtestfile3:3 col 1: Line3'], l)
121
122  let l = split(execute('Xlist! 3,4', ''), "\n")
123  call assert_equal([' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
124
125  let l = split(execute('Xlist -6,-4', ''), "\n")
126  call assert_equal([' 2 Xtestfile1:1 col 3: Line1'], l)
127
128  let l = split(execute('Xlist! -5,-3', ''), "\n")
129  call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
130		   \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
131
132  " Test for '+'
133  let l = split(execute('Xlist! +2', ''), "\n")
134  call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
135		   \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
136
137  " Ranged entries
138  call g:Xsetlist([{'lnum':10,'text':'Line1'},
139	      \ {'lnum':20,'col':10,'text':'Line2'},
140	      \ {'lnum':30,'col':15,'end_col':20,'text':'Line3'},
141	      \ {'lnum':40,'end_lnum':45,'text':'Line4'},
142	      \ {'lnum':50,'end_lnum':55,'col':15,'text':'Line5'},
143	      \ {'lnum':60,'end_lnum':65,'col':25,'end_col':35,'text':'Line6'}])
144  let l = split(execute('Xlist', ""), "\n")
145  call assert_equal([' 1:10: Line1',
146	      \ ' 2:20 col 10: Line2',
147	      \ ' 3:30 col 15-20: Line3',
148	      \ ' 4:40-45: Line4',
149	      \ ' 5:50-55 col 15: Line5',
150	      \ ' 6:60-65 col 25-35: Line6'], l)
151
152  " Different types of errors
153  call g:Xsetlist([{'lnum':10,'col':5,'type':'W', 'text':'Warning','nr':11},
154	      \ {'lnum':20,'col':10,'type':'e','text':'Error','nr':22},
155	      \ {'lnum':30,'col':15,'type':'i','text':'Info','nr':33},
156	      \ {'lnum':40,'col':20,'type':'x', 'text':'Other','nr':44},
157	      \ {'lnum':50,'col':25,'type':"\<C-A>",'text':'one','nr':55}])
158  let l = split(execute('Xlist', ""), "\n")
159  call assert_equal([' 1:10 col 5 warning  11: Warning',
160	      \ ' 2:20 col 10 error  22: Error',
161	      \ ' 3:30 col 15 info  33: Info',
162	      \ ' 4:40 col 20 x  44: Other',
163	      \ ' 5:50 col 25  55: one'], l)
164
165  " Test for module names, one needs to explicitly set `'valid':v:true` so
166  call g:Xsetlist([
167        \ {'lnum':10,'col':5,'type':'W','module':'Data.Text','text':'ModuleWarning','nr':11,'valid':v:true},
168        \ {'lnum':20,'col':10,'type':'W','module':'Data.Text','filename':'Data/Text.hs','text':'ModuleWarning','nr':22,'valid':v:true},
169        \ {'lnum':30,'col':15,'type':'W','filename':'Data/Text.hs','text':'FileWarning','nr':33,'valid':v:true}])
170  let l = split(execute('Xlist', ""), "\n")
171  call assert_equal([' 1 Data.Text:10 col 5 warning  11: ModuleWarning',
172        \ ' 2 Data.Text:20 col 10 warning  22: ModuleWarning',
173        \ ' 3 Data/Text.hs:30 col 15 warning  33: FileWarning'], l)
174
175  " For help entries in the quickfix list, only the filename without directory
176  " should be displayed
177  Xhelpgrep setqflist()
178  let l = split(execute('Xlist 1', ''), "\n")
179  call assert_match('^ 1 [^\\/]\{-}:', l[0])
180
181  " Error cases
182  call assert_fails('Xlist abc', 'E488:')
183endfunc
184
185func Test_clist()
186  call XlistTests('c')
187  call XlistTests('l')
188endfunc
189
190" Tests for the :colder, :cnewer, :lolder and :lnewer commands
191" Note that this test assumes that a quickfix/location list is
192" already set by the caller.
193func XageTests(cchar)
194  call s:setup_commands(a:cchar)
195
196  if a:cchar == 'l'
197    " No location list for the current window
198    call assert_fails('lolder', 'E776:')
199    call assert_fails('lnewer', 'E776:')
200  endif
201
202  let list = [{'bufnr': bufnr('%'), 'lnum': 1}]
203  call g:Xsetlist(list)
204
205  " Jumping to a non existent list should return error
206  silent! Xolder 99
207  call assert_true(v:errmsg ==# 'E380: At bottom of quickfix stack')
208
209  silent! Xnewer 99
210  call assert_true(v:errmsg ==# 'E381: At top of quickfix stack')
211
212  " Add three quickfix/location lists
213  Xgetexpr ['Xtestfile1:1:3:Line1']
214  Xgetexpr ['Xtestfile2:2:2:Line2']
215  Xgetexpr ['Xtestfile3:3:1:Line3']
216
217  " Go back two lists
218  Xolder
219  let l = g:Xgetlist()
220  call assert_equal('Line2', l[0].text)
221
222  " Go forward two lists
223  Xnewer
224  let l = g:Xgetlist()
225  call assert_equal('Line3', l[0].text)
226
227  " Test for the optional count argument
228  Xolder 2
229  let l = g:Xgetlist()
230  call assert_equal('Line1', l[0].text)
231
232  Xnewer 2
233  let l = g:Xgetlist()
234  call assert_equal('Line3', l[0].text)
235endfunc
236
237func Test_cage()
238  call XageTests('c')
239  call XageTests('l')
240endfunc
241
242" Tests for the :cwindow, :lwindow :cclose, :lclose, :copen and :lopen
243" commands
244func XwindowTests(cchar)
245  call s:setup_commands(a:cchar)
246
247  " Opening the location list window without any errors should fail
248  if a:cchar == 'l'
249      call assert_fails('lopen', 'E776:')
250  endif
251
252  " Create a list with no valid entries
253  Xgetexpr ['non-error 1', 'non-error 2', 'non-error 3']
254
255  " Quickfix/Location window should not open with no valid errors
256  Xwindow
257  call assert_true(winnr('$') == 1)
258
259  " Create a list with valid entries
260  Xgetexpr ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2',
261		  \ 'Xtestfile3:3:1:Line3']
262
263  " Open the window
264  Xwindow
265  call assert_true(winnr('$') == 2 && winnr() == 2 &&
266	\ getline('.') ==# 'Xtestfile1|1 col 3| Line1')
267  redraw!
268
269  " Close the window
270  Xclose
271  call assert_true(winnr('$') == 1)
272
273  " Create a list with no valid entries
274  Xgetexpr ['non-error 1', 'non-error 2', 'non-error 3']
275
276  " Open the window
277  Xopen 5
278  call assert_true(winnr('$') == 2 && getline('.') ==# '|| non-error 1'
279		      \  && winheight(0) == 5)
280
281  " Opening the window again, should move the cursor to that window
282  wincmd t
283  Xopen 7
284  call assert_true(winnr('$') == 2 && winnr() == 2 &&
285	\ winheight(0) == 7 &&
286	\ getline('.') ==# '|| non-error 1')
287
288  " :cnext in quickfix window should move to the next entry
289  Xnext
290  call assert_equal(2, g:Xgetlist({'idx' : 0}).idx)
291
292  " Calling cwindow should close the quickfix window with no valid errors
293  Xwindow
294  call assert_true(winnr('$') == 1)
295
296  " Specifying the width should adjust the width for a vertically split
297  " quickfix window.
298  vert Xopen
299  call assert_equal(10, winwidth(0))
300  vert Xopen 12
301  call assert_equal(12, winwidth(0))
302  Xclose
303
304  if a:cchar == 'c'
305      " Opening the quickfix window in multiple tab pages should reuse the
306      " quickfix buffer
307      Xgetexpr ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2',
308		  \ 'Xtestfile3:3:1:Line3']
309      Xopen
310      let qfbufnum = bufnr('%')
311      tabnew
312      Xopen
313      call assert_equal(qfbufnum, bufnr('%'))
314      new | only | tabonly
315  endif
316endfunc
317
318func Test_cwindow()
319  call XwindowTests('c')
320  call XwindowTests('l')
321endfunc
322
323func Test_copenHeight()
324  copen
325  wincmd H
326  let height = winheight(0)
327  copen 10
328  call assert_equal(height, winheight(0))
329  quit
330endfunc
331
332func Test_copenHeight_tabline()
333  set tabline=foo showtabline=2
334  copen
335  wincmd H
336  let height = winheight(0)
337  copen 10
338  call assert_equal(height, winheight(0))
339  quit
340  set tabline& showtabline&
341endfunc
342
343
344" Tests for the :cfile, :lfile, :caddfile, :laddfile, :cgetfile and :lgetfile
345" commands.
346func XfileTests(cchar)
347  call s:setup_commands(a:cchar)
348
349  call writefile(['Xtestfile1:700:10:Line 700',
350	\ 'Xtestfile2:800:15:Line 800'], 'Xqftestfile1')
351
352  enew!
353  Xfile Xqftestfile1
354  let l = g:Xgetlist()
355  call assert_true(len(l) == 2 &&
356	\ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' &&
357	\ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800')
358
359  " Test with a non existent file
360  call assert_fails('Xfile non_existent_file', 'E40')
361
362  " Run cfile/lfile from a modified buffer
363  enew!
364  silent! put ='Quickfix'
365  silent! Xfile Xqftestfile1
366  call assert_true(v:errmsg ==# 'E37: No write since last change (add ! to override)')
367
368  call writefile(['Xtestfile3:900:30:Line 900'], 'Xqftestfile1')
369  Xaddfile Xqftestfile1
370  let l = g:Xgetlist()
371  call assert_true(len(l) == 3 &&
372	\ l[2].lnum == 900 && l[2].col == 30 && l[2].text ==# 'Line 900')
373
374  call writefile(['Xtestfile1:222:77:Line 222',
375	\ 'Xtestfile2:333:88:Line 333'], 'Xqftestfile1')
376
377  enew!
378  Xgetfile Xqftestfile1
379  let l = g:Xgetlist()
380  call assert_true(len(l) == 2 &&
381	\ l[0].lnum == 222 && l[0].col == 77 && l[0].text ==# 'Line 222' &&
382	\ l[1].lnum == 333 && l[1].col == 88 && l[1].text ==# 'Line 333')
383
384  " Test for a file with a long line and without a newline at the end
385  let text = repeat('x', 1024)
386  let t = 'a.txt:18:' . text
387  call writefile([t], 'Xqftestfile1', 'b')
388  silent! Xfile Xqftestfile1
389  call assert_equal(text, g:Xgetlist()[0].text)
390
391  call delete('Xqftestfile1')
392endfunc
393
394func Test_cfile()
395  call XfileTests('c')
396  call XfileTests('l')
397endfunc
398
399" Tests for the :cbuffer, :lbuffer, :caddbuffer, :laddbuffer, :cgetbuffer and
400" :lgetbuffer commands.
401func XbufferTests(cchar)
402  call s:setup_commands(a:cchar)
403
404  enew!
405  silent! call setline(1, ['Xtestfile7:700:10:Line 700',
406	\ 'Xtestfile8:800:15:Line 800'])
407  Xbuffer!
408  let l = g:Xgetlist()
409  call assert_true(len(l) == 2 &&
410	\ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' &&
411	\ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800')
412
413  enew!
414  silent! call setline(1, ['Xtestfile9:900:55:Line 900',
415	\ 'Xtestfile10:950:66:Line 950'])
416  Xgetbuffer
417  let l = g:Xgetlist()
418  call assert_true(len(l) == 2 &&
419	\ l[0].lnum == 900 && l[0].col == 55 && l[0].text ==# 'Line 900' &&
420	\ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950')
421
422  enew!
423  silent! call setline(1, ['Xtestfile11:700:20:Line 700',
424	\ 'Xtestfile12:750:25:Line 750'])
425  Xaddbuffer
426  let l = g:Xgetlist()
427  call assert_true(len(l) == 4 &&
428	\ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950' &&
429	\ l[2].lnum == 700 && l[2].col == 20 && l[2].text ==# 'Line 700' &&
430	\ l[3].lnum == 750 && l[3].col == 25 && l[3].text ==# 'Line 750')
431  enew!
432
433  " Check for invalid buffer
434  call assert_fails('Xbuffer 199', 'E474:')
435
436  " Check for unloaded buffer
437  edit Xtestfile1
438  let bnr = bufnr('%')
439  enew!
440  call assert_fails('Xbuffer ' . bnr, 'E681:')
441
442  " Check for invalid range
443  " Using Xbuffer will not run the range check in the cbuffer/lbuffer
444  " commands. So directly call the commands.
445  if (a:cchar == 'c')
446      call assert_fails('900,999cbuffer', 'E16:')
447  else
448      call assert_fails('900,999lbuffer', 'E16:')
449  endif
450endfunc
451
452func Test_cbuffer()
453  call XbufferTests('c')
454  call XbufferTests('l')
455endfunc
456
457func XexprTests(cchar)
458  call s:setup_commands(a:cchar)
459
460  call assert_fails('Xexpr 10', 'E777:')
461endfunc
462
463func Test_cexpr()
464  call XexprTests('c')
465  call XexprTests('l')
466endfunc
467
468" Tests for :cnext, :cprev, :cfirst, :clast commands
469func Xtest_browse(cchar)
470  call s:setup_commands(a:cchar)
471
472  call g:Xsetlist([], 'f')
473  " Jumping to first or next location list entry without any error should
474  " result in failure
475  if a:cchar == 'c'
476    let err = 'E42:'
477    let cmd = '$cc'
478  else
479    let err = 'E776:'
480    let cmd = '$ll'
481  endif
482  call assert_fails('Xnext', err)
483  call assert_fails('Xprev', err)
484  call assert_fails('Xnfile', err)
485  call assert_fails('Xpfile', err)
486  call assert_fails(cmd, err)
487
488  Xexpr ''
489  call assert_fails(cmd, 'E42:')
490
491  call s:create_test_file('Xqftestfile1')
492  call s:create_test_file('Xqftestfile2')
493
494  Xgetexpr ['Xqftestfile1:5:Line5',
495		\ 'Xqftestfile1:6:Line6',
496		\ 'Xqftestfile2:10:Line10',
497		\ 'Xqftestfile2:11:Line11',
498		\ 'RegularLine1',
499		\ 'RegularLine2']
500
501  Xfirst
502  call assert_fails('Xprev', 'E553')
503  call assert_fails('Xpfile', 'E553')
504  Xnfile
505  call assert_equal('Xqftestfile2', bufname('%'))
506  call assert_equal(10, line('.'))
507  Xpfile
508  call assert_equal('Xqftestfile1', bufname('%'))
509  call assert_equal(6, line('.'))
510  5Xcc
511  call assert_equal(5, g:Xgetlist({'idx':0}).idx)
512  2Xcc
513  call assert_equal(2, g:Xgetlist({'idx':0}).idx)
514  if a:cchar == 'c'
515    cc
516  else
517    ll
518  endif
519  call assert_equal(2, g:Xgetlist({'idx':0}).idx)
520  10Xcc
521  call assert_equal(6, g:Xgetlist({'idx':0}).idx)
522  Xlast
523  Xprev
524  call assert_equal('Xqftestfile2', bufname('%'))
525  call assert_equal(11, line('.'))
526  call assert_fails('Xnext', 'E553')
527  call assert_fails('Xnfile', 'E553')
528  " To process the range using quickfix list entries, directly use the
529  " quickfix commands (don't use the user defined commands)
530  if a:cchar == 'c'
531    $cc
532  else
533    $ll
534  endif
535  call assert_equal(6, g:Xgetlist({'idx':0}).idx)
536  Xrewind
537  call assert_equal('Xqftestfile1', bufname('%'))
538  call assert_equal(5, line('.'))
539
540  10Xnext
541  call assert_equal('Xqftestfile2', bufname('%'))
542  call assert_equal(11, line('.'))
543  10Xprev
544  call assert_equal('Xqftestfile1', bufname('%'))
545  call assert_equal(5, line('.'))
546
547  " Jumping to an error from the error window using cc command
548  Xgetexpr ['Xqftestfile1:5:Line5',
549		\ 'Xqftestfile1:6:Line6',
550		\ 'Xqftestfile2:10:Line10',
551		\ 'Xqftestfile2:11:Line11']
552  Xopen
553  10Xcc
554  call assert_equal(11, line('.'))
555  call assert_equal('Xqftestfile2', bufname('%'))
556
557  " Jumping to an error from the error window (when only the error window is
558  " present)
559  Xopen | only
560  Xlast 1
561  call assert_equal(5, line('.'))
562  call assert_equal('Xqftestfile1', bufname('%'))
563
564  Xexpr ""
565  call assert_fails('Xnext', 'E42:')
566
567  call delete('Xqftestfile1')
568  call delete('Xqftestfile2')
569
570  " Should be able to use next/prev with invalid entries
571  Xexpr ""
572  call assert_equal(0, g:Xgetlist({'idx' : 0}).idx)
573  call assert_equal(0, g:Xgetlist({'size' : 0}).size)
574  Xaddexpr ['foo', 'bar', 'baz', 'quux', 'sh|moo']
575  call assert_equal(5, g:Xgetlist({'size' : 0}).size)
576  Xlast
577  call assert_equal(5, g:Xgetlist({'idx' : 0}).idx)
578  Xfirst
579  call assert_equal(1, g:Xgetlist({'idx' : 0}).idx)
580  2Xnext
581  call assert_equal(3, g:Xgetlist({'idx' : 0}).idx)
582endfunc
583
584func Test_browse()
585  call Xtest_browse('c')
586  call Xtest_browse('l')
587endfunc
588
589func s:test_xhelpgrep(cchar)
590  call s:setup_commands(a:cchar)
591  Xhelpgrep quickfix
592  Xopen
593  if a:cchar == 'c'
594    let title_text = ':helpgrep quickfix'
595  else
596    let title_text = ':lhelpgrep quickfix'
597  endif
598  call assert_true(w:quickfix_title =~ title_text, w:quickfix_title)
599
600  " Jumping to a help topic should open the help window
601  only
602  Xnext
603  call assert_true(&buftype == 'help')
604  call assert_true(winnr('$') == 2)
605  " Jumping to the next match should reuse the help window
606  Xnext
607  call assert_true(&buftype == 'help')
608  call assert_true(winnr() == 1)
609  call assert_true(winnr('$') == 2)
610  " Jumping to the next match from the quickfix window should reuse the help
611  " window
612  Xopen
613  Xnext
614  call assert_true(&buftype == 'help')
615  call assert_true(winnr() == 1)
616  call assert_true(winnr('$') == 2)
617  call assert_match('|\d\+ col \d\+-\d\+|', getbufline(winbufnr(2), 1)[0])
618
619  " This wipes out the buffer, make sure that doesn't cause trouble.
620  Xclose
621
622  " When the current window is vertically split, jumping to a help match
623  " should open the help window at the top.
624  only | enew
625  let w1 = win_getid()
626  vert new
627  let w2 = win_getid()
628  Xnext
629  let w3 = win_getid()
630  call assert_true(&buftype == 'help')
631  call assert_true(winnr() == 1)
632  " See jump_to_help_window() for details
633  let w2_width = winwidth(w2)
634  if w2_width != &columns && w2_width < 80
635    call assert_equal(['col', [['leaf', w3],
636          \ ['row', [['leaf', w2], ['leaf', w1]]]]], winlayout())
637  else
638    call assert_equal(['row', [['col', [['leaf', w3], ['leaf', w2]]],
639          \ ['leaf', w1]]] , winlayout())
640  endif
641
642  new | only
643  set buftype=help
644  set modified
645  call assert_fails('Xnext', 'E37:')
646  set nomodified
647  new | only
648
649  if a:cchar == 'l'
650      " When a help window is present, running :lhelpgrep should reuse the
651      " help window and not the current window
652      new | only
653      call g:Xsetlist([], 'f')
654      help index.txt
655      wincmd w
656      lhelpgrep quickfix
657      call assert_equal(1, winnr())
658      call assert_notequal([], getloclist(1))
659      call assert_equal([], getloclist(2))
660  endif
661
662  new | only
663
664  " Search for non existing help string
665  call assert_fails('Xhelpgrep a1b2c3', 'E480:')
666  " Invalid regular expression
667  call assert_fails('Xhelpgrep \@<!', 'E480:')
668endfunc
669
670func Test_helpgrep()
671  call s:test_xhelpgrep('c')
672  helpclose
673  call s:test_xhelpgrep('l')
674endfunc
675
676func Test_errortitle()
677  augroup QfBufWinEnter
678    au!
679    au BufWinEnter * :let g:a=get(w:, 'quickfix_title', 'NONE')
680  augroup END
681  copen
682  let a=[{'lnum': 308, 'bufnr': bufnr(''), 'col': 58, 'valid': 1, 'vcol': 0, 'nr': 0, 'type': '', 'pattern': '', 'text': '    au BufWinEnter * :let g:a=get(w:, ''quickfix_title'', ''NONE'')'}]
683  call setqflist(a)
684  call assert_equal(':setqflist()', g:a)
685  augroup QfBufWinEnter
686    au!
687  augroup END
688  augroup! QfBufWinEnter
689endfunc
690
691func Test_vimgreptitle()
692  augroup QfBufWinEnter
693    au!
694    au BufWinEnter * :let g:a=get(w:, 'quickfix_title', 'NONE')
695  augroup END
696  try
697    vimgrep /pattern/j file
698  catch /E480/
699  endtry
700  copen
701  call assert_equal(':    vimgrep /pattern/j file', g:a)
702  augroup QfBufWinEnter
703    au!
704  augroup END
705  augroup! QfBufWinEnter
706endfunc
707
708func Test_bufwinenter_once()
709  augroup QfBufWinEnter
710    au!
711    au BufWinEnter * let g:got_afile ..= 'got ' .. expand('<afile>')
712  augroup END
713  let g:got_afile = ''
714  copen
715  call assert_equal('got quickfix', g:got_afile)
716
717  cclose
718  unlet g:got_afile
719  augroup QfBufWinEnter
720    au!
721  augroup END
722  augroup! QfBufWinEnter
723endfunc
724
725func XqfTitleTests(cchar)
726  call s:setup_commands(a:cchar)
727
728  Xgetexpr ['file:1:1:message']
729  let l = g:Xgetlist()
730  if a:cchar == 'c'
731    call setqflist(l, 'r')
732  else
733    call setloclist(0, l, 'r')
734  endif
735
736  Xopen
737  if a:cchar == 'c'
738    let title = ':setqflist()'
739  else
740    let title = ':setloclist()'
741  endif
742  call assert_equal(title, w:quickfix_title)
743  Xclose
744endfunc
745
746" Tests for quickfix window's title
747func Test_qf_title()
748  call XqfTitleTests('c')
749  call XqfTitleTests('l')
750endfunc
751
752" Tests for 'errorformat'
753func Test_efm()
754  let save_efm = &efm
755  set efm=%EEEE%m,%WWWW%m,%+CCCC%.%#,%-GGGG%.%#
756  cgetexpr ['WWWW', 'EEEE', 'CCCC']
757  let l = strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]')))
758  call assert_equal("[['W', 1], ['E^@CCCC', 1]]", l)
759  cgetexpr ['WWWW', 'GGGG', 'EEEE', 'CCCC']
760  let l = strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]')))
761  call assert_equal("[['W', 1], ['E^@CCCC', 1]]", l)
762  cgetexpr ['WWWW', 'GGGG', 'ZZZZ', 'EEEE', 'CCCC', 'YYYY']
763  let l = strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]')))
764  call assert_equal("[['W', 1], ['ZZZZ', 0], ['E^@CCCC', 1], ['YYYY', 0]]", l)
765  let &efm = save_efm
766endfunc
767
768" This will test for problems in quickfix:
769" A. incorrectly copying location lists which caused the location list to show
770"    a different name than the file that was actually being displayed.
771" B. not reusing the window for which the location list window is opened but
772"    instead creating new windows.
773" C. make sure that the location list window is not reused instead of the
774"    window it belongs to.
775"
776" Set up the test environment:
777func ReadTestProtocol(name)
778  let base = substitute(a:name, '\v^test://(.*)%(\.[^.]+)?', '\1', '')
779  let word = substitute(base, '\v(.*)\..*', '\1', '')
780
781  setl modifiable
782  setl noreadonly
783  setl noswapfile
784  setl bufhidden=delete
785  %del _
786  " For problem 2:
787  " 'buftype' has to be set to reproduce the constant opening of new windows
788  setl buftype=nofile
789
790  call setline(1, word)
791
792  setl nomodified
793  setl nomodifiable
794  setl readonly
795  exe 'doautocmd BufRead ' . substitute(a:name, '\v^test://(.*)', '\1', '')
796endfunc
797
798func Test_locationlist()
799    enew
800
801    augroup testgroup
802      au!
803      autocmd BufReadCmd test://* call ReadTestProtocol(expand("<amatch>"))
804    augroup END
805
806    let words = [ "foo", "bar", "baz", "quux", "shmoo", "spam", "eggs" ]
807
808    let qflist = []
809    for word in words
810      call add(qflist, {'filename': 'test://' . word . '.txt', 'text': 'file ' . word . '.txt', })
811      " NOTE: problem 1:
812      " intentionally not setting 'lnum' so that the quickfix entries are not
813      " valid
814      call setloclist(0, qflist, ' ')
815    endfor
816
817    " Test A
818    lrewind
819    enew
820    lopen
821    4lnext
822    vert split
823    wincmd L
824    lopen
825    wincmd p
826    lnext
827    let fileName = expand("%")
828    wincmd p
829    let locationListFileName = substitute(getline(line('.')), '\([^|]*\)|.*', '\1', '')
830    let fileName = substitute(fileName, '\\', '/', 'g')
831    let locationListFileName = substitute(locationListFileName, '\\', '/', 'g')
832    call assert_equal("test://bar.txt", fileName)
833    call assert_equal("test://bar.txt", locationListFileName)
834
835    wincmd n | only
836
837    " Test B:
838    lrewind
839    lopen
840    2
841    exe "normal \<CR>"
842    wincmd p
843    3
844    exe "normal \<CR>"
845    wincmd p
846    4
847    exe "normal \<CR>"
848    call assert_equal(2, winnr('$'))
849    wincmd n | only
850
851    " Test C:
852    lrewind
853    lopen
854    " Let's move the location list window to the top to check whether it (the
855    " first window found) will be reused when we try to open new windows:
856    wincmd K
857    2
858    exe "normal \<CR>"
859    wincmd p
860    3
861    exe "normal \<CR>"
862    wincmd p
863    4
864    exe "normal \<CR>"
865    1wincmd w
866    call assert_equal('quickfix', &buftype)
867    2wincmd w
868    let bufferName = expand("%")
869    let bufferName = substitute(bufferName, '\\', '/', 'g')
870    call assert_equal('test://quux.txt', bufferName)
871
872    wincmd n | only
873
874    augroup! testgroup
875endfunc
876
877func Test_locationlist_curwin_was_closed()
878    augroup testgroup
879      au!
880      autocmd BufReadCmd test_curwin.txt call R(expand("<amatch>"))
881    augroup END
882
883    func! R(n)
884      quit
885    endfunc
886
887    new
888    let q = []
889    call add(q, {'filename': 'test_curwin.txt' })
890    call setloclist(0, q)
891    call assert_fails('lrewind', 'E924:')
892
893    augroup! testgroup
894endfunc
895
896func Test_locationlist_cross_tab_jump()
897  call writefile(['loclistfoo'], 'loclistfoo')
898  call writefile(['loclistbar'], 'loclistbar')
899  set switchbuf=usetab
900
901  edit loclistfoo
902  tabedit loclistbar
903  silent lgrep loclistfoo loclist*
904  call assert_equal(1, tabpagenr())
905
906  enew | only | tabonly
907  set switchbuf&vim
908  call delete('loclistfoo')
909  call delete('loclistbar')
910endfunc
911
912" More tests for 'errorformat'
913func Test_efm1()
914    if !has('unix')
915	" The 'errorformat' setting is different on non-Unix systems.
916	" This test works only on Unix-like systems.
917	return
918    endif
919
920    let l =<< trim [DATA]
921      "Xtestfile", line 4.12: 1506-045 (S) Undeclared identifier fd_set.
922      "Xtestfile", line 6 col 19; this is an error
923      gcc -c -DHAVE_CONFIsing-prototypes -I/usr/X11R6/include  version.c
924      Xtestfile:9: parse error before `asd'
925      make: *** [vim] Error 1
926      in file "Xtestfile" linenr 10: there is an error
927
928      2 returned
929      "Xtestfile", line 11 col 1; this is an error
930      "Xtestfile", line 12 col 2; this is another error
931      "Xtestfile", line 14:10; this is an error in column 10
932      =Xtestfile=, line 15:10; this is another error, but in vcol 10 this time
933      "Xtestfile", linenr 16: yet another problem
934      Error in "Xtestfile" at line 17:
935      x should be a dot
936      	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 17
937                  ^
938      Error in "Xtestfile" at line 18:
939      x should be a dot
940      	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 18
941      .............^
942      Error in "Xtestfile" at line 19:
943      x should be a dot
944      	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 19
945      --------------^
946      Error in "Xtestfile" at line 20:
947      x should be a dot
948      	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 20
949      	       ^
950
951      Does anyone know what is the problem and how to correction it?
952      "Xtestfile", line 21 col 9: What is the title of the quickfix window?
953      "Xtestfile", line 22 col 9: What is the title of the quickfix window?
954    [DATA]
955
956    call writefile(l, 'Xerrorfile1')
957    call writefile(l[:-2], 'Xerrorfile2')
958
959    let m =<< [DATA]
960	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line  2
961	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line  3
962	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line  4
963	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line  5
964	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line  6
965	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line  7
966	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line  8
967	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line  9
968	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 10
969	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 11
970	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 12
971	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 13
972	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 14
973	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 15
974	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 16
975	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 17
976	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 18
977	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 19
978	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 20
979	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 21
980	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    line 22
981[DATA]
982    call writefile(m, 'Xtestfile')
983
984    let save_efm = &efm
985    set efm+==%f=\\,\ line\ %l%*\\D%v%*[^\ ]\ %m
986    set efm^=%AError\ in\ \"%f\"\ at\ line\ %l:,%Z%p^,%C%m
987
988    exe 'cf Xerrorfile2'
989    clast
990    copen
991    call assert_equal(':cf Xerrorfile2', w:quickfix_title)
992    wincmd p
993
994    exe 'cf Xerrorfile1'
995    call assert_equal([4, 12], [line('.'), col('.')])
996    cn
997    call assert_equal([6, 19], [line('.'), col('.')])
998    cn
999    call assert_equal([9, 2], [line('.'), col('.')])
1000    cn
1001    call assert_equal([10, 2], [line('.'), col('.')])
1002    cn
1003    call assert_equal([11, 1], [line('.'), col('.')])
1004    cn
1005    call assert_equal([12, 2], [line('.'), col('.')])
1006    cn
1007    call assert_equal([14, 10], [line('.'), col('.')])
1008    cn
1009    call assert_equal([15, 3, 10], [line('.'), col('.'), virtcol('.')])
1010    cn
1011    call assert_equal([16, 2], [line('.'), col('.')])
1012    cn
1013    call assert_equal([17, 6], [line('.'), col('.')])
1014    cn
1015    call assert_equal([18, 7], [line('.'), col('.')])
1016    cn
1017    call assert_equal([19, 8], [line('.'), col('.')])
1018    cn
1019    call assert_equal([20, 9], [line('.'), col('.')])
1020    clast
1021    cprev
1022    cprev
1023    wincmd w
1024    call assert_equal(':cf Xerrorfile1', w:quickfix_title)
1025    wincmd p
1026
1027    let &efm = save_efm
1028    call delete('Xerrorfile1')
1029    call delete('Xerrorfile2')
1030    call delete('Xtestfile')
1031endfunc
1032
1033" Test for quickfix directory stack support
1034func s:dir_stack_tests(cchar)
1035  call s:setup_commands(a:cchar)
1036
1037  let save_efm=&efm
1038  set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f'
1039
1040  let lines =<< trim [DATA]
1041  Entering dir 'dir1/a'
1042  habits2.txt:1:Nine Healthy Habits
1043  Entering dir 'b'
1044  habits3.txt:2:0 Hours of television
1045  habits2.txt:7:5 Small meals
1046  Entering dir 'dir1/c'
1047  habits4.txt:3:1 Hour of exercise
1048  Leaving dir 'dir1/c'
1049  Leaving dir 'dir1/a'
1050  habits1.txt:4:2 Liters of water
1051  Entering dir 'dir2'
1052  habits5.txt:5:3 Cups of hot green tea
1053  Leaving dir 'dir2
1054  [DATA]
1055
1056  Xexpr ""
1057  for l in lines
1058      Xaddexpr l
1059  endfor
1060
1061  let qf = g:Xgetlist()
1062
1063  call assert_equal(expand('dir1/a/habits2.txt'), bufname(qf[1].bufnr))
1064  call assert_equal(1, qf[1].lnum)
1065  call assert_equal(expand('dir1/a/b/habits3.txt'), bufname(qf[3].bufnr))
1066  call assert_equal(2, qf[3].lnum)
1067  call assert_equal(expand('dir1/a/habits2.txt'), bufname(qf[4].bufnr))
1068  call assert_equal(7, qf[4].lnum)
1069  call assert_equal(expand('dir1/c/habits4.txt'), bufname(qf[6].bufnr))
1070  call assert_equal(3, qf[6].lnum)
1071  call assert_equal('habits1.txt', bufname(qf[9].bufnr))
1072  call assert_equal(4, qf[9].lnum)
1073  call assert_equal(expand('dir2/habits5.txt'), bufname(qf[11].bufnr))
1074  call assert_equal(5, qf[11].lnum)
1075
1076  let &efm=save_efm
1077endfunc
1078
1079" Tests for %D and %X errorformat options
1080func Test_efm_dirstack()
1081  " Create the directory stack and files
1082  call mkdir('dir1')
1083  call mkdir('dir1/a')
1084  call mkdir('dir1/a/b')
1085  call mkdir('dir1/c')
1086  call mkdir('dir2')
1087
1088  let lines =<< trim [DATA]
1089  Nine Healthy Habits,
1090  0 Hours of television,
1091  1 Hour of exercise,
1092  2 Liters of water,
1093  3 Cups of hot green tea,
1094  4 Short mental breaks,
1095  5 Small meals,
1096  6 AM wake up time,
1097  7 Minutes of laughter,
1098  8 Hours of sleep (at least),
1099  9 PM end of the day and off to bed
1100  [DATA]
1101
1102  call writefile(lines, 'habits1.txt')
1103  call writefile(lines, 'dir1/a/habits2.txt')
1104  call writefile(lines, 'dir1/a/b/habits3.txt')
1105  call writefile(lines, 'dir1/c/habits4.txt')
1106  call writefile(lines, 'dir2/habits5.txt')
1107
1108  call s:dir_stack_tests('c')
1109  call s:dir_stack_tests('l')
1110
1111  call delete('dir1', 'rf')
1112  call delete('dir2', 'rf')
1113  call delete('habits1.txt')
1114endfunc
1115
1116" Test for resync after continuing an ignored message
1117func Xefm_ignore_continuations(cchar)
1118  call s:setup_commands(a:cchar)
1119
1120  let save_efm = &efm
1121
1122  let &efm =
1123	\ '%Eerror %m %l,' .
1124	\ '%-Wignored %m %l,' .
1125	\ '%+Cmore ignored %m %l,' .
1126	\ '%Zignored end'
1127  Xgetexpr ['ignored warning 1', 'more ignored continuation 2', 'ignored end', 'error resync 4']
1128  let l = map(g:Xgetlist(), '[v:val.text, v:val.valid, v:val.lnum, v:val.type]')
1129  call assert_equal([['resync', 1, 4, 'E']], l)
1130
1131  let &efm = save_efm
1132endfunc
1133
1134func Test_efm_ignore_continuations()
1135  call Xefm_ignore_continuations('c')
1136  call Xefm_ignore_continuations('l')
1137endfunc
1138
1139" Tests for invalid error format specifies
1140func Xinvalid_efm_Tests(cchar)
1141  call s:setup_commands(a:cchar)
1142
1143  let save_efm = &efm
1144
1145  set efm=%f:%l:%m,%f:%f:%l:%m
1146  call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E372:')
1147
1148  set efm=%f:%l:%m,%f:%l:%r:%m
1149  call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E373:')
1150
1151  set efm=%f:%l:%m,%O:%f:%l:%m
1152  call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E373:')
1153
1154  set efm=%f:%l:%m,%f:%l:%*[^a-z
1155  call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E374:')
1156
1157  set efm=%f:%l:%m,%f:%l:%*c
1158  call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E375:')
1159
1160  set efm=%f:%l:%m,%L%M%N
1161  call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E376:')
1162
1163  set efm=%f:%l:%m,%f:%l:%m:%R
1164  call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E377:')
1165
1166  " Invalid regular expression
1167  set efm=%\\%%k
1168  call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E867:')
1169
1170  set efm=
1171  call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E378:')
1172
1173  set efm=%DEntering\ dir\ abc,%f:%l:%m
1174  call assert_fails('Xexpr ["Entering dir abc", "abc.txt:1:Hello world"]', 'E379:')
1175
1176  let &efm = save_efm
1177endfunc
1178
1179func Test_invalid_efm()
1180  call Xinvalid_efm_Tests('c')
1181  call Xinvalid_efm_Tests('l')
1182endfunc
1183
1184" TODO:
1185" Add tests for the following formats in 'errorformat'
1186"	%r  %O
1187func Test_efm2()
1188  let save_efm = &efm
1189
1190  " Test for %s format in efm
1191  set efm=%f:%s
1192  cexpr 'Xtestfile:Line search text'
1193  let l = getqflist()
1194  call assert_equal('^\VLine search text\$', l[0].pattern)
1195  call assert_equal(0, l[0].lnum)
1196
1197  let l = split(execute('clist', ''), "\n")
1198  call assert_equal([' 1 Xtestfile:^\VLine search text\$:  '], l)
1199
1200  " Test for a long line
1201  cexpr 'Xtestfile:' . repeat('a', 1026)
1202  let l = getqflist()
1203  call assert_equal('^\V' . repeat('a', 1019) . '\$', l[0].pattern)
1204
1205  " Test for %P, %Q and %t format specifiers
1206  let lines =<< trim [DATA]
1207    [Xtestfile1]
1208    (1,17)  error: ';' missing
1209    (21,2)  warning: variable 'z' not defined
1210    (67,3)  error: end of file found before string ended
1211    --
1212
1213    [Xtestfile2]
1214    --
1215
1216    [Xtestfile3]
1217    NEW compiler v1.1
1218    (2,2)   warning: variable 'x' not defined
1219    (67,3)  warning: 's' already defined
1220    --
1221  [DATA]
1222  set efm=%+P[%f]%r,(%l\\,%c)%*[\ ]%t%*[^:]:\ %m,%+Q--%r
1223  " To exercise the push/pop file functionality in quickfix, the test files
1224  " need to be created.
1225  call writefile(['Line1'], 'Xtestfile1')
1226  call writefile(['Line2'], 'Xtestfile2')
1227  call writefile(['Line3'], 'Xtestfile3')
1228  cexpr ""
1229  for l in lines
1230      caddexpr l
1231  endfor
1232  let l = getqflist()
1233  call assert_equal(12, len(l))
1234  call assert_equal(21, l[2].lnum)
1235  call assert_equal(2, l[2].col)
1236  call assert_equal('w', l[2].type)
1237  call assert_equal('e', l[3].type)
1238  call delete('Xtestfile1')
1239  call delete('Xtestfile2')
1240  call delete('Xtestfile3')
1241
1242  " Test for %P, %Q with non-existing files
1243  cexpr lines
1244  let l = getqflist()
1245  call assert_equal(14, len(l))
1246  call assert_equal('[Xtestfile1]', l[0].text)
1247  call assert_equal('[Xtestfile2]', l[6].text)
1248  call assert_equal('[Xtestfile3]', l[9].text)
1249
1250  " Tests for %E, %C and %Z format specifiers
1251  let lines =<< trim [DATA]
1252    Error 275
1253    line 42
1254    column 3
1255    ' ' expected after '--'
1256  [DATA]
1257
1258  set efm=%EError\ %n,%Cline\ %l,%Ccolumn\ %c,%Z%m
1259  cgetexpr lines
1260  let l = getqflist()
1261  call assert_equal(275, l[0].nr)
1262  call assert_equal(42, l[0].lnum)
1263  call assert_equal(3, l[0].col)
1264  call assert_equal('E', l[0].type)
1265  call assert_equal("\n' ' expected after '--'", l[0].text)
1266
1267  " Test for %>
1268  let lines =<< trim [DATA]
1269    Error in line 147 of foo.c:
1270    unknown variable 'i'
1271  [DATA]
1272
1273  set efm=unknown\ variable\ %m,%E%>Error\ in\ line\ %l\ of\ %f:,%Z%m
1274  cgetexpr lines
1275  let l = getqflist()
1276  call assert_equal(147, l[0].lnum)
1277  call assert_equal('E', l[0].type)
1278  call assert_equal("\nunknown variable 'i'", l[0].text)
1279
1280  " Test for %A, %C and other formats
1281  let lines =<< trim [DATA]
1282  ==============================================================
1283  FAIL: testGetTypeIdCachesResult (dbfacadeTest.DjsDBFacadeTest)
1284  --------------------------------------------------------------
1285  Traceback (most recent call last):
1286    File "unittests/dbfacadeTest.py", line 89, in testFoo
1287      self.assertEquals(34, dtid)
1288    File "/usr/lib/python2.2/unittest.py", line 286, in
1289   failUnlessEqual
1290      raise self.failureException, \\
1291  W:AssertionError: 34 != 33
1292
1293  --------------------------------------------------------------
1294  Ran 27 tests in 0.063s
1295  [DATA]
1296  set efm=%C\ %.%#,%A\ \ File\ \"%f\"\\,\ line\ %l%.%#,%Z%[%^\ ]%\\@=%t:%m
1297  cgetexpr lines
1298  let l = getqflist()
1299  call assert_equal(8, len(l))
1300  call assert_equal(89, l[4].lnum)
1301  call assert_equal(1, l[4].valid)
1302  call assert_equal(expand('unittests/dbfacadeTest.py'), bufname(l[4].bufnr))
1303  call assert_equal('W', l[4].type)
1304
1305  " Test for %o
1306  set efm=%f(%o):%l\ %m
1307  cgetexpr ['Xotestfile(Language.PureScript.Types):20 Error']
1308  call writefile(['Line1'], 'Xotestfile')
1309  let l = getqflist()
1310  call assert_equal(1, len(l), string(l))
1311  call assert_equal('Language.PureScript.Types', l[0].module)
1312  copen
1313  call assert_equal('Language.PureScript.Types|20| Error', getline(1))
1314  call feedkeys("\<CR>", 'xn')
1315  call assert_equal('Xotestfile', expand('%:t'))
1316  cclose
1317  bd
1318  call delete("Xotestfile")
1319
1320  " Test for a long module name
1321  cexpr 'Xtest(' . repeat('m', 1026) . '):15 message'
1322  let l = getqflist()
1323  " call assert_equal(repeat('m', 1024), l[0].module)
1324  call assert_equal(repeat('m', 1023), l[0].module)
1325  call assert_equal(15, l[0].lnum)
1326  call assert_equal('message', l[0].text)
1327
1328  " The following sequence of commands used to crash Vim
1329  set efm=%W%m
1330  cgetexpr ['msg1']
1331  let l = getqflist()
1332  call assert_equal(1, len(l), string(l))
1333  call assert_equal('msg1', l[0].text)
1334  set efm=%C%m
1335  lexpr 'msg2'
1336  let l = getloclist(0)
1337  call assert_equal(1, len(l), string(l))
1338  call assert_equal('msg2', l[0].text)
1339  lopen
1340  call setqflist([], 'r')
1341  caddbuf
1342  let l = getqflist()
1343  call assert_equal(1, len(l), string(l))
1344  call assert_equal('|| msg2', l[0].text)
1345
1346  " When matching error lines, case should be ignored. Test for this.
1347  set noignorecase
1348  let l=getqflist({'lines' : ['Xtest:FOO10:Line 20'], 'efm':'%f:foo%l:%m'})
1349  call assert_equal(10, l.items[0].lnum)
1350  call assert_equal('Line 20', l.items[0].text)
1351  set ignorecase&
1352
1353  new | only
1354  let &efm = save_efm
1355endfunc
1356
1357" Test for '%t' (error type) field in 'efm'
1358func Test_efm_error_type()
1359  let save_efm = &efm
1360
1361  " error type
1362  set efm=%f:%l:%t:%m
1363  cexpr ["Xfile1:10:E:msg1", "Xfile1:20:W:msg2", "Xfile1:30:I:msg3",
1364        \ "Xfile1:40:N:msg4", "Xfile1:50:R:msg5"]
1365  let output = split(execute('clist'), "\n")
1366  call assert_equal([
1367        \ ' 1 Xfile1:10 error: msg1',
1368        \ ' 2 Xfile1:20 warning: msg2',
1369        \ ' 3 Xfile1:30 info: msg3',
1370        \ ' 4 Xfile1:40 note: msg4',
1371        \ ' 5 Xfile1:50 R: msg5'], output)
1372
1373  " error type and a error number
1374  set efm=%f:%l:%t:%n:%m
1375  cexpr ["Xfile1:10:E:2:msg1", "Xfile1:20:W:4:msg2", "Xfile1:30:I:6:msg3",
1376        \ "Xfile1:40:N:8:msg4", "Xfile1:50:R:3:msg5"]
1377  let output = split(execute('clist'), "\n")
1378  call assert_equal([
1379        \ ' 1 Xfile1:10 error   2: msg1',
1380        \ ' 2 Xfile1:20 warning   4: msg2',
1381        \ ' 3 Xfile1:30 info   6: msg3',
1382        \ ' 4 Xfile1:40 note   8: msg4',
1383        \ ' 5 Xfile1:50 R   3: msg5'], output)
1384  let &efm = save_efm
1385endfunc
1386
1387func XquickfixChangedByAutocmd(cchar)
1388  call s:setup_commands(a:cchar)
1389  if a:cchar == 'c'
1390    let ErrorNr = 'E925'
1391    func! ReadFunc()
1392      colder
1393      cgetexpr []
1394    endfunc
1395  else
1396    let ErrorNr = 'E926'
1397    func! ReadFunc()
1398      lolder
1399      lgetexpr []
1400    endfunc
1401  endif
1402
1403  augroup testgroup
1404    au!
1405    autocmd BufReadCmd test_changed.txt call ReadFunc()
1406  augroup END
1407
1408  new | only
1409  let words = [ "a", "b" ]
1410  let qflist = []
1411  for word in words
1412    call add(qflist, {'filename': 'test_changed.txt'})
1413    call g:Xsetlist(qflist, ' ')
1414  endfor
1415  call assert_fails('Xrewind', ErrorNr . ':')
1416
1417  augroup! testgroup
1418endfunc
1419
1420func Test_quickfix_was_changed_by_autocmd()
1421  call XquickfixChangedByAutocmd('c')
1422  call XquickfixChangedByAutocmd('l')
1423endfunc
1424
1425func Test_setloclist_in_autocommand()
1426  call writefile(['test1', 'test2'], 'Xfile')
1427  edit Xfile
1428  let s:bufnr = bufnr()
1429  call setloclist(1,
1430        \ [{'bufnr' : s:bufnr, 'lnum' : 1, 'text' : 'test1'},
1431        \  {'bufnr' : s:bufnr, 'lnum' : 2, 'text' : 'test2'}])
1432
1433  augroup Test_LocList
1434    au!
1435    autocmd BufEnter * call setloclist(1,
1436          \ [{'bufnr' : s:bufnr, 'lnum' : 1, 'text' : 'test1'},
1437          \  {'bufnr' : s:bufnr, 'lnum' : 2, 'text' : 'test2'}], 'r')
1438  augroup END
1439
1440  lopen
1441  call assert_fails('exe "normal j\<CR>"', 'E926:')
1442
1443  augroup Test_LocList
1444    au!
1445  augroup END
1446  call delete('Xfile')
1447endfunc
1448
1449func Test_caddbuffer_to_empty()
1450  helpgr quickfix
1451  call setqflist([], 'r')
1452  cad
1453  try
1454    cn
1455  catch
1456    " number of matches is unknown
1457    call assert_true(v:exception =~ 'E553:')
1458  endtry
1459  quit!
1460endfunc
1461
1462func Test_cgetexpr_works()
1463  " this must not crash Vim
1464  cgetexpr [$x]
1465  lgetexpr [$x]
1466endfunc
1467
1468" Tests for the setqflist() and setloclist() functions
1469func SetXlistTests(cchar, bnum)
1470  call s:setup_commands(a:cchar)
1471
1472  call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 1},
1473	      \  {'bufnr': a:bnum, 'lnum': 2, 'end_lnum': 3, 'col': 4, 'end_col': 5}])
1474  let l = g:Xgetlist()
1475  call assert_equal(2, len(l))
1476  call assert_equal(2, l[1].lnum)
1477  call assert_equal(3, l[1].end_lnum)
1478  call assert_equal(4, l[1].col)
1479  call assert_equal(5, l[1].end_col)
1480
1481  Xnext
1482  call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 3}], 'a')
1483  let l = g:Xgetlist()
1484  call assert_equal(3, len(l))
1485  Xnext
1486  call assert_equal(3, line('.'))
1487
1488  " Appending entries to the list should not change the cursor position
1489  " in the quickfix window
1490  Xwindow
1491  1
1492  call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 4},
1493	      \  {'bufnr': a:bnum, 'lnum': 5}], 'a')
1494  call assert_equal(1, line('.'))
1495  close
1496
1497  call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 3},
1498	      \  {'bufnr': a:bnum, 'lnum': 4},
1499	      \  {'bufnr': a:bnum, 'lnum': 5}], 'r')
1500  let l = g:Xgetlist()
1501  call assert_equal(3, len(l))
1502  call assert_equal(5, l[2].lnum)
1503
1504  call g:Xsetlist([])
1505  let l = g:Xgetlist()
1506  call assert_equal(0, len(l))
1507
1508  " Tests for setting the 'valid' flag
1509  call g:Xsetlist([{'bufnr':a:bnum, 'lnum':4, 'valid':0}])
1510  Xwindow
1511  call assert_equal(1, winnr('$'))
1512  let l = g:Xgetlist()
1513  call g:Xsetlist(l)
1514  call assert_equal(0, g:Xgetlist()[0].valid)
1515  " Adding a non-valid entry should not mark the list as having valid entries
1516  call g:Xsetlist([{'bufnr':a:bnum, 'lnum':5, 'valid':0}], 'a')
1517  Xwindow
1518  call assert_equal(1, winnr('$'))
1519
1520  " :cnext/:cprev should still work even with invalid entries in the list
1521  let l = [{'bufnr' : a:bnum, 'lnum' : 1, 'text' : '1', 'valid' : 0},
1522	      \ {'bufnr' : a:bnum, 'lnum' : 2, 'text' : '2', 'valid' : 0}]
1523  call g:Xsetlist(l)
1524  Xnext
1525  call assert_equal(2, g:Xgetlist({'idx' : 0}).idx)
1526  Xprev
1527  call assert_equal(1, g:Xgetlist({'idx' : 0}).idx)
1528  " :cnext/:cprev should still work after appending invalid entries to an
1529  " empty list
1530  call g:Xsetlist([])
1531  call g:Xsetlist(l, 'a')
1532  Xnext
1533  call assert_equal(2, g:Xgetlist({'idx' : 0}).idx)
1534  Xprev
1535  call assert_equal(1, g:Xgetlist({'idx' : 0}).idx)
1536
1537  call g:Xsetlist([{'text':'Text1', 'valid':1}])
1538  Xwindow
1539  call assert_equal(2, winnr('$'))
1540  Xclose
1541  let save_efm = &efm
1542  set efm=%m
1543  Xgetexpr 'TestMessage'
1544  let l = g:Xgetlist()
1545  call g:Xsetlist(l)
1546  call assert_equal(1, g:Xgetlist()[0].valid)
1547  let &efm = save_efm
1548
1549  " Error cases:
1550  " Refer to a non-existing buffer and pass a non-dictionary type
1551  call assert_fails("call g:Xsetlist([{'bufnr':998, 'lnum':4}," .
1552	      \ " {'bufnr':999, 'lnum':5}])", 'E92:')
1553  call g:Xsetlist([[1, 2,3]])
1554  call assert_equal(0, len(g:Xgetlist()))
1555endfunc
1556
1557func Test_setqflist()
1558  new Xtestfile | only
1559  let bnum = bufnr('%')
1560  call setline(1, range(1,5))
1561
1562  call SetXlistTests('c', bnum)
1563  call SetXlistTests('l', bnum)
1564
1565  enew!
1566  call delete('Xtestfile')
1567endfunc
1568
1569func Xlist_empty_middle(cchar)
1570  call s:setup_commands(a:cchar)
1571
1572  " create three quickfix lists
1573  let @/ = 'Test_'
1574  Xvimgrep // test_quickfix.vim
1575  let testlen = len(g:Xgetlist())
1576  call assert_true(testlen > 0)
1577  Xvimgrep empty test_quickfix.vim
1578  call assert_true(len(g:Xgetlist()) > 0)
1579  Xvimgrep matches test_quickfix.vim
1580  let matchlen = len(g:Xgetlist())
1581  call assert_true(matchlen > 0)
1582  Xolder
1583  " make the middle list empty
1584  call g:Xsetlist([], 'r')
1585  call assert_true(len(g:Xgetlist()) == 0)
1586  Xolder
1587  call assert_equal(testlen, len(g:Xgetlist()))
1588  Xnewer
1589  Xnewer
1590  call assert_equal(matchlen, len(g:Xgetlist()))
1591endfunc
1592
1593func Test_setqflist_empty_middle()
1594  call Xlist_empty_middle('c')
1595  call Xlist_empty_middle('l')
1596endfunc
1597
1598func Xlist_empty_older(cchar)
1599  call s:setup_commands(a:cchar)
1600
1601  " create three quickfix lists
1602  Xvimgrep one test_quickfix.vim
1603  let onelen = len(g:Xgetlist())
1604  call assert_true(onelen > 0)
1605  Xvimgrep two test_quickfix.vim
1606  let twolen = len(g:Xgetlist())
1607  call assert_true(twolen > 0)
1608  Xvimgrep three test_quickfix.vim
1609  let threelen = len(g:Xgetlist())
1610  call assert_true(threelen > 0)
1611  Xolder 2
1612  " make the first list empty, check the others didn't change
1613  call g:Xsetlist([], 'r')
1614  call assert_true(len(g:Xgetlist()) == 0)
1615  Xnewer
1616  call assert_equal(twolen, len(g:Xgetlist()))
1617  Xnewer
1618  call assert_equal(threelen, len(g:Xgetlist()))
1619endfunc
1620
1621func Test_setqflist_empty_older()
1622  call Xlist_empty_older('c')
1623  call Xlist_empty_older('l')
1624endfunc
1625
1626func XquickfixSetListWithAct(cchar)
1627  call s:setup_commands(a:cchar)
1628
1629  let list1 = [{'filename': 'fnameA', 'text': 'A'},
1630          \    {'filename': 'fnameB', 'text': 'B'}]
1631  let list2 = [{'filename': 'fnameC', 'text': 'C'},
1632          \    {'filename': 'fnameD', 'text': 'D'},
1633          \    {'filename': 'fnameE', 'text': 'E'}]
1634
1635  " {action} is unspecified.  Same as specifing ' '.
1636  new | only
1637  silent! Xnewer 99
1638  call g:Xsetlist(list1)
1639  call g:Xsetlist(list2)
1640  let li = g:Xgetlist()
1641  call assert_equal(3, len(li))
1642  call assert_equal('C', li[0]['text'])
1643  call assert_equal('D', li[1]['text'])
1644  call assert_equal('E', li[2]['text'])
1645  silent! Xolder
1646  let li = g:Xgetlist()
1647  call assert_equal(2, len(li))
1648  call assert_equal('A', li[0]['text'])
1649  call assert_equal('B', li[1]['text'])
1650
1651  " {action} is specified ' '.
1652  new | only
1653  silent! Xnewer 99
1654  call g:Xsetlist(list1)
1655  call g:Xsetlist(list2, ' ')
1656  let li = g:Xgetlist()
1657  call assert_equal(3, len(li))
1658  call assert_equal('C', li[0]['text'])
1659  call assert_equal('D', li[1]['text'])
1660  call assert_equal('E', li[2]['text'])
1661  silent! Xolder
1662  let li = g:Xgetlist()
1663  call assert_equal(2, len(li))
1664  call assert_equal('A', li[0]['text'])
1665  call assert_equal('B', li[1]['text'])
1666
1667  " {action} is specified 'a'.
1668  new | only
1669  silent! Xnewer 99
1670  call g:Xsetlist(list1)
1671  call g:Xsetlist(list2, 'a')
1672  let li = g:Xgetlist()
1673  call assert_equal(5, len(li))
1674  call assert_equal('A', li[0]['text'])
1675  call assert_equal('B', li[1]['text'])
1676  call assert_equal('C', li[2]['text'])
1677  call assert_equal('D', li[3]['text'])
1678  call assert_equal('E', li[4]['text'])
1679
1680  " {action} is specified 'r'.
1681  new | only
1682  silent! Xnewer 99
1683  call g:Xsetlist(list1)
1684  call g:Xsetlist(list2, 'r')
1685  let li = g:Xgetlist()
1686  call assert_equal(3, len(li))
1687  call assert_equal('C', li[0]['text'])
1688  call assert_equal('D', li[1]['text'])
1689  call assert_equal('E', li[2]['text'])
1690
1691  " Test for wrong value.
1692  new | only
1693  call assert_fails("call g:Xsetlist(0)", 'E714:')
1694  call assert_fails("call g:Xsetlist(list1, '')", 'E927:')
1695  call assert_fails("call g:Xsetlist(list1, 'aa')", 'E927:')
1696  call assert_fails("call g:Xsetlist(list1, ' a')", 'E927:')
1697  call assert_fails("call g:Xsetlist(list1, 0)", 'E928:')
1698endfunc
1699
1700func Test_setqflist_invalid_nr()
1701  " The following command used to crash Vim
1702  call setqflist([], ' ', {'nr' : $XXX_DOES_NOT_EXIST})
1703endfunc
1704
1705func Test_setqflist_user_sets_buftype()
1706  call setqflist([{'text': 'foo'}, {'text': 'bar'}])
1707  set buftype=quickfix
1708  call setqflist([], 'a')
1709  enew
1710endfunc
1711
1712func Test_quickfix_set_list_with_act()
1713  call XquickfixSetListWithAct('c')
1714  call XquickfixSetListWithAct('l')
1715endfunc
1716
1717func XLongLinesTests(cchar)
1718  let l = g:Xgetlist()
1719
1720  call assert_equal(4, len(l))
1721  call assert_equal(1, l[0].lnum)
1722  call assert_equal(1, l[0].col)
1723  call assert_equal(1975, len(l[0].text))
1724  call assert_equal(2, l[1].lnum)
1725  call assert_equal(1, l[1].col)
1726  call assert_equal(4070, len(l[1].text))
1727  call assert_equal(3, l[2].lnum)
1728  call assert_equal(1, l[2].col)
1729  call assert_equal(4070, len(l[2].text))
1730  call assert_equal(4, l[3].lnum)
1731  call assert_equal(1, l[3].col)
1732  call assert_equal(10, len(l[3].text))
1733
1734  call g:Xsetlist([], 'r')
1735endfunc
1736
1737func s:long_lines_tests(cchar)
1738  call s:setup_commands(a:cchar)
1739
1740  let testfile = 'samples/quickfix.txt'
1741
1742  " file
1743  exe 'Xgetfile' testfile
1744  call XLongLinesTests(a:cchar)
1745
1746  " list
1747  Xexpr readfile(testfile)
1748  call XLongLinesTests(a:cchar)
1749
1750  " string
1751  Xexpr join(readfile(testfile), "\n")
1752  call XLongLinesTests(a:cchar)
1753
1754  " buffer
1755  exe 'edit' testfile
1756  exe 'Xbuffer' bufnr('%')
1757  call XLongLinesTests(a:cchar)
1758endfunc
1759
1760func Test_long_lines()
1761  call s:long_lines_tests('c')
1762  call s:long_lines_tests('l')
1763endfunc
1764
1765func Test_cgetfile_on_long_lines()
1766  " Problematic values if the line is longer than 4096 bytes.  Then 1024 bytes
1767  " are read at a time.
1768  for len in [4078, 4079, 4080, 5102, 5103, 5104, 6126, 6127, 6128, 7150, 7151, 7152]
1769    let lines = [
1770      \ '/tmp/file1:1:1:aaa',
1771      \ '/tmp/file2:1:1:%s',
1772      \ '/tmp/file3:1:1:bbb',
1773      \ '/tmp/file4:1:1:ccc',
1774      \ ]
1775    let lines[1] = substitute(lines[1], '%s', repeat('x', len), '')
1776    call writefile(lines, 'Xcqetfile.txt')
1777    cgetfile Xcqetfile.txt
1778    call assert_equal(4, getqflist(#{size: v:true}).size, 'with length ' .. len)
1779  endfor
1780  call delete('Xcqetfile.txt')
1781endfunc
1782
1783func s:create_test_file(filename)
1784  let l = []
1785  for i in range(1, 20)
1786      call add(l, 'Line' . i)
1787  endfor
1788  call writefile(l, a:filename)
1789endfunc
1790
1791func Test_switchbuf()
1792  call s:create_test_file('Xqftestfile1')
1793  call s:create_test_file('Xqftestfile2')
1794  call s:create_test_file('Xqftestfile3')
1795
1796  new | only
1797  edit Xqftestfile1
1798  let file1_winid = win_getid()
1799  new Xqftestfile2
1800  let file2_winid = win_getid()
1801  cgetexpr ['Xqftestfile1:5:Line5',
1802		\ 'Xqftestfile1:6:Line6',
1803		\ 'Xqftestfile2:10:Line10',
1804		\ 'Xqftestfile2:11:Line11',
1805		\ 'Xqftestfile3:15:Line15',
1806		\ 'Xqftestfile3:16:Line16']
1807
1808  new
1809  let winid = win_getid()
1810  cfirst | cnext
1811  call assert_equal(winid, win_getid())
1812  2cnext
1813  call assert_equal(winid, win_getid())
1814  2cnext
1815  call assert_equal(winid, win_getid())
1816
1817  " Test for 'switchbuf' set to search for files in windows in the current
1818  " tabpage and jump to an existing window (if present)
1819  set switchbuf=useopen
1820  enew
1821  cfirst | cnext
1822  call assert_equal(file1_winid, win_getid())
1823  2cnext
1824  call assert_equal(file2_winid, win_getid())
1825  2cnext
1826  call assert_equal(file2_winid, win_getid())
1827
1828  " Test for 'switchbuf' set to search for files in tabpages and jump to an
1829  " existing tabpage (if present)
1830  enew | only
1831  set switchbuf=usetab
1832  tabedit Xqftestfile1
1833  tabedit Xqftestfile2
1834  tabedit Xqftestfile3
1835  tabfirst
1836  cfirst | cnext
1837  call assert_equal(2, tabpagenr())
1838  2cnext
1839  call assert_equal(3, tabpagenr())
1840  6cnext
1841  call assert_equal(4, tabpagenr())
1842  2cpfile
1843  call assert_equal(2, tabpagenr())
1844  2cnfile
1845  call assert_equal(4, tabpagenr())
1846  tabfirst | tabonly | enew
1847
1848  " Test for 'switchbuf' set to open a new window for every file
1849  set switchbuf=split
1850  cfirst | cnext
1851  call assert_equal(1, winnr('$'))
1852  cnext | cnext
1853  call assert_equal(2, winnr('$'))
1854  cnext | cnext
1855  call assert_equal(3, winnr('$'))
1856
1857  " Test for 'switchbuf' set to open a new tabpage for every file
1858  set switchbuf=newtab
1859  enew | only
1860  cfirst | cnext
1861  call assert_equal(1, tabpagenr('$'))
1862  cnext | cnext
1863  call assert_equal(2, tabpagenr('$'))
1864  cnext | cnext
1865  call assert_equal(3, tabpagenr('$'))
1866  tabfirst | enew | tabonly | only
1867
1868  set switchbuf=uselast
1869  split
1870  let last_winid = win_getid()
1871  copen
1872  exe "normal 1G\<CR>"
1873  call assert_equal(last_winid, win_getid())
1874  enew | only
1875
1876  " With an empty 'switchbuf', jumping to a quickfix entry should open the
1877  " file in an existing window (if present)
1878  set switchbuf=
1879  edit Xqftestfile1
1880  let file1_winid = win_getid()
1881  new Xqftestfile2
1882  let file2_winid = win_getid()
1883  copen
1884  exe "normal 1G\<CR>"
1885  call assert_equal(file1_winid, win_getid())
1886  copen
1887  exe "normal 3G\<CR>"
1888  call assert_equal(file2_winid, win_getid())
1889  copen | only
1890  exe "normal 5G\<CR>"
1891  call assert_equal(2, winnr('$'))
1892  call assert_equal(1, bufwinnr('Xqftestfile3'))
1893
1894  " If only quickfix window is open in the current tabpage, jumping to an
1895  " entry with 'switchbuf' set to 'usetab' should search in other tabpages.
1896  enew | only
1897  set switchbuf=usetab
1898  tabedit Xqftestfile1
1899  tabedit Xqftestfile2
1900  tabedit Xqftestfile3
1901  tabfirst
1902  copen | only
1903  clast
1904  call assert_equal(4, tabpagenr())
1905  tabfirst | tabonly | enew | only
1906
1907  " Jumping to a file that is not present in any of the tabpages and the
1908  " current tabpage doesn't have any usable windows, should open it in a new
1909  " window in the current tabpage.
1910  copen | only
1911  cfirst
1912  call assert_equal(1, tabpagenr())
1913  call assert_equal('Xqftestfile1', bufname(''))
1914
1915  " If opening a file changes 'switchbuf', then the new value should be
1916  " retained.
1917  call writefile(["vim: switchbuf=split"], 'Xqftestfile1')
1918  enew | only
1919  set switchbuf&vim
1920  cexpr "Xqftestfile1:1:10"
1921  call assert_equal('split', &switchbuf)
1922  call writefile(["vim: switchbuf=usetab"], 'Xqftestfile1')
1923  enew | only
1924  set switchbuf=useopen
1925  cexpr "Xqftestfile1:1:10"
1926  call assert_equal('usetab', &switchbuf)
1927  call writefile(["vim: switchbuf&vim"], 'Xqftestfile1')
1928  enew | only
1929  set switchbuf=useopen
1930  cexpr "Xqftestfile1:1:10"
1931  call assert_equal('uselast', &switchbuf)
1932
1933  call delete('Xqftestfile1')
1934  call delete('Xqftestfile2')
1935  call delete('Xqftestfile3')
1936  set switchbuf&vim
1937
1938  enew | only
1939endfunc
1940
1941func Xadjust_qflnum(cchar)
1942  call s:setup_commands(a:cchar)
1943
1944  enew | only
1945
1946  let fname = 'Xqftestfile' . a:cchar
1947  call s:create_test_file(fname)
1948  exe 'edit ' . fname
1949
1950  Xgetexpr [fname . ':5:Line5',
1951	      \ fname . ':10:Line10',
1952	      \ fname . ':15:Line15',
1953	      \ fname . ':20:Line20']
1954
1955  6,14delete
1956  call append(6, ['Buffer', 'Window'])
1957
1958  let l = g:Xgetlist()
1959  call assert_equal(5, l[0].lnum)
1960  call assert_equal(6, l[2].lnum)
1961  call assert_equal(13, l[3].lnum)
1962
1963  " If a file doesn't have any quickfix entries, then deleting lines in the
1964  " file should not update the quickfix list
1965  call g:Xsetlist([], 'f')
1966  1,2delete
1967  call assert_equal([], g:Xgetlist())
1968
1969  enew!
1970  call delete(fname)
1971endfunc
1972
1973func Test_adjust_lnum()
1974  call setloclist(0, [])
1975  call Xadjust_qflnum('c')
1976  call setqflist([])
1977  call Xadjust_qflnum('l')
1978endfunc
1979
1980" Tests for the :grep/:lgrep and :grepadd/:lgrepadd commands
1981func s:test_xgrep(cchar)
1982  call s:setup_commands(a:cchar)
1983
1984  " The following lines are used for the grep test. Don't remove.
1985  " Grep_Test_Text: Match 1
1986  " Grep_Test_Text: Match 2
1987  " GrepAdd_Test_Text: Match 1
1988  " GrepAdd_Test_Text: Match 2
1989  enew! | only
1990  set makeef&vim
1991  silent Xgrep Grep_Test_Text: test_quickfix.vim
1992  call assert_true(len(g:Xgetlist()) == 5)
1993  Xopen
1994  call assert_true(w:quickfix_title =~ '^:grep')
1995  Xclose
1996  enew
1997  set makeef=Temp_File_##
1998  silent Xgrepadd GrepAdd_Test_Text: test_quickfix.vim
1999
2000  " Try with 'grepprg' set to 'internal'
2001  set grepprg=internal
2002  silent Xgrep Grep_Test_Text: test_quickfix.vim
2003  silent Xgrepadd GrepAdd_Test_Text: test_quickfix.vim
2004  call assert_true(len(g:Xgetlist()) == 9)
2005  set grepprg&vim
2006
2007   call writefile(['Vim'], 'XtestTempFile')
2008   set makeef=XtestTempFile
2009   silent Xgrep Grep_Test_Text: test_quickfix.vim
2010   call assert_equal(5, len(g:Xgetlist()))
2011   call assert_false(filereadable('XtestTempFile'))
2012   set makeef&vim
2013endfunc
2014
2015func Test_grep()
2016  if !has('unix')
2017    " The grepprg may not be set on non-Unix systems
2018    return
2019  endif
2020
2021  call s:test_xgrep('c')
2022  call s:test_xgrep('l')
2023endfunc
2024
2025func Test_two_windows()
2026  " Use one 'errorformat' for two windows.  Add an expression to each of them,
2027  " make sure they each keep their own state.
2028  set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f'
2029  call mkdir('Xone/a', 'p')
2030  call mkdir('Xtwo/a', 'p')
2031  let lines = ['1', '2', 'one one one', '4', 'two two two', '6', '7']
2032  call writefile(lines, 'Xone/a/one.txt')
2033  call writefile(lines, 'Xtwo/a/two.txt')
2034
2035  new one
2036  let one_id = win_getid()
2037  lexpr ""
2038  new two
2039  let two_id = win_getid()
2040  lexpr ""
2041
2042  laddexpr "Entering dir 'Xtwo/a'"
2043  call win_gotoid(one_id)
2044  laddexpr "Entering dir 'Xone/a'"
2045  call win_gotoid(two_id)
2046  laddexpr 'two.txt:5:two two two'
2047  call win_gotoid(one_id)
2048  laddexpr 'one.txt:3:one one one'
2049
2050  let loc_one = getloclist(one_id)
2051  call assert_equal(expand('Xone/a/one.txt'), bufname(loc_one[1].bufnr))
2052  call assert_equal(3, loc_one[1].lnum)
2053
2054  let loc_two = getloclist(two_id)
2055  call assert_equal(expand('Xtwo/a/two.txt'), bufname(loc_two[1].bufnr))
2056  call assert_equal(5, loc_two[1].lnum)
2057
2058  call win_gotoid(one_id)
2059  bwipe!
2060  call win_gotoid(two_id)
2061  bwipe!
2062  call delete('Xone', 'rf')
2063  call delete('Xtwo', 'rf')
2064endfunc
2065
2066func XbottomTests(cchar)
2067  call s:setup_commands(a:cchar)
2068
2069  " Calling lbottom without any errors should fail
2070  if a:cchar == 'l'
2071      call assert_fails('lbottom', 'E776:')
2072  endif
2073
2074  call g:Xsetlist([{'filename': 'foo', 'lnum': 42}])
2075  Xopen
2076  let wid = win_getid()
2077  call assert_equal(1, line('.'))
2078  wincmd w
2079  call g:Xsetlist([{'filename': 'var', 'lnum': 24}], 'a')
2080  Xbottom
2081  call win_gotoid(wid)
2082  call assert_equal(2, line('.'))
2083  Xclose
2084endfunc
2085
2086" Tests for the :cbottom and :lbottom commands
2087func Test_cbottom()
2088  call XbottomTests('c')
2089  call XbottomTests('l')
2090endfunc
2091
2092func HistoryTest(cchar)
2093  call s:setup_commands(a:cchar)
2094
2095  " clear all lists after the first one, then replace the first one.
2096  call g:Xsetlist([])
2097  call assert_fails('Xolder 99', 'E380:')
2098  let entry = {'filename': 'foo', 'lnum': 42}
2099  call g:Xsetlist([entry], 'r')
2100  call g:Xsetlist([entry, entry])
2101  call g:Xsetlist([entry, entry, entry])
2102  let res = split(execute(a:cchar . 'hist'), "\n")
2103  call assert_equal(3, len(res))
2104  let common = 'errors     :set' . (a:cchar == 'c' ? 'qf' : 'loc') . 'list()'
2105  call assert_equal('  error list 1 of 3; 1 ' . common, res[0])
2106  call assert_equal('  error list 2 of 3; 2 ' . common, res[1])
2107  call assert_equal('> error list 3 of 3; 3 ' . common, res[2])
2108
2109  " Test for changing the quickfix lists
2110  call assert_equal(3, g:Xgetlist({'nr' : 0}).nr)
2111  exe '1' . a:cchar . 'hist'
2112  call assert_equal(1, g:Xgetlist({'nr' : 0}).nr)
2113  exe '3' . a:cchar . 'hist'
2114  call assert_equal(3, g:Xgetlist({'nr' : 0}).nr)
2115  call assert_fails('-2' . a:cchar . 'hist', 'E16:')
2116  call assert_fails('4' . a:cchar . 'hist', 'E16:')
2117
2118  call g:Xsetlist([], 'f')
2119  let l = split(execute(a:cchar . 'hist'), "\n")
2120  call assert_equal('No entries', l[0])
2121  if a:cchar == 'c'
2122    call assert_fails('4chist', 'E16:')
2123  else
2124    call assert_fails('4lhist', 'E776:')
2125  endif
2126
2127  " An empty list should still show the stack history
2128  call g:Xsetlist([])
2129  let res = split(execute(a:cchar . 'hist'), "\n")
2130  call assert_equal('> error list 1 of 1; 0 ' . common, res[0])
2131
2132  call g:Xsetlist([], 'f')
2133endfunc
2134
2135func Test_history()
2136  call HistoryTest('c')
2137  call HistoryTest('l')
2138endfunc
2139
2140func Test_duplicate_buf()
2141  " make sure we can get the highest buffer number
2142  edit DoesNotExist
2143  edit DoesNotExist2
2144  let last_buffer = bufnr("$")
2145
2146  " make sure only one buffer is created
2147  call writefile(['this one', 'that one'], 'Xgrepthis')
2148  vimgrep one Xgrepthis
2149  vimgrep one Xgrepthis
2150  call assert_equal(last_buffer + 1, bufnr("$"))
2151
2152  call delete('Xgrepthis')
2153endfunc
2154
2155" Quickfix/Location list set/get properties tests
2156func Xproperty_tests(cchar)
2157    call s:setup_commands(a:cchar)
2158
2159    " Error cases
2160    call assert_fails('call g:Xgetlist(99)', 'E715:')
2161    call assert_fails('call g:Xsetlist(99)', 'E714:')
2162    call assert_fails('call g:Xsetlist([], "a", [])', 'E715:')
2163
2164    " Set and get the title
2165    call g:Xsetlist([])
2166    Xopen
2167    wincmd p
2168    call g:Xsetlist([{'filename':'foo', 'lnum':27}])
2169    let s = g:Xsetlist([], 'a', {'title' : 'Sample'})
2170    call assert_equal(0, s)
2171    let d = g:Xgetlist({"title":1})
2172    call assert_equal('Sample', d.title)
2173    " Try setting title to a non-string value
2174    call assert_equal(-1, g:Xsetlist([], 'a', {'title' : ['Test']}))
2175    call assert_equal('Sample', g:Xgetlist({"title":1}).title)
2176
2177    Xopen
2178    call assert_equal('Sample', w:quickfix_title)
2179    Xclose
2180
2181    " Tests for action argument
2182    silent! Xolder 999
2183    let qfnr = g:Xgetlist({'all':1}).nr
2184    call g:Xsetlist([], 'r', {'title' : 'N1'})
2185    call assert_equal('N1', g:Xgetlist({'all':1}).title)
2186    call g:Xsetlist([], ' ', {'title' : 'N2'})
2187    call assert_equal(qfnr + 1, g:Xgetlist({'all':1}).nr)
2188
2189    let res = g:Xgetlist({'nr': 0})
2190    call assert_equal(qfnr + 1, res.nr)
2191    call assert_equal(['nr'], keys(res))
2192
2193    call g:Xsetlist([], ' ', {'title' : 'N3'})
2194    call assert_equal('N2', g:Xgetlist({'nr':2, 'title':1}).title)
2195
2196    " Changing the title of an earlier quickfix list
2197    call g:Xsetlist([], 'r', {'title' : 'NewTitle', 'nr' : 2})
2198    call assert_equal('NewTitle', g:Xgetlist({'nr':2, 'title':1}).title)
2199
2200    " Changing the title of an invalid quickfix list
2201    call assert_equal(-1, g:Xsetlist([], ' ',
2202		\ {'title' : 'SomeTitle', 'nr' : 99}))
2203    call assert_equal(-1, g:Xsetlist([], ' ',
2204		\ {'title' : 'SomeTitle', 'nr' : 'abc'}))
2205
2206    if a:cchar == 'c'
2207	copen
2208	call assert_equal({'winid':win_getid()}, getqflist({'winid':1}))
2209	cclose
2210    endif
2211
2212    " Invalid arguments
2213    call assert_fails('call g:Xgetlist([])', 'E715')
2214    call assert_fails('call g:Xsetlist([], "a", [])', 'E715')
2215    let s = g:Xsetlist([], 'a', {'abc':1})
2216    call assert_equal(-1, s)
2217
2218    call assert_equal({}, g:Xgetlist({'abc':1}))
2219    call assert_equal('', g:Xgetlist({'nr':99, 'title':1}).title)
2220    call assert_equal('', g:Xgetlist({'nr':[], 'title':1}).title)
2221
2222    if a:cchar == 'l'
2223	call assert_equal({}, getloclist(99, {'title': 1}))
2224    endif
2225
2226    " Context related tests
2227    let s = g:Xsetlist([], 'a', {'context':[1,2,3]})
2228    call assert_equal(0, s)
2229    call test_garbagecollect_now()
2230    let d = g:Xgetlist({'context':1})
2231    call assert_equal([1,2,3], d.context)
2232    call g:Xsetlist([], 'a', {'context':{'color':'green'}})
2233    let d = g:Xgetlist({'context':1})
2234    call assert_equal({'color':'green'}, d.context)
2235    call g:Xsetlist([], 'a', {'context':"Context info"})
2236    let d = g:Xgetlist({'context':1})
2237    call assert_equal("Context info", d.context)
2238    call g:Xsetlist([], 'a', {'context':246})
2239    let d = g:Xgetlist({'context':1})
2240    call assert_equal(246, d.context)
2241    " set other Vim data types as context
2242    call g:Xsetlist([], 'a', {'context' : v:_null_blob})
2243    call g:Xsetlist([], 'a', {'context' : ''})
2244    call test_garbagecollect_now()
2245    if a:cchar == 'l'
2246	" Test for copying context across two different location lists
2247	new | only
2248	let w1_id = win_getid()
2249	let l = [1]
2250	call setloclist(0, [], 'a', {'context':l})
2251	new
2252	let w2_id = win_getid()
2253	call add(l, 2)
2254	call assert_equal([1, 2], getloclist(w1_id, {'context':1}).context)
2255	call assert_equal([1, 2], getloclist(w2_id, {'context':1}).context)
2256	unlet! l
2257	call assert_equal([1, 2], getloclist(w2_id, {'context':1}).context)
2258	only
2259	call setloclist(0, [], 'f')
2260	call assert_equal('', getloclist(0, {'context':1}).context)
2261    endif
2262
2263    " Test for changing the context of previous quickfix lists
2264    call g:Xsetlist([], 'f')
2265    Xexpr "One"
2266    Xexpr "Two"
2267    Xexpr "Three"
2268    call g:Xsetlist([], 'r', {'context' : [1], 'nr' : 1})
2269    call g:Xsetlist([], 'a', {'context' : [2], 'nr' : 2})
2270    " Also, check for setting the context using quickfix list number zero.
2271    call g:Xsetlist([], 'r', {'context' : [3], 'nr' : 0})
2272    call test_garbagecollect_now()
2273    let l = g:Xgetlist({'nr' : 1, 'context' : 1})
2274    call assert_equal([1], l.context)
2275    let l = g:Xgetlist({'nr' : 2, 'context' : 1})
2276    call assert_equal([2], l.context)
2277    let l = g:Xgetlist({'nr' : 3, 'context' : 1})
2278    call assert_equal([3], l.context)
2279
2280    " Test for changing the context through reference and for garbage
2281    " collection of quickfix context
2282    let l = ["red"]
2283    call g:Xsetlist([], ' ', {'context' : l})
2284    call add(l, "blue")
2285    let x = g:Xgetlist({'context' : 1})
2286    call add(x.context, "green")
2287    call assert_equal(["red", "blue", "green"], l)
2288    call assert_equal(["red", "blue", "green"], x.context)
2289    unlet l
2290    call test_garbagecollect_now()
2291    let m = g:Xgetlist({'context' : 1})
2292    call assert_equal(["red", "blue", "green"], m.context)
2293
2294    " Test for setting/getting items
2295    Xexpr ""
2296    let qfprev = g:Xgetlist({'nr':0})
2297    let s = g:Xsetlist([], ' ', {'title':'Green',
2298		\ 'items' : [{'filename':'F1', 'lnum':10}]})
2299    call assert_equal(0, s)
2300    let qfcur = g:Xgetlist({'nr':0})
2301    call assert_true(qfcur.nr == qfprev.nr + 1)
2302    let l = g:Xgetlist({'items':1})
2303    call assert_equal('F1', bufname(l.items[0].bufnr))
2304    call assert_equal(10, l.items[0].lnum)
2305    call g:Xsetlist([], 'a', {'items' : [{'filename':'F2', 'lnum':20},
2306		\  {'filename':'F2', 'lnum':30}]})
2307    let l = g:Xgetlist({'items':1})
2308    call assert_equal('F2', bufname(l.items[2].bufnr))
2309    call assert_equal(30, l.items[2].lnum)
2310    call g:Xsetlist([], 'r', {'items' : [{'filename':'F3', 'lnum':40}]})
2311    let l = g:Xgetlist({'items':1})
2312    call assert_equal('F3', bufname(l.items[0].bufnr))
2313    call assert_equal(40, l.items[0].lnum)
2314    call g:Xsetlist([], 'r', {'items' : []})
2315    let l = g:Xgetlist({'items':1})
2316    call assert_equal(0, len(l.items))
2317
2318    call g:Xsetlist([], 'r', {'title' : 'TestTitle'})
2319    call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F1', 'lnum' : 10, 'text' : 'L10'}]})
2320    call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F1', 'lnum' : 10, 'text' : 'L10'}]})
2321    call assert_equal('TestTitle', g:Xgetlist({'title' : 1}).title)
2322
2323    " Test for getting id of window associated with a location list window
2324    if a:cchar == 'l'
2325      only
2326      call assert_equal(0, g:Xgetlist({'all' : 1}).filewinid)
2327      let wid = win_getid()
2328      Xopen
2329      call assert_equal(wid, g:Xgetlist({'filewinid' : 1}).filewinid)
2330      wincmd w
2331      call assert_equal(0, g:Xgetlist({'filewinid' : 1}).filewinid)
2332      only
2333    endif
2334
2335    " The following used to crash Vim with address sanitizer
2336    call g:Xsetlist([], 'f')
2337    call g:Xsetlist([], 'a', {'items' : [{'filename':'F1', 'lnum':10}]})
2338    call assert_equal(10, g:Xgetlist({'items':1}).items[0].lnum)
2339
2340    " Try setting the items using a string
2341    call assert_equal(-1, g:Xsetlist([], ' ', {'items' : 'Test'}))
2342
2343    " Save and restore the quickfix stack
2344    call g:Xsetlist([], 'f')
2345    call assert_equal(0, g:Xgetlist({'nr':'$'}).nr)
2346    Xexpr "File1:10:Line1"
2347    Xexpr "File2:20:Line2"
2348    Xexpr "File3:30:Line3"
2349    let last_qf = g:Xgetlist({'nr':'$'}).nr
2350    call assert_equal(3, last_qf)
2351    let qstack = []
2352    for i in range(1, last_qf)
2353	let qstack = add(qstack, g:Xgetlist({'nr':i, 'all':1}))
2354    endfor
2355    call g:Xsetlist([], 'f')
2356    for i in range(len(qstack))
2357	call g:Xsetlist([], ' ', qstack[i])
2358    endfor
2359    call assert_equal(3, g:Xgetlist({'nr':'$'}).nr)
2360    call assert_equal(10, g:Xgetlist({'nr':1, 'items':1}).items[0].lnum)
2361    call assert_equal(20, g:Xgetlist({'nr':2, 'items':1}).items[0].lnum)
2362    call assert_equal(30, g:Xgetlist({'nr':3, 'items':1}).items[0].lnum)
2363    call g:Xsetlist([], 'f')
2364
2365    " Swap two quickfix lists
2366    Xexpr "File1:10:Line10"
2367    Xexpr "File2:20:Line20"
2368    Xexpr "File3:30:Line30"
2369    call g:Xsetlist([], 'r', {'nr':1,'title':'Colors','context':['Colors']})
2370    call g:Xsetlist([], 'r', {'nr':2,'title':'Fruits','context':['Fruits']})
2371    let l1=g:Xgetlist({'nr':1,'all':1})
2372    let l2=g:Xgetlist({'nr':2,'all':1})
2373    let save_id = l1.id
2374    let l1.id=l2.id
2375    let l2.id=save_id
2376    call g:Xsetlist([], 'r', l1)
2377    call g:Xsetlist([], 'r', l2)
2378    let newl1=g:Xgetlist({'nr':1,'all':1})
2379    let newl2=g:Xgetlist({'nr':2,'all':1})
2380    call assert_equal('Fruits', newl1.title)
2381    call assert_equal(['Fruits'], newl1.context)
2382    call assert_equal('Line20', newl1.items[0].text)
2383    call assert_equal('Colors', newl2.title)
2384    call assert_equal(['Colors'], newl2.context)
2385    call assert_equal('Line10', newl2.items[0].text)
2386    call g:Xsetlist([], 'f')
2387
2388    " Cannot specify both a non-empty list argument and a dict argument
2389    call assert_fails("call g:Xsetlist([{}], ' ', {})", 'E475:')
2390endfunc
2391
2392func Test_qf_property()
2393    call Xproperty_tests('c')
2394    call Xproperty_tests('l')
2395endfunc
2396
2397" Test for setting the current index in the location/quickfix list
2398func Xtest_setqfidx(cchar)
2399  call s:setup_commands(a:cchar)
2400
2401  Xgetexpr "F1:10:1:Line1\nF2:20:2:Line2\nF3:30:3:Line3"
2402  Xgetexpr "F4:10:1:Line1\nF5:20:2:Line2\nF6:30:3:Line3"
2403  Xgetexpr "F7:10:1:Line1\nF8:20:2:Line2\nF9:30:3:Line3"
2404
2405  call g:Xsetlist([], 'a', {'nr' : 3, 'idx' : 2})
2406  call g:Xsetlist([], 'a', {'nr' : 2, 'idx' : 2})
2407  call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 3})
2408  Xolder 2
2409  Xopen
2410  call assert_equal(3, line('.'))
2411  Xnewer
2412  call assert_equal(2, line('.'))
2413  Xnewer
2414  call assert_equal(2, line('.'))
2415  " Update the current index with the quickfix window open
2416  wincmd w
2417  call g:Xsetlist([], 'a', {'nr' : 3, 'idx' : 3})
2418  Xopen
2419  call assert_equal(3, line('.'))
2420  Xclose
2421
2422  " Set the current index to the last entry
2423  call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : '$'})
2424  call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
2425  " A large value should set the index to the last index
2426  call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 1})
2427  call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 999})
2428  call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
2429  " Invalid index values
2430  call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : -1})
2431  call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
2432  call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 0})
2433  call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
2434  call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 'xx'})
2435  call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
2436  call assert_fails("call g:Xsetlist([], 'a', {'nr':1, 'idx':[]})", 'E745:')
2437
2438  call g:Xsetlist([], 'f')
2439  new | only
2440endfunc
2441
2442func Test_setqfidx()
2443  call Xtest_setqfidx('c')
2444  call Xtest_setqfidx('l')
2445endfunc
2446
2447" Tests for the QuickFixCmdPre/QuickFixCmdPost autocommands
2448func QfAutoCmdHandler(loc, cmd)
2449  call add(g:acmds, a:loc . a:cmd)
2450endfunc
2451
2452func Test_Autocmd()
2453  autocmd QuickFixCmdPre * call QfAutoCmdHandler('pre', expand('<amatch>'))
2454  autocmd QuickFixCmdPost * call QfAutoCmdHandler('post', expand('<amatch>'))
2455
2456  let g:acmds = []
2457  cexpr "F1:10:Line 10"
2458  caddexpr "F1:20:Line 20"
2459  cgetexpr "F1:30:Line 30"
2460  cexpr ""
2461  caddexpr ""
2462  cgetexpr ""
2463  silent! cexpr non_existing_func()
2464  silent! caddexpr non_existing_func()
2465  silent! cgetexpr non_existing_func()
2466  let l = ['precexpr',
2467        \ 'postcexpr',
2468        \ 'precaddexpr',
2469        \ 'postcaddexpr',
2470        \ 'precgetexpr',
2471        \ 'postcgetexpr',
2472        \ 'precexpr',
2473        \ 'postcexpr',
2474        \ 'precaddexpr',
2475        \ 'postcaddexpr',
2476        \ 'precgetexpr',
2477        \ 'postcgetexpr',
2478        \ 'precexpr',
2479        \ 'precaddexpr',
2480        \ 'precgetexpr']
2481  call assert_equal(l, g:acmds)
2482
2483  let g:acmds = []
2484  enew! | call append(0, "F2:10:Line 10")
2485  cbuffer!
2486  enew! | call append(0, "F2:20:Line 20")
2487  cgetbuffer
2488  enew! | call append(0, "F2:30:Line 30")
2489  caddbuffer
2490
2491  new
2492  let bnum = bufnr('%')
2493  bunload
2494  exe 'silent! cbuffer! ' . bnum
2495  exe 'silent! cgetbuffer ' . bnum
2496  exe 'silent! caddbuffer ' . bnum
2497  enew!
2498  let l = ['precbuffer',
2499      \ 'postcbuffer',
2500      \ 'precgetbuffer',
2501      \ 'postcgetbuffer',
2502      \ 'precaddbuffer',
2503      \ 'postcaddbuffer',
2504      \ 'precbuffer',
2505      \ 'precgetbuffer',
2506      \ 'precaddbuffer']
2507  call assert_equal(l, g:acmds)
2508
2509  call writefile(['Xtest:1:Line1'], 'Xtest')
2510  call writefile([], 'Xempty')
2511  let g:acmds = []
2512  cfile Xtest
2513  caddfile Xtest
2514  cgetfile Xtest
2515  cfile Xempty
2516  caddfile Xempty
2517  cgetfile Xempty
2518  silent! cfile do_not_exist
2519  silent! caddfile do_not_exist
2520  silent! cgetfile do_not_exist
2521  let l = ['precfile',
2522        \ 'postcfile',
2523        \ 'precaddfile',
2524        \ 'postcaddfile',
2525        \ 'precgetfile',
2526        \ 'postcgetfile',
2527        \ 'precfile',
2528        \ 'postcfile',
2529        \ 'precaddfile',
2530        \ 'postcaddfile',
2531        \ 'precgetfile',
2532        \ 'postcgetfile',
2533        \ 'precfile',
2534        \ 'postcfile',
2535        \ 'precaddfile',
2536        \ 'postcaddfile',
2537        \ 'precgetfile',
2538        \ 'postcgetfile']
2539  call assert_equal(l, g:acmds)
2540
2541  let g:acmds = []
2542  helpgrep quickfix
2543  silent! helpgrep non_existing_help_topic
2544  vimgrep test Xtest
2545  vimgrepadd test Xtest
2546  silent! vimgrep non_existing_test Xtest
2547  silent! vimgrepadd non_existing_test Xtest
2548  set makeprg=
2549  silent! make
2550  set makeprg&
2551  let l = ['prehelpgrep',
2552        \ 'posthelpgrep',
2553        \ 'prehelpgrep',
2554        \ 'posthelpgrep',
2555        \ 'previmgrep',
2556        \ 'postvimgrep',
2557        \ 'previmgrepadd',
2558        \ 'postvimgrepadd',
2559        \ 'previmgrep',
2560        \ 'postvimgrep',
2561        \ 'previmgrepadd',
2562        \ 'postvimgrepadd',
2563        \ 'premake',
2564        \ 'postmake']
2565  call assert_equal(l, g:acmds)
2566
2567  if has('unix')
2568    " Run this test only on Unix-like systems. The grepprg may not be set on
2569    " non-Unix systems.
2570    " The following lines are used for the grep test. Don't remove.
2571    " Grep_Autocmd_Text: Match 1
2572    " GrepAdd_Autocmd_Text: Match 2
2573    let g:acmds = []
2574    silent grep Grep_Autocmd_Text test_quickfix.vim
2575    silent grepadd GrepAdd_Autocmd_Text test_quickfix.vim
2576    silent grep abc123def Xtest
2577    silent grepadd abc123def Xtest
2578    set grepprg=internal
2579    silent grep Grep_Autocmd_Text test_quickfix.vim
2580    silent grepadd GrepAdd_Autocmd_Text test_quickfix.vim
2581    silent lgrep Grep_Autocmd_Text test_quickfix.vim
2582    silent lgrepadd GrepAdd_Autocmd_Text test_quickfix.vim
2583    set grepprg&vim
2584    let l = ['pregrep',
2585		\ 'postgrep',
2586		\ 'pregrepadd',
2587		\ 'postgrepadd',
2588		\ 'pregrep',
2589		\ 'postgrep',
2590		\ 'pregrepadd',
2591		\ 'postgrepadd',
2592		\ 'pregrep',
2593		\ 'postgrep',
2594		\ 'pregrepadd',
2595		\ 'postgrepadd',
2596		\ 'prelgrep',
2597		\ 'postlgrep',
2598		\ 'prelgrepadd',
2599		\ 'postlgrepadd']
2600    call assert_equal(l, g:acmds)
2601  endif
2602
2603  call delete('Xtest')
2604  call delete('Xempty')
2605  au! QuickFixCmdPre
2606  au! QuickFixCmdPost
2607endfunc
2608
2609func Test_Autocmd_Exception()
2610  set efm=%m
2611  lgetexpr '?'
2612
2613  try
2614    call DoesNotExit()
2615  catch
2616    lgetexpr '1'
2617  finally
2618    lgetexpr '1'
2619  endtry
2620
2621  call assert_equal('1', getloclist(0)[0].text)
2622
2623  set efm&vim
2624endfunc
2625
2626func Test_caddbuffer_wrong()
2627  " This used to cause a memory access in freed memory.
2628  let save_efm = &efm
2629  set efm=%EEEE%m,%WWWW,%+CCCC%>%#,%GGGG%.#
2630  cgetexpr ['WWWW', 'EEEE', 'CCCC']
2631  let &efm = save_efm
2632  caddbuffer
2633  bwipe!
2634endfunc
2635
2636func Test_caddexpr_wrong()
2637  " This used to cause a memory access in freed memory.
2638  cbuffer
2639  cbuffer
2640  copen
2641  let save_efm = &efm
2642  set efm=%
2643  call assert_fails('caddexpr ""', 'E376:')
2644  let &efm = save_efm
2645endfunc
2646
2647func Test_dirstack_cleanup()
2648  " This used to cause a memory access in freed memory.
2649  let save_efm = &efm
2650  lexpr '0'
2651  lopen
2652  fun X(c)
2653    let save_efm=&efm
2654    set efm=%D%f
2655    if a:c == 'c'
2656      caddexpr '::'
2657    else
2658      laddexpr ':0:0'
2659    endif
2660    let &efm=save_efm
2661  endfun
2662  call X('c')
2663  call X('l')
2664  call setqflist([], 'r')
2665  caddbuffer
2666  let &efm = save_efm
2667endfunc
2668
2669" Tests for jumping to entries from the location list window and quickfix
2670" window
2671func Test_cwindow_jump()
2672  set efm=%f%%%l%%%m
2673  lgetexpr ["F1%10%Line 10", "F2%20%Line 20", "F3%30%Line 30"]
2674  lopen | only
2675  lfirst
2676  call assert_true(winnr('$') == 2)
2677  call assert_true(winnr() == 1)
2678  " Location list for the new window should be set
2679  call assert_true(getloclist(0)[2].text == 'Line 30')
2680
2681  " Open a scratch buffer
2682  " Open a new window and create a location list
2683  " Open the location list window and close the other window
2684  " Jump to an entry.
2685  " Should create a new window and jump to the entry. The scrtach buffer
2686  " should not be used.
2687  enew | only
2688  set buftype=nofile
2689  below new
2690  lgetexpr ["F1%10%Line 10", "F2%20%Line 20", "F3%30%Line 30"]
2691  lopen
2692  2wincmd c
2693  lnext
2694  call assert_true(winnr('$') == 3)
2695  call assert_true(winnr() == 2)
2696
2697  " Open two windows with two different location lists
2698  " Open the location list window and close the previous window
2699  " Jump to an entry in the location list window
2700  " Should open the file in the first window and not set the location list.
2701  enew | only
2702  lgetexpr ["F1%5%Line 5"]
2703  below new
2704  lgetexpr ["F1%10%Line 10", "F2%20%Line 20", "F3%30%Line 30"]
2705  lopen
2706  2wincmd c
2707  lnext
2708  call assert_true(winnr() == 1)
2709  call assert_true(getloclist(0)[0].text == 'Line 5')
2710
2711  enew | only
2712  cgetexpr ["F1%10%Line 10", "F2%20%Line 20", "F3%30%Line 30"]
2713  copen
2714  cnext
2715  call assert_true(winnr('$') == 2)
2716  call assert_true(winnr() == 1)
2717
2718  " Jumping to a file from the location list window should find a usuable
2719  " window by wrapping around the window list.
2720  enew | only
2721  call setloclist(0, [], 'f')
2722  new | new
2723  lgetexpr ["F1%10%Line 10", "F2%20%Line 20", "F3%30%Line 30"]
2724  lopen
2725  1close
2726  call assert_equal(0, getloclist(3, {'id' : 0}).id)
2727  lnext
2728  call assert_equal(3, winnr())
2729  call assert_equal(getloclist(1, {'id' : 0}).id, getloclist(3, {'id' : 0}).id)
2730
2731  enew | only
2732  set efm&vim
2733endfunc
2734
2735func Test_cwindow_highlight()
2736  CheckScreendump
2737
2738  let lines =<< trim END
2739	call setline(1, ['some', 'text', 'with', 'matches'])
2740	write XCwindow
2741	vimgrep e XCwindow
2742	redraw
2743	cwindow 4
2744  END
2745  call writefile(lines, 'XtestCwindow')
2746  let buf = RunVimInTerminal('-S XtestCwindow', #{rows: 12})
2747  call VerifyScreenDump(buf, 'Test_quickfix_cwindow_1', {})
2748  call term_sendkeys(buf, ":cnext\<CR>")
2749  call VerifyScreenDump(buf, 'Test_quickfix_cwindow_2', {})
2750
2751  " clean up
2752  call StopVimInTerminal(buf)
2753  call delete('XtestCwindow')
2754  call delete('XCwindow')
2755endfunc
2756
2757func XvimgrepTests(cchar)
2758  call s:setup_commands(a:cchar)
2759
2760  call writefile(['Editor:VIM vim',
2761	      \ 'Editor:Emacs EmAcS',
2762	      \ 'Editor:Notepad NOTEPAD'], 'Xtestfile1')
2763  call writefile(['Linux', 'MacOS', 'MS-Windows'], 'Xtestfile2')
2764
2765  " Error cases
2766  call assert_fails('Xvimgrep /abc *', 'E682:')
2767
2768  let @/=''
2769  call assert_fails('Xvimgrep // *', 'E35:')
2770
2771  call assert_fails('Xvimgrep abc', 'E683:')
2772  call assert_fails('Xvimgrep a1b2c3 Xtestfile1', 'E480:')
2773  call assert_fails('Xvimgrep pat Xa1b2c3', 'E480:')
2774
2775  Xexpr ""
2776  Xvimgrepadd Notepad Xtestfile1
2777  Xvimgrepadd MacOS Xtestfile2
2778  let l = g:Xgetlist()
2779  call assert_equal(2, len(l))
2780  call assert_equal('Editor:Notepad NOTEPAD', l[0].text)
2781
2782  10Xvimgrep #\cvim#g Xtestfile?
2783  let l = g:Xgetlist()
2784  call assert_equal(2, len(l))
2785  call assert_equal(8, l[0].col)
2786  call assert_equal(11, l[0].end_col)
2787  call assert_equal(12, l[1].col)
2788  call assert_equal(15, l[1].end_col)
2789
2790  1Xvimgrep ?Editor? Xtestfile*
2791  let l = g:Xgetlist()
2792  call assert_equal(1, len(l))
2793  call assert_equal('Editor:VIM vim', l[0].text)
2794
2795  edit +3 Xtestfile2
2796  Xvimgrep +\cemacs+j Xtestfile1
2797  let l = g:Xgetlist()
2798  call assert_equal('Xtestfile2', bufname(''))
2799  call assert_equal('Editor:Emacs EmAcS', l[0].text)
2800
2801  " Test for unloading a buffer after vimgrep searched the buffer
2802  %bwipe
2803  Xvimgrep /Editor/j Xtestfile*
2804  call assert_equal(0, getbufinfo('Xtestfile1')[0].loaded)
2805  call assert_equal([], getbufinfo('Xtestfile2'))
2806
2807  call delete('Xtestfile1')
2808  call delete('Xtestfile2')
2809endfunc
2810
2811" Tests for the :vimgrep command
2812func Test_vimgrep()
2813  call XvimgrepTests('c')
2814  call XvimgrepTests('l')
2815endfunc
2816
2817func Test_vimgrep_wildcards_expanded_once()
2818  new X[id-01] file.txt
2819  call setline(1, 'some text to search for')
2820  vimgrep text %
2821  bwipe!
2822endfunc
2823
2824" Test for incsearch highlighting of the :vimgrep pattern
2825" This test used to cause "E315: ml_get: invalid lnum" errors.
2826func Test_vimgrep_incsearch()
2827  CheckFunction test_override
2828  enew
2829  set incsearch
2830  call test_override("char_avail", 1)
2831
2832  call feedkeys(":2vimgrep assert test_quickfix.vim test_cdo.vim\<CR>", "ntx")
2833  let l = getqflist()
2834  call assert_equal(2, len(l))
2835
2836  call test_override("ALL", 0)
2837  set noincsearch
2838endfunc
2839
2840" Test vimgrep without swap file
2841func Test_vimgrep_without_swap_file()
2842  let lines =<< trim [SCRIPT]
2843    vimgrep grep test_c*
2844    call writefile(['done'], 'Xresult')
2845    qall!
2846  [SCRIPT]
2847  call writefile(lines, 'Xscript')
2848  if RunVim([], [], '--clean -n -S Xscript Xscript')
2849    call assert_equal(['done'], readfile('Xresult'))
2850  endif
2851  call delete('Xscript')
2852  call delete('Xresult')
2853endfunc
2854
2855func Test_vimgrep_existing_swapfile()
2856  call writefile(['match apple with apple'], 'Xapple')
2857  call writefile(['swapfile'], '.Xapple.swp')
2858  let g:foundSwap = 0
2859  let g:ignoreSwapExists = 1
2860  augroup grep
2861    au SwapExists * let foundSwap = 1 | let v:swapchoice = 'e'
2862  augroup END
2863  vimgrep apple Xapple
2864  call assert_equal(1, g:foundSwap)
2865  call assert_match('.Xapple.swo', swapname(''))
2866
2867  call delete('Xapple')
2868  call delete('Xapple.swp')
2869  augroup grep
2870    au! SwapExists
2871  augroup END
2872  unlet g:ignoreSwapExists
2873endfunc
2874
2875func XfreeTests(cchar)
2876  call s:setup_commands(a:cchar)
2877
2878  enew | only
2879
2880  " Deleting the quickfix stack should work even When the current list is
2881  " somewhere in the middle of the stack
2882  Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15']
2883  Xexpr ['Xfile2:20:20:Line 20', 'Xfile2:25:25:Line 25']
2884  Xexpr ['Xfile3:30:30:Line 30', 'Xfile3:35:35:Line 35']
2885  Xolder
2886  call g:Xsetlist([], 'f')
2887  call assert_equal(0, len(g:Xgetlist()))
2888
2889  " After deleting the stack, adding a new list should create a stack with a
2890  " single list.
2891  Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15']
2892  call assert_equal(1, g:Xgetlist({'all':1}).nr)
2893
2894  " Deleting the stack from a quickfix window should update/clear the
2895  " quickfix/location list window.
2896  Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15']
2897  Xexpr ['Xfile2:20:20:Line 20', 'Xfile2:25:25:Line 25']
2898  Xexpr ['Xfile3:30:30:Line 30', 'Xfile3:35:35:Line 35']
2899  Xolder
2900  Xwindow
2901  call g:Xsetlist([], 'f')
2902  call assert_equal(2, winnr('$'))
2903  call assert_equal(1, line('$'))
2904  Xclose
2905
2906  " Deleting the stack from a non-quickfix window should update/clear the
2907  " quickfix/location list window.
2908  Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15']
2909  Xexpr ['Xfile2:20:20:Line 20', 'Xfile2:25:25:Line 25']
2910  Xexpr ['Xfile3:30:30:Line 30', 'Xfile3:35:35:Line 35']
2911  Xolder
2912  Xwindow
2913  wincmd p
2914  call g:Xsetlist([], 'f')
2915  call assert_equal(0, len(g:Xgetlist()))
2916  wincmd p
2917  call assert_equal(2, winnr('$'))
2918  call assert_equal(1, line('$'))
2919
2920  " After deleting the location list stack, if the location list window is
2921  " opened, then a new location list should be created. So opening the
2922  " location list window again should not create a new window.
2923  if a:cchar == 'l'
2924      lexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15']
2925      wincmd p
2926      lopen
2927      call assert_equal(2, winnr('$'))
2928  endif
2929  Xclose
2930endfunc
2931
2932" Tests for the quickfix free functionality
2933func Test_qf_free()
2934  call XfreeTests('c')
2935  call XfreeTests('l')
2936endfunc
2937
2938" Test for buffer overflow when parsing lines and adding new entries to
2939" the quickfix list.
2940func Test_bufoverflow()
2941  set efm=%f:%l:%m
2942  cgetexpr ['File1:100:' . repeat('x', 1025)]
2943
2944  set efm=%+GCompiler:\ %.%#,%f:%l:%m
2945  cgetexpr ['Compiler: ' . repeat('a', 1015), 'File1:10:Hello World']
2946
2947  set efm=%DEntering\ directory\ %f,%f:%l:%m
2948  cgetexpr ['Entering directory ' . repeat('a', 1006),
2949	      \ 'File1:10:Hello World']
2950  set efm&vim
2951endfunc
2952
2953" Tests for getting the quickfix stack size
2954func XsizeTests(cchar)
2955  call s:setup_commands(a:cchar)
2956
2957  call g:Xsetlist([], 'f')
2958  call assert_equal(0, g:Xgetlist({'nr':'$'}).nr)
2959  call assert_equal('', g:Xgetlist({'nr':'$', 'all':1}).title)
2960  call assert_equal(0, g:Xgetlist({'nr':0}).nr)
2961
2962  Xexpr "File1:10:Line1"
2963  Xexpr "File2:20:Line2"
2964  Xexpr "File3:30:Line3"
2965  Xolder | Xolder
2966  call assert_equal(3, g:Xgetlist({'nr':'$'}).nr)
2967  call g:Xsetlist([], 'f')
2968
2969  Xexpr "File1:10:Line1"
2970  Xexpr "File2:20:Line2"
2971  Xexpr "File3:30:Line3"
2972  Xolder | Xolder
2973  call g:Xsetlist([], 'a', {'nr':'$', 'title':'Compiler'})
2974  call assert_equal('Compiler', g:Xgetlist({'nr':3, 'all':1}).title)
2975endfunc
2976
2977func Test_Qf_Size()
2978  call XsizeTests('c')
2979  call XsizeTests('l')
2980endfunc
2981
2982func Test_cclose_from_copen()
2983    augroup QF_Test
2984	au!
2985        au FileType qf :call assert_fails(':cclose', 'E788')
2986    augroup END
2987    copen
2988    augroup QF_Test
2989	au!
2990    augroup END
2991    augroup! QF_Test
2992endfunc
2993
2994func Test_cclose_in_autocmd()
2995  " Problem is only triggered if "starting" is zero, so that the OptionsSet
2996  " event will be triggered.
2997  " call test_override('starting', 1)
2998  augroup QF_Test
2999    au!
3000    au FileType qf :call assert_fails(':cclose', 'E788')
3001  augroup END
3002  copen
3003  augroup QF_Test
3004    au!
3005  augroup END
3006  augroup! QF_Test
3007  " call test_override('starting', 0)
3008endfunc
3009
3010" Check that ":file" without an argument is possible even when curbuf is locked
3011" is set.
3012func Test_file_from_copen()
3013  " Works without argument.
3014  augroup QF_Test
3015    au!
3016    au FileType qf file
3017  augroup END
3018  copen
3019
3020  augroup QF_Test
3021    au!
3022  augroup END
3023  cclose
3024
3025  " Fails with argument.
3026  augroup QF_Test
3027    au!
3028    au FileType qf call assert_fails(':file foo', 'E788')
3029  augroup END
3030  copen
3031  augroup QF_Test
3032    au!
3033  augroup END
3034  cclose
3035
3036  augroup! QF_Test
3037endfunc
3038
3039func Test_resize_from_copen()
3040    augroup QF_Test
3041	au!
3042        au FileType qf resize 5
3043    augroup END
3044    try
3045	" This should succeed without any exception.  No other buffers are
3046	" involved in the autocmd.
3047	copen
3048    finally
3049	augroup QF_Test
3050	    au!
3051	augroup END
3052	augroup! QF_Test
3053    endtry
3054endfunc
3055
3056" Tests for the quickfix buffer b:changedtick variable
3057func Xchangedtick_tests(cchar)
3058  call s:setup_commands(a:cchar)
3059
3060  new | only
3061
3062  Xexpr "" | Xexpr "" | Xexpr ""
3063
3064  Xopen
3065  Xolder
3066  Xolder
3067  Xaddexpr "F1:10:Line10"
3068  Xaddexpr "F2:20:Line20"
3069  call g:Xsetlist([{"filename":"F3", "lnum":30, "text":"Line30"}], 'a')
3070  call g:Xsetlist([], 'f')
3071  call assert_equal(8, getbufvar('%', 'changedtick'))
3072  Xclose
3073endfunc
3074
3075func Test_changedtick()
3076  call Xchangedtick_tests('c')
3077  call Xchangedtick_tests('l')
3078endfunc
3079
3080" Tests for parsing an expression using setqflist()
3081func Xsetexpr_tests(cchar)
3082  call s:setup_commands(a:cchar)
3083
3084  let t = ["File1:10:Line10", "File1:20:Line20"]
3085  call g:Xsetlist([], ' ', {'lines' : t})
3086  call g:Xsetlist([], 'a', {'lines' : ["File1:30:Line30"]})
3087
3088  let l = g:Xgetlist()
3089  call assert_equal(3, len(l))
3090  call assert_equal(20, l[1].lnum)
3091  call assert_equal('Line30', l[2].text)
3092  call g:Xsetlist([], 'r', {'lines' : ["File2:5:Line5"]})
3093  let l = g:Xgetlist()
3094  call assert_equal(1, len(l))
3095  call assert_equal('Line5', l[0].text)
3096  call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : 10}))
3097  call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : "F1:10:L10"}))
3098
3099  call g:Xsetlist([], 'f')
3100  " Add entries to multiple lists
3101  call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:10:Line10"]})
3102  call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:20:Line20"]})
3103  call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:15:Line15"]})
3104  call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:25:Line25"]})
3105  call assert_equal('Line15', g:Xgetlist({'nr':1, 'items':1}).items[1].text)
3106  call assert_equal('Line25', g:Xgetlist({'nr':2, 'items':1}).items[1].text)
3107
3108  " Adding entries using a custom efm
3109  set efm&
3110  call g:Xsetlist([], ' ', {'efm' : '%f#%l#%m',
3111				\ 'lines' : ["F1#10#L10", "F2#20#L20"]})
3112  call assert_equal(20, g:Xgetlist({'items':1}).items[1].lnum)
3113  call g:Xsetlist([], 'a', {'efm' : '%f#%l#%m', 'lines' : ["F3:30:L30"]})
3114  call assert_equal('F3:30:L30', g:Xgetlist({'items':1}).items[2].text)
3115  call assert_equal(20, g:Xgetlist({'items':1}).items[1].lnum)
3116  call assert_equal(-1, g:Xsetlist([], 'a', {'efm' : [],
3117				\ 'lines' : ['F1:10:L10']}))
3118endfunc
3119
3120func Test_setexpr()
3121  call Xsetexpr_tests('c')
3122  call Xsetexpr_tests('l')
3123endfunc
3124
3125" Tests for per quickfix/location list directory stack
3126func Xmultidirstack_tests(cchar)
3127  call s:setup_commands(a:cchar)
3128
3129  call g:Xsetlist([], 'f')
3130  Xexpr "" | Xexpr ""
3131
3132  call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["Entering dir 'Xone/a'"]})
3133  call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["Entering dir 'Xtwo/a'"]})
3134  call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["one.txt:3:one one one"]})
3135  call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["two.txt:5:two two two"]})
3136
3137  let l1 = g:Xgetlist({'nr':1, 'items':1})
3138  let l2 = g:Xgetlist({'nr':2, 'items':1})
3139  call assert_equal(expand('Xone/a/one.txt'), bufname(l1.items[1].bufnr))
3140  call assert_equal(3, l1.items[1].lnum)
3141  call assert_equal(expand('Xtwo/a/two.txt'), bufname(l2.items[1].bufnr))
3142  call assert_equal(5, l2.items[1].lnum)
3143endfunc
3144
3145func Test_multidirstack()
3146  call mkdir('Xone/a', 'p')
3147  call mkdir('Xtwo/a', 'p')
3148  let lines = ['1', '2', 'one one one', '4', 'two two two', '6', '7']
3149  call writefile(lines, 'Xone/a/one.txt')
3150  call writefile(lines, 'Xtwo/a/two.txt')
3151  let save_efm = &efm
3152  set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f'
3153
3154  call Xmultidirstack_tests('c')
3155  call Xmultidirstack_tests('l')
3156
3157  let &efm = save_efm
3158  call delete('Xone', 'rf')
3159  call delete('Xtwo', 'rf')
3160endfunc
3161
3162" Tests for per quickfix/location list file stack
3163func Xmultifilestack_tests(cchar)
3164  call s:setup_commands(a:cchar)
3165
3166  call g:Xsetlist([], 'f')
3167  Xexpr "" | Xexpr ""
3168
3169  call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["[one.txt]"]})
3170  call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["[two.txt]"]})
3171  call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["(3,5) one one one"]})
3172  call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["(5,9) two two two"]})
3173
3174  let l1 = g:Xgetlist({'nr':1, 'items':1})
3175  let l2 = g:Xgetlist({'nr':2, 'items':1})
3176  call assert_equal('one.txt', bufname(l1.items[1].bufnr))
3177  call assert_equal(3, l1.items[1].lnum)
3178  call assert_equal('two.txt', bufname(l2.items[1].bufnr))
3179  call assert_equal(5, l2.items[1].lnum)
3180
3181  " Test for start of a new error line in the same line where a previous
3182  " error line ends with a file stack.
3183  let efm_val = 'Error\ l%l\ in\ %f,'
3184  let efm_val .= '%-P%>(%f%r,Error\ l%l\ in\ %m,%-Q)%r'
3185  let l = g:Xgetlist({'lines' : [
3186              \ '(one.txt',
3187              \ 'Error l4 in one.txt',
3188              \ ') (two.txt',
3189              \ 'Error l6 in two.txt',
3190              \ ')',
3191              \ 'Error l8 in one.txt'
3192              \ ], 'efm' : efm_val})
3193  call assert_equal(3, len(l.items))
3194  call assert_equal('one.txt', bufname(l.items[0].bufnr))
3195  call assert_equal(4, l.items[0].lnum)
3196  call assert_equal('one.txt', l.items[0].text)
3197  call assert_equal('two.txt', bufname(l.items[1].bufnr))
3198  call assert_equal(6, l.items[1].lnum)
3199  call assert_equal('two.txt', l.items[1].text)
3200  call assert_equal('one.txt', bufname(l.items[2].bufnr))
3201  call assert_equal(8, l.items[2].lnum)
3202  call assert_equal('', l.items[2].text)
3203endfunc
3204
3205func Test_multifilestack()
3206  let lines = ['1', '2', 'one one one', '4', 'two two two', '6', '7']
3207  call writefile(lines, 'one.txt')
3208  call writefile(lines, 'two.txt')
3209  let save_efm = &efm
3210  set efm=%+P[%f],(%l\\,%c)\ %m,%-Q
3211
3212  call Xmultifilestack_tests('c')
3213  call Xmultifilestack_tests('l')
3214
3215  let &efm = save_efm
3216  call delete('one.txt')
3217  call delete('two.txt')
3218endfunc
3219
3220" Tests for per buffer 'efm' setting
3221func Test_perbuf_efm()
3222  call writefile(["File1-10-Line10"], 'one.txt')
3223  call writefile(["File2#20#Line20"], 'two.txt')
3224  set efm=%f#%l#%m
3225  new | only
3226  new
3227  setlocal efm=%f-%l-%m
3228  cfile one.txt
3229  wincmd w
3230  caddfile two.txt
3231
3232  let l = getqflist()
3233  call assert_equal(10, l[0].lnum)
3234  call assert_equal('Line20', l[1].text)
3235
3236  set efm&
3237  new | only
3238  call delete('one.txt')
3239  call delete('two.txt')
3240endfunc
3241
3242" Open multiple help windows using ":lhelpgrep
3243" This test used to crash Vim
3244func Test_Multi_LL_Help()
3245    new | only
3246    lhelpgrep window
3247    lopen
3248    e#
3249    lhelpgrep buffer
3250    call assert_equal(3, winnr('$'))
3251    call assert_true(len(getloclist(1)) != 0)
3252    call assert_true(len(getloclist(2)) != 0)
3253    new | only
3254endfunc
3255
3256" Tests for adding new quickfix lists using setqflist()
3257func XaddQf_tests(cchar)
3258  call s:setup_commands(a:cchar)
3259
3260  " Create a new list using ' ' for action
3261  call g:Xsetlist([], 'f')
3262  call g:Xsetlist([], ' ', {'title' : 'Test1'})
3263  let l = g:Xgetlist({'nr' : '$', 'all' : 1})
3264  call assert_equal(1, l.nr)
3265  call assert_equal('Test1', l.title)
3266
3267  " Create a new list using ' ' for action and '$' for 'nr'
3268  call g:Xsetlist([], 'f')
3269  call g:Xsetlist([], ' ', {'title' : 'Test2', 'nr' : '$'})
3270  let l = g:Xgetlist({'nr' : '$', 'all' : 1})
3271  call assert_equal(1, l.nr)
3272  call assert_equal('Test2', l.title)
3273
3274  " Create a new list using 'a' for action
3275  call g:Xsetlist([], 'f')
3276  call g:Xsetlist([], 'a', {'title' : 'Test3'})
3277  let l = g:Xgetlist({'nr' : '$', 'all' : 1})
3278  call assert_equal(1, l.nr)
3279  call assert_equal('Test3', l.title)
3280
3281  " Create a new list using 'a' for action and '$' for 'nr'
3282  call g:Xsetlist([], 'f')
3283  call g:Xsetlist([], 'a', {'title' : 'Test3', 'nr' : '$'})
3284  call g:Xsetlist([], 'a', {'title' : 'Test4'})
3285  let l = g:Xgetlist({'nr' : '$', 'all' : 1})
3286  call assert_equal(1, l.nr)
3287  call assert_equal('Test4', l.title)
3288
3289  " Adding a quickfix list should remove all the lists following the current
3290  " list.
3291  Xexpr "" | Xexpr "" | Xexpr ""
3292  silent! 10Xolder
3293  call g:Xsetlist([], ' ', {'title' : 'Test5'})
3294  let l = g:Xgetlist({'nr' : '$', 'all' : 1})
3295  call assert_equal(2, l.nr)
3296  call assert_equal('Test5', l.title)
3297
3298  " Add a quickfix list using '$' as the list number.
3299  let lastqf = g:Xgetlist({'nr':'$'}).nr
3300  silent! 99Xolder
3301  call g:Xsetlist([], ' ', {'nr' : '$', 'title' : 'Test6'})
3302  let l = g:Xgetlist({'nr' : '$', 'all' : 1})
3303  call assert_equal(lastqf + 1, l.nr)
3304  call assert_equal('Test6', l.title)
3305
3306  " Add a quickfix list using 'nr' set to one more than the quickfix
3307  " list size.
3308  let lastqf = g:Xgetlist({'nr':'$'}).nr
3309  silent! 99Xolder
3310  call g:Xsetlist([], ' ', {'nr' : lastqf + 1, 'title' : 'Test7'})
3311  let l = g:Xgetlist({'nr' : '$', 'all' : 1})
3312  call assert_equal(lastqf + 1, l.nr)
3313  call assert_equal('Test7', l.title)
3314
3315  " Add a quickfix list to a stack with 10 lists using 'nr' set to '$'
3316  exe repeat('Xexpr "" |', 9) . 'Xexpr ""'
3317  silent! 99Xolder
3318  call g:Xsetlist([], ' ', {'nr' : '$', 'title' : 'Test8'})
3319  let l = g:Xgetlist({'nr' : '$', 'all' : 1})
3320  call assert_equal(10, l.nr)
3321  call assert_equal('Test8', l.title)
3322
3323  " Add a quickfix list using 'nr' set to a value greater than 10
3324  call assert_equal(-1, g:Xsetlist([], ' ', {'nr' : 12, 'title' : 'Test9'}))
3325
3326  " Try adding a quickfix list with 'nr' set to a value greater than the
3327  " quickfix list size but less than 10.
3328  call g:Xsetlist([], 'f')
3329  Xexpr "" | Xexpr "" | Xexpr ""
3330  silent! 99Xolder
3331  call assert_equal(-1, g:Xsetlist([], ' ', {'nr' : 8, 'title' : 'Test10'}))
3332
3333  " Add a quickfix list using 'nr' set to a some string or list
3334  call assert_equal(-1, g:Xsetlist([], ' ', {'nr' : [1,2], 'title' : 'Test11'}))
3335endfunc
3336
3337func Test_add_qf()
3338  call XaddQf_tests('c')
3339  call XaddQf_tests('l')
3340endfunc
3341
3342" Test for getting the quickfix list items from some text without modifying
3343" the quickfix stack
3344func XgetListFromLines(cchar)
3345  call s:setup_commands(a:cchar)
3346  call g:Xsetlist([], 'f')
3347
3348  let l = g:Xgetlist({'lines' : ["File2:20:Line20", "File2:30:Line30"]}).items
3349  call assert_equal(2, len(l))
3350  call assert_equal(30, l[1].lnum)
3351
3352  call assert_equal({}, g:Xgetlist({'lines' : 10}))
3353  call assert_equal({}, g:Xgetlist({'lines' : 'File1:10:Line10'}))
3354  call assert_equal([], g:Xgetlist({'lines' : []}).items)
3355  call assert_equal([], g:Xgetlist({'lines' : [10, 20]}).items)
3356
3357  " Parse text using a custom efm
3358  set efm&
3359  let l = g:Xgetlist({'lines':['File3#30#Line30'], 'efm' : '%f#%l#%m'}).items
3360  call assert_equal('Line30', l[0].text)
3361  let l = g:Xgetlist({'lines':['File3:30:Line30'], 'efm' : '%f-%l-%m'}).items
3362  call assert_equal('File3:30:Line30', l[0].text)
3363  let l = g:Xgetlist({'lines':['File3:30:Line30'], 'efm' : [1,2]})
3364  call assert_equal({}, l)
3365  call assert_fails("call g:Xgetlist({'lines':['abc'], 'efm':'%2'})", 'E376:')
3366  call assert_fails("call g:Xgetlist({'lines':['abc'], 'efm':''})", 'E378:')
3367
3368  " Make sure that the quickfix stack is not modified
3369  call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
3370endfunc
3371
3372func Test_get_list_from_lines()
3373  call XgetListFromLines('c')
3374  call XgetListFromLines('l')
3375endfunc
3376
3377" Tests for the quickfix list id
3378func Xqfid_tests(cchar)
3379  call s:setup_commands(a:cchar)
3380
3381  call g:Xsetlist([], 'f')
3382  call assert_equal(0, g:Xgetlist({'id':0}).id)
3383  Xexpr ''
3384  let start_id = g:Xgetlist({'id' : 0}).id
3385  Xexpr '' | Xexpr ''
3386  Xolder
3387  call assert_equal(start_id, g:Xgetlist({'id':0, 'nr':1}).id)
3388  call assert_equal(start_id + 1, g:Xgetlist({'id':0, 'nr':0}).id)
3389  call assert_equal(start_id + 2, g:Xgetlist({'id':0, 'nr':'$'}).id)
3390  call assert_equal(0, g:Xgetlist({'id':0, 'nr':99}).id)
3391  call assert_equal(2, g:Xgetlist({'id':start_id + 1, 'nr':0}).nr)
3392  call assert_equal(0, g:Xgetlist({'id':99, 'nr':0}).id)
3393  call assert_equal(0, g:Xgetlist({'id':"abc", 'nr':0}).id)
3394
3395  call g:Xsetlist([], 'a', {'id':start_id, 'context':[1,2]})
3396  call assert_equal([1,2], g:Xgetlist({'nr':1, 'context':1}).context)
3397  call g:Xsetlist([], 'a', {'id':start_id+1, 'lines':['F1:10:L10']})
3398  call assert_equal('L10', g:Xgetlist({'nr':2, 'items':1}).items[0].text)
3399  call assert_equal(-1, g:Xsetlist([], 'a', {'id':999, 'title':'Vim'}))
3400  call assert_equal(-1, g:Xsetlist([], 'a', {'id':'abc', 'title':'Vim'}))
3401
3402  let qfid = g:Xgetlist({'id':0, 'nr':0})
3403  call g:Xsetlist([], 'f')
3404  call assert_equal(0, g:Xgetlist({'id':qfid, 'nr':0}).id)
3405endfunc
3406
3407func Test_qf_id()
3408  call Xqfid_tests('c')
3409  call Xqfid_tests('l')
3410endfunc
3411
3412func Xqfjump_tests(cchar)
3413  call s:setup_commands(a:cchar)
3414
3415  call writefile(["Line1\tFoo", "Line2"], 'F1')
3416  call writefile(["Line1\tBar", "Line2"], 'F2')
3417  call writefile(["Line1\tBaz", "Line2"], 'F3')
3418
3419  call g:Xsetlist([], 'f')
3420
3421  " Tests for
3422  "   Jumping to a line using a pattern
3423  "   Jumping to a column greater than the last column in a line
3424  "   Jumping to a line greater than the last line in the file
3425  let l = []
3426  for i in range(1, 7)
3427    call add(l, {})
3428  endfor
3429  let l[0].filename='F1'
3430  let l[0].pattern='Line1'
3431  let l[1].filename='F2'
3432  let l[1].pattern='Line1'
3433  let l[2].filename='F3'
3434  let l[2].pattern='Line1'
3435  let l[3].filename='F3'
3436  let l[3].lnum=1
3437  let l[3].col=9
3438  let l[3].vcol=1
3439  let l[4].filename='F3'
3440  let l[4].lnum=99
3441  let l[5].filename='F3'
3442  let l[5].lnum=1
3443  let l[5].col=99
3444  let l[5].vcol=1
3445  let l[6].filename='F3'
3446  let l[6].pattern='abcxyz'
3447
3448  call g:Xsetlist([], ' ', {'items' : l})
3449  Xopen | only
3450  2Xnext
3451  call assert_equal(3, g:Xgetlist({'idx' : 0}).idx)
3452  call assert_equal('F3', bufname('%'))
3453  Xnext
3454  call assert_equal(7, col('.'))
3455  Xnext
3456  call assert_equal(2, line('.'))
3457  Xnext
3458  call assert_equal(9, col('.'))
3459  2
3460  Xnext
3461  call assert_equal(2, line('.'))
3462
3463  if a:cchar == 'l'
3464    " When jumping to a location list entry in the location list window and
3465    " no usable windows are available, then a new window should be opened.
3466    enew! | new | only
3467    call g:Xsetlist([], 'f')
3468    setlocal buftype=nofile
3469    new
3470    call g:Xsetlist([], ' ', {'lines' : ['F1:1:1:Line1', 'F1:2:2:Line2', 'F2:1:1:Line1', 'F2:2:2:Line2', 'F3:1:1:Line1', 'F3:2:2:Line2']})
3471    Xopen
3472    let winid = win_getid()
3473    wincmd p
3474    close
3475    call win_gotoid(winid)
3476    Xnext
3477    call assert_equal(3, winnr('$'))
3478    call assert_equal(1, winnr())
3479    call assert_equal(2, line('.'))
3480
3481    " When jumping to an entry in the location list window and the window
3482    " associated with the location list is not present and a window containing
3483    " the file is already present, then that window should be used.
3484    close
3485    belowright new
3486    call g:Xsetlist([], 'f')
3487    edit F3
3488    call win_gotoid(winid)
3489    Xlast
3490    call assert_equal(3, winnr())
3491    call assert_equal(6, g:Xgetlist({'size' : 1}).size)
3492    call assert_equal(winid, g:Xgetlist({'winid' : 1}).winid)
3493  endif
3494
3495  " Cleanup
3496  enew!
3497  new | only
3498
3499  call delete('F1')
3500  call delete('F2')
3501  call delete('F3')
3502endfunc
3503
3504func Test_qfjump()
3505  call Xqfjump_tests('c')
3506  call Xqfjump_tests('l')
3507endfunc
3508
3509" Tests for the getqflist() and getloclist() functions when the list is not
3510" present or is empty
3511func Xgetlist_empty_tests(cchar)
3512  call s:setup_commands(a:cchar)
3513
3514  " Empty quickfix stack
3515  call g:Xsetlist([], 'f')
3516  call assert_equal('', g:Xgetlist({'context' : 0}).context)
3517  call assert_equal(0, g:Xgetlist({'id' : 0}).id)
3518  call assert_equal(0, g:Xgetlist({'idx' : 0}).idx)
3519  call assert_equal([], g:Xgetlist({'items' : 0}).items)
3520  call assert_equal(0, g:Xgetlist({'nr' : 0}).nr)
3521  call assert_equal(0, g:Xgetlist({'size' : 0}).size)
3522  call assert_equal('', g:Xgetlist({'title' : 0}).title)
3523  call assert_equal(0, g:Xgetlist({'winid' : 0}).winid)
3524  call assert_equal(0, g:Xgetlist({'changedtick' : 0}).changedtick)
3525  if a:cchar == 'c'
3526    call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
3527		  \ 'items' : [], 'nr' : 0, 'size' : 0,
3528		  \ 'title' : '', 'winid' : 0, 'changedtick': 0,
3529                  \ 'quickfixtextfunc' : ''}, g:Xgetlist({'all' : 0}))
3530  else
3531    call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
3532		\ 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '',
3533		\ 'winid' : 0, 'changedtick': 0, 'filewinid' : 0,
3534		\ 'quickfixtextfunc' : ''},
3535		\ g:Xgetlist({'all' : 0}))
3536  endif
3537
3538  " Quickfix window with empty stack
3539  silent! Xopen
3540  let qfwinid = (a:cchar == 'c') ? win_getid() : 0
3541  call assert_equal(qfwinid, g:Xgetlist({'winid' : 0}).winid)
3542  Xclose
3543
3544  " Empty quickfix list
3545  Xexpr ""
3546  call assert_equal('', g:Xgetlist({'context' : 0}).context)
3547  call assert_notequal(0, g:Xgetlist({'id' : 0}).id)
3548  call assert_equal(0, g:Xgetlist({'idx' : 0}).idx)
3549  call assert_equal([], g:Xgetlist({'items' : 0}).items)
3550  call assert_notequal(0, g:Xgetlist({'nr' : 0}).nr)
3551  call assert_equal(0, g:Xgetlist({'size' : 0}).size)
3552  call assert_notequal('', g:Xgetlist({'title' : 0}).title)
3553  call assert_equal(0, g:Xgetlist({'winid' : 0}).winid)
3554  call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
3555
3556  let qfid = g:Xgetlist({'id' : 0}).id
3557  call g:Xsetlist([], 'f')
3558
3559  " Non-existing quickfix identifier
3560  call assert_equal('', g:Xgetlist({'id' : qfid, 'context' : 0}).context)
3561  call assert_equal(0, g:Xgetlist({'id' : qfid}).id)
3562  call assert_equal(0, g:Xgetlist({'id' : qfid, 'idx' : 0}).idx)
3563  call assert_equal([], g:Xgetlist({'id' : qfid, 'items' : 0}).items)
3564  call assert_equal(0, g:Xgetlist({'id' : qfid, 'nr' : 0}).nr)
3565  call assert_equal(0, g:Xgetlist({'id' : qfid, 'size' : 0}).size)
3566  call assert_equal('', g:Xgetlist({'id' : qfid, 'title' : 0}).title)
3567  call assert_equal(0, g:Xgetlist({'id' : qfid, 'winid' : 0}).winid)
3568  call assert_equal(0, g:Xgetlist({'id' : qfid, 'changedtick' : 0}).changedtick)
3569  if a:cchar == 'c'
3570    call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
3571		\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
3572		\ 'quickfixtextfunc' : '',
3573		\ 'changedtick' : 0}, g:Xgetlist({'id' : qfid, 'all' : 0}))
3574  else
3575    call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
3576		\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
3577		\ 'changedtick' : 0, 'filewinid' : 0,
3578                \ 'quickfixtextfunc' : ''},
3579		\ g:Xgetlist({'id' : qfid, 'all' : 0}))
3580  endif
3581
3582  " Non-existing quickfix list number
3583  call assert_equal('', g:Xgetlist({'nr' : 5, 'context' : 0}).context)
3584  call assert_equal(0, g:Xgetlist({'nr' : 5}).nr)
3585  call assert_equal(0, g:Xgetlist({'nr' : 5, 'idx' : 0}).idx)
3586  call assert_equal([], g:Xgetlist({'nr' : 5, 'items' : 0}).items)
3587  call assert_equal(0, g:Xgetlist({'nr' : 5, 'id' : 0}).id)
3588  call assert_equal(0, g:Xgetlist({'nr' : 5, 'size' : 0}).size)
3589  call assert_equal('', g:Xgetlist({'nr' : 5, 'title' : 0}).title)
3590  call assert_equal(0, g:Xgetlist({'nr' : 5, 'winid' : 0}).winid)
3591  call assert_equal(0, g:Xgetlist({'nr' : 5, 'changedtick' : 0}).changedtick)
3592  if a:cchar == 'c'
3593    call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
3594		\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
3595		\ 'changedtick' : 0,
3596                \ 'quickfixtextfunc' : ''}, g:Xgetlist({'nr' : 5, 'all' : 0}))
3597  else
3598    call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
3599		\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
3600		\ 'changedtick' : 0, 'filewinid' : 0,
3601                \ 'quickfixtextfunc' : ''}, g:Xgetlist({'nr' : 5, 'all' : 0}))
3602  endif
3603endfunc
3604
3605func Test_getqflist()
3606  call Xgetlist_empty_tests('c')
3607  call Xgetlist_empty_tests('l')
3608endfunc
3609
3610
3611func Test_getqflist_invalid_nr()
3612  " The following commands used to crash Vim
3613  cexpr ""
3614  call getqflist({'nr' : $XXX_DOES_NOT_EXIST_XXX})
3615
3616  " Cleanup
3617  call setqflist([], 'r')
3618endfunc
3619
3620" Tests for the quickfix/location list changedtick
3621func Xqftick_tests(cchar)
3622  call s:setup_commands(a:cchar)
3623
3624  call g:Xsetlist([], 'f')
3625
3626  Xexpr "F1:10:Line10"
3627  let qfid = g:Xgetlist({'id' : 0}).id
3628  call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
3629  Xaddexpr "F2:20:Line20\nF2:21:Line21"
3630  call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
3631  call g:Xsetlist([], 'a', {'lines' : ["F3:30:Line30", "F3:31:Line31"]})
3632  call assert_equal(3, g:Xgetlist({'changedtick' : 0}).changedtick)
3633  call g:Xsetlist([], 'r', {'lines' : ["F4:40:Line40"]})
3634  call assert_equal(4, g:Xgetlist({'changedtick' : 0}).changedtick)
3635  call g:Xsetlist([], 'a', {'title' : 'New Title'})
3636  call assert_equal(5, g:Xgetlist({'changedtick' : 0}).changedtick)
3637
3638  enew!
3639  call append(0, ["F5:50:L50", "F6:60:L60"])
3640  Xaddbuffer
3641  call assert_equal(6, g:Xgetlist({'changedtick' : 0}).changedtick)
3642  enew!
3643
3644  call g:Xsetlist([], 'a', {'context' : {'bus' : 'pci'}})
3645  call assert_equal(7, g:Xgetlist({'changedtick' : 0}).changedtick)
3646  call g:Xsetlist([{'filename' : 'F7', 'lnum' : 10, 'text' : 'L7'},
3647	      \ {'filename' : 'F7', 'lnum' : 11, 'text' : 'L11'}], 'a')
3648  call assert_equal(8, g:Xgetlist({'changedtick' : 0}).changedtick)
3649  call g:Xsetlist([{'filename' : 'F7', 'lnum' : 10, 'text' : 'L7'},
3650	      \ {'filename' : 'F7', 'lnum' : 11, 'text' : 'L11'}], ' ')
3651  call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
3652  call g:Xsetlist([{'filename' : 'F7', 'lnum' : 10, 'text' : 'L7'},
3653	      \ {'filename' : 'F7', 'lnum' : 11, 'text' : 'L11'}], 'r')
3654  call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
3655
3656  if isdirectory("Xone")
3657    call delete("Xone", 'rf')
3658  endif
3659  call writefile(["F8:80:L80", "F8:81:L81"], "Xone")
3660  Xfile Xone
3661  call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
3662  Xaddfile Xone
3663  call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
3664
3665  " Test case for updating a non-current quickfix list
3666  call g:Xsetlist([], 'f')
3667  Xexpr "F1:1:L1"
3668  Xexpr "F2:2:L2"
3669  call g:Xsetlist([], 'a', {'nr' : 1, "lines" : ["F10:10:L10"]})
3670  call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
3671  call assert_equal(2, g:Xgetlist({'nr' : 1, 'changedtick' : 0}).changedtick)
3672
3673  call delete("Xone")
3674endfunc
3675
3676func Test_qf_tick()
3677  call Xqftick_tests('c')
3678  call Xqftick_tests('l')
3679endfunc
3680
3681" Test helpgrep with lang specifier
3682func Xtest_helpgrep_with_lang_specifier(cchar)
3683  call s:setup_commands(a:cchar)
3684  Xhelpgrep Vim@en
3685  call assert_equal('help', &filetype)
3686  call assert_notequal(0, g:Xgetlist({'nr' : '$'}).nr)
3687  new | only
3688endfunc
3689
3690func Test_helpgrep_with_lang_specifier()
3691  call Xtest_helpgrep_with_lang_specifier('c')
3692  call Xtest_helpgrep_with_lang_specifier('l')
3693endfunc
3694
3695" The following test used to crash Vim.
3696" Open the location list window and close the regular window associated with
3697" the location list. When the garbage collection runs now, it incorrectly
3698" marks the location list context as not in use and frees the context.
3699func Test_ll_window_ctx()
3700  call setloclist(0, [], 'f')
3701  call setloclist(0, [], 'a', {'context' : []})
3702  lopen | only
3703  call test_garbagecollect_now()
3704  echo getloclist(0, {'context' : 1}).context
3705  enew | only
3706endfunc
3707
3708" The following test used to crash vim
3709func Test_lfile_crash()
3710  sp Xtest
3711  au QuickFixCmdPre * bw
3712  call assert_fails('lfile', 'E40')
3713  au! QuickFixCmdPre
3714endfunc
3715
3716" The following test used to crash vim
3717func Test_lbuffer_crash()
3718  sv Xtest
3719  augroup QF_Test
3720    au!
3721    au QuickFixCmdPre,QuickFixCmdPost,BufEnter,BufLeave * bw
3722  augroup END
3723  lbuffer
3724  augroup QF_Test
3725    au!
3726  augroup END
3727endfunc
3728
3729" The following test used to crash vim
3730func Test_lexpr_crash()
3731  augroup QF_Test
3732    au!
3733    au QuickFixCmdPre,QuickFixCmdPost,BufEnter,BufLeave * call setloclist(0, [], 'f')
3734  augroup END
3735  lexpr ""
3736  augroup QF_Test
3737    au!
3738  augroup END
3739
3740  enew | only
3741  augroup QF_Test
3742    au!
3743    au BufNew * call setloclist(0, [], 'f')
3744  augroup END
3745  lexpr 'x:1:x'
3746  augroup QF_Test
3747    au!
3748  augroup END
3749
3750  enew | only
3751  lexpr ''
3752  lopen
3753  augroup QF_Test
3754    au!
3755    au FileType * call setloclist(0, [], 'f')
3756  augroup END
3757  lexpr ''
3758  augroup QF_Test
3759    au!
3760  augroup END
3761endfunc
3762
3763" The following test used to crash Vim
3764func Test_lvimgrep_crash()
3765  sv Xtest
3766  augroup QF_Test
3767    au!
3768    au QuickFixCmdPre,QuickFixCmdPost,BufEnter,BufLeave * call setloclist(0, [], 'f')
3769  augroup END
3770  lvimgrep quickfix test_quickfix.vim
3771  augroup QF_Test
3772    au!
3773  augroup END
3774
3775  new | only
3776  augroup QF_Test
3777    au!
3778    au BufEnter * call setloclist(0, [], 'r')
3779  augroup END
3780  call assert_fails('lvimgrep Test_lvimgrep_crash *', 'E926:')
3781  augroup QF_Test
3782    au!
3783  augroup END
3784
3785  enew | only
3786endfunc
3787
3788func Test_lvimgrep_crash2()
3789  au BufNewFile x sfind
3790  call assert_fails('lvimgrep x x', 'E480:')
3791  call assert_fails('lvimgrep x x x', 'E480:')
3792
3793  au! BufNewFile
3794endfunc
3795
3796" Test for the position of the quickfix and location list window
3797func Test_qfwin_pos()
3798  " Open two windows
3799  new | only
3800  new
3801  cexpr ['F1:10:L10']
3802  copen
3803  " Quickfix window should be the bottom most window
3804  call assert_equal(3, winnr())
3805  close
3806  " Open at the very top
3807  wincmd t
3808  topleft copen
3809  call assert_equal(1, winnr())
3810  close
3811  " open left of the current window
3812  wincmd t
3813  below new
3814  leftabove copen
3815  call assert_equal(2, winnr())
3816  close
3817  " open right of the current window
3818  rightbelow copen
3819  call assert_equal(3, winnr())
3820  close
3821endfunc
3822
3823" Tests for quickfix/location lists changed by autocommands when
3824" :vimgrep/:lvimgrep commands are running.
3825func Test_vimgrep_autocmd()
3826  call setqflist([], 'f')
3827  call writefile(['stars'], 'Xtest1.txt')
3828  call writefile(['stars'], 'Xtest2.txt')
3829
3830  " Test 1:
3831  " When searching for a pattern using :vimgrep, if the quickfix list is
3832  " changed by an autocmd, the results should be added to the correct quickfix
3833  " list.
3834  autocmd BufRead Xtest2.txt cexpr '' | cexpr ''
3835  silent vimgrep stars Xtest*.txt
3836  call assert_equal(1, getqflist({'nr' : 0}).nr)
3837  call assert_equal(3, getqflist({'nr' : '$'}).nr)
3838  call assert_equal('Xtest2.txt', bufname(getqflist()[1].bufnr))
3839  au! BufRead Xtest2.txt
3840
3841  " Test 2:
3842  " When searching for a pattern using :vimgrep, if the quickfix list is
3843  " freed, then a error should be given.
3844  silent! %bwipe!
3845  call setqflist([], 'f')
3846  autocmd BufRead Xtest2.txt for i in range(10) | cexpr '' | endfor
3847  call assert_fails('vimgrep stars Xtest*.txt', 'E925:')
3848  au! BufRead Xtest2.txt
3849
3850  " Test 3:
3851  " When searching for a pattern using :lvimgrep, if the location list is
3852  " freed, then the command should error out.
3853  silent! %bwipe!
3854  let g:save_winid = win_getid()
3855  autocmd BufRead Xtest2.txt call setloclist(g:save_winid, [], 'f')
3856  call assert_fails('lvimgrep stars Xtest*.txt', 'E926:')
3857  au! BufRead Xtest2.txt
3858
3859  call delete('Xtest1.txt')
3860  call delete('Xtest2.txt')
3861  call setqflist([], 'f')
3862endfunc
3863
3864" Test for an autocmd changing the current directory when running vimgrep
3865func Xvimgrep_autocmd_cd(cchar)
3866  call s:setup_commands(a:cchar)
3867
3868  %bwipe
3869  let save_cwd = getcwd()
3870
3871  augroup QF_Test
3872    au!
3873    autocmd BufRead * silent cd %:p:h
3874  augroup END
3875
3876  10Xvimgrep /vim/ Xdir/**
3877  let l = g:Xgetlist()
3878  call assert_equal('f1.txt', bufname(l[0].bufnr))
3879  call assert_equal('f2.txt', fnamemodify(bufname(l[2].bufnr), ':t'))
3880
3881  augroup QF_Test
3882    au!
3883  augroup END
3884
3885  exe 'cd ' . save_cwd
3886endfunc
3887
3888func Test_vimgrep_autocmd_cd()
3889  call mkdir('Xdir/a', 'p')
3890  call mkdir('Xdir/b', 'p')
3891  call writefile(['a_L1_vim', 'a_L2_vim'], 'Xdir/a/f1.txt')
3892  call writefile(['b_L1_vim', 'b_L2_vim'], 'Xdir/b/f2.txt')
3893  call Xvimgrep_autocmd_cd('c')
3894  call Xvimgrep_autocmd_cd('l')
3895  %bwipe
3896  call delete('Xdir', 'rf')
3897endfunc
3898
3899" The following test used to crash Vim
3900func Test_lhelpgrep_autocmd()
3901  lhelpgrep quickfix
3902  autocmd QuickFixCmdPost * call setloclist(0, [], 'f')
3903  lhelpgrep buffer
3904  call assert_equal('help', &filetype)
3905  call assert_equal(0, getloclist(0, {'nr' : '$'}).nr)
3906  lhelpgrep tabpage
3907  call assert_equal('help', &filetype)
3908  call assert_equal(1, getloclist(0, {'nr' : '$'}).nr)
3909  au! QuickFixCmdPost
3910
3911  new | only
3912  augroup QF_Test
3913    au!
3914    au BufEnter * call setqflist([], 'f')
3915  augroup END
3916  call assert_fails('helpgrep quickfix', 'E925:')
3917  " run the test with a help window already open
3918  help
3919  wincmd w
3920  call assert_fails('helpgrep quickfix', 'E925:')
3921  augroup QF_Test
3922    au! BufEnter
3923  augroup END
3924
3925  new | only
3926  augroup QF_Test
3927    au!
3928    au BufEnter * call setqflist([], 'r')
3929  augroup END
3930  call assert_fails('helpgrep quickfix', 'E925:')
3931  augroup QF_Test
3932    au! BufEnter
3933  augroup END
3934
3935  new | only
3936  augroup QF_Test
3937    au!
3938    au BufEnter * call setloclist(0, [], 'r')
3939  augroup END
3940  call assert_fails('lhelpgrep quickfix', 'E926:')
3941  augroup QF_Test
3942    au! BufEnter
3943  augroup END
3944
3945  new | only
3946endfunc
3947
3948" Test for shortening/simplifying the file name when opening the
3949" quickfix window or when displaying the quickfix list
3950func Test_shorten_fname()
3951  if !has('unix')
3952    return
3953  endif
3954  %bwipe
3955  " Create a quickfix list with a absolute path filename
3956  let fname = getcwd() . '/test_quickfix.vim'
3957  call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'})
3958  call assert_equal(fname, bufname('test_quickfix.vim'))
3959  " Opening the quickfix window should simplify the file path
3960  cwindow
3961  call assert_equal('test_quickfix.vim', bufname('test_quickfix.vim'))
3962  cclose
3963  %bwipe
3964  " Create a quickfix list with a absolute path filename
3965  call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'})
3966  call assert_equal(fname, bufname('test_quickfix.vim'))
3967  " Displaying the quickfix list should simplify the file path
3968  silent! clist
3969  call assert_equal('test_quickfix.vim', bufname('test_quickfix.vim'))
3970  " Add a few entries for the same file with different paths and check whether
3971  " the buffer name is shortened
3972  %bwipe
3973  call setqflist([], 'f')
3974  call setqflist([{'filename' : 'test_quickfix.vim', 'lnum' : 10},
3975        \ {'filename' : '../testdir/test_quickfix.vim', 'lnum' : 20},
3976        \ {'filename' : fname, 'lnum' : 30}], ' ')
3977  copen
3978  call assert_equal(['test_quickfix.vim|10| ',
3979        \ 'test_quickfix.vim|20| ',
3980        \ 'test_quickfix.vim|30| '], getline(1, '$'))
3981  cclose
3982endfunc
3983
3984" Quickfix title tests
3985" In the below tests, 'exe "cmd"' is used to invoke the quickfix commands.
3986" Otherwise due to indentation, the title is set with spaces at the beginning
3987" of the command.
3988func Test_qftitle()
3989  call writefile(["F1:1:Line1"], 'Xerr')
3990
3991  " :cexpr
3992  exe "cexpr readfile('Xerr')"
3993  call assert_equal(":cexpr readfile('Xerr')", getqflist({'title' : 1}).title)
3994
3995  " :cgetexpr
3996  exe "cgetexpr readfile('Xerr')"
3997  call assert_equal(":cgetexpr readfile('Xerr')",
3998					\ getqflist({'title' : 1}).title)
3999
4000  " :caddexpr
4001  call setqflist([], 'f')
4002  exe "caddexpr readfile('Xerr')"
4003  call assert_equal(":caddexpr readfile('Xerr')",
4004					\ getqflist({'title' : 1}).title)
4005
4006  " :cbuffer
4007  new Xerr
4008  exe "cbuffer"
4009  call assert_equal(':cbuffer (Xerr)', getqflist({'title' : 1}).title)
4010
4011  " :cgetbuffer
4012  edit Xerr
4013  exe "cgetbuffer"
4014  call assert_equal(':cgetbuffer (Xerr)', getqflist({'title' : 1}).title)
4015
4016  " :caddbuffer
4017  call setqflist([], 'f')
4018  edit Xerr
4019  exe "caddbuffer"
4020  call assert_equal(':caddbuffer (Xerr)', getqflist({'title' : 1}).title)
4021
4022  " :cfile
4023  exe "cfile Xerr"
4024  call assert_equal(':cfile Xerr', getqflist({'title' : 1}).title)
4025
4026  " :cgetfile
4027  exe "cgetfile Xerr"
4028  call assert_equal(':cgetfile Xerr', getqflist({'title' : 1}).title)
4029
4030  " :caddfile
4031  call setqflist([], 'f')
4032  exe "caddfile Xerr"
4033  call assert_equal(':caddfile Xerr', getqflist({'title' : 1}).title)
4034
4035  " :grep
4036  set grepprg=internal
4037  exe "grep F1 Xerr"
4038  call assert_equal(':grep F1 Xerr', getqflist({'title' : 1}).title)
4039
4040  " :grepadd
4041  call setqflist([], 'f')
4042  exe "grepadd F1 Xerr"
4043  call assert_equal(':grepadd F1 Xerr', getqflist({'title' : 1}).title)
4044  set grepprg&vim
4045
4046  " :vimgrep
4047  exe "vimgrep F1 Xerr"
4048  call assert_equal(':vimgrep F1 Xerr', getqflist({'title' : 1}).title)
4049
4050  " :vimgrepadd
4051  call setqflist([], 'f')
4052  exe "vimgrepadd F1 Xerr"
4053  call assert_equal(':vimgrepadd F1 Xerr', getqflist({'title' : 1}).title)
4054
4055  call setqflist(['F1:10:L10'], ' ')
4056  call assert_equal(':setqflist()', getqflist({'title' : 1}).title)
4057
4058  call setqflist([], 'f')
4059  call setqflist(['F1:10:L10'], 'a')
4060  call assert_equal(':setqflist()', getqflist({'title' : 1}).title)
4061
4062  call setqflist([], 'f')
4063  call setqflist(['F1:10:L10'], 'r')
4064  call assert_equal(':setqflist()', getqflist({'title' : 1}).title)
4065
4066  close
4067  call delete('Xerr')
4068
4069  call setqflist([], ' ', {'title' : 'Errors'})
4070  copen
4071  call assert_equal('Errors', w:quickfix_title)
4072  call setqflist([], 'r', {'items' : [{'filename' : 'a.c', 'lnum' : 10}]})
4073  call assert_equal('Errors', w:quickfix_title)
4074  cclose
4075
4076  " Switching to another quickfix list in one tab page should update the
4077  " quickfix window title and statusline in all the other tab pages also
4078  call setqflist([], 'f')
4079  %bw!
4080  cgetexpr ['file_one:1:1: error in the first quickfix list']
4081  call setqflist([], 'a', {'title': 'first quickfix list'})
4082  cgetexpr ['file_two:2:1: error in the second quickfix list']
4083  call setqflist([], 'a', {'title': 'second quickfix list'})
4084  copen
4085  wincmd t
4086  tabnew two
4087  copen
4088  wincmd t
4089  colder
4090  call assert_equal('first quickfix list', gettabwinvar(1, 2, 'quickfix_title'))
4091  call assert_equal('first quickfix list', gettabwinvar(2, 2, 'quickfix_title'))
4092  call assert_equal(1, tabpagewinnr(1))
4093  call assert_equal(1, tabpagewinnr(2))
4094  tabnew
4095  call setqflist([], 'a', {'title': 'new quickfix title'})
4096  call assert_equal('new quickfix title', gettabwinvar(1, 2, 'quickfix_title'))
4097  call assert_equal('new quickfix title', gettabwinvar(2, 2, 'quickfix_title'))
4098  %bw!
4099endfunc
4100
4101func Test_lbuffer_with_bwipe()
4102  new
4103  new
4104  augroup nasty
4105    au QuickFixCmdPre,QuickFixCmdPost,BufEnter,BufLeave * bwipe
4106  augroup END
4107  lbuffer
4108  augroup nasty
4109    au!
4110  augroup END
4111endfunc
4112
4113" Test for an autocmd freeing the quickfix/location list when cexpr/lexpr is
4114" running
4115func Xexpr_acmd_freelist(cchar)
4116  call s:setup_commands(a:cchar)
4117
4118  " This was using freed memory (but with what events?)
4119  augroup nasty
4120    au QuickFixCmdPre,QuickFixCmdPost,BufEnter,BufLeave * call g:Xsetlist([], 'f')
4121  augroup END
4122  Xexpr "x"
4123  augroup nasty
4124    au!
4125  augroup END
4126endfunc
4127
4128func Test_cexpr_acmd_freelist()
4129  call Xexpr_acmd_freelist('c')
4130  call Xexpr_acmd_freelist('l')
4131endfunc
4132
4133" Test for commands that create a new quickfix/location list and jump to the
4134" first error automatically.
4135func Xjumpto_first_error_test(cchar)
4136  call s:setup_commands(a:cchar)
4137
4138  call s:create_test_file('Xtestfile1')
4139  call s:create_test_file('Xtestfile2')
4140  let l = ['Xtestfile1:2:Line2', 'Xtestfile2:4:Line4']
4141
4142  " Test for cexpr/lexpr
4143  enew
4144  Xexpr l
4145  call assert_equal('Xtestfile1', bufname(''))
4146  call assert_equal(2, line('.'))
4147
4148  " Test for cfile/lfile
4149  enew
4150  call writefile(l, 'Xerr')
4151  Xfile Xerr
4152  call assert_equal('Xtestfile1', bufname(''))
4153  call assert_equal(2, line('.'))
4154
4155  " Test for cbuffer/lbuffer
4156  edit Xerr
4157  Xbuffer
4158  call assert_equal('Xtestfile1', bufname(''))
4159  call assert_equal(2, line('.'))
4160
4161  call delete('Xerr')
4162  call delete('Xtestfile1')
4163  call delete('Xtestfile2')
4164endfunc
4165
4166func Test_jumpto_first_error()
4167  call Xjumpto_first_error_test('c')
4168  call Xjumpto_first_error_test('l')
4169endfunc
4170
4171" Test for a quickfix autocmd changing the quickfix/location list before
4172" jumping to the first error in the new list.
4173func Xautocmd_changelist(cchar)
4174  call s:setup_commands(a:cchar)
4175
4176  " Test for cfile/lfile
4177  call s:create_test_file('Xtestfile1')
4178  call s:create_test_file('Xtestfile2')
4179  Xexpr 'Xtestfile1:2:Line2'
4180  autocmd QuickFixCmdPost * Xolder
4181  call writefile(['Xtestfile2:4:Line4'], 'Xerr')
4182  Xfile Xerr
4183  call assert_equal('Xtestfile2', bufname(''))
4184  call assert_equal(4, line('.'))
4185  autocmd! QuickFixCmdPost
4186
4187  " Test for cbuffer/lbuffer
4188  call g:Xsetlist([], 'f')
4189  Xexpr 'Xtestfile1:2:Line2'
4190  autocmd QuickFixCmdPost * Xolder
4191  call writefile(['Xtestfile2:4:Line4'], 'Xerr')
4192  edit Xerr
4193  Xbuffer
4194  call assert_equal('Xtestfile2', bufname(''))
4195  call assert_equal(4, line('.'))
4196  autocmd! QuickFixCmdPost
4197
4198  " Test for cexpr/lexpr
4199  call g:Xsetlist([], 'f')
4200  Xexpr 'Xtestfile1:2:Line2'
4201  autocmd QuickFixCmdPost * Xolder
4202  Xexpr 'Xtestfile2:4:Line4'
4203  call assert_equal('Xtestfile2', bufname(''))
4204  call assert_equal(4, line('.'))
4205  autocmd! QuickFixCmdPost
4206
4207  " The grepprg may not be set on non-Unix systems
4208  if has('unix')
4209    " Test for grep/lgrep
4210    call g:Xsetlist([], 'f')
4211    Xexpr 'Xtestfile1:2:Line2'
4212    autocmd QuickFixCmdPost * Xolder
4213    silent Xgrep Line5 Xtestfile2
4214    call assert_equal('Xtestfile2', bufname(''))
4215    call assert_equal(5, line('.'))
4216    autocmd! QuickFixCmdPost
4217  endif
4218
4219  " Test for vimgrep/lvimgrep
4220  call g:Xsetlist([], 'f')
4221  Xexpr 'Xtestfile1:2:Line2'
4222  autocmd QuickFixCmdPost * Xolder
4223  silent Xvimgrep Line5 Xtestfile2
4224  call assert_equal('Xtestfile2', bufname(''))
4225  call assert_equal(5, line('.'))
4226  autocmd! QuickFixCmdPost
4227
4228  " Test for autocommands clearing the quickfix list before jumping to the
4229  " first error. This should not result in an error
4230  autocmd QuickFixCmdPost * call g:Xsetlist([], 'r')
4231  let v:errmsg = ''
4232  " Test for cfile/lfile
4233  Xfile Xerr
4234  call assert_true(v:errmsg !~# 'E42:')
4235  " Test for cbuffer/lbuffer
4236  edit Xerr
4237  Xbuffer
4238  call assert_true(v:errmsg !~# 'E42:')
4239  " Test for cexpr/lexpr
4240  Xexpr 'Xtestfile2:4:Line4'
4241  call assert_true(v:errmsg !~# 'E42:')
4242  " Test for grep/lgrep
4243  " The grepprg may not be set on non-Unix systems
4244  if has('unix')
4245    silent Xgrep Line5 Xtestfile2
4246    call assert_true(v:errmsg !~# 'E42:')
4247  endif
4248  " Test for vimgrep/lvimgrep
4249  call assert_fails('silent Xvimgrep Line5 Xtestfile2', 'E480:')
4250  autocmd! QuickFixCmdPost
4251
4252  call delete('Xerr')
4253  call delete('Xtestfile1')
4254  call delete('Xtestfile2')
4255endfunc
4256
4257func Test_autocmd_changelist()
4258  call Xautocmd_changelist('c')
4259  call Xautocmd_changelist('l')
4260endfunc
4261
4262" Tests for the ':filter /pat/ clist' command
4263func Test_filter_clist()
4264  cexpr ['Xfile1:10:10:Line 10', 'Xfile2:15:15:Line 15']
4265  call assert_equal([' 2 Xfile2:15 col 15: Line 15'],
4266			\ split(execute('filter /Line 15/ clist'), "\n"))
4267  call assert_equal([' 1 Xfile1:10 col 10: Line 10'],
4268			\ split(execute('filter /Xfile1/ clist'), "\n"))
4269  call assert_equal([], split(execute('filter /abc/ clist'), "\n"))
4270
4271  call setqflist([{'module' : 'abc', 'pattern' : 'pat1'},
4272			\ {'module' : 'pqr', 'pattern' : 'pat2'}], ' ')
4273  call assert_equal([' 2 pqr:pat2:  '],
4274			\ split(execute('filter /pqr/ clist'), "\n"))
4275  call assert_equal([' 1 abc:pat1:  '],
4276			\ split(execute('filter /pat1/ clist'), "\n"))
4277endfunc
4278
4279" Tests for the "CTRL-W <CR>" command.
4280func Xview_result_split_tests(cchar)
4281  call s:setup_commands(a:cchar)
4282
4283  " Test that "CTRL-W <CR>" in a qf/ll window fails with empty list.
4284  call g:Xsetlist([])
4285  Xopen
4286  let l:win_count = winnr('$')
4287  call assert_fails('execute "normal! \<C-W>\<CR>"', 'E42')
4288  call assert_equal(l:win_count, winnr('$'))
4289  Xclose
4290endfunc
4291
4292func Test_view_result_split()
4293  call Xview_result_split_tests('c')
4294  call Xview_result_split_tests('l')
4295endfunc
4296
4297" Test that :cc sets curswant
4298func Test_curswant()
4299  helpgrep quickfix
4300  normal! llll
4301  1cc
4302  call assert_equal(getcurpos()[4], virtcol('.'))
4303  cclose | helpclose
4304endfunc
4305
4306" Test for opening a file from the quickfix window using CTRL-W <Enter>
4307" doesn't leave an empty buffer around.
4308func Test_splitview()
4309  call s:create_test_file('Xtestfile1')
4310  call s:create_test_file('Xtestfile2')
4311  new | only
4312  let last_bufnr = bufnr('Test_sv_1', 1)
4313  let l = ['Xtestfile1:2:Line2', 'Xtestfile2:4:Line4']
4314  cgetexpr l
4315  copen
4316  let numbufs = len(getbufinfo())
4317  exe "normal \<C-W>\<CR>"
4318  copen
4319  exe "normal j\<C-W>\<CR>"
4320  " Make sure new empty buffers are not created
4321  call assert_equal(numbufs, len(getbufinfo()))
4322  " Creating a new buffer should use the next available buffer number
4323  call assert_equal(last_bufnr + 4, bufnr("Test_sv_2", 1))
4324  bwipe Test_sv_1
4325  bwipe Test_sv_2
4326  new | only
4327
4328  " When split opening files from location list window, make sure that two
4329  " windows doesn't refer to the same location list
4330  lgetexpr l
4331  let locid = getloclist(0, {'id' : 0}).id
4332  lopen
4333  exe "normal \<C-W>\<CR>"
4334  call assert_notequal(locid, getloclist(0, {'id' : 0}).id)
4335  call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
4336  new | only
4337
4338  " When split opening files from a helpgrep location list window, a new help
4339  " window should be opend with a copy of the location list.
4340  lhelpgrep window
4341  let locid = getloclist(0, {'id' : 0}).id
4342  lwindow
4343  exe "normal j\<C-W>\<CR>"
4344  call assert_notequal(locid, getloclist(0, {'id' : 0}).id)
4345  call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
4346  new | only
4347
4348  call delete('Xtestfile1')
4349  call delete('Xtestfile2')
4350endfunc
4351
4352" Test for parsing entries using visual screen column
4353func Test_viscol()
4354  enew
4355  call writefile(["Col1\tCol2\tCol3"], 'Xfile1')
4356  edit Xfile1
4357
4358  " Use byte offset for column number
4359  set efm&
4360  cexpr "Xfile1:1:5:XX\nXfile1:1:9:YY\nXfile1:1:20:ZZ"
4361  call assert_equal([5, 8], [col('.'), virtcol('.')])
4362  cnext
4363  call assert_equal([9, 12], [col('.'), virtcol('.')])
4364  cnext
4365  call assert_equal([14, 20], [col('.'), virtcol('.')])
4366
4367  " Use screen column offset for column number
4368  set efm=%f:%l:%v:%m
4369  cexpr "Xfile1:1:8:XX\nXfile1:1:12:YY\nXfile1:1:20:ZZ"
4370  call assert_equal([5, 8], [col('.'), virtcol('.')])
4371  cnext
4372  call assert_equal([9, 12], [col('.'), virtcol('.')])
4373  cnext
4374  call assert_equal([14, 20], [col('.'), virtcol('.')])
4375  cexpr "Xfile1:1:6:XX\nXfile1:1:15:YY\nXfile1:1:24:ZZ"
4376  call assert_equal([5, 8], [col('.'), virtcol('.')])
4377  cnext
4378  call assert_equal([10, 16], [col('.'), virtcol('.')])
4379  cnext
4380  call assert_equal([14, 20], [col('.'), virtcol('.')])
4381
4382  enew
4383  call writefile(["Col1\täü\töß\tCol4"], 'Xfile1')
4384
4385  " Use byte offset for column number
4386  set efm&
4387  cexpr "Xfile1:1:8:XX\nXfile1:1:11:YY\nXfile1:1:16:ZZ"
4388  call assert_equal([8, 10], [col('.'), virtcol('.')])
4389  cnext
4390  call assert_equal([11, 17], [col('.'), virtcol('.')])
4391  cnext
4392  call assert_equal([16, 25], [col('.'), virtcol('.')])
4393
4394  " Use screen column offset for column number
4395  set efm=%f:%l:%v:%m
4396  cexpr "Xfile1:1:10:XX\nXfile1:1:17:YY\nXfile1:1:25:ZZ"
4397  call assert_equal([8, 10], [col('.'), virtcol('.')])
4398  cnext
4399  call assert_equal([11, 17], [col('.'), virtcol('.')])
4400  cnext
4401  call assert_equal([16, 25], [col('.'), virtcol('.')])
4402
4403  " Use screen column number with a multi-line error message
4404  enew
4405  call writefile(["à test"], 'Xfile1')
4406  set efm=%E===\ %f\ ===,%C%l:%v,%Z%m
4407  cexpr ["=== Xfile1 ===", "1:3", "errormsg"]
4408  call assert_equal('Xfile1', @%)
4409  call assert_equal([0, 1, 4, 0], getpos('.'))
4410
4411  " Repeat previous test with byte offset %c: ensure that fix to issue #7145
4412  " does not break this
4413  set efm=%E===\ %f\ ===,%C%l:%c,%Z%m
4414  cexpr ["=== Xfile1 ===", "1:3", "errormsg"]
4415  call assert_equal('Xfile1', @%)
4416  call assert_equal([0, 1, 3, 0], getpos('.'))
4417
4418  enew | only
4419  set efm&
4420  call delete('Xfile1')
4421endfunc
4422
4423" Test for the quickfix window buffer
4424func Xqfbuf_test(cchar)
4425  call s:setup_commands(a:cchar)
4426
4427  " Quickfix buffer should be reused across closing and opening a quickfix
4428  " window
4429  Xexpr "F1:10:Line10"
4430  Xopen
4431  let qfbnum = bufnr('')
4432  Xclose
4433  " Even after the quickfix window is closed, the buffer should be loaded
4434  call assert_true(bufloaded(qfbnum))
4435  Xopen
4436  " Buffer should be reused when opening the window again
4437  call assert_equal(qfbnum, bufnr(''))
4438  Xclose
4439
4440  if a:cchar == 'l'
4441    %bwipe
4442    " For a location list, when both the file window and the location list
4443    " window for the list are closed, then the buffer should be freed.
4444    new | only
4445    lexpr "F1:10:Line10"
4446    let wid = win_getid()
4447    lopen
4448    let qfbnum = bufnr('')
4449    call assert_match(qfbnum . ' %a-  "\[Location List]"', execute('ls'))
4450    close
4451    " When the location list window is closed, the buffer name should not
4452    " change to 'Quickfix List'
4453    call assert_match(qfbnum . '  h-  "\[Location List]"', execute('ls'))
4454    call assert_true(bufloaded(qfbnum))
4455
4456    " After deleting a location list buffer using ":bdelete", opening the
4457    " location list window should mark the buffer as a location list buffer.
4458    exe "bdelete " . qfbnum
4459    lopen
4460    call assert_equal("quickfix", &buftype)
4461    call assert_equal(1, getwininfo(win_getid(winnr()))[0].loclist)
4462    call assert_equal(wid, getloclist(0, {'filewinid' : 0}).filewinid)
4463    call assert_false(&swapfile)
4464    lclose
4465
4466    " When the location list is cleared for the window, the buffer should be
4467    " removed
4468    call setloclist(0, [], 'f')
4469    call assert_false(bufexists(qfbnum))
4470
4471    " When the location list is freed with the location list window open, the
4472    " location list buffer should not be lost. It should be reused when the
4473    " location list is again populated.
4474    lexpr "F1:10:Line10"
4475    lopen
4476    let wid = win_getid()
4477    let qfbnum = bufnr('')
4478    wincmd p
4479    call setloclist(0, [], 'f')
4480    lexpr "F1:10:Line10"
4481    lopen
4482    call assert_equal(wid, win_getid())
4483    call assert_equal(qfbnum, bufnr(''))
4484    lclose
4485
4486    " When the window with the location list is closed, the buffer should be
4487    " removed
4488    new | only
4489    call assert_false(bufexists(qfbnum))
4490  endif
4491endfunc
4492
4493func Test_qfbuf()
4494  throw 'skipped: enable after porting patch 8.1.0877'
4495  call Xqfbuf_test('c')
4496  call Xqfbuf_test('l')
4497endfunc
4498
4499" Test to make sure that an empty quickfix buffer is not reused for loading
4500" a normal buffer.
4501func Test_empty_qfbuf()
4502  enew | only
4503  call writefile(["Test"], 'Xfile1')
4504  call setqflist([], 'f')
4505  copen | only
4506  let qfbuf = bufnr('')
4507  edit Xfile1
4508  call assert_notequal(qfbuf, bufnr(''))
4509  enew
4510  call delete('Xfile1')
4511endfunc
4512
4513" Test for the :cbelow, :cabove, :lbelow and :labove commands.
4514" And for the :cafter, :cbefore, :lafter and :lbefore commands.
4515func Xtest_below(cchar)
4516  call s:setup_commands(a:cchar)
4517
4518  " No quickfix/location list
4519  call assert_fails('Xbelow', 'E42:')
4520  call assert_fails('Xabove', 'E42:')
4521  call assert_fails('Xbefore', 'E42:')
4522  call assert_fails('Xafter', 'E42:')
4523
4524  " Empty quickfix/location list
4525  call g:Xsetlist([])
4526  call assert_fails('Xbelow', 'E42:')
4527  call assert_fails('Xabove', 'E42:')
4528  call assert_fails('Xbefore', 'E42:')
4529  call assert_fails('Xafter', 'E42:')
4530
4531  call s:create_test_file('X1')
4532  call s:create_test_file('X2')
4533  call s:create_test_file('X3')
4534  call s:create_test_file('X4')
4535
4536  " Invalid entries
4537  edit X1
4538  call g:Xsetlist(["E1", "E2"])
4539  call assert_fails('Xbelow', 'E42:')
4540  call assert_fails('Xabove', 'E42:')
4541  call assert_fails('3Xbelow', 'E42:')
4542  call assert_fails('4Xabove', 'E42:')
4543  call assert_fails('Xbefore', 'E42:')
4544  call assert_fails('Xafter', 'E42:')
4545  call assert_fails('3Xbefore', 'E42:')
4546  call assert_fails('4Xafter', 'E42:')
4547
4548  " Test the commands with various arguments
4549  Xexpr ["X1:5:3:L5", "X2:5:2:L5", "X2:10:3:L10", "X2:15:4:L15", "X3:3:5:L3"]
4550  edit +7 X2
4551  Xabove
4552  call assert_equal(['X2', 5], [bufname(''), line('.')])
4553  call assert_fails('Xabove', 'E553:')
4554  normal 7G
4555  Xbefore
4556  call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')])
4557  call assert_fails('Xbefore', 'E553:')
4558
4559  normal 2j
4560  Xbelow
4561  call assert_equal(['X2', 10], [bufname(''), line('.')])
4562  normal 7G
4563  Xafter
4564  call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
4565
4566  " Last error in this file
4567  Xbelow 99
4568  call assert_equal(['X2', 15], [bufname(''), line('.')])
4569  call assert_fails('Xbelow', 'E553:')
4570  normal gg
4571  Xafter 99
4572  call assert_equal(['X2', 15, 4], [bufname(''), line('.'), col('.')])
4573  call assert_fails('Xafter', 'E553:')
4574
4575  " First error in this file
4576  Xabove 99
4577  call assert_equal(['X2', 5], [bufname(''), line('.')])
4578  call assert_fails('Xabove', 'E553:')
4579  normal G
4580  Xbefore 99
4581  call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')])
4582  call assert_fails('Xbefore', 'E553:')
4583
4584  normal gg
4585  Xbelow 2
4586  call assert_equal(['X2', 10], [bufname(''), line('.')])
4587  normal gg
4588  Xafter 2
4589  call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
4590
4591  normal G
4592  Xabove 2
4593  call assert_equal(['X2', 10], [bufname(''), line('.')])
4594  normal G
4595  Xbefore 2
4596  call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
4597
4598  edit X4
4599  call assert_fails('Xabove', 'E42:')
4600  call assert_fails('Xbelow', 'E42:')
4601  call assert_fails('Xbefore', 'E42:')
4602  call assert_fails('Xafter', 'E42:')
4603  if a:cchar == 'l'
4604    " If a buffer has location list entries from some other window but not
4605    " from the current window, then the commands should fail.
4606    edit X1 | split | call setloclist(0, [], 'f')
4607    call assert_fails('Xabove', 'E776:')
4608    call assert_fails('Xbelow', 'E776:')
4609    call assert_fails('Xbefore', 'E776:')
4610    call assert_fails('Xafter', 'E776:')
4611    close
4612  endif
4613
4614  " Test for lines with multiple quickfix entries
4615  Xexpr ["X1:5:L5", "X2:5:1:L5_1", "X2:5:2:L5_2", "X2:5:3:L5_3",
4616	      \ "X2:10:1:L10_1", "X2:10:2:L10_2", "X2:10:3:L10_3",
4617	      \ "X2:15:1:L15_1", "X2:15:2:L15_2", "X2:15:3:L15_3", "X3:3:L3"]
4618  edit +1 X2
4619  Xbelow 2
4620  call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')])
4621  normal 1G
4622  Xafter 2
4623  call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')])
4624
4625  normal gg
4626  Xbelow 99
4627  call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')])
4628  normal gg
4629  Xafter 99
4630  call assert_equal(['X2', 15, 3], [bufname(''), line('.'), col('.')])
4631
4632  normal G
4633  Xabove 2
4634  call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')])
4635  normal G
4636  Xbefore 2
4637  call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')])
4638
4639  normal G
4640  Xabove 99
4641  call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
4642  normal G
4643  Xbefore 99
4644  call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
4645
4646  normal 10G
4647  Xabove
4648  call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
4649  normal 10G$
4650  2Xbefore
4651  call assert_equal(['X2', 10, 2], [bufname(''), line('.'), col('.')])
4652
4653  normal 10G
4654  Xbelow
4655  call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')])
4656  normal 9G
4657  5Xafter
4658  call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')])
4659
4660  " Invalid range
4661  if a:cchar == 'c'
4662    call assert_fails('-2cbelow', 'E16:')
4663    call assert_fails('-2cafter', 'E16:')
4664  else
4665    call assert_fails('-2lbelow', 'E16:')
4666    call assert_fails('-2lafter', 'E16:')
4667  endif
4668
4669  call delete('X1')
4670  call delete('X2')
4671  call delete('X3')
4672  call delete('X4')
4673endfunc
4674
4675func Test_cbelow()
4676  call Xtest_below('c')
4677  call Xtest_below('l')
4678endfunc
4679
4680func Test_quickfix_count()
4681  let commands = [
4682	\ 'cNext',
4683	\ 'cNfile',
4684	\ 'cabove',
4685	\ 'cbelow',
4686	\ 'cfirst',
4687	\ 'clast',
4688	\ 'cnewer',
4689	\ 'cnext',
4690	\ 'cnfile',
4691	\ 'colder',
4692	\ 'cprevious',
4693	\ 'crewind',
4694	\
4695	\ 'lNext',
4696	\ 'lNfile',
4697	\ 'labove',
4698	\ 'lbelow',
4699	\ 'lfirst',
4700	\ 'llast',
4701	\ 'lnewer',
4702	\ 'lnext',
4703	\ 'lnfile',
4704	\ 'lolder',
4705	\ 'lprevious',
4706	\ 'lrewind',
4707	\ ]
4708  for cmd in commands
4709    call assert_fails('-1' .. cmd, 'E16:')
4710    call assert_fails('.' .. cmd, 'E16:')
4711    call assert_fails('%' .. cmd, 'E16:')
4712    call assert_fails('$' .. cmd, 'E16:')
4713  endfor
4714endfunc
4715
4716" Test for aborting quickfix commands using QuickFixCmdPre
4717func Xtest_qfcmd_abort(cchar)
4718  call s:setup_commands(a:cchar)
4719
4720  call g:Xsetlist([], 'f')
4721
4722  " cexpr/lexpr
4723  let e = ''
4724  try
4725    Xexpr ["F1:10:Line10", "F2:20:Line20"]
4726  catch /.*/
4727    let e = v:exception
4728  endtry
4729  call assert_equal('AbortCmd', e)
4730  call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
4731
4732  " cfile/lfile
4733  call writefile(["F1:10:Line10", "F2:20:Line20"], 'Xfile1')
4734  let e = ''
4735  try
4736    Xfile Xfile1
4737  catch /.*/
4738    let e = v:exception
4739  endtry
4740  call assert_equal('AbortCmd', e)
4741  call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
4742  call delete('Xfile1')
4743
4744  " cgetbuffer/lgetbuffer
4745  enew!
4746  call append(0, ["F1:10:Line10", "F2:20:Line20"])
4747  let e = ''
4748  try
4749    Xgetbuffer
4750  catch /.*/
4751    let e = v:exception
4752  endtry
4753  call assert_equal('AbortCmd', e)
4754  call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
4755  enew!
4756
4757  " vimgrep/lvimgrep
4758  let e = ''
4759  try
4760    Xvimgrep /func/ test_quickfix.vim
4761  catch /.*/
4762    let e = v:exception
4763  endtry
4764  call assert_equal('AbortCmd', e)
4765  call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
4766
4767  " helpgrep/lhelpgrep
4768  let e = ''
4769  try
4770    Xhelpgrep quickfix
4771  catch /.*/
4772    let e = v:exception
4773  endtry
4774  call assert_equal('AbortCmd', e)
4775  call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
4776
4777  " grep/lgrep
4778  if has('unix')
4779    let e = ''
4780    try
4781      silent Xgrep func test_quickfix.vim
4782    catch /.*/
4783      let e = v:exception
4784    endtry
4785    call assert_equal('AbortCmd', e)
4786    call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
4787  endif
4788endfunc
4789
4790func Test_qfcmd_abort()
4791  augroup QF_Test
4792    au!
4793    autocmd  QuickFixCmdPre * throw "AbortCmd"
4794  augroup END
4795
4796  call Xtest_qfcmd_abort('c')
4797  call Xtest_qfcmd_abort('l')
4798
4799  augroup QF_Test
4800    au!
4801  augroup END
4802endfunc
4803
4804" Test for using a file in one of the parent directories.
4805func Test_search_in_dirstack()
4806  call mkdir('Xtestdir/a/b/c', 'p')
4807  let save_cwd = getcwd()
4808  call writefile(["X1_L1", "X1_L2"], 'Xtestdir/Xfile1')
4809  call writefile(["X2_L1", "X2_L2"], 'Xtestdir/a/Xfile2')
4810  call writefile(["X3_L1", "X3_L2"], 'Xtestdir/a/b/Xfile3')
4811  call writefile(["X4_L1", "X4_L2"], 'Xtestdir/a/b/c/Xfile4')
4812
4813  let lines = "Entering dir Xtestdir\n" .
4814	      \ "Entering dir a\n" .
4815	      \ "Entering dir b\n" .
4816	      \ "Xfile2:2:X2_L2\n" .
4817	      \ "Leaving dir a\n" .
4818	      \ "Xfile1:2:X1_L2\n" .
4819	      \ "Xfile3:1:X3_L1\n" .
4820	      \ "Entering dir c\n" .
4821	      \ "Xfile4:2:X4_L2\n" .
4822	      \ "Leaving dir c\n"
4823  set efm=%DEntering\ dir\ %f,%XLeaving\ dir\ %f,%f:%l:%m
4824  cexpr lines .. "Leaving dir Xtestdir|\n" | let next = 1
4825  call assert_equal(11, getqflist({'size' : 0}).size)
4826  call assert_equal(4, getqflist({'idx' : 0}).idx)
4827  call assert_equal('X2_L2', getline('.'))
4828  call assert_equal(1, next)
4829  cnext
4830  call assert_equal(6, getqflist({'idx' : 0}).idx)
4831  call assert_equal('X1_L2', getline('.'))
4832  cnext
4833  call assert_equal(7, getqflist({'idx' : 0}).idx)
4834  call assert_equal(1, line('$'))
4835  call assert_equal('', getline(1))
4836  cnext
4837  call assert_equal(9, getqflist({'idx' : 0}).idx)
4838  call assert_equal(1, line('$'))
4839  call assert_equal('', getline(1))
4840
4841  set efm&
4842  exe 'cd ' . save_cwd
4843  call delete('Xtestdir', 'rf')
4844endfunc
4845
4846" Test for :cquit
4847func Test_cquit()
4848  " Exit Vim with a non-zero value
4849  if RunVim([], ["cquit 7"], '')
4850    call assert_equal(7, v:shell_error)
4851  endif
4852
4853  if RunVim([], ["50cquit"], '')
4854    call assert_equal(50, v:shell_error)
4855  endif
4856
4857  " Exit Vim with default value
4858  if RunVim([], ["cquit"], '')
4859    call assert_equal(1, v:shell_error)
4860  endif
4861
4862  " Exit Vim with zero value
4863  if RunVim([], ["cquit 0"], '')
4864    call assert_equal(0, v:shell_error)
4865  endif
4866
4867  " Exit Vim with negative value
4868  call assert_fails('-3cquit', 'E16:')
4869endfunc
4870
4871" Running :lhelpgrep command more than once in a help window, doesn't jump to
4872" the help topic
4873func Test_lhelpgrep_from_help_window()
4874  call mkdir('Xtestdir/doc', 'p')
4875  call writefile(['window'], 'Xtestdir/doc/a.txt')
4876  call writefile(['buffer'], 'Xtestdir/doc/b.txt')
4877  let save_rtp = &rtp
4878  let &rtp = 'Xtestdir'
4879  lhelpgrep window
4880  lhelpgrep buffer
4881  call assert_equal('b.txt', fnamemodify(@%, ":p:t"))
4882  lhelpgrep window
4883  call assert_equal('a.txt', fnamemodify(@%, ":p:t"))
4884  let &rtp = save_rtp
4885  call delete('Xtestdir', 'rf')
4886  new | only!
4887endfunc
4888
4889" Test for adding an invalid entry with the quickfix window open and making
4890" sure that the window contents are not changed
4891func Test_add_invalid_entry_with_qf_window()
4892  call setqflist([], 'f')
4893  cexpr "Xfile1:10:aa"
4894  copen
4895  call setqflist(['bb'], 'a')
4896  call assert_equal(1, line('$'))
4897  call assert_equal(['Xfile1|10| aa'], getline(1, '$'))
4898  call assert_equal([{'lnum': 10                    , 'end_lnum': 0    , 'bufnr': bufnr('Xfile1') , 'col': 0   , 'end_col': 0    , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
4899
4900  call setqflist([{'lnum': 10                                          , 'bufnr': bufnr('Xfile1') , 'col': 0                     , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
4901  call assert_equal(1                               , line('$'))
4902  call assert_equal(['Xfile1|10| aa']               , getline(1        , '$'))
4903  call assert_equal([{'lnum': 10                    , 'end_lnum': 0    , 'bufnr': bufnr('Xfile1') , 'col': 0   , 'end_col': 0    , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
4904
4905  call setqflist([{'lnum': 10                       , 'end_lnum': 0    , 'bufnr': bufnr('Xfile1') , 'col': 0   , 'end_col': 0    , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
4906  call assert_equal(1                               , line('$'))
4907  call assert_equal(['Xfile1|10| aa']               , getline(1        , '$'))
4908  call assert_equal([{'lnum': 10                    , 'end_lnum': 0    , 'bufnr': bufnr('Xfile1') , 'col': 0   , 'end_col': 0    , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
4909
4910  call setqflist([{'lnum': 10                       , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 0   , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
4911  call assert_equal(1                               , line('$'))
4912  call assert_equal(['Xfile1|10| aa']               , getline(1        , '$'))
4913  call assert_equal([{'lnum': 10                    , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 0   , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
4914
4915  call setqflist([{'lnum': 10                       , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 0    , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
4916  call assert_equal(1                               , line('$'))
4917  call assert_equal(['Xfile1|10 col 666| aa']       , getline(1        , '$'))
4918  call assert_equal([{'lnum': 10                    , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 0    , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
4919
4920  call setqflist([{'lnum': 10                       , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
4921  call assert_equal(1                               , line('$'))
4922  call assert_equal(['Xfile1|10 col 666| aa']       , getline(1        , '$'))
4923  call assert_equal([{'lnum': 10                    , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
4924
4925  call setqflist([{'lnum': 10                       , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222  , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
4926  call assert_equal(1                               , line('$'))
4927  call assert_equal(['Xfile1|10 col 666-222| aa']   , getline(1        , '$'))
4928  call assert_equal([{'lnum': 10                    , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222  , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
4929
4930  call setqflist([{'lnum': 10                       , 'end_lnum': 6 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222  , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
4931  call assert_equal(1                               , line('$'))
4932  call assert_equal(['Xfile1|10-6 col 666-222| aa'] , getline(1        , '$'))
4933  call assert_equal([{'lnum': 10                    , 'end_lnum': 6 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222  , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
4934  cclose
4935endfunc
4936
4937" Test for very weird problem: autocommand causes a failure, resulting opening
4938" the quickfix window to fail. This still splits the window, but otherwise
4939" should not mess up buffers.
4940func Test_quickfix_window_fails_to_open()
4941  CheckScreendump
4942
4943  let lines =<< trim END
4944      anything
4945      try
4946        anything
4947      endtry
4948  END
4949  call writefile(lines, 'XquickfixFails')
4950
4951  let lines =<< trim END
4952      split XquickfixFails
4953      silent vimgrep anything %
4954      normal o
4955      au BufLeave * ++once source XquickfixFails
4956      " This will trigger the autocommand, which causes an error, what follows
4957      " is aborted but the window was already split.
4958      silent! cwindow
4959  END
4960  call writefile(lines, 'XtestWinFails')
4961  let buf = RunVimInTerminal('-S XtestWinFails', #{rows: 13})
4962  call VerifyScreenDump(buf, 'Test_quickfix_window_fails', {})
4963
4964  " clean up
4965  call term_sendkeys(buf, ":bwipe!\<CR>")
4966  call term_wait(buf)
4967  call StopVimInTerminal(buf)
4968  call delete('XtestWinFails')
4969  call delete('XquickfixFails')
4970endfunc
4971
4972" Test for updating the quickfix buffer whenever the assocaited quickfix list
4973" is changed.
4974func Xqfbuf_update(cchar)
4975  call s:setup_commands(a:cchar)
4976
4977  Xexpr "F1:1:line1"
4978  Xopen
4979  call assert_equal(['F1|1| line1'], getline(1, '$'))
4980  call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
4981
4982  " Test setqflist() using the 'lines' key in 'what'
4983  " add a new entry
4984  call g:Xsetlist([], 'a', {'lines' : ['F2:2: line2']})
4985  call assert_equal(['F1|1| line1', 'F2|2| line2'], getline(1, '$'))
4986  call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
4987  " replace all the entries with a single entry
4988  call g:Xsetlist([], 'r', {'lines' : ['F3:3: line3']})
4989  call assert_equal(['F3|3| line3'], getline(1, '$'))
4990  call assert_equal(3, g:Xgetlist({'changedtick' : 0}).changedtick)
4991  " remove all the entries
4992  call g:Xsetlist([], 'r', {'lines' : []})
4993  call assert_equal([''], getline(1, '$'))
4994  call assert_equal(4, g:Xgetlist({'changedtick' : 0}).changedtick)
4995  " add a new list
4996  call g:Xsetlist([], ' ', {'lines' : ['F4:4: line4']})
4997  call assert_equal(['F4|4| line4'], getline(1, '$'))
4998  call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
4999
5000  " Test setqflist() using the 'items' key in 'what'
5001  " add a new entry
5002  call g:Xsetlist([], 'a', {'items' : [{'filename' : 'F5', 'lnum' : 5, 'text' : 'line5'}]})
5003  call assert_equal(['F4|4| line4', 'F5|5| line5'], getline(1, '$'))
5004  call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
5005  " replace all the entries with a single entry
5006  call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F6', 'lnum' : 6, 'text' : 'line6'}]})
5007  call assert_equal(['F6|6| line6'], getline(1, '$'))
5008  call assert_equal(3, g:Xgetlist({'changedtick' : 0}).changedtick)
5009  " remove all the entries
5010  call g:Xsetlist([], 'r', {'items' : []})
5011  call assert_equal([''], getline(1, '$'))
5012  call assert_equal(4, g:Xgetlist({'changedtick' : 0}).changedtick)
5013  " add a new list
5014  call g:Xsetlist([], ' ', {'items' : [{'filename' : 'F7', 'lnum' : 7, 'text' : 'line7'}]})
5015  call assert_equal(['F7|7| line7'], getline(1, '$'))
5016  call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
5017
5018  call g:Xsetlist([], ' ', {})
5019  call assert_equal([''], getline(1, '$'))
5020  call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
5021
5022  Xclose
5023endfunc
5024
5025func Test_qfbuf_update()
5026  call Xqfbuf_update('c')
5027  call Xqfbuf_update('l')
5028endfunc
5029
5030" Test for getting a specific item from a quickfix list
5031func Xtest_getqflist_by_idx(cchar)
5032  call s:setup_commands(a:cchar)
5033  " Empty list
5034  call assert_equal([], g:Xgetlist({'idx' : 1, 'items' : 0}).items)
5035  Xexpr ['F1:10:L10', 'F1:20:L20']
5036  let l = g:Xgetlist({'idx' : 2, 'items' : 0}).items
5037  call assert_equal(bufnr('F1'), l[0].bufnr)
5038  call assert_equal(20, l[0].lnum)
5039  call assert_equal('L20', l[0].text)
5040  call assert_equal([], g:Xgetlist({'idx' : -1, 'items' : 0}).items)
5041  call assert_equal([], g:Xgetlist({'idx' : 3, 'items' : 0}).items)
5042  %bwipe!
5043endfunc
5044
5045func Test_getqflist_by_idx()
5046  call Xtest_getqflist_by_idx('c')
5047  call Xtest_getqflist_by_idx('l')
5048endfunc
5049
5050" Test for the 'quickfixtextfunc' setting
5051func Tqfexpr(info)
5052  if a:info.quickfix
5053    let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items
5054  else
5055    let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'items' : 1}).items
5056  endif
5057
5058
5059  let l = []
5060  for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
5061    let e = qfl[idx]
5062    let s = ''
5063    if e.bufnr != 0
5064      let bname = bufname(e.bufnr)
5065      let s ..= fnamemodify(bname, ':.')
5066    endif
5067    let s ..= '-'
5068    let s ..= 'L' .. string(e.lnum) .. 'C' .. string(e.col) .. '-'
5069    let s ..= e.text
5070    call add(l, s)
5071  endfor
5072
5073  return l
5074endfunc
5075
5076func Xtest_qftextfunc(cchar)
5077  call s:setup_commands(a:cchar)
5078
5079  set efm=%f:%l:%c:%m
5080  set quickfixtextfunc=Tqfexpr
5081  call assert_equal('Tqfexpr', &quickfixtextfunc)
5082  call assert_equal('',
5083        \ g:Xgetlist({'quickfixtextfunc' : 1}).quickfixtextfunc)
5084  call g:Xsetlist([
5085        \ { 'filename': 'F1', 'lnum': 10, 'col': 2,
5086        \   'end_col': 7, 'text': 'green'},
5087        \ { 'filename': 'F1', 'lnum': 20, 'end_lnum': 25, 'col': 4,
5088        \   'end_col': 8, 'text': 'blue'},
5089        \ ])
5090
5091  Xwindow
5092  call assert_equal('F1-L10C2-green', getline(1))
5093  call assert_equal('F1-L20C4-blue', getline(2))
5094  Xclose
5095  set quickfixtextfunc&vim
5096  Xwindow
5097  call assert_equal('F1|10 col 2-7| green', getline(1))
5098  call assert_equal('F1|20-25 col 4-8| blue', getline(2))
5099  Xclose
5100  set efm&
5101  set quickfixtextfunc&
5102
5103  " Test for per list 'quickfixtextfunc' setting
5104  func PerQfText(info)
5105    if a:info.quickfix
5106      let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items
5107    else
5108      let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'items' : 1}).items
5109    endif
5110    if empty(qfl)
5111      return []
5112    endif
5113    let l = []
5114    for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
5115      call add(l, 'Line ' .. qfl[idx].lnum .. ', Col ' .. qfl[idx].col)
5116    endfor
5117    return l
5118  endfunc
5119  set quickfixtextfunc=Tqfexpr
5120  call g:Xsetlist([], ' ', {'quickfixtextfunc' : "PerQfText"})
5121  Xaddexpr ['F1:10:2:green', 'F1:20:4:blue']
5122  Xwindow
5123  call assert_equal('Line 10, Col 2', getline(1))
5124  call assert_equal('Line 20, Col 4', getline(2))
5125  Xclose
5126  call assert_equal(function('PerQfText'),
5127        \ g:Xgetlist({'quickfixtextfunc' : 1}).quickfixtextfunc)
5128  " Add entries to the list when the quickfix buffer is hidden
5129  Xaddexpr ['F1:30:6:red']
5130  Xwindow
5131  call assert_equal('Line 30, Col 6', getline(3))
5132  Xclose
5133  call g:Xsetlist([], 'r', {'quickfixtextfunc' : ''})
5134  call assert_equal('', g:Xgetlist({'quickfixtextfunc' : 1}).quickfixtextfunc)
5135  set quickfixtextfunc&
5136  delfunc PerQfText
5137
5138  " Non-existing function
5139  set quickfixtextfunc=Tabc
5140  " call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E117:')
5141  Xexpr ['F1:10:2:green', 'F1:20:4:blue']"
5142  call assert_fails("Xwindow", 'E117:')
5143  Xclose
5144  set quickfixtextfunc&
5145
5146  " set option to a non-function
5147  set quickfixtextfunc=[10,\ 20]
5148  " call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E117:')
5149  Xexpr ['F1:10:2:green', 'F1:20:4:blue']"
5150  call assert_fails("Xwindow", 'E117:')
5151  Xclose
5152  set quickfixtextfunc&
5153
5154  " set option to a function with different set of arguments
5155  func Xqftext(a, b, c)
5156    return a:a .. a:b .. a:c
5157  endfunc
5158  set quickfixtextfunc=Xqftext
5159  " call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E119:')
5160  Xexpr ['F1:10:2:green', 'F1:20:4:blue']"
5161  call assert_fails("Xwindow", 'E119:')
5162  Xclose
5163
5164  " set option to a function that returns a list with non-strings
5165  func Xqftext2(d)
5166    return ['one', [], 'two']
5167  endfunc
5168  set quickfixtextfunc=Xqftext2
5169  " call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue', 'F1:30:6:red']",
5170  "                                                                 \ 'E730:')
5171  Xexpr ['F1:10:2:green', 'F1:20:4:blue', 'F1:30:6:red']
5172  call assert_fails('Xwindow', 'E730:')
5173  call assert_equal(['one', 'F1|20 col 4| blue', 'F1|30 col 6| red'],
5174        \ getline(1, '$'))
5175  Xclose
5176
5177  set quickfixtextfunc&
5178  delfunc Xqftext
5179  delfunc Xqftext2
5180
5181  " set the global option to a lambda function
5182  set quickfixtextfunc={d\ ->\ map(g:Xgetlist({'id'\ :\ d.id,\ 'items'\ :\ 1}).items[d.start_idx-1:d.end_idx-1],\ 'v:val.text')}
5183  Xexpr ['F1:10:2:green', 'F1:20:4:blue']
5184  Xwindow
5185  call assert_equal(['green', 'blue'], getline(1, '$'))
5186  Xclose
5187  call assert_equal("{d -> map(g:Xgetlist({'id' : d.id, 'items' : 1}).items[d.start_idx-1:d.end_idx-1], 'v:val.text')}", &quickfixtextfunc)
5188  set quickfixtextfunc&
5189
5190  " use a lambda function that returns an empty list
5191  set quickfixtextfunc={d\ ->\ []}
5192  Xexpr ['F1:10:2:green', 'F1:20:4:blue']
5193  Xwindow
5194  call assert_equal(['F1|10 col 2| green', 'F1|20 col 4| blue'],
5195        \ getline(1, '$'))
5196  Xclose
5197  set quickfixtextfunc&
5198
5199  " use a lambda function that returns a list with empty strings
5200  set quickfixtextfunc={d\ ->\ ['',\ '']}
5201  Xexpr ['F1:10:2:green', 'F1:20:4:blue']
5202  Xwindow
5203  call assert_equal(['F1|10 col 2| green', 'F1|20 col 4| blue'],
5204        \ getline(1, '$'))
5205  Xclose
5206  set quickfixtextfunc&
5207
5208  " set the per-quickfix list text function to a lambda function
5209  call g:Xsetlist([], ' ',
5210        \ {'quickfixtextfunc' :
5211        \   {d -> map(g:Xgetlist({'id' : d.id, 'items' : 1}).items[d.start_idx-1:d.end_idx-1],
5212        \ "'Line ' .. v:val.lnum .. ', Col ' .. v:val.col")}})
5213  Xaddexpr ['F1:10:2:green', 'F1:20:4:blue']
5214  Xwindow
5215  call assert_equal('Line 10, Col 2', getline(1))
5216  call assert_equal('Line 20, Col 4', getline(2))
5217  Xclose
5218  call assert_match("function('<lambda>\\d\\+')", string(g:Xgetlist({'quickfixtextfunc' : 1}).quickfixtextfunc))
5219  call g:Xsetlist([], 'f')
5220endfunc
5221
5222func Test_qftextfunc()
5223  call Xtest_qftextfunc('c')
5224  call Xtest_qftextfunc('l')
5225endfunc
5226
5227" Test for updating a location list for some other window and check that
5228" 'qftextfunc' uses the correct location list.
5229func Test_qftextfunc_other_loclist()
5230  %bw!
5231  call setloclist(0, [], 'f')
5232
5233  " create a window and a location list for it and open the location list
5234  " window
5235  lexpr ['F1:10:12:one', 'F1:20:14:two']
5236  let w1_id = win_getid()
5237  call setloclist(0, [], ' ',
5238        \ {'lines': ['F1:10:12:one', 'F1:20:14:two'],
5239        \  'quickfixtextfunc':
5240        \    {d -> map(getloclist(d.winid, {'id' : d.id,
5241        \                'items' : 1}).items[d.start_idx-1:d.end_idx-1],
5242        \          "'Line ' .. v:val.lnum .. ', Col ' .. v:val.col")}})
5243  lwindow
5244  let w2_id = win_getid()
5245
5246  " create another window and a location list for it and open the location
5247  " list window
5248  topleft new
5249  let w3_id = win_getid()
5250  call setloclist(0, [], ' ',
5251        \ {'lines': ['F2:30:32:eleven', 'F2:40:34:twelve'],
5252        \  'quickfixtextfunc':
5253        \    {d -> map(getloclist(d.winid, {'id' : d.id,
5254        \                'items' : 1}).items[d.start_idx-1:d.end_idx-1],
5255        \          "'Ligne ' .. v:val.lnum .. ', Colonne ' .. v:val.col")}})
5256  lwindow
5257  let w4_id = win_getid()
5258
5259  topleft new
5260  lexpr ['F3:50:52:green', 'F3:60:54:blue']
5261  let w5_id = win_getid()
5262
5263  " change the location list for some other window
5264  call setloclist(0, [], 'r', {'lines': ['F3:55:56:aaa', 'F3:57:58:bbb']})
5265  call setloclist(w1_id, [], 'r', {'lines': ['F1:62:63:bbb', 'F1:64:65:ccc']})
5266  call setloclist(w3_id, [], 'r', {'lines': ['F2:76:77:ddd', 'F2:78:79:eee']})
5267  call assert_equal(['Line 62, Col 63', 'Line 64, Col 65'],
5268        \ getbufline(winbufnr(w2_id), 1, '$'))
5269  call assert_equal(['Ligne 76, Colonne 77', 'Ligne 78, Colonne 79'],
5270        \ getbufline(winbufnr(w4_id), 1, '$'))
5271  call setloclist(w2_id, [], 'r', {'lines': ['F1:32:33:fff', 'F1:34:35:ggg']})
5272  call setloclist(w4_id, [], 'r', {'lines': ['F2:46:47:hhh', 'F2:48:49:jjj']})
5273  call assert_equal(['Line 32, Col 33', 'Line 34, Col 35'],
5274        \ getbufline(winbufnr(w2_id), 1, '$'))
5275  call assert_equal(['Ligne 46, Colonne 47', 'Ligne 48, Colonne 49'],
5276        \ getbufline(winbufnr(w4_id), 1, '$'))
5277
5278  call win_gotoid(w5_id)
5279  lwindow
5280  call assert_equal(['F3|55 col 56| aaa', 'F3|57 col 58| bbb'],
5281        \ getline(1, '$'))
5282  %bw!
5283endfunc
5284
5285func Test_locationlist_open_in_newtab()
5286  call s:create_test_file('Xqftestfile1')
5287  call s:create_test_file('Xqftestfile2')
5288  call s:create_test_file('Xqftestfile3')
5289
5290  %bwipe!
5291
5292  lgetexpr ['Xqftestfile1:5:Line5',
5293		\ 'Xqftestfile2:10:Line10',
5294		\ 'Xqftestfile3:16:Line16']
5295
5296  silent! llast
5297  call assert_equal(1, tabpagenr('$'))
5298  call assert_equal('Xqftestfile3', bufname())
5299
5300  set switchbuf=newtab
5301
5302  silent! lfirst
5303  call assert_equal(2, tabpagenr('$'))
5304  call assert_equal('Xqftestfile1', bufname())
5305
5306  silent! lnext
5307  call assert_equal(3, tabpagenr('$'))
5308  call assert_equal('Xqftestfile2', bufname())
5309
5310  call delete('Xqftestfile1')
5311  call delete('Xqftestfile2')
5312  call delete('Xqftestfile3')
5313  set switchbuf&vim
5314
5315  %bwipe!
5316endfunc
5317
5318" Test for win_gettype() in quickfix and location list windows
5319func Test_win_gettype()
5320  copen
5321  call assert_equal("quickfix", win_gettype())
5322  let wid = win_getid()
5323  wincmd p
5324  call assert_equal("quickfix", win_gettype(wid))
5325  cclose
5326  lexpr ''
5327  lopen
5328  call assert_equal("loclist", win_gettype())
5329  let wid = win_getid()
5330  wincmd p
5331  call assert_equal("loclist", win_gettype(wid))
5332  lclose
5333endfunc
5334
5335" vim: shiftwidth=2 sts=2 expandtab
5336