blob: 8c3f33dd67b324d2f78ad4c295bdce70a32a4f23 [file] [log] [blame]
Bram Moolenaar53f0c962017-10-22 14:23:59 +02001" Test for user functions.
2" Also test an <expr> mapping calling a function.
3" Also test that a builtin function cannot be replaced.
4" Also test for regression when calling arbitrary expression.
5
Bram Moolenaar476a6132020-04-08 19:48:56 +02006source check.vim
7source shared.vim
Bram Moolenaar16900322022-09-08 19:51:45 +01008import './vim9.vim' as v9
Bram Moolenaar476a6132020-04-08 19:48:56 +02009
Bram Moolenaar53f0c962017-10-22 14:23:59 +020010func Table(title, ...)
11 let ret = a:title
12 let idx = 1
13 while idx <= a:0
14 exe "let ret = ret . a:" . idx
15 let idx = idx + 1
16 endwhile
17 return ret
18endfunc
19
20func Compute(n1, n2, divname)
21 if a:n2 == 0
22 return "fail"
23 endif
24 exe "let g:" . a:divname . " = ". a:n1 / a:n2
25 return "ok"
26endfunc
27
28func Expr1()
29 silent! normal! v
30 return "111"
31endfunc
32
33func Expr2()
34 call search('XX', 'b')
35 return "222"
36endfunc
37
38func ListItem()
39 let g:counter += 1
40 return g:counter . '. '
41endfunc
42
43func ListReset()
44 let g:counter = 0
45 return ''
46endfunc
47
48func FuncWithRef(a)
49 unlet g:FuncRef
50 return a:a
51endfunc
52
53func Test_user_func()
Bram Moolenaarfcfe1a92019-08-04 23:04:39 +020054 let g:FuncRef = function("FuncWithRef")
Bram Moolenaar53f0c962017-10-22 14:23:59 +020055 let g:counter = 0
56 inoremap <expr> ( ListItem()
57 inoremap <expr> [ ListReset()
58 imap <expr> + Expr1()
59 imap <expr> * Expr2()
60 let g:retval = "nop"
61
62 call assert_equal('xxx4asdf', Table("xxx", 4, "asdf"))
63 call assert_equal('fail', Compute(45, 0, "retval"))
64 call assert_equal('nop', g:retval)
65 call assert_equal('ok', Compute(45, 5, "retval"))
66 call assert_equal(9, g:retval)
67 call assert_equal(333, g:FuncRef(333))
68
Bram Moolenaarfcfe1a92019-08-04 23:04:39 +020069 let g:retval = "nop"
70 call assert_equal('xxx4asdf', "xxx"->Table(4, "asdf"))
71 call assert_equal('fail', 45->Compute(0, "retval"))
72 call assert_equal('nop', g:retval)
73 call assert_equal('ok', 45->Compute(5, "retval"))
74 call assert_equal(9, g:retval)
75 " call assert_equal(333, 333->g:FuncRef())
76
Bram Moolenaar53f0c962017-10-22 14:23:59 +020077 enew
78
79 normal oXX+-XX
80 call assert_equal('XX111-XX', getline('.'))
81 normal o---*---
82 call assert_equal('---222---', getline('.'))
83 normal o(one
84 call assert_equal('1. one', getline('.'))
85 normal o(two
86 call assert_equal('2. two', getline('.'))
87 normal o[(one again
88 call assert_equal('1. one again', getline('.'))
89
Bram Moolenaar476a6132020-04-08 19:48:56 +020090 " Try to overwrite a function in the global (g:) scope
Bram Moolenaar53f0c962017-10-22 14:23:59 +020091 call assert_equal(3, max([1, 2, 3]))
Bram Moolenaare2e40752020-09-04 21:18:46 +020092 call assert_fails("call extend(g:, {'max': function('min')})", 'E704:')
Bram Moolenaar53f0c962017-10-22 14:23:59 +020093 call assert_equal(3, max([1, 2, 3]))
94
Bram Moolenaar8dfcce32020-03-18 19:32:26 +010095 " Try to overwrite an user defined function with a function reference
96 call assert_fails("let Expr1 = function('min')", 'E705:')
97
Bram Moolenaar53f0c962017-10-22 14:23:59 +020098 " Regression: the first line below used to throw ?E110: Missing ')'?
99 " Second is here just to prove that this line is correct when not skipping
100 " rhs of &&.
101 call assert_equal(0, (0 && (function('tr'))(1, 2, 3)))
102 call assert_equal(1, (1 && (function('tr'))(1, 2, 3)))
103
104 delfunc Table
105 delfunc Compute
106 delfunc Expr1
107 delfunc Expr2
108 delfunc ListItem
109 delfunc ListReset
110 unlet g:retval g:counter
111 enew!
112endfunc
Bram Moolenaar42ae78c2019-05-09 21:08:58 +0200113
114func Log(val, base = 10)
115 return log(a:val) / log(a:base)
116endfunc
117
118func Args(mandatory, optional = v:null, ...)
119 return deepcopy(a:)
120endfunc
121
122func Args2(a = 1, b = 2, c = 3)
123 return deepcopy(a:)
124endfunc
125
126func MakeBadFunc()
127 func s:fcn(a, b=1, c)
128 endfunc
129endfunc
130
131func Test_default_arg()
Bram Moolenaar73e28dc2022-09-17 21:08:33 +0100132 call assert_equal(1.0, Log(10))
133 call assert_equal(log(10), Log(10, exp(1)))
134 call assert_fails("call Log(1,2,3)", 'E118:')
Bram Moolenaar42ae78c2019-05-09 21:08:58 +0200135
136 let res = Args(1)
137 call assert_equal(res.mandatory, 1)
138 call assert_equal(res.optional, v:null)
139 call assert_equal(res['0'], 0)
140
141 let res = Args(1,2)
142 call assert_equal(res.mandatory, 1)
143 call assert_equal(res.optional, 2)
144 call assert_equal(res['0'], 0)
145
146 let res = Args(1,2,3)
147 call assert_equal(res.mandatory, 1)
148 call assert_equal(res.optional, 2)
149 call assert_equal(res['0'], 1)
150
Bram Moolenaare2e40752020-09-04 21:18:46 +0200151 call assert_fails("call MakeBadFunc()", 'E989:')
Bram Moolenaare9b8b782021-04-06 20:18:29 +0200152 call assert_fails("fu F(a=1 ,) | endf", 'E1068:')
Bram Moolenaar42ae78c2019-05-09 21:08:58 +0200153
154 let d = Args2(7, v:none, 9)
155 call assert_equal([7, 2, 9], [d.a, d.b, d.c])
156
157 call assert_equal("\n"
158 \ .. " function Args2(a = 1, b = 2, c = 3)\n"
159 \ .. "1 return deepcopy(a:)\n"
160 \ .. " endfunction",
161 \ execute('func Args2'))
Yegappan Lakshmanan34fcb692021-05-25 20:14:00 +0200162
163 " Error in default argument expression
164 let l =<< trim END
165 func F1(x = y)
166 return a:x * 2
167 endfunc
168 echo F1()
169 END
170 let @a = l->join("\n")
171 call assert_fails("exe @a", 'E121:')
Bram Moolenaar42ae78c2019-05-09 21:08:58 +0200172endfunc
Bram Moolenaarfcfe1a92019-08-04 23:04:39 +0200173
174func s:addFoo(lead)
175 return a:lead .. 'foo'
176endfunc
177
178func Test_user_method()
179 eval 'bar'->s:addFoo()->assert_equal('barfoo')
180endfunc
Bram Moolenaare51bb172020-02-16 19:42:23 +0100181
Bram Moolenaar34820942022-12-19 20:28:38 +0000182func Test_method_with_linebreaks()
183 let lines =<< trim END
184 vim9script
185
186 export def Scan(ll: list<number>): func(func(number))
187 return (Emit: func(number)) => {
188 for v in ll
189 Emit(v)
190 endfor
191 }
192 enddef
193
194 export def Build(Cont: func(func(number))): list<number>
195 var result: list<number> = []
196 Cont((v) => {
197 add(result, v)
198 })
199 return result
200 enddef
201
202 export def Noop(Cont: func(func(number))): func(func(number))
203 return (Emit: func(number)) => {
204 Cont(Emit)
205 }
206 enddef
207 END
208 call writefile(lines, 'Xlib.vim', 'D')
209
210 let lines =<< trim END
211 vim9script
212
213 import "./Xlib.vim" as lib
214
215 const x = [1, 2, 3]
216
217 var result = lib.Scan(x)->lib.Noop()->lib.Build()
218 assert_equal([1, 2, 3], result)
219
220 result = lib.Scan(x)->lib.Noop()
221 ->lib.Build()
222 assert_equal([1, 2, 3], result)
223
224 result = lib.Scan(x)
225 ->lib.Noop()->lib.Build()
226 assert_equal([1, 2, 3], result)
227
228 result = lib.Scan(x)
229 ->lib.Noop()
230 ->lib.Build()
231 assert_equal([1, 2, 3], result)
232 END
233 call v9.CheckScriptSuccess(lines)
234endfunc
235
Bram Moolenaare51bb172020-02-16 19:42:23 +0100236func Test_failed_call_in_try()
237 try | call UnknownFunc() | catch | endtry
238endfunc
Bram Moolenaaree4e0c12020-04-06 21:35:05 +0200239
240" Test for listing user-defined functions
241func Test_function_list()
242 call assert_fails("function Xabc", 'E123:')
243endfunc
244
Bram Moolenaar476a6132020-04-08 19:48:56 +0200245" Test for <sfile>, <slnum> in a function
246func Test_sfile_in_function()
247 func Xfunc()
248 call assert_match('..Test_sfile_in_function\[5]..Xfunc', expand('<sfile>'))
249 call assert_equal('2', expand('<slnum>'))
250 endfunc
251 call Xfunc()
252 delfunc Xfunc
253endfunc
254
255" Test trailing text after :endfunction {{{1
256func Test_endfunction_trailing()
257 call assert_false(exists('*Xtest'))
258
259 exe "func Xtest()\necho 'hello'\nendfunc\nlet done = 'yes'"
260 call assert_true(exists('*Xtest'))
261 call assert_equal('yes', done)
262 delfunc Xtest
263 unlet done
264
265 exe "func Xtest()\necho 'hello'\nendfunc|let done = 'yes'"
266 call assert_true(exists('*Xtest'))
267 call assert_equal('yes', done)
268 delfunc Xtest
269 unlet done
270
271 " trailing line break
272 exe "func Xtest()\necho 'hello'\nendfunc\n"
273 call assert_true(exists('*Xtest'))
274 delfunc Xtest
275
276 set verbose=1
277 exe "func Xtest()\necho 'hello'\nendfunc \" garbage"
278 call assert_notmatch('W22:', split(execute('1messages'), "\n")[0])
279 call assert_true(exists('*Xtest'))
280 delfunc Xtest
281
282 exe "func Xtest()\necho 'hello'\nendfunc garbage"
283 call assert_match('W22:', split(execute('1messages'), "\n")[0])
284 call assert_true(exists('*Xtest'))
285 delfunc Xtest
286 set verbose=0
287
Bram Moolenaara0d072e2020-07-01 20:19:37 +0200288 func Xtest(a1, a2)
289 echo a:a1 .. a:a2
290 endfunc
291 set verbose=15
292 redir @a
293 call Xtest(123, repeat('x', 100))
294 redir END
295 call assert_match('calling Xtest(123, ''xxxxxxx.*x\.\.\.x.*xxxx'')', getreg('a'))
296 delfunc Xtest
297 set verbose=0
298
Bram Moolenaar476a6132020-04-08 19:48:56 +0200299 function Foo()
300 echo 'hello'
301 endfunction | echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
302 delfunc Foo
303endfunc
304
305func Test_delfunction_force()
306 delfunc! Xtest
307 delfunc! Xtest
308 func Xtest()
309 echo 'nothing'
310 endfunc
311 delfunc! Xtest
312 delfunc! Xtest
313
314 " Try deleting the current function
315 call assert_fails('delfunc Test_delfunction_force', 'E131:')
316endfunc
317
318func Test_function_defined_line()
319 CheckNotGui
320
321 let lines =<< trim [CODE]
322 " F1
323 func F1()
324 " F2
325 func F2()
326 "
327 "
328 "
329 return
330 endfunc
331 " F3
332 execute "func F3()\n\n\n\nreturn\nendfunc"
333 " F4
334 execute "func F4()\n
335 \\n
336 \\n
337 \\n
338 \return\n
339 \endfunc"
340 endfunc
341 " F5
342 execute "func F5()\n\n\n\nreturn\nendfunc"
343 " F6
344 execute "func F6()\n
345 \\n
346 \\n
347 \\n
348 \return\n
349 \endfunc"
350 call F1()
351 verbose func F1
352 verbose func F2
353 verbose func F3
354 verbose func F4
355 verbose func F5
356 verbose func F6
357 qall!
358 [CODE]
359
Bram Moolenaar5b148ef2022-10-15 21:35:56 +0100360 call writefile(lines, 'Xtest.vim', 'D')
Bram Moolenaar476a6132020-04-08 19:48:56 +0200361 let res = system(GetVimCommandClean() .. ' -es -X -S Xtest.vim')
362 call assert_equal(0, v:shell_error)
363
364 let m = matchstr(res, 'function F1()[^[:print:]]*[[:print:]]*')
365 call assert_match(' line 2$', m)
366
367 let m = matchstr(res, 'function F2()[^[:print:]]*[[:print:]]*')
368 call assert_match(' line 4$', m)
369
370 let m = matchstr(res, 'function F3()[^[:print:]]*[[:print:]]*')
371 call assert_match(' line 11$', m)
372
373 let m = matchstr(res, 'function F4()[^[:print:]]*[[:print:]]*')
374 call assert_match(' line 13$', m)
375
376 let m = matchstr(res, 'function F5()[^[:print:]]*[[:print:]]*')
377 call assert_match(' line 21$', m)
378
379 let m = matchstr(res, 'function F6()[^[:print:]]*[[:print:]]*')
380 call assert_match(' line 23$', m)
Bram Moolenaar476a6132020-04-08 19:48:56 +0200381endfunc
382
383" Test for defining a function reference in the global scope
384func Test_add_funcref_to_global_scope()
385 let x = g:
386 let caught_E862 = 0
387 try
388 func x.Xfunc()
389 return 1
390 endfunc
391 catch /E862:/
392 let caught_E862 = 1
393 endtry
394 call assert_equal(1, caught_E862)
395endfunc
396
397func Test_funccall_garbage_collect()
398 func Func(x, ...)
399 call add(a:x, a:000)
400 endfunc
401 call Func([], [])
402 " Must not crash cause by invalid freeing
403 call test_garbagecollect_now()
404 call assert_true(v:true)
405 delfunc Func
406endfunc
407
408" Test for script-local function
409func <SID>DoLast()
410 call append(line('$'), "last line")
411endfunc
412
413func s:DoNothing()
414 call append(line('$'), "nothing line")
415endfunc
416
417func Test_script_local_func()
418 set nocp nomore viminfo+=nviminfo
419 new
420 nnoremap <buffer> _x :call <SID>DoNothing()<bar>call <SID>DoLast()<bar>delfunc <SID>DoNothing<bar>delfunc <SID>DoLast<cr>
421
422 normal _x
423 call assert_equal('nothing line', getline(2))
424 call assert_equal('last line', getline(3))
425 close!
426
427 " Try to call a script local function in global scope
428 let lines =<< trim [CODE]
429 :call assert_fails('call s:Xfunc()', 'E81:')
430 :call assert_fails('let x = call("<SID>Xfunc", [])', 'E120:')
431 :call writefile(v:errors, 'Xresult')
432 :qall
433
434 [CODE]
Bram Moolenaar5b148ef2022-10-15 21:35:56 +0100435 call writefile(lines, 'Xscript', 'D')
Bram Moolenaar476a6132020-04-08 19:48:56 +0200436 if RunVim([], [], '-s Xscript')
437 call assert_equal([], readfile('Xresult'))
438 endif
439 call delete('Xresult')
Bram Moolenaar476a6132020-04-08 19:48:56 +0200440endfunc
441
442" Test for errors in defining new functions
443func Test_func_def_error()
444 call assert_fails('func Xfunc abc ()', 'E124:')
445 call assert_fails('func Xfunc(', 'E125:')
446 call assert_fails('func xfunc()', 'E128:')
447
448 " Try to redefine a function that is in use
449 let caught_E127 = 0
450 try
451 func! Test_func_def_error()
452 endfunc
453 catch /E127:/
454 let caught_E127 = 1
455 endtry
456 call assert_equal(1, caught_E127)
457
458 " Try to define a function in a dict twice
459 let d = {}
460 let lines =<< trim END
461 func d.F1()
462 return 1
463 endfunc
464 END
465 let l = join(lines, "\n") . "\n"
466 exe l
467 call assert_fails('exe l', 'E717:')
Yegappan Lakshmanan611728f2021-05-24 15:15:47 +0200468 call assert_fails('call feedkeys(":func d.F1()\<CR>", "xt")', 'E717:')
Bram Moolenaar476a6132020-04-08 19:48:56 +0200469
470 " Define an autoload function with an incorrect file name
Bram Moolenaar5b148ef2022-10-15 21:35:56 +0100471 call writefile(['func foo#Bar()', 'return 1', 'endfunc'], 'Xscript', 'D')
Bram Moolenaar476a6132020-04-08 19:48:56 +0200472 call assert_fails('source Xscript', 'E746:')
Bram Moolenaar531be472020-09-23 22:38:05 +0200473
474 " Try to list functions using an invalid search pattern
475 call assert_fails('function /\%(/', 'E53:')
Bram Moolenaar476a6132020-04-08 19:48:56 +0200476endfunc
477
478" Test for deleting a function
479func Test_del_func()
Bram Moolenaarc553a212021-12-26 20:20:34 +0000480 call assert_fails('delfunction Xabc', 'E117:')
Bram Moolenaar476a6132020-04-08 19:48:56 +0200481 let d = {'a' : 10}
482 call assert_fails('delfunc d.a', 'E718:')
Yegappan Lakshmanan611728f2021-05-24 15:15:47 +0200483 func d.fn()
484 return 1
485 endfunc
Bram Moolenaarddfc0512021-09-06 20:56:56 +0200486
487 " cannot delete the dict function by number
488 let nr = substitute(execute('echo d'), '.*function(''\(\d\+\)'').*', '\1', '')
489 call assert_fails('delfunction g:' .. nr, 'E475: Invalid argument: g:')
490
Yegappan Lakshmanan611728f2021-05-24 15:15:47 +0200491 delfunc d.fn
492 call assert_equal({'a' : 10}, d)
Bram Moolenaar476a6132020-04-08 19:48:56 +0200493endfunc
494
495" Test for calling return outside of a function
496func Test_return_outside_func()
Bram Moolenaar5b148ef2022-10-15 21:35:56 +0100497 call writefile(['return 10'], 'Xscript', 'D')
Bram Moolenaar476a6132020-04-08 19:48:56 +0200498 call assert_fails('source Xscript', 'E133:')
Bram Moolenaar476a6132020-04-08 19:48:56 +0200499endfunc
500
501" Test for errors in calling a function
502func Test_func_arg_error()
503 " Too many arguments
504 call assert_fails("call call('min', range(1,20))", 'E118:')
505 call assert_fails("call call('min', range(1,21))", 'E699:')
506 call assert_fails('echo min(0,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,0,1)',
507 \ 'E740:')
508
509 " Missing dict argument
510 func Xfunc() dict
511 return 1
512 endfunc
513 call assert_fails('call Xfunc()', 'E725:')
514 delfunc Xfunc
515endfunc
516
Bram Moolenaar67322bf2020-12-06 15:03:19 +0100517func Test_func_dict()
518 let mydict = {'a': 'b'}
519 function mydict.somefunc() dict
520 return len(self)
521 endfunc
522
Yegappan Lakshmanan611728f2021-05-24 15:15:47 +0200523 call assert_equal("{'a': 'b', 'somefunc': function('3')}", string(mydict))
Bram Moolenaar67322bf2020-12-06 15:03:19 +0100524 call assert_equal(2, mydict.somefunc())
525 call assert_match("^\n function \\d\\\+() dict"
526 \ .. "\n1 return len(self)"
527 \ .. "\n endfunction$", execute('func mydict.somefunc'))
Yegappan Lakshmanan611728f2021-05-24 15:15:47 +0200528 call assert_fails('call mydict.nonexist()', 'E716:')
Bram Moolenaar67322bf2020-12-06 15:03:19 +0100529endfunc
530
531func Test_func_range()
532 new
533 call setline(1, range(1, 8))
534 func FuncRange() range
535 echo a:firstline
536 echo a:lastline
537 endfunc
538 3
539 call assert_equal("\n3\n3", execute('call FuncRange()'))
540 call assert_equal("\n4\n6", execute('4,6 call FuncRange()'))
541 call assert_equal("\n function FuncRange() range"
542 \ .. "\n1 echo a:firstline"
543 \ .. "\n2 echo a:lastline"
544 \ .. "\n endfunction",
545 \ execute('function FuncRange'))
546
547 bwipe!
548endfunc
549
Yegappan Lakshmanan7c7e19c2022-04-09 11:09:07 +0100550" Test for memory allocation failure when defining a new function
551func Test_funcdef_alloc_failure()
552 new
553 let lines =<< trim END
554 func Xtestfunc()
555 return 321
556 endfunc
557 END
558 call setline(1, lines)
559 call test_alloc_fail(GetAllocId('get_func'), 0, 0)
560 call assert_fails('source', 'E342:')
561 call assert_false(exists('*Xtestfunc'))
562 call assert_fails('delfunc Xtestfunc', 'E117:')
563 %d _
564 let lines =<< trim END
565 def g:Xvim9func(): number
566 return 456
567 enddef
568 END
569 call setline(1, lines)
570 call test_alloc_fail(GetAllocId('get_func'), 0, 0)
571 call assert_fails('source', 'E342:')
572 call assert_false(exists('*Xvim9func'))
573 "call test_alloc_fail(GetAllocId('get_func'), 0, 0)
574 "call assert_fails('source', 'E342:')
575 "call assert_false(exists('*Xtestfunc'))
576 "call assert_fails('delfunc Xtestfunc', 'E117:')
577 bw!
578endfunc
579
Bram Moolenaar86d87252022-09-05 21:21:25 +0100580func AddDefer(arg1, ...)
581 call extend(g:deferred, [a:arg1])
582 if a:0 == 1
583 call extend(g:deferred, [a:1])
584 endif
Bram Moolenaar1d84f762022-09-03 21:35:53 +0100585endfunc
586
587func WithDeferTwo()
588 call extend(g:deferred, ['in Two'])
589 for nr in range(3)
590 defer AddDefer('Two' .. nr)
591 endfor
592 call extend(g:deferred, ['end Two'])
593endfunc
594
595func WithDeferOne()
596 call extend(g:deferred, ['in One'])
597 call writefile(['text'], 'Xfuncdefer')
598 defer delete('Xfuncdefer')
599 defer AddDefer('One')
600 call WithDeferTwo()
601 call extend(g:deferred, ['end One'])
602endfunc
603
Bram Moolenaar86d87252022-09-05 21:21:25 +0100604func WithPartialDefer()
605 call extend(g:deferred, ['in Partial'])
606 let Part = funcref('AddDefer', ['arg1'])
607 defer Part("arg2")
608 call extend(g:deferred, ['end Partial'])
609endfunc
610
Bram Moolenaar1d84f762022-09-03 21:35:53 +0100611func Test_defer()
612 let g:deferred = []
613 call WithDeferOne()
614
615 call assert_equal(['in One', 'in Two', 'end Two', 'Two2', 'Two1', 'Two0', 'end One', 'One'], g:deferred)
616 unlet g:deferred
617
618 call assert_equal('', glob('Xfuncdefer'))
Bram Moolenaar86d87252022-09-05 21:21:25 +0100619
620 call assert_fails('defer delete("Xfuncdefer")->Another()', 'E488:')
621 call assert_fails('defer delete("Xfuncdefer").member', 'E488:')
622
623 let g:deferred = []
624 call WithPartialDefer()
625 call assert_equal(['in Partial', 'end Partial', 'arg1', 'arg2'], g:deferred)
626 unlet g:deferred
627
628 let Part = funcref('AddDefer', ['arg1'], {})
629 call assert_fails('defer Part("arg2")', 'E1300:')
Bram Moolenaar1d84f762022-09-03 21:35:53 +0100630endfunc
631
Bram Moolenaar58779852022-09-06 18:31:14 +0100632func DeferLevelTwo()
633 call writefile(['text'], 'XDeleteTwo', 'D')
634 throw 'someerror'
635endfunc
636
637def DeferLevelOne()
638 call writefile(['text'], 'XDeleteOne', 'D')
639 call g:DeferLevelTwo()
640enddef
641
642func Test_defer_throw()
643 let caught = 'no'
644 try
645 call DeferLevelOne()
646 catch /someerror/
647 let caught = 'yes'
648 endtry
649 call assert_equal('yes', caught)
650 call assert_false(filereadable('XDeleteOne'))
651 call assert_false(filereadable('XDeleteTwo'))
652endfunc
653
zeertzjqa1f2b5d2023-04-18 21:04:53 +0100654func Test_defer_quitall_func()
Bram Moolenaar58779852022-09-06 18:31:14 +0100655 let lines =<< trim END
Bram Moolenaar58779852022-09-06 18:31:14 +0100656 func DeferLevelTwo()
zeertzjqa1f2b5d2023-04-18 21:04:53 +0100657 call writefile(['text'], 'XQuitallFuncTwo', 'D')
658 call writefile(['quit'], 'XQuitallFuncThree', 'a')
Bram Moolenaar58779852022-09-06 18:31:14 +0100659 qa!
660 endfunc
661
zeertzjqa1f2b5d2023-04-18 21:04:53 +0100662 func DeferLevelOne()
663 call writefile(['text'], 'XQuitalFunclOne', 'D')
664 defer DeferLevelTwo()
665 endfunc
666
667 call DeferLevelOne()
668 END
669 call writefile(lines, 'XdeferQuitallFunc', 'D')
670 call system(GetVimCommand() .. ' -X -S XdeferQuitallFunc')
671 call assert_equal(0, v:shell_error)
672 call assert_false(filereadable('XQuitallFuncOne'))
673 call assert_false(filereadable('XQuitallFuncTwo'))
674 call assert_equal(['quit'], readfile('XQuitallFuncThree'))
675
676 call delete('XQuitallFuncThree')
677endfunc
678
679func Test_defer_quitall_def()
680 let lines =<< trim END
681 vim9script
682 def DeferLevelTwo()
683 call writefile(['text'], 'XQuitallDefTwo', 'D')
684 call writefile(['quit'], 'XQuitallDefThree', 'a')
685 qa!
686 enddef
687
Bram Moolenaar58779852022-09-06 18:31:14 +0100688 def DeferLevelOne()
zeertzjqa1f2b5d2023-04-18 21:04:53 +0100689 call writefile(['text'], 'XQuitallDefOne', 'D')
690 defer DeferLevelTwo()
Bram Moolenaar58779852022-09-06 18:31:14 +0100691 enddef
692
693 DeferLevelOne()
694 END
zeertzjqa1f2b5d2023-04-18 21:04:53 +0100695 call writefile(lines, 'XdeferQuitallDef', 'D')
696 call system(GetVimCommand() .. ' -X -S XdeferQuitallDef')
Bram Moolenaar58779852022-09-06 18:31:14 +0100697 call assert_equal(0, v:shell_error)
zeertzjqa1f2b5d2023-04-18 21:04:53 +0100698 call assert_false(filereadable('XQuitallDefOne'))
699 call assert_false(filereadable('XQuitallDefTwo'))
700 call assert_equal(['quit'], readfile('XQuitallDefThree'))
Bram Moolenaar42994bf2023-04-17 19:23:45 +0100701
zeertzjqa1f2b5d2023-04-18 21:04:53 +0100702 call delete('XQuitallDefThree')
Bram Moolenaar58779852022-09-06 18:31:14 +0100703endfunc
704
zeertzjq960cf912023-04-18 21:52:54 +0100705func Test_defer_quitall_autocmd()
706 let lines =<< trim END
zeertzjq1be4b812023-04-19 14:21:24 +0100707 func DeferLevelFive()
708 defer writefile(['5'], 'XQuitallAutocmd', 'a')
709 qa!
zeertzjq960cf912023-04-18 21:52:54 +0100710 endfunc
711
zeertzjq1be4b812023-04-19 14:21:24 +0100712 autocmd User DeferAutocmdFive call DeferLevelFive()
zeertzjq960cf912023-04-18 21:52:54 +0100713
zeertzjq1be4b812023-04-19 14:21:24 +0100714 def DeferLevelFour()
715 defer writefile(['4'], 'XQuitallAutocmd', 'a')
716 doautocmd User DeferAutocmdFive
zeertzjq960cf912023-04-18 21:52:54 +0100717 enddef
718
zeertzjq1be4b812023-04-19 14:21:24 +0100719 func DeferLevelThree()
720 defer writefile(['3'], 'XQuitallAutocmd', 'a')
721 call DeferLevelFour()
722 endfunc
723
724 autocmd User DeferAutocmdThree ++nested call DeferLevelThree()
725
726 def DeferLevelTwo()
727 defer writefile(['2'], 'XQuitallAutocmd', 'a')
728 doautocmd User DeferAutocmdThree
729 enddef
730
731 func DeferLevelOne()
732 defer writefile(['1'], 'XQuitallAutocmd', 'a')
733 call DeferLevelTwo()
734 endfunc
735
zeertzjq960cf912023-04-18 21:52:54 +0100736 autocmd User DeferAutocmdOne ++nested call DeferLevelOne()
737
738 doautocmd User DeferAutocmdOne
739 END
740 call writefile(lines, 'XdeferQuitallAutocmd', 'D')
zeertzjq1be4b812023-04-19 14:21:24 +0100741 call system(GetVimCommand() .. ' -X -S XdeferQuitallAutocmd')
zeertzjq960cf912023-04-18 21:52:54 +0100742 call assert_equal(0, v:shell_error)
zeertzjq1be4b812023-04-19 14:21:24 +0100743 call assert_equal(['5', '4', '3', '2', '1'], readfile('XQuitallAutocmd'))
744
745 call delete('XQuitallAutocmd')
zeertzjq960cf912023-04-18 21:52:54 +0100746endfunc
747
Bram Moolenaar9667b2c2022-09-07 17:28:09 +0100748func Test_defer_quitall_in_expr_func()
749 let lines =<< trim END
750 def DefIndex(idx: number, val: string): bool
751 call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
752 if val == 'b'
753 qa!
754 endif
755 return val == 'c'
756 enddef
757
758 def Test_defer_in_funcref()
759 assert_equal(2, indexof(['a', 'b', 'c'], funcref('g:DefIndex')))
760 enddef
761 call Test_defer_in_funcref()
762 END
763 call writefile(lines, 'XdeferQuitallExpr', 'D')
zeertzjqa1f2b5d2023-04-18 21:04:53 +0100764 call system(GetVimCommand() .. ' -X -S XdeferQuitallExpr')
Bram Moolenaar9667b2c2022-09-07 17:28:09 +0100765 call assert_equal(0, v:shell_error)
766 call assert_false(filereadable('Xentry0'))
767 call assert_false(filereadable('Xentry1'))
768 call assert_false(filereadable('Xentry2'))
769endfunc
770
Bram Moolenaar98aff652022-09-06 21:02:35 +0100771func FuncIndex(idx, val)
772 call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D')
773 return a:val == 'c'
774endfunc
775
776def DefIndex(idx: number, val: string): bool
777 call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
778 return val == 'c'
779enddef
780
Bram Moolenaarc9c967d2022-09-07 16:48:46 +0100781def DefIndexXtra(xtra: string, idx: number, val: string): bool
782 call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
783 return val == 'c'
784enddef
785
Bram Moolenaar98aff652022-09-06 21:02:35 +0100786def Test_defer_in_funcref()
787 assert_equal(2, indexof(['a', 'b', 'c'], function('g:FuncIndex')))
788 assert_false(filereadable('Xentry0'))
789 assert_false(filereadable('Xentry1'))
790 assert_false(filereadable('Xentry2'))
791
792 assert_equal(2, indexof(['a', 'b', 'c'], g:DefIndex))
793 assert_false(filereadable('Xentry0'))
794 assert_false(filereadable('Xentry1'))
795 assert_false(filereadable('Xentry2'))
796
797 assert_equal(2, indexof(['a', 'b', 'c'], function('g:DefIndex')))
798 assert_false(filereadable('Xentry0'))
799 assert_false(filereadable('Xentry1'))
800 assert_false(filereadable('Xentry2'))
801
802 assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndex)))
803 assert_false(filereadable('Xentry0'))
804 assert_false(filereadable('Xentry1'))
805 assert_false(filereadable('Xentry2'))
Bram Moolenaarc9c967d2022-09-07 16:48:46 +0100806
807 assert_equal(2, indexof(['a', 'b', 'c'], function(g:DefIndexXtra, ['xtra'])))
808 assert_false(filereadable('Xentry0'))
809 assert_false(filereadable('Xentry1'))
810 assert_false(filereadable('Xentry2'))
811
812 assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndexXtra, ['xtra'])))
813 assert_false(filereadable('Xentry0'))
814 assert_false(filereadable('Xentry1'))
815 assert_false(filereadable('Xentry2'))
Bram Moolenaar98aff652022-09-06 21:02:35 +0100816enddef
817
Bram Moolenaar16900322022-09-08 19:51:45 +0100818func Test_defer_wrong_arguments()
819 call assert_fails('defer delete()', 'E119:')
820 call assert_fails('defer FuncIndex(1)', 'E119:')
821 call assert_fails('defer delete(1, 2, 3)', 'E118:')
822 call assert_fails('defer FuncIndex(1, 2, 3)', 'E118:')
823
824 let lines =<< trim END
825 def DeferFunc0()
826 defer delete()
827 enddef
828 defcompile
829 END
830 call v9.CheckScriptFailure(lines, 'E119:')
831 let lines =<< trim END
832 def DeferFunc3()
833 defer delete(1, 2, 3)
834 enddef
835 defcompile
836 END
837 call v9.CheckScriptFailure(lines, 'E118:')
838 let lines =<< trim END
839 def DeferFunc2()
840 defer delete(1, 2)
841 enddef
842 defcompile
843 END
844 call v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
845
846 def g:FuncOneArg(arg: string)
847 echo arg
848 enddef
849
850 let lines =<< trim END
851 def DeferUserFunc0()
852 defer g:FuncOneArg()
853 enddef
854 defcompile
855 END
856 call v9.CheckScriptFailure(lines, 'E119:')
857 let lines =<< trim END
858 def DeferUserFunc2()
859 defer g:FuncOneArg(1, 2)
860 enddef
861 defcompile
862 END
863 call v9.CheckScriptFailure(lines, 'E118:')
864 let lines =<< trim END
865 def DeferUserFunc1()
866 defer g:FuncOneArg(1)
867 enddef
868 defcompile
869 END
870 call v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
871endfunc
872
Yegappan Lakshmanan06725952023-10-18 11:47:37 +0200873" Test for calling a deferred function after an exception
874func Test_defer_after_exception()
875 let g:callTrace = []
Yegappan Lakshmananc59c1e02023-10-19 10:52:34 +0200876 func Bar()
877 let g:callTrace += [1]
878 throw 'InnerException'
879 endfunc
880
Yegappan Lakshmanan06725952023-10-18 11:47:37 +0200881 func Defer()
Yegappan Lakshmananc59c1e02023-10-19 10:52:34 +0200882 let g:callTrace += [2]
883 let g:callTrace += [3]
884 try
885 call Bar()
886 catch /InnerException/
887 let g:callTrace += [4]
888 endtry
889 let g:callTrace += [5]
890 let g:callTrace += [6]
Yegappan Lakshmanan06725952023-10-18 11:47:37 +0200891 endfunc
892
893 func Foo()
894 defer Defer()
895 throw "TestException"
896 endfunc
897
898 try
899 call Foo()
900 catch /TestException/
Yegappan Lakshmananc59c1e02023-10-19 10:52:34 +0200901 let g:callTrace += [7]
Yegappan Lakshmanan06725952023-10-18 11:47:37 +0200902 endtry
Yegappan Lakshmananc59c1e02023-10-19 10:52:34 +0200903 call assert_equal([2, 3, 1, 4, 5, 6, 7], g:callTrace)
Yegappan Lakshmanan06725952023-10-18 11:47:37 +0200904
905 delfunc Defer
906 delfunc Foo
907 unlet g:callTrace
908endfunc
Bram Moolenaar1d84f762022-09-03 21:35:53 +0100909
Bram Moolenaaree4e0c12020-04-06 21:35:05 +0200910" vim: shiftwidth=2 sts=2 expandtab