test_user_func.vim (25457B)
1 " 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 6 source check.vim 7 source shared.vim 8 source vim9.vim 9 10 func 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 18 endfunc 19 20 func 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" 26 endfunc 27 28 func Expr1() 29 silent! normal! v 30 return "111" 31 endfunc 32 33 func Expr2() 34 call search('XX', 'b') 35 return "222" 36 endfunc 37 38 func ListItem() 39 let g:counter += 1 40 return g:counter . '. ' 41 endfunc 42 43 func ListReset() 44 let g:counter = 0 45 return '' 46 endfunc 47 48 func FuncWithRef(a) 49 unlet g:FuncRef 50 return a:a 51 endfunc 52 53 func Test_user_func() 54 let g:FuncRef = function("FuncWithRef") 55 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 69 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 77 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 90 " Try to overwrite a function in the global (g:) scope 91 call assert_equal(3, max([1, 2, 3])) 92 call assert_fails("call extend(g:, {'max': function('min')})", 'E704') 93 call assert_equal(3, max([1, 2, 3])) 94 95 " Try to overwrite an user defined function with a function reference 96 call assert_fails("let Expr1 = function('min')", 'E705:') 97 98 " 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! 112 endfunc 113 114 func Log(val, base = 10) 115 return log(a:val) / log(a:base) 116 endfunc 117 118 func Args(mandatory, optional = v:null, ...) 119 return deepcopy(a:) 120 endfunc 121 122 func Args2(a = 1, b = 2, c = 3) 123 return deepcopy(a:) 124 endfunc 125 126 func MakeBadFunc() 127 func s:fcn(a, b=1, c) 128 endfunc 129 endfunc 130 131 func Test_default_arg() 132 if has('float') 133 call assert_equal(1.0, Log(10)) 134 call assert_equal(log(10), Log(10, exp(1))) 135 call assert_fails("call Log(1,2,3)", 'E118') 136 endif 137 138 let res = Args(1) 139 call assert_equal(res.mandatory, 1) 140 call assert_equal(res.optional, v:null) 141 call assert_equal(res['0'], 0) 142 143 let res = Args(1,2) 144 call assert_equal(res.mandatory, 1) 145 call assert_equal(res.optional, 2) 146 call assert_equal(res['0'], 0) 147 148 let res = Args(1,2,3) 149 call assert_equal(res.mandatory, 1) 150 call assert_equal(res.optional, 2) 151 call assert_equal(res['0'], 1) 152 153 call assert_fails("call MakeBadFunc()", 'E989:') 154 call assert_fails("fu F(a=1 ,) | endf", 'E1068:') 155 156 " Since neovim does not have v:none, the ability to use the default 157 " argument with the intermediate argument set to v:none has been omitted. 158 " Therefore, this test is not performed. 159 " let d = Args2(7, v:none, 9) 160 " call assert_equal([7, 2, 9], [d.a, d.b, d.c]) 161 162 call assert_equal("\n" 163 \ .. " function Args2(a = 1, b = 2, c = 3)\n" 164 \ .. "1 return deepcopy(a:)\n" 165 \ .. " endfunction", 166 \ execute('func Args2')) 167 168 " Error in default argument expression 169 func! s:f(x = s:undefined) 170 return a:x 171 endfunc 172 call assert_fails('echo s:f()', ['E121: Undefined variable: s:undefined', 173 \ 'E121: Undefined variable: a:x']) 174 175 func! s:f(x = s:undefined) abort 176 return a:x 177 endfunc 178 const expected_error = 'E121: Undefined variable: s:undefined' 179 " Only one error should be output; execution of the function should be aborted 180 " after the default argument expression error. 181 call assert_fails('echo s:f()', [expected_error, expected_error]) 182 endfunc 183 184 func Test_default_argument_expression_error_while_inside_of_a_try_block() 185 func! s:f(v = s:undefined_variable) 186 let s:entered_fn_body = 1 187 return a:v 188 endfunc 189 190 unlet! s:entered_fn_body 191 try 192 call s:f() 193 throw "No exception." 194 catch 195 call assert_exception("E121: Undefined variable: s:undefined_variable") 196 endtry 197 call assert_false(exists('s:entered_fn_body'), "exists('s:entered_fn_body')") 198 endfunc 199 200 func s:addFoo(lead) 201 return a:lead .. 'foo' 202 endfunc 203 204 func Test_user_method() 205 eval 'bar'->s:addFoo()->assert_equal('barfoo') 206 endfunc 207 208 func Test_failed_call_in_try() 209 try | call UnknownFunc() | catch | endtry 210 endfunc 211 212 " Test for listing user-defined functions 213 func Test_function_list() 214 call assert_fails("function Xabc", 'E123:') 215 endfunc 216 217 " Test for <sfile>, <slnum> in a function 218 func Test_sfile_in_function() 219 func Xfunc() 220 call assert_match('..Test_sfile_in_function\[5]..Xfunc', expand('<sfile>')) 221 call assert_equal('2', expand('<slnum>')) 222 endfunc 223 call Xfunc() 224 delfunc Xfunc 225 endfunc 226 227 " Test trailing text after :endfunction {{{1 228 func Test_endfunction_trailing() 229 call assert_false(exists('*Xtest')) 230 231 exe "func Xtest()\necho 'hello'\nendfunc\nlet done = 'yes'" 232 call assert_true(exists('*Xtest')) 233 call assert_equal('yes', done) 234 delfunc Xtest 235 unlet done 236 237 exe "func Xtest()\necho 'hello'\nendfunc|let done = 'yes'" 238 call assert_true(exists('*Xtest')) 239 call assert_equal('yes', done) 240 delfunc Xtest 241 unlet done 242 243 " trailing line break 244 exe "func Xtest()\necho 'hello'\nendfunc\n" 245 call assert_true(exists('*Xtest')) 246 delfunc Xtest 247 248 set verbose=1 249 exe "func Xtest()\necho 'hello'\nendfunc \" garbage" 250 call assert_notmatch('W22:', split(execute('1messages'), "\n")[0]) 251 call assert_true(exists('*Xtest')) 252 delfunc Xtest 253 254 exe "func Xtest()\necho 'hello'\nendfunc garbage" 255 call assert_match('W22:', split(execute('1messages'), "\n")[0]) 256 call assert_true(exists('*Xtest')) 257 delfunc Xtest 258 set verbose=0 259 260 func Xtest(a1, a2) 261 echo a:a1 .. a:a2 262 endfunc 263 set verbose=15 264 redir @a 265 call Xtest(123, repeat('x', 100)) 266 redir END 267 call assert_match('calling Xtest(123, ''xxxxxxx.*x\.\.\.x.*xxxx'')', getreg('a')) 268 delfunc Xtest 269 set verbose=0 270 271 function Foo() 272 echo 'hello' 273 endfunction | echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' 274 delfunc Foo 275 endfunc 276 277 func Test_delfunction_force() 278 delfunc! Xtest 279 delfunc! Xtest 280 func Xtest() 281 echo 'nothing' 282 endfunc 283 delfunc! Xtest 284 delfunc! Xtest 285 286 " Try deleting the current function 287 call assert_fails('delfunc Test_delfunction_force', 'E131:') 288 endfunc 289 290 func Test_function_defined_line() 291 CheckNotGui 292 293 let lines =<< trim [CODE] 294 " F1 295 func F1() 296 " F2 297 func F2() 298 " 299 " 300 " 301 return 302 endfunc 303 " F3 304 execute "func F3()\n\n\n\nreturn\nendfunc" 305 " F4 306 execute "func F4()\n 307 \\n 308 \\n 309 \\n 310 \return\n 311 \endfunc" 312 endfunc 313 " F5 314 execute "func F5()\n\n\n\nreturn\nendfunc" 315 " F6 316 execute "func F6()\n 317 \\n 318 \\n 319 \\n 320 \return\n 321 \endfunc" 322 call F1() 323 verbose func F1 324 verbose func F2 325 verbose func F3 326 verbose func F4 327 verbose func F5 328 verbose func F6 329 qall! 330 [CODE] 331 332 call writefile(lines, 'Xtest.vim') 333 let res = system(GetVimCommandClean() .. ' -es -X -S Xtest.vim') 334 call assert_equal(0, v:shell_error) 335 336 let m = matchstr(res, 'function F1()[^[:print:]]*[[:print:]]*') 337 call assert_match(' line 2$', m) 338 339 let m = matchstr(res, 'function F2()[^[:print:]]*[[:print:]]*') 340 call assert_match(' line 4$', m) 341 342 let m = matchstr(res, 'function F3()[^[:print:]]*[[:print:]]*') 343 call assert_match(' line 11$', m) 344 345 let m = matchstr(res, 'function F4()[^[:print:]]*[[:print:]]*') 346 call assert_match(' line 13$', m) 347 348 let m = matchstr(res, 'function F5()[^[:print:]]*[[:print:]]*') 349 call assert_match(' line 21$', m) 350 351 let m = matchstr(res, 'function F6()[^[:print:]]*[[:print:]]*') 352 call assert_match(' line 23$', m) 353 354 call delete('Xtest.vim') 355 endfunc 356 357 " Test for defining a function reference in the global scope 358 func Test_add_funcref_to_global_scope() 359 let x = g: 360 let caught_E862 = 0 361 try 362 func x.Xfunc() 363 return 1 364 endfunc 365 catch /E862:/ 366 let caught_E862 = 1 367 endtry 368 call assert_equal(1, caught_E862) 369 endfunc 370 371 func Test_funccall_garbage_collect() 372 func Func(x, ...) 373 call add(a:x, a:000) 374 endfunc 375 call Func([], []) 376 " Must not crash cause by invalid freeing 377 call test_garbagecollect_now() 378 call assert_true(v:true) 379 delfunc Func 380 endfunc 381 382 " Test for script-local function 383 func <SID>DoLast() 384 call append(line('$'), "last line") 385 endfunc 386 387 func s:DoNothing() 388 call append(line('$'), "nothing line") 389 endfunc 390 391 func Test_script_local_func() 392 set nocp nomore viminfo+=nviminfo 393 new 394 nnoremap <buffer> _x :call <SID>DoNothing()<bar>call <SID>DoLast()<bar>delfunc <SID>DoNothing<bar>delfunc <SID>DoLast<cr> 395 396 normal _x 397 call assert_equal('nothing line', getline(2)) 398 call assert_equal('last line', getline(3)) 399 close! 400 401 " Try to call a script local function in global scope 402 let lines =<< trim [CODE] 403 :call assert_fails('call s:Xfunc()', 'E81:') 404 :call assert_fails('let x = call("<SID>Xfunc", [])', ['E81:', 'E117:']) 405 :call writefile(v:errors, 'Xresult') 406 :qall 407 408 [CODE] 409 call writefile(lines, 'Xscript') 410 if RunVim([], [], '-s Xscript') 411 call assert_equal([], readfile('Xresult')) 412 endif 413 call delete('Xresult') 414 call delete('Xscript') 415 endfunc 416 417 " Test for errors in defining new functions 418 func Test_func_def_error() 419 call assert_fails('func Xfunc abc ()', 'E124:') 420 call assert_fails('func Xfunc(', 'E125:') 421 call assert_fails('func xfunc()', 'E128:') 422 423 " Try to redefine a function that is in use 424 let caught_E127 = 0 425 try 426 func! Test_func_def_error() 427 endfunc 428 catch /E127:/ 429 let caught_E127 = 1 430 endtry 431 call assert_equal(1, caught_E127) 432 433 " Try to define a function in a dict twice 434 let d = {} 435 let lines =<< trim END 436 func d.F1() 437 return 1 438 endfunc 439 END 440 let l = join(lines, "\n") . "\n" 441 exe l 442 call assert_fails('exe l', 'E717:') 443 444 " Define an autoload function with an incorrect file name 445 call writefile(['func foo#Bar()', 'return 1', 'endfunc'], 'Xscript', 'D') 446 call assert_fails('source Xscript', 'E746:') 447 448 " Try to list functions using an invalid search pattern 449 call assert_fails('function /\%(/', 'E53:') 450 451 " Use a script-local function to cover uf_name_exp. 452 func s:TestRedefine(arg1 = 1, arg2 = 10) 453 let caught_E122 = 0 454 try 455 func s:TestRedefine(arg1 = 1, arg2 = 10) 456 endfunc 457 catch /E122:/ 458 let caught_E122 = 1 459 endtry 460 call assert_equal(1, caught_E122) 461 462 let caught_E127 = 0 463 try 464 func! s:TestRedefine(arg1 = 1, arg2 = 10) 465 endfunc 466 catch /E127:/ 467 let caught_E127 = 1 468 endtry 469 call assert_equal(1, caught_E127) 470 471 " The failures above shouldn't cause heap-use-after-free here. 472 return [a:arg1 + a:arg2, expand('<stack>')] 473 endfunc 474 475 let stacks = [] 476 " Call the function twice. 477 " Failing to redefine a function shouldn't clear its argument list. 478 for i in range(2) 479 let [val, stack] = s:TestRedefine(1000) 480 call assert_equal(1010, val) 481 call assert_match(expand('<SID>') .. 'TestRedefine\[20\]$', stack) 482 call add(stacks, stack) 483 endfor 484 call assert_equal(stacks[0], stacks[1]) 485 486 delfunc s:TestRedefine 487 endfunc 488 489 " Test for deleting a function 490 func Test_del_func() 491 call assert_fails('delfunction Xabc', 'E130:') 492 let d = {'a' : 10} 493 call assert_fails('delfunc d.a', 'E718:') 494 func d.fn() 495 return 1 496 endfunc 497 498 " cannot delete the dict function by number 499 let nr = substitute(execute('echo d'), '.*function(''\(\d\+\)'').*', '\1', '') 500 call assert_fails('delfunction g:' .. nr, 'E475: Invalid argument: g:') 501 502 delfunc d.fn 503 call assert_equal({'a' : 10}, d) 504 endfunc 505 506 " Test for calling return outside of a function 507 func Test_return_outside_func() 508 call writefile(['return 10'], 'Xscript') 509 call assert_fails('source Xscript', 'E133:') 510 call delete('Xscript') 511 endfunc 512 513 " Test for errors in calling a function 514 func Test_func_arg_error() 515 " Too many arguments 516 call assert_fails("call call('min', range(1,20))", 'E118:') 517 call assert_fails("call call('min', range(1,21))", 'E699:') 518 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)', 519 \ 'E740:') 520 521 " Missing dict argument 522 func Xfunc() dict 523 return 1 524 endfunc 525 call assert_fails('call Xfunc()', 'E725:') 526 delfunc Xfunc 527 endfunc 528 529 func Test_func_dict() 530 let mydict = {'a': 'b'} 531 function mydict.somefunc() dict 532 return len(self) 533 endfunc 534 535 call assert_equal("{'a': 'b', 'somefunc': function('3')}", string(mydict)) 536 call assert_equal(2, mydict.somefunc()) 537 call assert_match("^\n function \\d\\\+() dict" 538 \ .. "\n1 return len(self)" 539 \ .. "\n endfunction$", execute('func mydict.somefunc')) 540 call assert_fails('call mydict.nonexist()', 'E716:') 541 endfunc 542 543 func Test_func_range() 544 new 545 call setline(1, range(1, 8)) 546 func FuncRange() range 547 echo a:firstline 548 echo a:lastline 549 endfunc 550 3 551 call assert_equal("\n3\n3", execute('call FuncRange()')) 552 call assert_equal("\n4\n6", execute('4,6 call FuncRange()')) 553 call assert_equal("\n function FuncRange() range" 554 \ .. "\n1 echo a:firstline" 555 \ .. "\n2 echo a:lastline" 556 \ .. "\n endfunction", 557 \ execute('function FuncRange')) 558 559 bwipe! 560 endfunc 561 562 " Test for memory allocation failure when defining a new function 563 func Test_funcdef_alloc_failure() 564 CheckFunction test_alloc_fail 565 new 566 let lines =<< trim END 567 func Xtestfunc() 568 return 321 569 endfunc 570 END 571 call setline(1, lines) 572 call test_alloc_fail(GetAllocId('get_func'), 0, 0) 573 call assert_fails('source', 'E342:') 574 call assert_false(exists('*Xtestfunc')) 575 call assert_fails('delfunc Xtestfunc', 'E117:') 576 %d _ 577 let lines =<< trim END 578 def g:Xvim9func(): number 579 return 456 580 enddef 581 END 582 call setline(1, lines) 583 call test_alloc_fail(GetAllocId('get_func'), 0, 0) 584 call assert_fails('source', 'E342:') 585 call assert_false(exists('*Xvim9func')) 586 "call test_alloc_fail(GetAllocId('get_func'), 0, 0) 587 "call assert_fails('source', 'E342:') 588 "call assert_false(exists('*Xtestfunc')) 589 "call assert_fails('delfunc Xtestfunc', 'E117:') 590 bw! 591 endfunc 592 593 func AddDefer(arg1, ...) 594 call extend(g:deferred, [a:arg1]) 595 if a:0 == 1 596 call extend(g:deferred, [a:1]) 597 endif 598 endfunc 599 600 func WithDeferTwo() 601 call extend(g:deferred, ['in Two']) 602 for nr in range(3) 603 defer AddDefer('Two' .. nr) 604 endfor 605 call extend(g:deferred, ['end Two']) 606 endfunc 607 608 func WithDeferOne() 609 call extend(g:deferred, ['in One']) 610 call writefile(['text'], 'Xfuncdefer') 611 defer delete('Xfuncdefer') 612 defer AddDefer('One') 613 call WithDeferTwo() 614 call extend(g:deferred, ['end One']) 615 endfunc 616 617 func WithPartialDefer() 618 call extend(g:deferred, ['in Partial']) 619 let Part = funcref('AddDefer', ['arg1']) 620 defer Part("arg2") 621 call extend(g:deferred, ['end Partial']) 622 endfunc 623 624 func Test_defer() 625 let g:deferred = [] 626 call WithDeferOne() 627 628 call assert_equal(['in One', 'in Two', 'end Two', 'Two2', 'Two1', 'Two0', 'end One', 'One'], g:deferred) 629 unlet g:deferred 630 631 call assert_equal('', glob('Xfuncdefer')) 632 633 call assert_fails('defer delete("Xfuncdefer")->Another()', 'E488:') 634 call assert_fails('defer delete("Xfuncdefer").member', 'E488:') 635 636 let g:deferred = [] 637 call WithPartialDefer() 638 call assert_equal(['in Partial', 'end Partial', 'arg1', 'arg2'], g:deferred) 639 unlet g:deferred 640 641 let Part = funcref('AddDefer', ['arg1'], {}) 642 call assert_fails('defer Part("arg2")', 'E1300:') 643 endfunc 644 645 func DeferLevelTwo() 646 call writefile(['text'], 'XDeleteTwo', 'D') 647 throw 'someerror' 648 endfunc 649 650 " def DeferLevelOne() 651 func DeferLevelOne() 652 call writefile(['text'], 'XDeleteOne', 'D') 653 call g:DeferLevelTwo() 654 " enddef 655 endfunc 656 657 func Test_defer_throw() 658 let caught = 'no' 659 try 660 call DeferLevelOne() 661 catch /someerror/ 662 let caught = 'yes' 663 endtry 664 call assert_equal('yes', caught) 665 call assert_false(filereadable('XDeleteOne')) 666 call assert_false(filereadable('XDeleteTwo')) 667 endfunc 668 669 func Test_defer_quitall_func() 670 let lines =<< trim END 671 func DeferLevelTwo() 672 call writefile(['text'], 'XQuitallFuncTwo', 'D') 673 call writefile(['quit'], 'XQuitallFuncThree', 'a') 674 qa! 675 endfunc 676 677 func DeferLevelOne() 678 call writefile(['text'], 'XQuitalFunclOne', 'D') 679 defer DeferLevelTwo() 680 endfunc 681 682 call DeferLevelOne() 683 END 684 call writefile(lines, 'XdeferQuitallFunc', 'D') 685 call system(GetVimCommand() .. ' -X -S XdeferQuitallFunc') 686 call assert_equal(0, v:shell_error) 687 call assert_false(filereadable('XQuitallFuncOne')) 688 call assert_false(filereadable('XQuitallFuncTwo')) 689 call assert_equal(['quit'], readfile('XQuitallFuncThree')) 690 691 call delete('XQuitallFuncThree') 692 endfunc 693 694 func Test_defer_quitall_def() 695 throw 'Skipped: Vim9 script is N/A' 696 let lines =<< trim END 697 vim9script 698 def DeferLevelTwo() 699 call writefile(['text'], 'XQuitallDefTwo', 'D') 700 call writefile(['quit'], 'XQuitallDefThree', 'a') 701 qa! 702 enddef 703 704 def DeferLevelOne() 705 call writefile(['text'], 'XQuitallDefOne', 'D') 706 defer DeferLevelTwo() 707 enddef 708 709 DeferLevelOne() 710 END 711 call writefile(lines, 'XdeferQuitallDef', 'D') 712 call system(GetVimCommand() .. ' -X -S XdeferQuitallDef') 713 call assert_equal(0, v:shell_error) 714 call assert_false(filereadable('XQuitallDefOne')) 715 call assert_false(filereadable('XQuitallDefTwo')) 716 call assert_equal(['quit'], readfile('XQuitallDefThree')) 717 718 call delete('XQuitallDefThree') 719 endfunc 720 721 func Test_defer_quitall_autocmd() 722 let lines =<< trim END 723 func DeferLevelFive() 724 defer writefile(['5'], 'XQuitallAutocmd', 'a') 725 qa! 726 endfunc 727 728 autocmd User DeferAutocmdFive call DeferLevelFive() 729 730 " def DeferLevelFour() 731 func DeferLevelFour() 732 defer writefile(['4'], 'XQuitallAutocmd', 'a') 733 doautocmd User DeferAutocmdFive 734 " enddef 735 endfunc 736 737 func DeferLevelThree() 738 defer writefile(['3'], 'XQuitallAutocmd', 'a') 739 call DeferLevelFour() 740 endfunc 741 742 autocmd User DeferAutocmdThree ++nested call DeferLevelThree() 743 744 " def DeferLevelTwo() 745 func DeferLevelTwo() 746 defer writefile(['2'], 'XQuitallAutocmd', 'a') 747 doautocmd User DeferAutocmdThree 748 " enddef 749 endfunc 750 751 func DeferLevelOne() 752 defer writefile(['1'], 'XQuitallAutocmd', 'a') 753 call DeferLevelTwo() 754 endfunc 755 756 autocmd User DeferAutocmdOne ++nested call DeferLevelOne() 757 758 doautocmd User DeferAutocmdOne 759 END 760 call writefile(lines, 'XdeferQuitallAutocmd', 'D') 761 call system(GetVimCommand() .. ' -X -S XdeferQuitallAutocmd') 762 call assert_equal(0, v:shell_error) 763 call assert_equal(['5', '4', '3', '2', '1'], readfile('XQuitallAutocmd')) 764 765 call delete('XQuitallAutocmd') 766 endfunc 767 768 func Test_defer_quitall_in_expr_func() 769 throw 'Skipped: Vim9 script is N/A' 770 let lines =<< trim END 771 def DefIndex(idx: number, val: string): bool 772 call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D') 773 if val == 'b' 774 qa! 775 endif 776 return val == 'c' 777 enddef 778 779 def Test_defer_in_funcref() 780 assert_equal(2, indexof(['a', 'b', 'c'], funcref('g:DefIndex'))) 781 enddef 782 call Test_defer_in_funcref() 783 END 784 call writefile(lines, 'XdeferQuitallExpr', 'D') 785 call system(GetVimCommand() .. ' -X -S XdeferQuitallExpr') 786 call assert_equal(0, v:shell_error) 787 call assert_false(filereadable('Xentry0')) 788 call assert_false(filereadable('Xentry1')) 789 call assert_false(filereadable('Xentry2')) 790 endfunc 791 792 func FuncIndex(idx, val) 793 call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D') 794 return a:val == 'c' 795 endfunc 796 797 func Test_defer_wrong_arguments() 798 call assert_fails('defer delete()', 'E119:') 799 call assert_fails('defer FuncIndex(1)', 'E119:') 800 call assert_fails('defer delete(1, 2, 3)', 'E118:') 801 call assert_fails('defer FuncIndex(1, 2, 3)', 'E118:') 802 803 throw 'Skipped: Vim9 script is N/A' 804 let lines =<< trim END 805 def DeferFunc0() 806 defer delete() 807 enddef 808 defcompile 809 END 810 call v9.CheckScriptFailure(lines, 'E119:') 811 let lines =<< trim END 812 def DeferFunc3() 813 defer delete(1, 2, 3) 814 enddef 815 defcompile 816 END 817 call v9.CheckScriptFailure(lines, 'E118:') 818 let lines =<< trim END 819 def DeferFunc2() 820 defer delete(1, 2) 821 enddef 822 defcompile 823 END 824 call v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number') 825 826 def g:FuncOneArg(arg: string) 827 echo arg 828 enddef 829 830 let lines =<< trim END 831 def DeferUserFunc0() 832 defer g:FuncOneArg() 833 enddef 834 defcompile 835 END 836 call v9.CheckScriptFailure(lines, 'E119:') 837 let lines =<< trim END 838 def DeferUserFunc2() 839 defer g:FuncOneArg(1, 2) 840 enddef 841 defcompile 842 END 843 call v9.CheckScriptFailure(lines, 'E118:') 844 let lines =<< trim END 845 def DeferUserFunc1() 846 defer g:FuncOneArg(1) 847 enddef 848 defcompile 849 END 850 call v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number') 851 endfunc 852 853 " Test for calling a deferred function after an exception 854 func Test_defer_after_exception() 855 let g:callTrace = [] 856 func Bar() 857 let g:callTrace += [1] 858 throw 'InnerException' 859 endfunc 860 861 func Defer() 862 let g:callTrace += [2] 863 let g:callTrace += [3] 864 try 865 call Bar() 866 catch /InnerException/ 867 let g:callTrace += [4] 868 endtry 869 let g:callTrace += [5] 870 let g:callTrace += [6] 871 endfunc 872 873 func Foo() 874 defer Defer() 875 throw "TestException" 876 endfunc 877 878 try 879 call Foo() 880 catch /TestException/ 881 let g:callTrace += [7] 882 endtry 883 call assert_equal([2, 3, 1, 4, 5, 6, 7], g:callTrace) 884 885 delfunc Defer 886 delfunc Foo 887 delfunc Bar 888 unlet g:callTrace 889 endfunc 890 891 " Test for multiple deferred function which throw exceptions. 892 " Exceptions thrown by deferred functions should result in error messages but 893 " not propagated into the calling functions. 894 func Test_multidefer_with_exception() 895 let g:callTrace = [] 896 func Except() 897 let g:callTrace += [1] 898 throw 'InnerException' 899 let g:callTrace += [2] 900 endfunc 901 902 func FirstDefer() 903 let g:callTrace += [3] 904 let g:callTrace += [4] 905 endfunc 906 907 func SecondDeferWithExcept() 908 let g:callTrace += [5] 909 call Except() 910 let g:callTrace += [6] 911 endfunc 912 913 func ThirdDefer() 914 let g:callTrace += [7] 915 let g:callTrace += [8] 916 endfunc 917 918 func Foo() 919 let g:callTrace += [9] 920 defer FirstDefer() 921 defer SecondDeferWithExcept() 922 defer ThirdDefer() 923 let g:callTrace += [10] 924 endfunc 925 926 let v:errmsg = '' 927 try 928 let g:callTrace += [11] 929 call Foo() 930 let g:callTrace += [12] 931 catch /TestException/ 932 let g:callTrace += [13] 933 catch 934 let g:callTrace += [14] 935 finally 936 let g:callTrace += [15] 937 endtry 938 let g:callTrace += [16] 939 940 call assert_equal('E605: Exception not caught: InnerException', v:errmsg) 941 call assert_equal([11, 9, 10, 7, 8, 5, 1, 3, 4, 12, 15, 16], g:callTrace) 942 943 unlet g:callTrace 944 delfunc Except 945 delfunc FirstDefer 946 delfunc SecondDeferWithExcept 947 delfunc ThirdDefer 948 delfunc Foo 949 endfunc 950 951 func Test_func_curly_brace_invalid_name() 952 func Fail() 953 func Foo{'()'}bar() 954 endfunc 955 endfunc 956 957 call assert_fails('call Fail()', 'E475: Invalid argument: Foo()bar') 958 959 silent! call Fail() 960 call assert_equal([], getcompletion('Foo', 'function')) 961 962 set formatexpr=Fail() 963 normal! gqq 964 call assert_equal([], getcompletion('Foo', 'function')) 965 966 set formatexpr& 967 delfunc Fail 968 endfunc 969 970 func Test_func_return_in_try_verbose() 971 func TryReturnList() 972 try 973 return [1, 2, 3] 974 endtry 975 endfunc 976 func TryReturnNumber() 977 try 978 return 123 979 endtry 980 endfunc 981 func TryReturnOverlongString() 982 try 983 return repeat('a', 9999) 984 endtry 985 endfunc 986 987 " This should not cause heap-use-after-free 988 call assert_match('\n:return \[1, 2, 3\] made pending\n', 989 \ execute('14verbose call TryReturnList()')) 990 " This should not cause stack-use-after-scope 991 call assert_match('\n:return 123 made pending\n', 992 \ execute('14verbose call TryReturnNumber()')) 993 " An overlong string is truncated 994 call assert_match('\n:return a\{100,}\.\.\.', 995 \ execute('14verbose call TryReturnOverlongString()')) 996 997 delfunc TryReturnList 998 delfunc TryReturnNumber 999 delfunc TryReturnOverlongString 1000 endfunc 1001 1002 " vim: shiftwidth=2 sts=2 expandtab