xref: /vim-8.2.3635/src/testdir/test_signs.vim (revision a6c27c47)
1" Test for signs
2
3if !has('signs')
4  finish
5endif
6
7func Test_sign()
8  new
9  call setline(1, ['a', 'b', 'c', 'd'])
10
11  " Define some signs.
12  " We can specify icons even if not all versions of vim support icons as
13  " icon is ignored when not supported.  "(not supported)" is shown after
14  " the icon name when listing signs.
15  sign define Sign1 text=x
16  try
17    sign define Sign2 text=xy texthl=Title linehl=Error
18		\ icon=../../pixmaps/stock_vim_find_help.png
19  catch /E255:/
20    " Ignore error: E255: Couldn't read in sign data!
21    " This error can happen when running in the GUI.
22    " Some gui like Motif do not support the png icon format.
23  endtry
24
25  " Test listing signs.
26  let a=execute('sign list')
27  call assert_match('^\nsign Sign1 text=x \nsign Sign2 ' .
28	      \ 'icon=../../pixmaps/stock_vim_find_help.png .*text=xy ' .
29	      \ 'linehl=Error texthl=Title$', a)
30
31  let a=execute('sign list Sign1')
32  call assert_equal("\nsign Sign1 text=x ", a)
33
34  " Split the window to the bottom to verify sign jump will stay in the
35  " current window if the buffer is displayed there.
36  let bn = bufnr('%')
37  let wn = winnr()
38  exe 'sign place 41 line=3 name=Sign1 buffer=' . bn
39  1
40  bot split
41  exe 'sign jump 41 buffer=' . bufnr('%')
42  call assert_equal('c', getline('.'))
43  call assert_equal(3, winnr())
44  call assert_equal(bn, bufnr('%'))
45  call assert_notequal(wn, winnr())
46
47  " Create a new buffer and check that ":sign jump" switches to the old buffer.
48  1
49  new foo
50  call assert_notequal(bn, bufnr('%'))
51  exe 'sign jump 41 buffer=' . bn
52  call assert_equal(bn, bufnr('%'))
53  call assert_equal('c', getline('.'))
54
55  " Redraw to make sure that screen redraw with sign gets exercised,
56  " with and without 'rightleft'.
57  if has('rightleft')
58    set rightleft
59    redraw
60    set norightleft
61  endif
62  redraw
63
64  " Check that we can't change sign.
65  call assert_fails("sign place 40 name=Sign1 buffer=" . bufnr('%'), 'E885:')
66
67  " Check placed signs
68  let a=execute('sign place')
69  call assert_equal("\n--- Signs ---\nSigns for [NULL]:\n" .
70		\ "    line=3  id=41  name=Sign1  priority=10\n", a)
71
72  " Unplace the sign and try jumping to it again should fail.
73  sign unplace 41
74  1
75  call assert_fails("sign jump 41 buffer=" . bufnr('%'), 'E157:')
76  call assert_equal('a', getline('.'))
77
78  " Unplace sign on current line.
79  exe 'sign place 42 line=4 name=Sign2 buffer=' . bufnr('%')
80  4
81  sign unplace
82  let a=execute('sign place')
83  call assert_equal("\n--- Signs ---\n", a)
84
85  " Try again to unplace sign on current line, it should fail this time.
86  call assert_fails('sign unplace', 'E159:')
87
88  " Unplace all signs.
89  exe 'sign place 41 line=3 name=Sign1 buffer=' . bufnr('%')
90  sign unplace *
91  let a=execute('sign place')
92  call assert_equal("\n--- Signs ---\n", a)
93
94  " Place a sign without specifying the filename or buffer
95  sign place 77 line=9 name=Sign2
96  let a=execute('sign place')
97  call assert_equal("\n--- Signs ---\nSigns for [NULL]:\n" .
98		\ "    line=9  id=77  name=Sign2  priority=10\n", a)
99  sign unplace *
100
101  " Check :jump with file=...
102  edit foo
103  call setline(1, ['A', 'B', 'C', 'D'])
104
105  try
106    sign define Sign3 text=y texthl=DoesNotExist linehl=DoesNotExist
107		\ icon=doesnotexist.xpm
108  catch /E255:/
109    " ignore error: E255: it can happens for guis.
110  endtry
111
112  let fn = expand('%:p')
113  exe 'sign place 43 line=2 name=Sign3 file=' . fn
114  edit bar
115  call assert_notequal(fn, expand('%:p'))
116  exe 'sign jump 43 file=' . fn
117  call assert_equal('B', getline('.'))
118
119  " Check for jumping to a sign in a hidden buffer
120  enew! | only!
121  edit foo
122  call setline(1, ['A', 'B', 'C', 'D'])
123  let fn = expand('%:p')
124  exe 'sign place 21 line=3 name=Sign3 file=' . fn
125  hide edit bar
126  exe 'sign jump 21 file=' . fn
127  call assert_equal('C', getline('.'))
128
129  " can't define a sign with a non-printable character as text
130  call assert_fails("sign define Sign4 text=\e linehl=Comment", 'E239:')
131  call assert_fails("sign define Sign4 text=a\e linehl=Comment", 'E239:')
132  call assert_fails("sign define Sign4 text=\ea linehl=Comment", 'E239:')
133
134  " Only 1 or 2 character text is allowed
135  call assert_fails("sign define Sign4 text=abc linehl=Comment", 'E239:')
136  call assert_fails("sign define Sign4 text= linehl=Comment", 'E239:')
137  call assert_fails("sign define Sign4 text=\\ ab  linehl=Comment", 'E239:')
138
139  " define sign with whitespace
140  sign define Sign4 text=\ X linehl=Comment
141  sign undefine Sign4
142  sign define Sign4 linehl=Comment text=\ X
143  sign undefine Sign4
144
145  sign define Sign5 text=X\  linehl=Comment
146  sign undefine Sign5
147  sign define Sign5 linehl=Comment text=X\
148  sign undefine Sign5
149
150  " define sign with backslash
151  sign define Sign4 text=\\\\ linehl=Comment
152  sign undefine Sign4
153  sign define Sign4 text=\\ linehl=Comment
154  sign undefine Sign4
155
156  " define a sign with a leading 0 in the name
157  sign unplace *
158  sign define 004 text=#> linehl=Comment
159  let a = execute('sign list 4')
160  call assert_equal("\nsign 4 text=#> linehl=Comment", a)
161  exe 'sign place 20 line=3 name=004 buffer=' . bufnr('')
162  let a = execute('sign place')
163  call assert_equal("\n--- Signs ---\nSigns for foo:\n" .
164		\ "    line=3  id=20  name=4  priority=10\n", a)
165  exe 'sign unplace 20 buffer=' . bufnr('')
166  sign undefine 004
167  call assert_fails('sign list 4', 'E155:')
168
169  " After undefining the sign, we should no longer be able to place it.
170  sign undefine Sign1
171  sign undefine Sign2
172  sign undefine Sign3
173  call assert_fails("sign place 41 line=3 name=Sign1 buffer=" .
174			  \ bufnr('%'), 'E155:')
175endfunc
176
177" Undefining placed sign is not recommended.
178" Quoting :help sign
179"
180" :sign undefine {name}
181"                Deletes a previously defined sign.  If signs with this {name}
182"                are still placed this will cause trouble.
183func Test_sign_undefine_still_placed()
184  new foobar
185  sign define Sign text=x
186  exe 'sign place 41 line=1 name=Sign buffer=' . bufnr('%')
187  sign undefine Sign
188
189  " Listing placed sign should show that sign is deleted.
190  let a=execute('sign place')
191  call assert_equal("\n--- Signs ---\nSigns for foobar:\n" .
192		\ "    line=1  id=41  name=[Deleted]  priority=10\n", a)
193
194  sign unplace 41
195  let a=execute('sign place')
196  call assert_equal("\n--- Signs ---\n", a)
197endfunc
198
199func Test_sign_completion()
200  sign define Sign1 text=x
201  sign define Sign2 text=y
202
203  call feedkeys(":sign \<C-A>\<C-B>\"\<CR>", 'tx')
204  call assert_equal('"sign define jump list place undefine unplace', @:)
205
206  call feedkeys(":sign define Sign \<C-A>\<C-B>\"\<CR>", 'tx')
207  call assert_equal('"sign define Sign icon= linehl= text= texthl=', @:)
208
209  call feedkeys(":sign define Sign linehl=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
210  call assert_equal('"sign define Sign linehl=SpellBad SpellCap ' .
211	      \ 'SpellLocal SpellRare', @:)
212
213  call feedkeys(":sign define Sign texthl=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
214  call assert_equal('"sign define Sign texthl=SpellBad SpellCap ' .
215	      \ 'SpellLocal SpellRare', @:)
216
217  call writefile(repeat(["Sun is shining"], 30), "XsignOne")
218  call writefile(repeat(["Sky is blue"], 30), "XsignTwo")
219  call feedkeys(":sign define Sign icon=Xsig\<C-A>\<C-B>\"\<CR>", 'tx')
220  call assert_equal('"sign define Sign icon=XsignOne XsignTwo', @:)
221
222  " Test for completion of arguments to ':sign undefine'
223  call feedkeys(":sign undefine \<C-A>\<C-B>\"\<CR>", 'tx')
224  call assert_equal('"sign undefine Sign1 Sign2', @:)
225
226  call feedkeys(":sign place 1 \<C-A>\<C-B>\"\<CR>", 'tx')
227  call assert_equal('"sign place 1 buffer= file= group= line= name= priority=',
228	      \ @:)
229
230  call feedkeys(":sign place 1 name=\<C-A>\<C-B>\"\<CR>", 'tx')
231  call assert_equal('"sign place 1 name=Sign1 Sign2', @:)
232
233  edit XsignOne
234  sign place 1 name=Sign1 line=5
235  sign place 1 name=Sign1 group=g1 line=10
236  edit XsignTwo
237  sign place 1 name=Sign2 group=g2 line=15
238
239  " Test for completion of group= and file= arguments to ':sign place'
240  call feedkeys(":sign place 1 name=Sign1 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx')
241  call assert_equal('"sign place 1 name=Sign1 file=XsignOne XsignTwo', @:)
242  call feedkeys(":sign place 1 name=Sign1 group=\<C-A>\<C-B>\"\<CR>", 'tx')
243  call assert_equal('"sign place 1 name=Sign1 group=g1 g2', @:)
244
245  " Test for completion of arguments to 'sign place' without sign identifier
246  call feedkeys(":sign place \<C-A>\<C-B>\"\<CR>", 'tx')
247  call assert_equal('"sign place buffer= file= group=', @:)
248  call feedkeys(":sign place file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx')
249  call assert_equal('"sign place file=XsignOne XsignTwo', @:)
250  call feedkeys(":sign place group=\<C-A>\<C-B>\"\<CR>", 'tx')
251  call assert_equal('"sign place group=g1 g2', @:)
252  call feedkeys(":sign place group=g1 file=\<C-A>\<C-B>\"\<CR>", 'tx')
253  call assert_equal('"sign place group=g1 file=XsignOne XsignTwo', @:)
254
255  " Test for completion of arguments to ':sign unplace'
256  call feedkeys(":sign unplace 1 \<C-A>\<C-B>\"\<CR>", 'tx')
257  call assert_equal('"sign unplace 1 buffer= file= group=', @:)
258  call feedkeys(":sign unplace 1 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx')
259  call assert_equal('"sign unplace 1 file=XsignOne XsignTwo', @:)
260  call feedkeys(":sign unplace 1 group=\<C-A>\<C-B>\"\<CR>", 'tx')
261  call assert_equal('"sign unplace 1 group=g1 g2', @:)
262  call feedkeys(":sign unplace 1 group=g2 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx')
263  call assert_equal('"sign unplace 1 group=g2 file=XsignOne XsignTwo', @:)
264
265  " Test for completion of arguments to ':sign list'
266  call feedkeys(":sign list \<C-A>\<C-B>\"\<CR>", 'tx')
267  call assert_equal('"sign list Sign1 Sign2', @:)
268
269  " Test for completion of arguments to ':sign jump'
270  call feedkeys(":sign jump 1 \<C-A>\<C-B>\"\<CR>", 'tx')
271  call assert_equal('"sign jump 1 buffer= file= group=', @:)
272  call feedkeys(":sign jump 1 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx')
273  call assert_equal('"sign jump 1 file=XsignOne XsignTwo', @:)
274  call feedkeys(":sign jump 1 group=\<C-A>\<C-B>\"\<CR>", 'tx')
275  call assert_equal('"sign jump 1 group=g1 g2', @:)
276
277  " Error cases
278  call feedkeys(":sign here\<C-A>\<C-B>\"\<CR>", 'tx')
279  call assert_equal('"sign here', @:)
280  call feedkeys(":sign define Sign here=\<C-A>\<C-B>\"\<CR>", 'tx')
281  call assert_equal("\"sign define Sign here=\<C-A>", @:)
282  call feedkeys(":sign place 1 here=\<C-A>\<C-B>\"\<CR>", 'tx')
283  call assert_equal("\"sign place 1 here=\<C-A>", @:)
284  call feedkeys(":sign jump 1 here=\<C-A>\<C-B>\"\<CR>", 'tx')
285  call assert_equal("\"sign jump 1 here=\<C-A>", @:)
286  call feedkeys(":sign here there\<C-A>\<C-B>\"\<CR>", 'tx')
287  call assert_equal("\"sign here there\<C-A>", @:)
288  call feedkeys(":sign here there=\<C-A>\<C-B>\"\<CR>", 'tx')
289  call assert_equal("\"sign here there=\<C-A>", @:)
290
291  sign unplace * group=*
292  sign undefine Sign1
293  sign undefine Sign2
294  enew
295  call delete('XsignOne')
296  call delete('XsignTwo')
297endfunc
298
299func Test_sign_invalid_commands()
300  sign define Sign1 text=x
301
302  call assert_fails('sign', 'E471:')
303  call assert_fails('sign jump', 'E471:')
304  call assert_fails('sign xxx', 'E160:')
305  call assert_fails('sign define', 'E156:')
306  call assert_fails('sign define Sign1 xxx', 'E475:')
307  call assert_fails('sign undefine', 'E156:')
308  call assert_fails('sign list xxx', 'E155:')
309  call assert_fails('sign place 1 buffer=999', 'E158:')
310  call assert_fails('sign place 1 name=Sign1 buffer=999', 'E158:')
311  call assert_fails('sign place buffer=999', 'E158:')
312  call assert_fails('sign jump buffer=999', 'E158:')
313  call assert_fails('sign jump 1 file=', 'E158:')
314  call assert_fails('sign jump 1 group=', 'E474:')
315  call assert_fails('sign jump 1 name=', 'E474:')
316  call assert_fails('sign jump 1 name=Sign1', 'E474:')
317  call assert_fails('sign jump 1 line=100', '474:')
318  call assert_fails('sign define Sign2 text=', 'E239:')
319  " Non-numeric identifier for :sign place
320  call assert_fails("sign place abc line=3 name=Sign1 buffer=" . bufnr(''),
321								\ 'E474:')
322  " Non-numeric identifier for :sign unplace
323  call assert_fails("sign unplace abc name=Sign1 buffer=" . bufnr(''),
324								\ 'E474:')
325  " Number followed by an alphabet as sign identifier for :sign place
326  call assert_fails("sign place 1abc line=3 name=Sign1 buffer=" . bufnr(''),
327								\ 'E474:')
328  " Number followed by an alphabet as sign identifier for :sign unplace
329  call assert_fails("sign unplace 2abc name=Sign1 buffer=" . bufnr(''),
330								\ 'E474:')
331  " Sign identifier and '*' for :sign unplace
332  call assert_fails("sign unplace 2 *", 'E474:')
333  " Trailing characters after buffer number for :sign place
334  call assert_fails("sign place 1 line=3 name=Sign1 buffer=" .
335						\ bufnr('%') . 'xxx', 'E488:')
336  " Trailing characters after buffer number for :sign unplace
337  call assert_fails("sign unplace 1 buffer=" . bufnr('%') . 'xxx', 'E488:')
338  call assert_fails("sign unplace * buffer=" . bufnr('%') . 'xxx', 'E488:')
339  call assert_fails("sign unplace 1 xxx", 'E474:')
340  call assert_fails("sign unplace * xxx", 'E474:')
341  call assert_fails("sign unplace xxx", 'E474:')
342  " Placing a sign without line number
343  call assert_fails("sign place name=Sign1 buffer=" . bufnr('%'), 'E474:')
344  " Placing a sign without sign name
345  call assert_fails("sign place line=10 buffer=" . bufnr('%'), 'E474:')
346  " Unplacing a sign with line number
347  call assert_fails("sign unplace 2 line=10 buffer=" . bufnr('%'), 'E474:')
348  " Unplacing a sign with sign name
349  call assert_fails("sign unplace 2 name=Sign1 buffer=" . bufnr('%'), 'E474:')
350  " Placing a sign without sign name
351  call assert_fails("sign place 2 line=3 buffer=" . bufnr('%'), 'E474:')
352  " Placing a sign with only sign identifier
353  call assert_fails("sign place 2", 'E474:')
354  " Placing a sign with only a name
355  call assert_fails("sign place abc", 'E474:')
356  " Placing a sign with only line number
357  call assert_fails("sign place 5 line=3", 'E474:')
358  " Placing a sign with only sign group
359  call assert_fails("sign place 5 group=g1", 'E474:')
360  call assert_fails("sign place 5 group=*", 'E474:')
361  " Placing a sign with only sign priority
362  call assert_fails("sign place 5 priority=10", 'E474:')
363
364  sign undefine Sign1
365endfunc
366
367func Test_sign_delete_buffer()
368  new
369  sign define Sign text=x
370  let bufnr = bufnr('%')
371  new
372  exe 'bd ' . bufnr
373  exe 'sign place 61 line=3 name=Sign buffer=' . bufnr
374  call assert_fails('sign jump 61 buffer=' . bufnr, 'E934:')
375  sign unplace 61
376  sign undefine Sign
377endfunc
378
379" Test for Vim script functions for managing signs
380func Test_sign_funcs()
381  " Remove all the signs
382  call sign_unplace('*')
383  call sign_undefine()
384
385  " Tests for sign_define()
386  let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
387  call assert_equal(0, sign_define("sign1", attr))
388  call assert_equal([{'name' : 'sign1', 'texthl' : 'Error',
389	      \ 'linehl' : 'Search', 'text' : '=>'}], sign_getdefined())
390
391  " Define a new sign without attributes and then update it
392  call sign_define("sign2")
393  let attr = {'text' : '!!', 'linehl' : 'DiffAdd', 'texthl' : 'DiffChange',
394	      \ 'icon' : 'sign2.ico'}
395  try
396    call sign_define("sign2", attr)
397  catch /E255:/
398    " ignore error: E255: Couldn't read in sign data!
399    " This error can happen when running in gui.
400  endtry
401  call assert_equal([{'name' : 'sign2', 'texthl' : 'DiffChange',
402	      \ 'linehl' : 'DiffAdd', 'text' : '!!', 'icon' : 'sign2.ico'}],
403	      \ sign_getdefined("sign2"))
404
405  " Test for a sign name with digits
406  call assert_equal(0, sign_define(0002, {'linehl' : 'StatusLine'}))
407  call assert_equal([{'name' : '2', 'linehl' : 'StatusLine'}],
408	      \ sign_getdefined(0002))
409  call sign_undefine(0002)
410
411  " Tests for invalid arguments to sign_define()
412  call assert_fails('call sign_define("sign4", {"text" : "===>"})', 'E239:')
413  call assert_fails('call sign_define("sign5", {"text" : ""})', 'E239:')
414  call assert_fails('call sign_define([])', 'E730:')
415  call assert_fails('call sign_define("sign6", [])', 'E715:')
416
417  " Tests for sign_getdefined()
418  call assert_equal([], sign_getdefined("none"))
419  call assert_fails('call sign_getdefined({})', 'E731:')
420
421  " Tests for sign_place()
422  call writefile(repeat(["Sun is shining"], 30), "Xsign")
423  edit Xsign
424
425  call assert_equal(10, sign_place(10, '', 'sign1', 'Xsign',
426	      \ {'lnum' : 20}))
427  call assert_equal([{'bufnr' : bufnr(''), 'signs' :
428	      \ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
429	      \ 'priority' : 10}]}], sign_getplaced('Xsign'))
430  call assert_equal([{'bufnr' : bufnr(''), 'signs' :
431	      \ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
432	      \ 'priority' : 10}]}],
433	      \ sign_getplaced('%', {'lnum' : 20}))
434  call assert_equal([{'bufnr' : bufnr(''), 'signs' :
435	      \ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
436	      \ 'priority' : 10}]}],
437	      \ sign_getplaced('', {'id' : 10}))
438
439  " Tests for invalid arguments to sign_place()
440  call assert_fails('call sign_place([], "", "mySign", 1)', 'E745:')
441  call assert_fails('call sign_place(5, "", "mySign", -1)', 'E158:')
442  call assert_fails('call sign_place(-1, "", "sign1", "Xsign", [])',
443	      \ 'E474:')
444  call assert_fails('call sign_place(-1, "", "sign1", "Xsign",
445	      \ {"lnum" : 30})', 'E474:')
446  call assert_fails('call sign_place(10, "", "xsign1x", "Xsign",
447	      \ {"lnum" : 30})', 'E155:')
448  call assert_fails('call sign_place(10, "", "", "Xsign",
449	      \ {"lnum" : 30})', 'E155:')
450  call assert_fails('call sign_place(10, "", [], "Xsign",
451	      \ {"lnum" : 30})', 'E730:')
452  call assert_fails('call sign_place(5, "", "sign1", "abcxyz.xxx",
453	      \ {"lnum" : 10})', 'E158:')
454  call assert_fails('call sign_place(5, "", "sign1", "@", {"lnum" : 10})',
455	      \ 'E158:')
456  call assert_fails('call sign_place(5, "", "sign1", [], {"lnum" : 10})',
457	      \ 'E158:')
458  call assert_fails('call sign_place(21, "", "sign1", "Xsign",
459	      \ {"lnum" : -1})', 'E885:')
460  call assert_fails('call sign_place(22, "", "sign1", "Xsign",
461	      \ {"lnum" : 0})', 'E885:')
462  call assert_fails('call sign_place(22, "", "sign1", "Xsign",
463	      \ {"lnum" : []})', 'E745:')
464  call assert_equal(-1, sign_place(1, "*", "sign1", "Xsign", {"lnum" : 10}))
465
466  " Tests for sign_getplaced()
467  call assert_equal([{'bufnr' : bufnr(''), 'signs' :
468	      \ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
469	      \ 'priority' : 10}]}],
470	      \ sign_getplaced(bufnr('Xsign')))
471  call assert_equal([{'bufnr' : bufnr(''), 'signs' :
472	      \ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
473	      \ 'priority' : 10}]}],
474	      \ sign_getplaced())
475  call assert_fails("call sign_getplaced('dummy.sign')", 'E158:')
476  call assert_fails('call sign_getplaced("&")', 'E158:')
477  call assert_fails('call sign_getplaced(-1)', 'E158:')
478  call assert_fails('call sign_getplaced("Xsign", [])', 'E715:')
479  call assert_equal([{'bufnr' : bufnr(''), 'signs' : []}],
480	      \ sign_getplaced('Xsign', {'lnum' : 1000000}))
481  call assert_fails("call sign_getplaced('Xsign', {'lnum' : []})",
482	      \ 'E745:')
483  call assert_equal([{'bufnr' : bufnr(''), 'signs' : []}],
484	      \ sign_getplaced('Xsign', {'id' : 44}))
485  call assert_fails("call sign_getplaced('Xsign', {'id' : []})",
486	      \ 'E745:')
487
488  " Tests for sign_unplace()
489  call sign_place(20, '', 'sign2', 'Xsign', {"lnum" : 30})
490  call assert_equal(0, sign_unplace('',
491	      \ {'id' : 20, 'buffer' : 'Xsign'}))
492  call assert_equal(-1, sign_unplace('',
493	      \ {'id' : 30, 'buffer' : 'Xsign'}))
494  call sign_place(20, '', 'sign2', 'Xsign', {"lnum" : 30})
495  call assert_fails("call sign_unplace('',
496	      \ {'id' : 20, 'buffer' : 'buffer.c'})", 'E158:')
497  call assert_fails("call sign_unplace('',
498	      \ {'id' : 20, 'buffer' : '&'})", 'E158:')
499  call assert_fails("call sign_unplace('g1',
500	      \ {'id' : 20, 'buffer' : 200})", 'E158:')
501  call assert_fails("call sign_unplace('g1', 'mySign')", 'E715:')
502
503  " Tests for sign_undefine()
504  call assert_equal(0, sign_undefine("sign1"))
505  call assert_equal([], sign_getdefined("sign1"))
506  call assert_fails('call sign_undefine("none")', 'E155:')
507  call assert_fails('call sign_undefine([])', 'E730:')
508
509  call delete("Xsign")
510  call sign_unplace('*')
511  call sign_undefine()
512  enew | only
513endfunc
514
515" Tests for sign groups
516func Test_sign_group()
517  enew | only
518  " Remove all the signs
519  call sign_unplace('*')
520  call sign_undefine()
521
522  call writefile(repeat(["Sun is shining"], 30), "Xsign")
523
524  let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
525  call assert_equal(0, sign_define("sign1", attr))
526
527  edit Xsign
528  let bnum = bufnr('%')
529
530  " Error case
531  call assert_fails("call sign_place(5, [], 'sign1', 'Xsign',
532	      \ {'lnum' : 30})", 'E730:')
533
534  " place three signs with the same identifier. One in the global group and
535  " others in the named groups
536  call assert_equal(5, sign_place(5, '', 'sign1', 'Xsign',
537	      \ {'lnum' : 10}))
538  call assert_equal(5, sign_place(5, 'g1', 'sign1', bnum, {'lnum' : 20}))
539  call assert_equal(5, sign_place(5, 'g2', 'sign1', bnum, {'lnum' : 30}))
540
541  " Test for sign_getplaced() with group
542  let s = sign_getplaced('Xsign')
543  call assert_equal(1, len(s[0].signs))
544  call assert_equal(s[0].signs[0].group, '')
545  let s = sign_getplaced(bnum, {'group' : ''})
546  call assert_equal([{'id' : 5, 'group' : '', 'name' : 'sign1', 'lnum' : 10,
547	      \ 'priority' : 10}], s[0].signs)
548  call assert_equal(1, len(s[0].signs))
549  let s = sign_getplaced(bnum, {'group' : 'g2'})
550  call assert_equal('g2', s[0].signs[0].group)
551  let s = sign_getplaced(bnum, {'group' : 'g3'})
552  call assert_equal([], s[0].signs)
553  let s = sign_getplaced(bnum, {'group' : '*'})
554  call assert_equal([{'id' : 5, 'group' : '', 'name' : 'sign1', 'lnum' : 10,
555	      \ 'priority' : 10},
556	      \ {'id' : 5, 'group' : 'g1', 'name' : 'sign1', 'lnum' : 20,
557	      \  'priority' : 10},
558	      \ {'id' : 5, 'group' : 'g2', 'name' : 'sign1', 'lnum' : 30,
559	      \  'priority' : 10}],
560	      \ s[0].signs)
561
562  " Test for sign_getplaced() with id
563  let s = sign_getplaced(bnum, {'id' : 5})
564  call assert_equal([{'id' : 5, 'group' : '', 'name' : 'sign1', 'lnum' : 10,
565	      \ 'priority' : 10}],
566	      \ s[0].signs)
567  let s = sign_getplaced(bnum, {'id' : 5, 'group' : 'g2'})
568  call assert_equal(
569	      \ [{'id' : 5, 'name' : 'sign1', 'lnum' : 30, 'group' : 'g2',
570	      \ 'priority' : 10}],
571	      \ s[0].signs)
572  let s = sign_getplaced(bnum, {'id' : 5, 'group' : '*'})
573  call assert_equal([{'id' : 5, 'group' : '', 'name' : 'sign1', 'lnum' : 10,
574	      \ 'priority' : 10},
575	      \ {'id' : 5, 'group' : 'g1', 'name' : 'sign1', 'lnum' : 20,
576	      \ 'priority' : 10},
577	      \ {'id' : 5, 'group' : 'g2', 'name' : 'sign1', 'lnum' : 30,
578	      \ 'priority' : 10}],
579	      \ s[0].signs)
580  let s = sign_getplaced(bnum, {'id' : 5, 'group' : 'g3'})
581  call assert_equal([], s[0].signs)
582
583  " Test for sign_getplaced() with lnum
584  let s = sign_getplaced(bnum, {'lnum' : 20})
585  call assert_equal([], s[0].signs)
586  let s = sign_getplaced(bnum, {'lnum' : 20, 'group' : 'g1'})
587  call assert_equal(
588	      \ [{'id' : 5, 'name' : 'sign1', 'lnum' : 20, 'group' : 'g1',
589	      \ 'priority' : 10}],
590	      \ s[0].signs)
591  let s = sign_getplaced(bnum, {'lnum' : 30, 'group' : '*'})
592  call assert_equal(
593	      \ [{'id' : 5, 'name' : 'sign1', 'lnum' : 30, 'group' : 'g2',
594	      \ 'priority' : 10}],
595	      \ s[0].signs)
596  let s = sign_getplaced(bnum, {'lnum' : 40, 'group' : '*'})
597  call assert_equal([], s[0].signs)
598
599  " Error case
600  call assert_fails("call sign_getplaced(bnum, {'group' : []})",
601	      \ 'E730:')
602
603  " Clear the sign in global group
604  call sign_unplace('', {'id' : 5, 'buffer' : bnum})
605  let s = sign_getplaced(bnum, {'group' : '*'})
606  call assert_equal([
607	      \ {'id' : 5, 'name' : 'sign1', 'lnum' : 20, 'group' : 'g1',
608	      \ 'priority' : 10},
609	      \ {'id' : 5, 'name' : 'sign1', 'lnum' : 30, 'group' : 'g2',
610	      \ 'priority' : 10}],
611	      \ s[0].signs)
612
613  " Clear the sign in one of the groups
614  call sign_unplace('g1', {'buffer' : 'Xsign'})
615  let s = sign_getplaced(bnum, {'group' : '*'})
616  call assert_equal([
617	      \ {'id' : 5, 'name' : 'sign1', 'lnum' : 30, 'group' : 'g2',
618	      \ 'priority' : 10}],
619	      \ s[0].signs)
620
621  " Clear all the signs from the buffer
622  call sign_unplace('*', {'buffer' : bnum})
623  call assert_equal([], sign_getplaced(bnum, {'group' : '*'})[0].signs)
624
625  " Clear sign across groups using an identifier
626  call sign_place(25, '', 'sign1', bnum, {'lnum' : 10})
627  call sign_place(25, 'g1', 'sign1', bnum, {'lnum' : 11})
628  call sign_place(25, 'g2', 'sign1', bnum, {'lnum' : 12})
629  call assert_equal(0, sign_unplace('*', {'id' : 25}))
630  call assert_equal([], sign_getplaced(bnum, {'group' : '*'})[0].signs)
631
632  " Error case
633  call assert_fails("call sign_unplace([])", 'E474:')
634
635  " Place a sign in the global group and try to delete it using a group
636  call assert_equal(5, sign_place(5, '', 'sign1', bnum, {'lnum' : 10}))
637  call assert_equal(-1, sign_unplace('g1', {'id' : 5}))
638
639  " Place signs in multiple groups and delete all the signs in one of the
640  " group
641  call assert_equal(5, sign_place(5, '', 'sign1', bnum, {'lnum' : 10}))
642  call assert_equal(6, sign_place(6, '', 'sign1', bnum, {'lnum' : 11}))
643  call assert_equal(5, sign_place(5, 'g1', 'sign1', bnum, {'lnum' : 10}))
644  call assert_equal(5, sign_place(5, 'g2', 'sign1', bnum, {'lnum' : 10}))
645  call assert_equal(6, sign_place(6, 'g1', 'sign1', bnum, {'lnum' : 11}))
646  call assert_equal(6, sign_place(6, 'g2', 'sign1', bnum, {'lnum' : 11}))
647  call assert_equal(0, sign_unplace('g1'))
648  let s = sign_getplaced(bnum, {'group' : 'g1'})
649  call assert_equal([], s[0].signs)
650  let s = sign_getplaced(bnum)
651  call assert_equal(2, len(s[0].signs))
652  let s = sign_getplaced(bnum, {'group' : 'g2'})
653  call assert_equal('g2', s[0].signs[0].group)
654  call assert_equal(0, sign_unplace('', {'id' : 5}))
655  call assert_equal(0, sign_unplace('', {'id' : 6}))
656  let s = sign_getplaced(bnum, {'group' : 'g2'})
657  call assert_equal('g2', s[0].signs[0].group)
658  call assert_equal(0, sign_unplace('', {'buffer' : bnum}))
659
660  call sign_unplace('*')
661
662  " Test for :sign command and groups
663  sign place 5 line=10 name=sign1 file=Xsign
664  sign place 5 group=g1 line=10 name=sign1 file=Xsign
665  sign place 5 group=g2 line=10 name=sign1 file=Xsign
666
667  " Tests for the ':sign place' command
668
669  " :sign place file={fname}
670  let a = execute('sign place file=Xsign')
671  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
672	      \ "    line=10  id=5  name=sign1  priority=10\n", a)
673
674  " :sign place group={group} file={fname}
675  let a = execute('sign place group=g2 file=Xsign')
676  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
677	      \ "    line=10  id=5  group=g2  name=sign1  priority=10\n", a)
678
679  " :sign place group=* file={fname}
680  let a = execute('sign place group=* file=Xsign')
681  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
682	      \ "    line=10  id=5  group=g2  name=sign1  priority=10\n" .
683	      \ "    line=10  id=5  group=g1  name=sign1  priority=10\n" .
684	      \ "    line=10  id=5  name=sign1  priority=10\n", a)
685
686  " Error case: non-existing group
687  let a = execute('sign place group=xyz file=Xsign')
688  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n", a)
689
690  call sign_unplace('*')
691  let bnum = bufnr('Xsign')
692  exe 'sign place 5 line=10 name=sign1 buffer=' . bnum
693  exe 'sign place 5 group=g1 line=11 name=sign1 buffer=' . bnum
694  exe 'sign place 5 group=g2 line=12 name=sign1 buffer=' . bnum
695
696  " :sign place buffer={fname}
697  let a = execute('sign place buffer=' . bnum)
698  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
699	      \ "    line=10  id=5  name=sign1  priority=10\n", a)
700
701  " :sign place group={group} buffer={fname}
702  let a = execute('sign place group=g2 buffer=' . bnum)
703  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
704	      \ "    line=12  id=5  group=g2  name=sign1  priority=10\n", a)
705
706  " :sign place group=* buffer={fname}
707  let a = execute('sign place group=* buffer=' . bnum)
708  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
709	      \ "    line=10  id=5  name=sign1  priority=10\n" .
710	      \ "    line=11  id=5  group=g1  name=sign1  priority=10\n" .
711	      \ "    line=12  id=5  group=g2  name=sign1  priority=10\n", a)
712
713  " Error case: non-existing group
714  let a = execute('sign place group=xyz buffer=' . bnum)
715  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n", a)
716
717  " :sign place
718  let a = execute('sign place')
719  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
720	      \ "    line=10  id=5  name=sign1  priority=10\n", a)
721
722  " Place signs in more than one buffer and list the signs
723  split foo
724  set buftype=nofile
725  sign place 25 line=76 name=sign1 priority=99 file=foo
726  let a = execute('sign place')
727  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
728	      \ "    line=10  id=5  name=sign1  priority=10\n" .
729	      \ "Signs for foo:\n" .
730	      \ "    line=76  id=25  name=sign1  priority=99\n", a)
731  close
732  bwipe foo
733
734  " :sign place group={group}
735  let a = execute('sign place group=g1')
736  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
737	      \ "    line=11  id=5  group=g1  name=sign1  priority=10\n", a)
738
739  " :sign place group=*
740  let a = execute('sign place group=*')
741  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
742	      \ "    line=10  id=5  name=sign1  priority=10\n" .
743	      \ "    line=11  id=5  group=g1  name=sign1  priority=10\n" .
744	      \ "    line=12  id=5  group=g2  name=sign1  priority=10\n", a)
745
746  " Test for ':sign jump' command with groups
747  sign jump 5 group=g1 file=Xsign
748  call assert_equal(11, line('.'))
749  call assert_equal('Xsign', bufname(''))
750  sign jump 5 group=g2 file=Xsign
751  call assert_equal(12, line('.'))
752
753  " Test for :sign jump command without the filename or buffer
754  sign jump 5
755  call assert_equal(10, line('.'))
756  sign jump 5 group=g1
757  call assert_equal(11, line('.'))
758
759  " Error cases
760  call assert_fails("sign place 3 group= name=sign1 buffer=" . bnum, 'E474:')
761
762  call delete("Xsign")
763  call sign_unplace('*')
764  call sign_undefine()
765  enew | only
766endfunc
767
768" Place signs used for ":sign unplace" command test
769func Place_signs_for_test()
770  call sign_unplace('*')
771
772  sign place 3 line=10 name=sign1 file=Xsign1
773  sign place 3 group=g1 line=11 name=sign1 file=Xsign1
774  sign place 3 group=g2 line=12 name=sign1 file=Xsign1
775  sign place 4 line=15 name=sign1 file=Xsign1
776  sign place 4 group=g1 line=16 name=sign1 file=Xsign1
777  sign place 4 group=g2 line=17 name=sign1 file=Xsign1
778  sign place 5 line=20 name=sign1 file=Xsign2
779  sign place 5 group=g1 line=21 name=sign1 file=Xsign2
780  sign place 5 group=g2 line=22 name=sign1 file=Xsign2
781  sign place 6 line=25 name=sign1 file=Xsign2
782  sign place 6 group=g1 line=26 name=sign1 file=Xsign2
783  sign place 6 group=g2 line=27 name=sign1 file=Xsign2
784endfunc
785
786" Place multiple signs in a single line for test
787func Place_signs_at_line_for_test()
788  call sign_unplace('*')
789  sign place 3 line=13 name=sign1 file=Xsign1
790  sign place 3 group=g1 line=13 name=sign1 file=Xsign1
791  sign place 3 group=g2 line=13 name=sign1 file=Xsign1
792  sign place 4 line=13 name=sign1 file=Xsign1
793  sign place 4 group=g1 line=13 name=sign1 file=Xsign1
794  sign place 4 group=g2 line=13 name=sign1 file=Xsign1
795endfunc
796
797" Tests for the ':sign unplace' command
798func Test_sign_unplace()
799  enew | only
800  " Remove all the signs
801  call sign_unplace('*')
802  call sign_undefine()
803
804  " Create two files and define signs
805  call writefile(repeat(["Sun is shining"], 30), "Xsign1")
806  call writefile(repeat(["It is beautiful"], 30), "Xsign2")
807
808  let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
809  call sign_define("sign1", attr)
810
811  edit Xsign1
812  let bnum1 = bufnr('%')
813  split Xsign2
814  let bnum2 = bufnr('%')
815
816  let signs1 = [{'id' : 3, 'name' : 'sign1', 'lnum' : 10, 'group' : '',
817	      \ 'priority' : 10},
818	      \ {'id' : 3, 'name' : 'sign1', 'lnum' : 11, 'group' : 'g1',
819	      \ 'priority' : 10},
820	      \ {'id' : 3, 'name' : 'sign1', 'lnum' : 12, 'group' : 'g2',
821	      \ 'priority' : 10},
822	      \ {'id' : 4, 'name' : 'sign1', 'lnum' : 15, 'group' : '',
823	      \ 'priority' : 10},
824	      \ {'id' : 4, 'name' : 'sign1', 'lnum' : 16, 'group' : 'g1',
825	      \ 'priority' : 10},
826	      \ {'id' : 4, 'name' : 'sign1', 'lnum' : 17, 'group' : 'g2',
827	      \ 'priority' : 10},]
828  let signs2 = [{'id' : 5, 'name' : 'sign1', 'lnum' : 20, 'group' : '',
829	      \ 'priority' : 10},
830	      \ {'id' : 5, 'name' : 'sign1', 'lnum' : 21, 'group' : 'g1',
831	      \ 'priority' : 10},
832	      \ {'id' : 5, 'name' : 'sign1', 'lnum' : 22, 'group' : 'g2',
833	      \ 'priority' : 10},
834	      \ {'id' : 6, 'name' : 'sign1', 'lnum' : 25, 'group' : '',
835	      \ 'priority' : 10},
836	      \ {'id' : 6, 'name' : 'sign1', 'lnum' : 26, 'group' : 'g1',
837	      \ 'priority' : 10},
838	      \ {'id' : 6, 'name' : 'sign1', 'lnum' : 27, 'group' : 'g2',
839	      \ 'priority' : 10},]
840
841  " Test for :sign unplace {id} file={fname}
842  call Place_signs_for_test()
843  sign unplace 3 file=Xsign1
844  sign unplace 6 file=Xsign2
845  call assert_equal(
846	      \ filter(copy(signs1),
847	      \     {idx, val -> val.id != 3 || val.group != ''}),
848	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
849  call assert_equal(
850	      \ filter(copy(signs2),
851	      \     {idx, val -> val.id != 6 || val.group != ''}),
852	      \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
853
854  " Test for :sign unplace {id} group={group} file={fname}
855  call Place_signs_for_test()
856  sign unplace 4 group=g1 file=Xsign1
857  sign unplace 5 group=g2 file=Xsign2
858  call assert_equal(
859	      \ filter(copy(signs1),
860	      \     {idx, val -> val.id != 4 || val.group != 'g1'}),
861	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
862  call assert_equal(
863	      \ filter(copy(signs2),
864	      \     {idx, val -> val.id != 5 || val.group != 'g2'}),
865	      \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
866
867  " Test for :sign unplace {id} group=* file={fname}
868  call Place_signs_for_test()
869  sign unplace 3 group=* file=Xsign1
870  sign unplace 6 group=* file=Xsign2
871  call assert_equal(
872	      \ filter(copy(signs1),
873	      \     {idx, val -> val.id != 3}),
874	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
875  call assert_equal(
876	      \ filter(copy(signs2),
877	      \     {idx, val -> val.id != 6}),
878	      \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
879
880  " Test for :sign unplace * file={fname}
881  call Place_signs_for_test()
882  sign unplace * file=Xsign1
883  call assert_equal(
884	      \ filter(copy(signs1),
885	      \     {idx, val -> val.group != ''}),
886	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
887  call assert_equal(signs2, sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
888
889  " Test for :sign unplace * group={group} file={fname}
890  call Place_signs_for_test()
891  sign unplace * group=g1 file=Xsign1
892  sign unplace * group=g2 file=Xsign2
893  call assert_equal(
894	      \ filter(copy(signs1),
895	      \     {idx, val -> val.group != 'g1'}),
896	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
897  call assert_equal(
898	      \ filter(copy(signs2),
899	      \     {idx, val -> val.group != 'g2'}),
900	      \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
901
902  " Test for :sign unplace * group=* file={fname}
903  call Place_signs_for_test()
904  sign unplace * group=* file=Xsign2
905  call assert_equal(signs1, sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
906  call assert_equal([], sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
907
908  " Test for :sign unplace {id} buffer={nr}
909  call Place_signs_for_test()
910  exe 'sign unplace 3 buffer=' . bnum1
911  exe 'sign unplace 6 buffer=' . bnum2
912  call assert_equal(
913	      \ filter(copy(signs1),
914	      \     {idx, val -> val.id != 3 || val.group != ''}),
915	      \ sign_getplaced(bnum1, {'group' : '*'})[0].signs)
916  call assert_equal(
917	      \ filter(copy(signs2),
918	      \     {idx, val -> val.id != 6 || val.group != ''}),
919	      \ sign_getplaced(bnum2, {'group' : '*'})[0].signs)
920
921  " Test for :sign unplace {id} group={group} buffer={nr}
922  call Place_signs_for_test()
923  exe 'sign unplace 4 group=g1 buffer=' . bnum1
924  exe 'sign unplace 5 group=g2 buffer=' . bnum2
925  call assert_equal(
926	      \ filter(copy(signs1),
927	      \     {idx, val -> val.id != 4 || val.group != 'g1'}),
928	      \ sign_getplaced(bnum1, {'group' : '*'})[0].signs)
929  call assert_equal(
930	      \ filter(copy(signs2),
931	      \     {idx, val -> val.id != 5 || val.group != 'g2'}),
932	      \ sign_getplaced(bnum2, {'group' : '*'})[0].signs)
933
934  " Test for :sign unplace {id} group=* buffer={nr}
935  call Place_signs_for_test()
936  exe 'sign unplace 3 group=* buffer=' . bnum1
937  exe 'sign unplace 6 group=* buffer=' . bnum2
938  call assert_equal(
939	      \ filter(copy(signs1),
940	      \     {idx, val -> val.id != 3}),
941	      \ sign_getplaced(bnum1, {'group' : '*'})[0].signs)
942  call assert_equal(
943	      \ filter(copy(signs2),
944	      \     {idx, val -> val.id != 6}),
945	      \ sign_getplaced(bnum2, {'group' : '*'})[0].signs)
946
947  " Test for :sign unplace * buffer={nr}
948  call Place_signs_for_test()
949  exe 'sign unplace * buffer=' . bnum1
950  call assert_equal(
951	      \ filter(copy(signs1),
952	      \     {idx, val -> val.group != ''}),
953	      \ sign_getplaced(bnum1, {'group' : '*'})[0].signs)
954  call assert_equal(signs2, sign_getplaced(bnum2, {'group' : '*'})[0].signs)
955
956  " Test for :sign unplace * group={group} buffer={nr}
957  call Place_signs_for_test()
958  exe 'sign unplace * group=g1 buffer=' . bnum1
959  exe 'sign unplace * group=g2 buffer=' . bnum2
960  call assert_equal(
961	      \ filter(copy(signs1),
962	      \     {idx, val -> val.group != 'g1'}),
963	      \ sign_getplaced(bnum1, {'group' : '*'})[0].signs)
964  call assert_equal(
965	      \ filter(copy(signs2),
966	      \     {idx, val -> val.group != 'g2'}),
967	      \ sign_getplaced(bnum2, {'group' : '*'})[0].signs)
968
969  " Test for :sign unplace * group=* buffer={nr}
970  call Place_signs_for_test()
971  exe 'sign unplace * group=* buffer=' . bnum2
972  call assert_equal(signs1, sign_getplaced(bnum1, {'group' : '*'})[0].signs)
973  call assert_equal([], sign_getplaced(bnum2, {'group' : '*'})[0].signs)
974
975  " Test for :sign unplace {id}
976  call Place_signs_for_test()
977  sign unplace 4
978  sign unplace 6
979  call assert_equal(
980	      \ filter(copy(signs1),
981	      \     {idx, val -> val.id != 4 || val.group != ''}),
982	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
983  call assert_equal(
984	      \ filter(copy(signs2),
985	      \     {idx, val -> val.id != 6 || val.group != ''}),
986	      \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
987
988  " Test for :sign unplace {id} group={group}
989  call Place_signs_for_test()
990  sign unplace 4 group=g1
991  sign unplace 6 group=g2
992  call assert_equal(
993	      \ filter(copy(signs1),
994	      \     {idx, val -> val.id != 4 || val.group != 'g1'}),
995	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
996  call assert_equal(
997	      \ filter(copy(signs2),
998	      \     {idx, val -> val.id != 6 || val.group != 'g2'}),
999	      \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
1000
1001  " Test for :sign unplace {id} group=*
1002  call Place_signs_for_test()
1003  sign unplace 3 group=*
1004  sign unplace 5 group=*
1005  call assert_equal(
1006	      \ filter(copy(signs1),
1007	      \     {idx, val -> val.id != 3}),
1008	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
1009  call assert_equal(
1010	      \ filter(copy(signs2),
1011	      \     {idx, val -> val.id != 5}),
1012	      \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
1013
1014  " Test for :sign unplace *
1015  call Place_signs_for_test()
1016  sign unplace *
1017  call assert_equal(
1018	      \ filter(copy(signs1),
1019	      \     {idx, val -> val.group != ''}),
1020	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
1021  call assert_equal(
1022	      \ filter(copy(signs2),
1023	      \     {idx, val -> val.group != ''}),
1024	      \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
1025
1026  " Test for :sign unplace * group={group}
1027  call Place_signs_for_test()
1028  sign unplace * group=g1
1029  call assert_equal(
1030	      \ filter(copy(signs1),
1031	      \     {idx, val -> val.group != 'g1'}),
1032	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
1033  call assert_equal(
1034	      \ filter(copy(signs2),
1035	      \     {idx, val -> val.group != 'g1'}),
1036	      \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
1037
1038  " Test for :sign unplace * group=*
1039  call Place_signs_for_test()
1040  sign unplace * group=*
1041  call assert_equal([], sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
1042  call assert_equal([], sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
1043
1044  " Negative test cases
1045  call Place_signs_for_test()
1046  sign unplace 3 group=xy file=Xsign1
1047  sign unplace * group=xy file=Xsign1
1048  silent! sign unplace * group=* file=FileNotPresent
1049  call assert_equal(signs1, sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
1050  call assert_equal(signs2, sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
1051
1052  " Tests for removing sign at the current cursor position
1053
1054  " Test for ':sign unplace'
1055  let signs1 = [{'id' : 4, 'name' : 'sign1', 'lnum' : 13, 'group' : 'g2',
1056	      \ 'priority' : 10},
1057	      \ {'id' : 4, 'name' : 'sign1', 'lnum' : 13, 'group' : 'g1',
1058	      \ 'priority' : 10},
1059	      \ {'id' : 4, 'name' : 'sign1', 'lnum' : 13, 'group' : '',
1060	      \ 'priority' : 10},
1061	      \ {'id' : 3, 'name' : 'sign1', 'lnum' : 13, 'group' : 'g2',
1062	      \ 'priority' : 10},
1063	      \ {'id' : 3, 'name' : 'sign1', 'lnum' : 13, 'group' : 'g1',
1064	      \ 'priority' : 10},
1065	      \ {'id' : 3, 'name' : 'sign1', 'lnum' : 13, 'group' : '',
1066	      \ 'priority' : 10},]
1067  exe bufwinnr('Xsign1') . 'wincmd w'
1068  call cursor(13, 1)
1069
1070  " Should remove only one sign in the global group
1071  call Place_signs_at_line_for_test()
1072  sign unplace
1073  call assert_equal(
1074	      \ filter(copy(signs1),
1075	      \     {idx, val -> val.id != 4 || val.group != ''}),
1076	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
1077  " Should remove the second sign in the global group
1078  sign unplace
1079  call assert_equal(
1080	      \ filter(copy(signs1),
1081	      \     {idx, val -> val.group != ''}),
1082	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
1083
1084  " Test for ':sign unplace group={group}'
1085  call Place_signs_at_line_for_test()
1086  " Should remove only one sign in group g1
1087  sign unplace group=g1
1088  call assert_equal(
1089	      \ filter(copy(signs1),
1090	      \     {idx, val -> val.id != 4 || val.group != 'g1'}),
1091	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
1092  sign unplace group=g2
1093  call assert_equal(
1094	      \ filter(copy(signs1),
1095	      \     {idx, val -> val.id != 4 || val.group == ''}),
1096	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
1097
1098  " Test for ':sign unplace group=*'
1099  call Place_signs_at_line_for_test()
1100  sign unplace group=*
1101  sign unplace group=*
1102  sign unplace group=*
1103  call assert_equal(
1104	      \ filter(copy(signs1),
1105	      \     {idx, val -> val.id != 4}),
1106	      \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
1107  sign unplace group=*
1108  sign unplace group=*
1109  sign unplace group=*
1110  call assert_equal([], sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
1111
1112  call sign_unplace('*')
1113  call sign_undefine()
1114  enew | only
1115  call delete("Xsign1")
1116  call delete("Xsign2")
1117endfunc
1118
1119" Tests for auto-generating the sign identifier
1120func Test_sign_id_autogen()
1121  enew | only
1122  call sign_unplace('*')
1123  call sign_undefine()
1124
1125  let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
1126  call assert_equal(0, sign_define("sign1", attr))
1127
1128  call writefile(repeat(["Sun is shining"], 30), "Xsign")
1129  edit Xsign
1130
1131  call assert_equal(1, sign_place(0, '', 'sign1', 'Xsign',
1132	      \ {'lnum' : 10}))
1133  call assert_equal(2, sign_place(2, '', 'sign1', 'Xsign',
1134	      \ {'lnum' : 12}))
1135  call assert_equal(3, sign_place(0, '', 'sign1', 'Xsign',
1136	      \ {'lnum' : 14}))
1137  call sign_unplace('', {'buffer' : 'Xsign', 'id' : 2})
1138  call assert_equal(4, sign_place(0, '', 'sign1', 'Xsign',
1139	      \ {'lnum' : 12}))
1140
1141  call assert_equal(1, sign_place(0, 'g1', 'sign1', 'Xsign',
1142	      \ {'lnum' : 11}))
1143  " Check for the next generated sign id in this group
1144  call assert_equal(2, sign_place(0, 'g1', 'sign1', 'Xsign',
1145	      \ {'lnum' : 12}))
1146  call assert_equal(0, sign_unplace('g1', {'id' : 1}))
1147  call assert_equal(10,
1148	      \ sign_getplaced('Xsign', {'id' : 1})[0].signs[0].lnum)
1149
1150  call delete("Xsign")
1151  call sign_unplace('*')
1152  call sign_undefine()
1153  enew | only
1154endfunc
1155
1156" Test for sign priority
1157func Test_sign_priority()
1158  enew | only
1159  call sign_unplace('*')
1160  call sign_undefine()
1161
1162  let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Search'}
1163  call sign_define("sign1", attr)
1164  call sign_define("sign2", attr)
1165  call sign_define("sign3", attr)
1166
1167  " Place three signs with different priority in the same line
1168  call writefile(repeat(["Sun is shining"], 30), "Xsign")
1169  edit Xsign
1170
1171  call sign_place(1, 'g1', 'sign1', 'Xsign',
1172	      \ {'lnum' : 11, 'priority' : 50})
1173  call sign_place(2, 'g2', 'sign2', 'Xsign',
1174	      \ {'lnum' : 11, 'priority' : 100})
1175  call sign_place(3, '', 'sign3', 'Xsign', {'lnum' : 11})
1176  let s = sign_getplaced('Xsign', {'group' : '*'})
1177  call assert_equal([
1178	      \ {'id' : 2, 'name' : 'sign2', 'lnum' : 11, 'group' : 'g2',
1179	      \ 'priority' : 100},
1180	      \ {'id' : 1, 'name' : 'sign1', 'lnum' : 11, 'group' : 'g1',
1181	      \ 'priority' : 50},
1182	      \ {'id' : 3, 'name' : 'sign3', 'lnum' : 11, 'group' : '',
1183	      \ 'priority' : 10}],
1184	      \ s[0].signs)
1185
1186  " Error case
1187  call assert_fails("call sign_place(1, 'g1', 'sign1', 'Xsign',
1188	      \ [])", 'E715:')
1189  call assert_fails("call sign_place(1, 'g1', 'sign1', 'Xsign',
1190	      \ {'priority' : []})", 'E745:')
1191  call sign_unplace('*')
1192
1193  " Tests for the :sign place command with priority
1194  sign place 5 line=10 name=sign1 priority=30 file=Xsign
1195  sign place 5 group=g1 line=10 name=sign1 priority=20 file=Xsign
1196  sign place 5 group=g2 line=10 name=sign1 priority=25 file=Xsign
1197  let a = execute('sign place group=*')
1198  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
1199	      \ "    line=10  id=5  name=sign1  priority=30\n" .
1200	      \ "    line=10  id=5  group=g2  name=sign1  priority=25\n" .
1201	      \ "    line=10  id=5  group=g1  name=sign1  priority=20\n", a)
1202
1203  " Test for :sign place group={group}
1204  let a = execute('sign place group=g1')
1205  call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
1206	      \ "    line=10  id=5  group=g1  name=sign1  priority=20\n", a)
1207
1208  call sign_unplace('*')
1209  call sign_undefine()
1210  enew | only
1211  call delete("Xsign")
1212endfunc
1213
1214" Tests for memory allocation failures in sign functions
1215func Test_sign_memfailures()
1216  call writefile(repeat(["Sun is shining"], 30), "Xsign")
1217  edit Xsign
1218
1219  call test_alloc_fail(GetAllocId('sign_getdefined'), 0, 0)
1220  call assert_fails('call sign_getdefined("sign1")', 'E342:')
1221  call test_alloc_fail(GetAllocId('sign_getplaced'), 0, 0)
1222  call assert_fails('call sign_getplaced("Xsign")', 'E342:')
1223  call test_alloc_fail(GetAllocId('sign_define_by_name'), 0, 0)
1224  let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
1225  call assert_fails('call sign_define("sign1", attr)', 'E342:')
1226
1227  let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
1228  call sign_define("sign1", attr)
1229  call test_alloc_fail(GetAllocId('sign_getlist'), 0, 0)
1230  call assert_fails('call sign_getdefined("sign1")', 'E342:')
1231
1232  call sign_place(3, 'g1', 'sign1', 'Xsign', {'lnum' : 10})
1233  call test_alloc_fail(GetAllocId('sign_getplaced_dict'), 0, 0)
1234  call assert_fails('call sign_getplaced("Xsign")', 'E342:')
1235  call test_alloc_fail(GetAllocId('sign_getplaced_list'), 0, 0)
1236  call assert_fails('call sign_getplaced("Xsign")', 'E342:')
1237
1238  call test_alloc_fail(GetAllocId('insert_sign'), 0, 0)
1239  call assert_fails('call sign_place(4, "g1", "sign1", "Xsign", {"lnum" : 11})',
1240								\ 'E342:')
1241
1242  call test_alloc_fail(GetAllocId('sign_getinfo'), 0, 0)
1243  call assert_fails('call getbufinfo()', 'E342:')
1244  call sign_place(4, 'g1', 'sign1', 'Xsign', {'lnum' : 11})
1245  call test_alloc_fail(GetAllocId('sign_getinfo'), 0, 0)
1246  call assert_fails('let binfo=getbufinfo("Xsign")', 'E342:')
1247  call assert_equal([{'lnum': 11, 'id': 4, 'name': 'sign1',
1248	      \ 'priority': 10, 'group': 'g1'}], binfo[0].signs)
1249
1250  call sign_unplace('*')
1251  call sign_undefine()
1252  enew | only
1253  call delete("Xsign")
1254endfunc
1255
1256" Test for auto-adjusting the line number of a placed sign.
1257func Test_sign_lnum_adjust()
1258  enew! | only!
1259
1260  sign define sign1 text=#> linehl=Comment
1261  call setline(1, ['A', 'B', 'C', 'D', 'E'])
1262  exe 'sign place 5 line=3 name=sign1 buffer=' . bufnr('')
1263  let l = sign_getplaced(bufnr(''))
1264  call assert_equal(3, l[0].signs[0].lnum)
1265
1266  " Add some lines before the sign and check the sign line number
1267  call append(2, ['BA', 'BB', 'BC'])
1268  let l = sign_getplaced(bufnr(''))
1269  call assert_equal(6, l[0].signs[0].lnum)
1270
1271  " Delete some lines before the sign and check the sign line number
1272  call deletebufline('%', 1, 2)
1273  let l = sign_getplaced(bufnr(''))
1274  call assert_equal(4, l[0].signs[0].lnum)
1275
1276  " Insert some lines after the sign and check the sign line number
1277  call append(5, ['DA', 'DB'])
1278  let l = sign_getplaced(bufnr(''))
1279  call assert_equal(4, l[0].signs[0].lnum)
1280
1281  " Delete some lines after the sign and check the sign line number
1282  call deletebufline('', 6, 7)
1283  let l = sign_getplaced(bufnr(''))
1284  call assert_equal(4, l[0].signs[0].lnum)
1285
1286  " Break the undo. Otherwise the undo operation below will undo all the
1287  " changes made by this function.
1288  let &undolevels=&undolevels
1289
1290  " Delete the line with the sign
1291  call deletebufline('', 4)
1292  let l = sign_getplaced(bufnr(''))
1293  call assert_equal(4, l[0].signs[0].lnum)
1294
1295  " Undo the delete operation
1296  undo
1297  let l = sign_getplaced(bufnr(''))
1298  call assert_equal(5, l[0].signs[0].lnum)
1299
1300  " Break the undo
1301  let &undolevels=&undolevels
1302
1303  " Delete few lines at the end of the buffer including the line with the sign
1304  " Sign line number should not change (as it is placed outside of the buffer)
1305  call deletebufline('', 3, 6)
1306  let l = sign_getplaced(bufnr(''))
1307  call assert_equal(5, l[0].signs[0].lnum)
1308
1309  " Undo the delete operation. Sign should be restored to the previous line
1310  undo
1311  let l = sign_getplaced(bufnr(''))
1312  call assert_equal(5, l[0].signs[0].lnum)
1313
1314  sign unplace * group=*
1315  sign undefine sign1
1316  enew!
1317endfunc
1318
1319" Test for changing the type of a placed sign
1320func Test_sign_change_type()
1321  enew! | only!
1322
1323  sign define sign1 text=#> linehl=Comment
1324  sign define sign2 text=@@ linehl=Comment
1325
1326  call setline(1, ['A', 'B', 'C', 'D'])
1327  exe 'sign place 4 line=3 name=sign1 buffer=' . bufnr('')
1328  let l = sign_getplaced(bufnr(''))
1329  call assert_equal('sign1', l[0].signs[0].name)
1330  exe 'sign place 4 name=sign2 buffer=' . bufnr('')
1331  let l = sign_getplaced(bufnr(''))
1332  call assert_equal('sign2', l[0].signs[0].name)
1333  call sign_place(4, '', 'sign1', '')
1334  let l = sign_getplaced(bufnr(''))
1335  call assert_equal('sign1', l[0].signs[0].name)
1336
1337  exe 'sign place 4 group=g1 line=4 name=sign1 buffer=' . bufnr('')
1338  let l = sign_getplaced(bufnr(''), {'group' : 'g1'})
1339  call assert_equal('sign1', l[0].signs[0].name)
1340  exe 'sign place 4 group=g1 name=sign2 buffer=' . bufnr('')
1341  let l = sign_getplaced(bufnr(''), {'group' : 'g1'})
1342  call assert_equal('sign2', l[0].signs[0].name)
1343  call sign_place(4, 'g1', 'sign1', '')
1344  let l = sign_getplaced(bufnr(''), {'group' : 'g1'})
1345  call assert_equal('sign1', l[0].signs[0].name)
1346
1347  sign unplace * group=*
1348  sign undefine sign1
1349  sign undefine sign2
1350  enew!
1351endfunc
1352
1353" Test for the sign_jump() function
1354func Test_sign_jump_func()
1355  enew! | only!
1356
1357  sign define sign1 text=#> linehl=Comment
1358
1359  edit foo
1360  set buftype=nofile
1361  call setline(1, ['A', 'B', 'C', 'D', 'E'])
1362  call sign_place(5, '', 'sign1', '', {'lnum' : 2})
1363  call sign_place(5, 'g1', 'sign1', '', {'lnum' : 3})
1364  call sign_place(6, '', 'sign1', '', {'lnum' : 4})
1365  call sign_place(6, 'g1', 'sign1', '', {'lnum' : 5})
1366  split bar
1367  set buftype=nofile
1368  call setline(1, ['P', 'Q', 'R', 'S', 'T'])
1369  call sign_place(5, '', 'sign1', '', {'lnum' : 2})
1370  call sign_place(5, 'g1', 'sign1', '', {'lnum' : 3})
1371  call sign_place(6, '', 'sign1', '', {'lnum' : 4})
1372  call sign_place(6, 'g1', 'sign1', '', {'lnum' : 5})
1373
1374  let r = sign_jump(5, '', 'foo')
1375  call assert_equal(2, r)
1376  call assert_equal(2, line('.'))
1377  let r = sign_jump(6, 'g1', 'foo')
1378  call assert_equal(5, r)
1379  call assert_equal(5, line('.'))
1380  let r = sign_jump(5, '', 'bar')
1381  call assert_equal(2, r)
1382  call assert_equal(2, line('.'))
1383
1384  " Error cases
1385  call assert_fails("call sign_jump(99, '', 'bar')", 'E157:')
1386  call assert_fails("call sign_jump(0, '', 'foo')", 'E474:')
1387  call assert_fails("call sign_jump(5, 'g5', 'foo')", 'E157:')
1388  call assert_fails('call sign_jump([], "", "foo")', 'E745:')
1389  call assert_fails('call sign_jump(2, [], "foo")', 'E730:')
1390  call assert_fails('call sign_jump(2, "", {})', 'E158:')
1391  call assert_fails('call sign_jump(2, "", "baz")', 'E158:')
1392
1393  sign unplace * group=*
1394  sign undefine sign1
1395  enew! | only!
1396endfunc
1397