neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

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