blob: 8715a0b78a7c6d77dd67e545af10ce3cde95d61f [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
654func Test_defer_quitall()
655 let lines =<< trim END
656 vim9script
657 func DeferLevelTwo()
658 call writefile(['text'], 'XQuitallTwo', 'D')
Bram Moolenaar42994bf2023-04-17 19:23:45 +0100659 call writefile(['quit'], 'XQuitallThree', 'a')
Bram Moolenaar58779852022-09-06 18:31:14 +0100660 qa!
661 endfunc
662
663 def DeferLevelOne()
664 call writefile(['text'], 'XQuitallOne', 'D')
665 call DeferLevelTwo()
666 enddef
667
668 DeferLevelOne()
669 END
670 call writefile(lines, 'XdeferQuitall', 'D')
Bram Moolenaar16900322022-09-08 19:51:45 +0100671 let res = system(GetVimCommand() .. ' -X -S XdeferQuitall')
Bram Moolenaar58779852022-09-06 18:31:14 +0100672 call assert_equal(0, v:shell_error)
673 call assert_false(filereadable('XQuitallOne'))
674 call assert_false(filereadable('XQuitallTwo'))
Bram Moolenaar42994bf2023-04-17 19:23:45 +0100675 call assert_equal(['quit'], readfile('XQuitallThree'))
676
677 call delete('XQuitallThree')
Bram Moolenaar58779852022-09-06 18:31:14 +0100678endfunc
679
Bram Moolenaar9667b2c2022-09-07 17:28:09 +0100680func Test_defer_quitall_in_expr_func()
681 let lines =<< trim END
682 def DefIndex(idx: number, val: string): bool
683 call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
684 if val == 'b'
685 qa!
686 endif
687 return val == 'c'
688 enddef
689
690 def Test_defer_in_funcref()
691 assert_equal(2, indexof(['a', 'b', 'c'], funcref('g:DefIndex')))
692 enddef
693 call Test_defer_in_funcref()
694 END
695 call writefile(lines, 'XdeferQuitallExpr', 'D')
Bram Moolenaar16900322022-09-08 19:51:45 +0100696 let res = system(GetVimCommand() .. ' -X -S XdeferQuitallExpr')
Bram Moolenaar9667b2c2022-09-07 17:28:09 +0100697 call assert_equal(0, v:shell_error)
698 call assert_false(filereadable('Xentry0'))
699 call assert_false(filereadable('Xentry1'))
700 call assert_false(filereadable('Xentry2'))
701endfunc
702
Bram Moolenaar98aff652022-09-06 21:02:35 +0100703func FuncIndex(idx, val)
704 call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D')
705 return a:val == 'c'
706endfunc
707
708def DefIndex(idx: number, val: string): bool
709 call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
710 return val == 'c'
711enddef
712
Bram Moolenaarc9c967d2022-09-07 16:48:46 +0100713def DefIndexXtra(xtra: string, idx: number, val: string): bool
714 call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
715 return val == 'c'
716enddef
717
Bram Moolenaar98aff652022-09-06 21:02:35 +0100718def Test_defer_in_funcref()
719 assert_equal(2, indexof(['a', 'b', 'c'], function('g:FuncIndex')))
720 assert_false(filereadable('Xentry0'))
721 assert_false(filereadable('Xentry1'))
722 assert_false(filereadable('Xentry2'))
723
724 assert_equal(2, indexof(['a', 'b', 'c'], g:DefIndex))
725 assert_false(filereadable('Xentry0'))
726 assert_false(filereadable('Xentry1'))
727 assert_false(filereadable('Xentry2'))
728
729 assert_equal(2, indexof(['a', 'b', 'c'], function('g:DefIndex')))
730 assert_false(filereadable('Xentry0'))
731 assert_false(filereadable('Xentry1'))
732 assert_false(filereadable('Xentry2'))
733
734 assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndex)))
735 assert_false(filereadable('Xentry0'))
736 assert_false(filereadable('Xentry1'))
737 assert_false(filereadable('Xentry2'))
Bram Moolenaarc9c967d2022-09-07 16:48:46 +0100738
739 assert_equal(2, indexof(['a', 'b', 'c'], function(g:DefIndexXtra, ['xtra'])))
740 assert_false(filereadable('Xentry0'))
741 assert_false(filereadable('Xentry1'))
742 assert_false(filereadable('Xentry2'))
743
744 assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndexXtra, ['xtra'])))
745 assert_false(filereadable('Xentry0'))
746 assert_false(filereadable('Xentry1'))
747 assert_false(filereadable('Xentry2'))
Bram Moolenaar98aff652022-09-06 21:02:35 +0100748enddef
749
Bram Moolenaar16900322022-09-08 19:51:45 +0100750func Test_defer_wrong_arguments()
751 call assert_fails('defer delete()', 'E119:')
752 call assert_fails('defer FuncIndex(1)', 'E119:')
753 call assert_fails('defer delete(1, 2, 3)', 'E118:')
754 call assert_fails('defer FuncIndex(1, 2, 3)', 'E118:')
755
756 let lines =<< trim END
757 def DeferFunc0()
758 defer delete()
759 enddef
760 defcompile
761 END
762 call v9.CheckScriptFailure(lines, 'E119:')
763 let lines =<< trim END
764 def DeferFunc3()
765 defer delete(1, 2, 3)
766 enddef
767 defcompile
768 END
769 call v9.CheckScriptFailure(lines, 'E118:')
770 let lines =<< trim END
771 def DeferFunc2()
772 defer delete(1, 2)
773 enddef
774 defcompile
775 END
776 call v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
777
778 def g:FuncOneArg(arg: string)
779 echo arg
780 enddef
781
782 let lines =<< trim END
783 def DeferUserFunc0()
784 defer g:FuncOneArg()
785 enddef
786 defcompile
787 END
788 call v9.CheckScriptFailure(lines, 'E119:')
789 let lines =<< trim END
790 def DeferUserFunc2()
791 defer g:FuncOneArg(1, 2)
792 enddef
793 defcompile
794 END
795 call v9.CheckScriptFailure(lines, 'E118:')
796 let lines =<< trim END
797 def DeferUserFunc1()
798 defer g:FuncOneArg(1)
799 enddef
800 defcompile
801 END
802 call v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
803endfunc
804
Bram Moolenaar1d84f762022-09-03 21:35:53 +0100805
Bram Moolenaaree4e0c12020-04-06 21:35:05 +0200806" vim: shiftwidth=2 sts=2 expandtab