blob: 71353c8f8184eae7b22c9fd7df2ee131e2c9b605 [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
707 autocmd User DeferAutocmdThree qa!
708
709 func DeferLevelTwo()
710 call writefile(['text'], 'XQuitallAutocmdTwo', 'D')
711 doautocmd User DeferAutocmdThree
712 endfunc
713
714 autocmd User DeferAutocmdTwo ++nested call DeferLevelTwo()
715
716 def DeferLevelOne()
717 call writefile(['text'], 'XQuitallAutocmdOne', 'D')
718 doautocmd User DeferAutocmdTwo
719 enddef
720
721 autocmd User DeferAutocmdOne ++nested call DeferLevelOne()
722
723 doautocmd User DeferAutocmdOne
724 END
725 call writefile(lines, 'XdeferQuitallAutocmd', 'D')
726 let res = system(GetVimCommand() .. ' -X -S XdeferQuitallAutocmd')
727 call assert_equal(0, v:shell_error)
728 call assert_false(filereadable('XQuitallAutocmdOne'))
729 call assert_false(filereadable('XQuitallAutocmdTwo'))
730endfunc
731
Bram Moolenaar9667b2c2022-09-07 17:28:09 +0100732func Test_defer_quitall_in_expr_func()
733 let lines =<< trim END
734 def DefIndex(idx: number, val: string): bool
735 call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
736 if val == 'b'
737 qa!
738 endif
739 return val == 'c'
740 enddef
741
742 def Test_defer_in_funcref()
743 assert_equal(2, indexof(['a', 'b', 'c'], funcref('g:DefIndex')))
744 enddef
745 call Test_defer_in_funcref()
746 END
747 call writefile(lines, 'XdeferQuitallExpr', 'D')
zeertzjqa1f2b5d2023-04-18 21:04:53 +0100748 call system(GetVimCommand() .. ' -X -S XdeferQuitallExpr')
Bram Moolenaar9667b2c2022-09-07 17:28:09 +0100749 call assert_equal(0, v:shell_error)
750 call assert_false(filereadable('Xentry0'))
751 call assert_false(filereadable('Xentry1'))
752 call assert_false(filereadable('Xentry2'))
753endfunc
754
Bram Moolenaar98aff652022-09-06 21:02:35 +0100755func FuncIndex(idx, val)
756 call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D')
757 return a:val == 'c'
758endfunc
759
760def DefIndex(idx: number, val: string): bool
761 call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
762 return val == 'c'
763enddef
764
Bram Moolenaarc9c967d2022-09-07 16:48:46 +0100765def DefIndexXtra(xtra: string, idx: number, val: string): bool
766 call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
767 return val == 'c'
768enddef
769
Bram Moolenaar98aff652022-09-06 21:02:35 +0100770def Test_defer_in_funcref()
771 assert_equal(2, indexof(['a', 'b', 'c'], function('g:FuncIndex')))
772 assert_false(filereadable('Xentry0'))
773 assert_false(filereadable('Xentry1'))
774 assert_false(filereadable('Xentry2'))
775
776 assert_equal(2, indexof(['a', 'b', 'c'], g:DefIndex))
777 assert_false(filereadable('Xentry0'))
778 assert_false(filereadable('Xentry1'))
779 assert_false(filereadable('Xentry2'))
780
781 assert_equal(2, indexof(['a', 'b', 'c'], function('g:DefIndex')))
782 assert_false(filereadable('Xentry0'))
783 assert_false(filereadable('Xentry1'))
784 assert_false(filereadable('Xentry2'))
785
786 assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndex)))
787 assert_false(filereadable('Xentry0'))
788 assert_false(filereadable('Xentry1'))
789 assert_false(filereadable('Xentry2'))
Bram Moolenaarc9c967d2022-09-07 16:48:46 +0100790
791 assert_equal(2, indexof(['a', 'b', 'c'], function(g:DefIndexXtra, ['xtra'])))
792 assert_false(filereadable('Xentry0'))
793 assert_false(filereadable('Xentry1'))
794 assert_false(filereadable('Xentry2'))
795
796 assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndexXtra, ['xtra'])))
797 assert_false(filereadable('Xentry0'))
798 assert_false(filereadable('Xentry1'))
799 assert_false(filereadable('Xentry2'))
Bram Moolenaar98aff652022-09-06 21:02:35 +0100800enddef
801
Bram Moolenaar16900322022-09-08 19:51:45 +0100802func Test_defer_wrong_arguments()
803 call assert_fails('defer delete()', 'E119:')
804 call assert_fails('defer FuncIndex(1)', 'E119:')
805 call assert_fails('defer delete(1, 2, 3)', 'E118:')
806 call assert_fails('defer FuncIndex(1, 2, 3)', 'E118:')
807
808 let lines =<< trim END
809 def DeferFunc0()
810 defer delete()
811 enddef
812 defcompile
813 END
814 call v9.CheckScriptFailure(lines, 'E119:')
815 let lines =<< trim END
816 def DeferFunc3()
817 defer delete(1, 2, 3)
818 enddef
819 defcompile
820 END
821 call v9.CheckScriptFailure(lines, 'E118:')
822 let lines =<< trim END
823 def DeferFunc2()
824 defer delete(1, 2)
825 enddef
826 defcompile
827 END
828 call v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
829
830 def g:FuncOneArg(arg: string)
831 echo arg
832 enddef
833
834 let lines =<< trim END
835 def DeferUserFunc0()
836 defer g:FuncOneArg()
837 enddef
838 defcompile
839 END
840 call v9.CheckScriptFailure(lines, 'E119:')
841 let lines =<< trim END
842 def DeferUserFunc2()
843 defer g:FuncOneArg(1, 2)
844 enddef
845 defcompile
846 END
847 call v9.CheckScriptFailure(lines, 'E118:')
848 let lines =<< trim END
849 def DeferUserFunc1()
850 defer g:FuncOneArg(1)
851 enddef
852 defcompile
853 END
854 call v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
855endfunc
856
Bram Moolenaar1d84f762022-09-03 21:35:53 +0100857
Bram Moolenaaree4e0c12020-04-06 21:35:05 +0200858" vim: shiftwidth=2 sts=2 expandtab