diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-03 22:21:25 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-04 00:23:03 +0300 |
| commit | 2eae5db069dc171f74cd863487655f6a88e5384d (patch) | |
| tree | 2d9d05e09978a2a44acbfbb8d651f240df3ca052 /uvim/src/testdir/test_user_func.vim | |
| parent | 473d922faed49241a5d29d9e37dc4819cd512006 (diff) | |
| download | Project-Tick-2eae5db069dc171f74cd863487655f6a88e5384d.tar.gz Project-Tick-2eae5db069dc171f74cd863487655f6a88e5384d.zip | |
NOISSUE rebrand vim to MNV's not Vim
Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
Diffstat (limited to 'uvim/src/testdir/test_user_func.vim')
| -rw-r--r-- | uvim/src/testdir/test_user_func.vim | 1090 |
1 files changed, 0 insertions, 1090 deletions
diff --git a/uvim/src/testdir/test_user_func.vim b/uvim/src/testdir/test_user_func.vim deleted file mode 100644 index 56b21a481b..0000000000 --- a/uvim/src/testdir/test_user_func.vim +++ /dev/null @@ -1,1090 +0,0 @@ -" Test for user functions. -" Also test an <expr> mapping calling a function. -" Also test that a builtin function cannot be replaced. -" Also test for regression when calling arbitrary expression. - -import './util/vim9.vim' as v9 - -func Table(title, ...) - let ret = a:title - let idx = 1 - while idx <= a:0 - exe "let ret = ret . a:" . idx - let idx = idx + 1 - endwhile - return ret -endfunc - -func Compute(n1, n2, divname) - if a:n2 == 0 - return "fail" - endif - exe "let g:" . a:divname . " = ". a:n1 / a:n2 - return "ok" -endfunc - -func Expr1() - silent! normal! v - return "111" -endfunc - -func Expr2() - call search('XX', 'b') - return "222" -endfunc - -func ListItem() - let g:counter += 1 - return g:counter . '. ' -endfunc - -func ListReset() - let g:counter = 0 - return '' -endfunc - -func FuncWithRef(a) - unlet g:FuncRef - return a:a -endfunc - -func Test_user_func() - let g:FuncRef = function("FuncWithRef") - let g:counter = 0 - inoremap <expr> ( ListItem() - inoremap <expr> [ ListReset() - imap <expr> + Expr1() - imap <expr> * Expr2() - let g:retval = "nop" - - call assert_equal('xxx4asdf', Table("xxx", 4, "asdf")) - call assert_equal('fail', Compute(45, 0, "retval")) - call assert_equal('nop', g:retval) - call assert_equal('ok', Compute(45, 5, "retval")) - call assert_equal(9, g:retval) - call assert_equal(333, g:FuncRef(333)) - - let g:retval = "nop" - call assert_equal('xxx4asdf', "xxx"->Table(4, "asdf")) - call assert_equal('fail', 45->Compute(0, "retval")) - call assert_equal('nop', g:retval) - call assert_equal('ok', 45->Compute(5, "retval")) - call assert_equal(9, g:retval) - " call assert_equal(333, 333->g:FuncRef()) - - enew - - normal oXX+-XX - call assert_equal('XX111-XX', getline('.')) - normal o---*--- - call assert_equal('---222---', getline('.')) - normal o(one - call assert_equal('1. one', getline('.')) - normal o(two - call assert_equal('2. two', getline('.')) - normal o[(one again - call assert_equal('1. one again', getline('.')) - - " Try to overwrite a function in the global (g:) scope - call assert_equal(3, max([1, 2, 3])) - call assert_fails("call extend(g:, {'max': function('min')})", 'E704:') - call assert_equal(3, max([1, 2, 3])) - - " Try to overwrite an user defined function with a function reference - call assert_fails("let Expr1 = function('min')", 'E705:') - - " Regression: the first line below used to throw ?E110: Missing ')'? - " Second is here just to prove that this line is correct when not skipping - " rhs of &&. - call assert_equal(0, (0 && (function('tr'))(1, 2, 3))) - call assert_equal(1, (1 && (function('tr'))(1, 2, 3))) - - delfunc Table - delfunc Compute - delfunc Expr1 - delfunc Expr2 - delfunc ListItem - delfunc ListReset - unlet g:retval g:counter - enew! -endfunc - -func Log(val, base = 10) - return log(a:val) / log(a:base) -endfunc - -func Args(mandatory, optional = v:null, ...) - return deepcopy(a:) -endfunc - -func Args2(a = 1, b = 2, c = 3) - return deepcopy(a:) -endfunc - -func MakeBadFunc() - func s:fcn(a, b=1, c) - endfunc -endfunc - -func Test_default_arg() - call assert_equal(1.0, Log(10)) - call assert_equal(log(10), Log(10, exp(1))) - call assert_fails("call Log(1,2,3)", 'E118:') - - let res = Args(1) - call assert_equal(res.mandatory, 1) - call assert_equal(res.optional, v:null) - call assert_equal(res['0'], 0) - - let res = Args(1,2) - call assert_equal(res.mandatory, 1) - call assert_equal(res.optional, 2) - call assert_equal(res['0'], 0) - - let res = Args(1,2,3) - call assert_equal(res.mandatory, 1) - call assert_equal(res.optional, 2) - call assert_equal(res['0'], 1) - - call assert_fails("call MakeBadFunc()", 'E989:') - call assert_fails("fu F(a=1 ,) | endf", 'E1068:') - - let d = Args2(7, v:none, 9) - call assert_equal([7, 2, 9], [d.a, d.b, d.c]) - - call assert_equal("\n" - \ .. " function Args2(a = 1, b = 2, c = 3)\n" - \ .. "1 return deepcopy(a:)\n" - \ .. " endfunction", - \ execute('func Args2')) - - " Error in default argument expression - func! s:f(x = s:undefined) - return a:x - endfunc - call assert_fails('echo s:f()', ['E121: Undefined variable: s:undefined', - \ 'E121: Undefined variable: a:x']) - - func! s:f(x = s:undefined) abort - return a:x - endfunc - const expected_error = 'E121: Undefined variable: s:undefined' - " Only one error should be output; execution of the function should be aborted - " after the default argument expression error. - call assert_fails('echo s:f()', [expected_error, expected_error]) -endfunc - -func Test_default_argument_expression_error_while_inside_of_a_try_block() - func! s:f(v = s:undefined_variable) - let s:entered_fn_body = 1 - return a:v - endfunc - - unlet! s:entered_fn_body - try - call s:f() - throw "No exception." - catch - call assert_exception("E121: Undefined variable: s:undefined_variable") - endtry - call assert_false(exists('s:entered_fn_body'), "exists('s:entered_fn_body')") -endfunc - -func s:addFoo(lead) - return a:lead .. 'foo' -endfunc - -func Test_user_method() - eval 'bar'->s:addFoo()->assert_equal('barfoo') -endfunc - -func Test_method_with_linebreaks() - let lines =<< trim END - vim9script - - export def Scan(ll: list<number>): func(func(number)) - return (Emit: func(number)) => { - for v in ll - Emit(v) - endfor - } - enddef - - export def Build(Cont: func(func(number))): list<number> - var result: list<number> = [] - Cont((v) => { - add(result, v) - }) - return result - enddef - - export def Noop(Cont: func(func(number))): func(func(number)) - return (Emit: func(number)) => { - Cont(Emit) - } - enddef - END - call writefile(lines, 'Xlib.vim', 'D') - - let lines =<< trim END - vim9script - - import "./Xlib.vim" as lib - - const x = [1, 2, 3] - - var result = lib.Scan(x)->lib.Noop()->lib.Build() - assert_equal([1, 2, 3], result) - - result = lib.Scan(x)->lib.Noop() - ->lib.Build() - assert_equal([1, 2, 3], result) - - result = lib.Scan(x) - ->lib.Noop()->lib.Build() - assert_equal([1, 2, 3], result) - - result = lib.Scan(x) - ->lib.Noop() - ->lib.Build() - assert_equal([1, 2, 3], result) - END - call v9.CheckScriptSuccess(lines) -endfunc - -func Test_failed_call_in_try() - try | call UnknownFunc() | catch | endtry -endfunc - -" Test for listing user-defined functions -func Test_function_list() - call assert_fails("function Xabc", 'E123:') -endfunc - -" Test for <sfile>, <slnum> in a function -func Test_sfile_in_function() - func Xfunc() - call assert_match('..Test_sfile_in_function\[5]..Xfunc', expand('<sfile>')) - call assert_equal('2', expand('<slnum>')) - endfunc - call Xfunc() - delfunc Xfunc -endfunc - -" Test trailing text after :endfunction {{{1 -func Test_endfunction_trailing() - call assert_false(exists('*Xtest')) - - exe "func Xtest()\necho 'hello'\nendfunc\nlet done = 'yes'" - call assert_true(exists('*Xtest')) - call assert_equal('yes', done) - delfunc Xtest - unlet done - - exe "func Xtest()\necho 'hello'\nendfunc|let done = 'yes'" - call assert_true(exists('*Xtest')) - call assert_equal('yes', done) - delfunc Xtest - unlet done - - " trailing line break - exe "func Xtest()\necho 'hello'\nendfunc\n" - call assert_true(exists('*Xtest')) - delfunc Xtest - - set verbose=1 - exe "func Xtest()\necho 'hello'\nendfunc \" garbage" - call assert_notmatch('W22:', split(execute('1messages'), "\n")[0]) - call assert_true(exists('*Xtest')) - delfunc Xtest - - exe "func Xtest()\necho 'hello'\nendfunc garbage" - call assert_match('W22:', split(execute('1messages'), "\n")[0]) - call assert_true(exists('*Xtest')) - delfunc Xtest - set verbose=0 - - func Xtest(a1, a2) - echo a:a1 .. a:a2 - endfunc - set verbose=15 - redir @a - call Xtest(123, repeat('x', 100)) - redir END - call assert_match('calling Xtest(123, ''xxxxxxx.*x\.\.\.x.*xxxx'')', getreg('a')) - delfunc Xtest - set verbose=0 - - function Foo() - echo 'hello' - endfunction | echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' - delfunc Foo -endfunc - -func Test_delfunction_force() - delfunc! Xtest - delfunc! Xtest - func Xtest() - echo 'nothing' - endfunc - delfunc! Xtest - delfunc! Xtest - - " Try deleting the current function - call assert_fails('delfunc Test_delfunction_force', 'E131:') -endfunc - -func Test_function_defined_line() - CheckNotGui - - let lines =<< trim [CODE] - " F1 - func F1() - " F2 - func F2() - " - " - " - return - endfunc - " F3 - execute "func F3()\n\n\n\nreturn\nendfunc" - " F4 - execute "func F4()\n - \\n - \\n - \\n - \return\n - \endfunc" - endfunc - " F5 - execute "func F5()\n\n\n\nreturn\nendfunc" - " F6 - execute "func F6()\n - \\n - \\n - \\n - \return\n - \endfunc" - call F1() - verbose func F1 - verbose func F2 - verbose func F3 - verbose func F4 - verbose func F5 - verbose func F6 - qall! - [CODE] - - call writefile(lines, 'Xtest.vim', 'D') - let res = system(GetVimCommandClean() .. ' -es -X -S Xtest.vim') - call assert_equal(0, v:shell_error) - - let m = matchstr(res, 'function F1()[^[:print:]]*[[:print:]]*') - call assert_match(' line 2$', m) - - let m = matchstr(res, 'function F2()[^[:print:]]*[[:print:]]*') - call assert_match(' line 4$', m) - - let m = matchstr(res, 'function F3()[^[:print:]]*[[:print:]]*') - call assert_match(' line 11$', m) - - let m = matchstr(res, 'function F4()[^[:print:]]*[[:print:]]*') - call assert_match(' line 13$', m) - - let m = matchstr(res, 'function F5()[^[:print:]]*[[:print:]]*') - call assert_match(' line 21$', m) - - let m = matchstr(res, 'function F6()[^[:print:]]*[[:print:]]*') - call assert_match(' line 23$', m) -endfunc - -" Test for defining a function reference in the global scope -func Test_add_funcref_to_global_scope() - let x = g: - let caught_E862 = 0 - try - func x.Xfunc() - return 1 - endfunc - catch /E862:/ - let caught_E862 = 1 - endtry - call assert_equal(1, caught_E862) -endfunc - -func Test_funccall_garbage_collect() - func Func(x, ...) - call add(a:x, a:000) - endfunc - call Func([], []) - " Must not crash cause by invalid freeing - call test_garbagecollect_now() - call assert_true(v:true) - delfunc Func -endfunc - -" Test for script-local function -func <SID>DoLast() - call append(line('$'), "last line") -endfunc - -func s:DoNothing() - call append(line('$'), "nothing line") -endfunc - -func Test_script_local_func() - set nocp nomore viminfo+=nviminfo - new - nnoremap <buffer> _x :call <SID>DoNothing()<bar>call <SID>DoLast()<bar>delfunc <SID>DoNothing<bar>delfunc <SID>DoLast<cr> - - normal _x - call assert_equal('nothing line', getline(2)) - call assert_equal('last line', getline(3)) - close! - - " Try to call a script local function in global scope - let lines =<< trim [CODE] - :call assert_fails('call s:Xfunc()', 'E81:') - :call assert_fails('let x = call("<SID>Xfunc", [])', ['E81:', 'E117:']) - :call writefile(v:errors, 'Xresult') - :qall - - [CODE] - call writefile(lines, 'Xscript', 'D') - if RunVim([], [], '-s Xscript') - call assert_equal([], readfile('Xresult')) - endif - call delete('Xresult') -endfunc - -" Test for errors in defining new functions -func Test_func_def_error() - call assert_fails('func Xfunc abc ()', 'E124:') - call assert_fails('func Xfunc(', 'E125:') - call assert_fails('func xfunc()', 'E128:') - - " Try to redefine a function that is in use - let caught_E127 = 0 - try - func! Test_func_def_error() - endfunc - catch /E127:/ - let caught_E127 = 1 - endtry - call assert_equal(1, caught_E127) - - " Try to define a function in a dict twice - let d = {} - let lines =<< trim END - func d.F1() - return 1 - endfunc - END - let l = join(lines, "\n") . "\n" - exe l - call assert_fails('exe l', 'E717:') - call assert_fails('call feedkeys(":func d.F1()\<CR>", "xt")', 'E717:') - - " Define an autoload function with an incorrect file name - call writefile(['func foo#Bar()', 'return 1', 'endfunc'], 'Xscript', 'D') - call assert_fails('source Xscript', 'E746:') - - " Try to list functions using an invalid search pattern - call assert_fails('function /\%(/', 'E53:') - - " Use a script-local function to cover uf_name_exp. - func s:TestRedefine(arg1 = 1, arg2 = 10) - let caught_E122 = 0 - try - func s:TestRedefine(arg1 = 1, arg2 = 10) - endfunc - catch /E122:/ - let caught_E122 = 1 - endtry - call assert_equal(1, caught_E122) - - let caught_E127 = 0 - try - func! s:TestRedefine(arg1 = 1, arg2 = 10) - endfunc - catch /E127:/ - let caught_E127 = 1 - endtry - call assert_equal(1, caught_E127) - - " The failures above shouldn't cause heap-use-after-free here. - return [a:arg1 + a:arg2, expand('<stack>')] - endfunc - - let stacks = [] - " Call the function twice. - " Failing to redefine a function shouldn't clear its argument list. - for i in range(2) - let [val, stack] = s:TestRedefine(1000) - call assert_equal(1010, val) - call assert_match(expand('<SID>') .. 'TestRedefine\[20\]$', stack) - call add(stacks, stack) - endfor - call assert_equal(stacks[0], stacks[1]) - - delfunc s:TestRedefine -endfunc - -" Test for deleting a function -func Test_del_func() - call assert_fails('delfunction Xabc', 'E117:') - let d = {'a' : 10} - call assert_fails('delfunc d.a', 'E718:') - func d.fn() - return 1 - endfunc - - " cannot delete the dict function by number - let nr = substitute(execute('echo d'), '.*function(''\(\d\+\)'').*', '\1', '') - call assert_fails('delfunction g:' .. nr, 'E475: Invalid argument: g:') - - delfunc d.fn - call assert_equal({'a' : 10}, d) -endfunc - -" Test for calling return outside of a function -func Test_return_outside_func() - call writefile(['return 10'], 'Xscript', 'D') - call assert_fails('source Xscript', 'E133:') -endfunc - -" Test for errors in calling a function -func Test_func_arg_error() - " Too many arguments - call assert_fails("call call('min', range(1,20))", 'E118:') - call assert_fails("call call('min', range(1,21))", 'E699:') - 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)', - \ 'E740:') - - " Missing dict argument - func Xfunc() dict - return 1 - endfunc - call assert_fails('call Xfunc()', 'E725:') - delfunc Xfunc -endfunc - -func Test_func_dict() - let mydict = {'a': 'b'} - function mydict.somefunc() dict - return len(self) - endfunc - - call assert_equal("{'a': 'b', 'somefunc': function('3')}", string(mydict)) - call assert_equal(2, mydict.somefunc()) - call assert_match("^\n function \\d\\\+() dict" - \ .. "\n1 return len(self)" - \ .. "\n endfunction$", execute('func mydict.somefunc')) - call assert_fails('call mydict.nonexist()', 'E716:') -endfunc - -func Test_func_dict_bracket_key() - " Dictionary function can be defined with bracket notation using a key - " that does not follow function naming rules (e.g. containing a hyphen). - let obj = {} - function obj['foo-bar']() dict - return self.value - endfunction - let obj.value = 42 - call assert_equal(42, obj['foo-bar']()) - call assert_equal(42, call(obj['foo-bar'], [])) -endfunc - -func Test_func_range() - new - call setline(1, range(1, 8)) - func FuncRange() range - echo a:firstline - echo a:lastline - endfunc - 3 - call assert_equal("\n3\n3", execute('call FuncRange()')) - call assert_equal("\n4\n6", execute('4,6 call FuncRange()')) - call assert_equal("\n function FuncRange() range" - \ .. "\n1 echo a:firstline" - \ .. "\n2 echo a:lastline" - \ .. "\n endfunction", - \ execute('function FuncRange')) - - bwipe! -endfunc - -" Test for memory allocation failure when defining a new function -func Test_funcdef_alloc_failure() - new - let lines =<< trim END - func Xtestfunc() - return 321 - endfunc - END - call setline(1, lines) - call test_alloc_fail(GetAllocId('get_func'), 0, 0) - call assert_fails('source', 'E342:') - call assert_false(exists('*Xtestfunc')) - call assert_fails('delfunc Xtestfunc', 'E117:') - %d _ - let lines =<< trim END - def g:Xvim9func(): number - return 456 - enddef - END - call setline(1, lines) - call test_alloc_fail(GetAllocId('get_func'), 0, 0) - call assert_fails('source', 'E342:') - call assert_false(exists('*Xvim9func')) - "call test_alloc_fail(GetAllocId('get_func'), 0, 0) - "call assert_fails('source', 'E342:') - "call assert_false(exists('*Xtestfunc')) - "call assert_fails('delfunc Xtestfunc', 'E117:') - bw! -endfunc - -func AddDefer(arg1, ...) - call extend(g:deferred, [a:arg1]) - if a:0 == 1 - call extend(g:deferred, [a:1]) - endif -endfunc - -func WithDeferTwo() - call extend(g:deferred, ['in Two']) - for nr in range(3) - defer AddDefer('Two' .. nr) - endfor - call extend(g:deferred, ['end Two']) -endfunc - -func WithDeferOne() - call extend(g:deferred, ['in One']) - call writefile(['text'], 'Xfuncdefer') - defer delete('Xfuncdefer') - defer AddDefer('One') - call WithDeferTwo() - call extend(g:deferred, ['end One']) -endfunc - -func WithPartialDefer() - call extend(g:deferred, ['in Partial']) - let Part = funcref('AddDefer', ['arg1']) - defer Part("arg2") - call extend(g:deferred, ['end Partial']) -endfunc - -func Test_defer() - let g:deferred = [] - call WithDeferOne() - - call assert_equal(['in One', 'in Two', 'end Two', 'Two2', 'Two1', 'Two0', 'end One', 'One'], g:deferred) - unlet g:deferred - - call assert_equal('', glob('Xfuncdefer')) - - call assert_fails('defer delete("Xfuncdefer")->Another()', 'E488:') - call assert_fails('defer delete("Xfuncdefer").member', 'E488:') - - let g:deferred = [] - call WithPartialDefer() - call assert_equal(['in Partial', 'end Partial', 'arg1', 'arg2'], g:deferred) - unlet g:deferred - - let Part = funcref('AddDefer', ['arg1'], {}) - call assert_fails('defer Part("arg2")', 'E1300:') -endfunc - -func DeferLevelTwo() - call writefile(['text'], 'XDeleteTwo', 'D') - throw 'someerror' -endfunc - -def DeferLevelOne() - call writefile(['text'], 'XDeleteOne', 'D') - call g:DeferLevelTwo() -enddef - -func Test_defer_throw() - let caught = 'no' - try - call DeferLevelOne() - catch /someerror/ - let caught = 'yes' - endtry - call assert_equal('yes', caught) - call assert_false(filereadable('XDeleteOne')) - call assert_false(filereadable('XDeleteTwo')) -endfunc - -func Test_defer_quitall_func() - let lines =<< trim END - func DeferLevelTwo() - call writefile(['text'], 'XQuitallFuncTwo', 'D') - call writefile(['quit'], 'XQuitallFuncThree', 'a') - qa! - endfunc - - func DeferLevelOne() - call writefile(['text'], 'XQuitalFunclOne', 'D') - defer DeferLevelTwo() - endfunc - - call DeferLevelOne() - END - call writefile(lines, 'XdeferQuitallFunc', 'D') - call system(GetVimCommand() .. ' -X -S XdeferQuitallFunc') - call assert_equal(0, v:shell_error) - call assert_false(filereadable('XQuitallFuncOne')) - call assert_false(filereadable('XQuitallFuncTwo')) - call assert_equal(['quit'], readfile('XQuitallFuncThree')) - - call delete('XQuitallFuncThree') -endfunc - -func Test_defer_quitall_def() - let lines =<< trim END - vim9script - def DeferLevelTwo() - call writefile(['text'], 'XQuitallDefTwo', 'D') - call writefile(['quit'], 'XQuitallDefThree', 'a') - qa! - enddef - - def DeferLevelOne() - call writefile(['text'], 'XQuitallDefOne', 'D') - defer DeferLevelTwo() - enddef - - DeferLevelOne() - END - call writefile(lines, 'XdeferQuitallDef', 'D') - call system(GetVimCommand() .. ' -X -S XdeferQuitallDef') - call assert_equal(0, v:shell_error) - call assert_false(filereadable('XQuitallDefOne')) - call assert_false(filereadable('XQuitallDefTwo')) - call assert_equal(['quit'], readfile('XQuitallDefThree')) - - call delete('XQuitallDefThree') -endfunc - -func Test_defer_quitall_autocmd() - let lines =<< trim END - func DeferLevelFive() - defer writefile(['5'], 'XQuitallAutocmd', 'a') - qa! - endfunc - - autocmd User DeferAutocmdFive call DeferLevelFive() - - def DeferLevelFour() - defer writefile(['4'], 'XQuitallAutocmd', 'a') - doautocmd User DeferAutocmdFive - enddef - - func DeferLevelThree() - defer writefile(['3'], 'XQuitallAutocmd', 'a') - call DeferLevelFour() - endfunc - - autocmd User DeferAutocmdThree ++nested call DeferLevelThree() - - def DeferLevelTwo() - defer writefile(['2'], 'XQuitallAutocmd', 'a') - doautocmd User DeferAutocmdThree - enddef - - func DeferLevelOne() - defer writefile(['1'], 'XQuitallAutocmd', 'a') - call DeferLevelTwo() - endfunc - - autocmd User DeferAutocmdOne ++nested call DeferLevelOne() - - doautocmd User DeferAutocmdOne - END - call writefile(lines, 'XdeferQuitallAutocmd', 'D') - call system(GetVimCommand() .. ' -X -S XdeferQuitallAutocmd') - call assert_equal(0, v:shell_error) - call assert_equal(['5', '4', '3', '2', '1'], readfile('XQuitallAutocmd')) - - call delete('XQuitallAutocmd') -endfunc - -func Test_defer_quitall_in_expr_func() - let lines =<< trim END - def DefIndex(idx: number, val: string): bool - call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D') - if val == 'b' - qa! - endif - return val == 'c' - enddef - - def Test_defer_in_funcref() - assert_equal(2, indexof(['a', 'b', 'c'], funcref('g:DefIndex'))) - enddef - call Test_defer_in_funcref() - END - call writefile(lines, 'XdeferQuitallExpr', 'D') - call system(GetVimCommand() .. ' -X -S XdeferQuitallExpr') - call assert_equal(0, v:shell_error) - call assert_false(filereadable('Xentry0')) - call assert_false(filereadable('Xentry1')) - call assert_false(filereadable('Xentry2')) -endfunc - -func FuncIndex(idx, val) - call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D') - return a:val == 'c' -endfunc - -def DefIndex(idx: number, val: string): bool - call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D') - return val == 'c' -enddef - -def DefIndexXtra(xtra: string, idx: number, val: string): bool - call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D') - return val == 'c' -enddef - -def Test_defer_in_funcref() - assert_equal(2, indexof(['a', 'b', 'c'], function('g:FuncIndex'))) - assert_false(filereadable('Xentry0')) - assert_false(filereadable('Xentry1')) - assert_false(filereadable('Xentry2')) - - assert_equal(2, indexof(['a', 'b', 'c'], g:DefIndex)) - assert_false(filereadable('Xentry0')) - assert_false(filereadable('Xentry1')) - assert_false(filereadable('Xentry2')) - - assert_equal(2, indexof(['a', 'b', 'c'], function('g:DefIndex'))) - assert_false(filereadable('Xentry0')) - assert_false(filereadable('Xentry1')) - assert_false(filereadable('Xentry2')) - - assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndex))) - assert_false(filereadable('Xentry0')) - assert_false(filereadable('Xentry1')) - assert_false(filereadable('Xentry2')) - - assert_equal(2, indexof(['a', 'b', 'c'], function(g:DefIndexXtra, ['xtra']))) - assert_false(filereadable('Xentry0')) - assert_false(filereadable('Xentry1')) - assert_false(filereadable('Xentry2')) - - assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndexXtra, ['xtra']))) - assert_false(filereadable('Xentry0')) - assert_false(filereadable('Xentry1')) - assert_false(filereadable('Xentry2')) -enddef - -func Test_defer_wrong_arguments() - call assert_fails('defer delete()', 'E119:') - call assert_fails('defer FuncIndex(1)', 'E119:') - call assert_fails('defer delete(1, 2, 3)', 'E118:') - call assert_fails('defer FuncIndex(1, 2, 3)', 'E118:') - - let lines =<< trim END - def DeferFunc0() - defer delete() - enddef - defcompile - END - call v9.CheckScriptFailure(lines, 'E119:') - let lines =<< trim END - def DeferFunc3() - defer delete(1, 2, 3) - enddef - defcompile - END - call v9.CheckScriptFailure(lines, 'E118:') - let lines =<< trim END - def DeferFunc2() - defer delete(1, 2) - enddef - defcompile - END - call v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number') - - def g:FuncOneArg(arg: string) - echo arg - enddef - - let lines =<< trim END - def DeferUserFunc0() - defer g:FuncOneArg() - enddef - defcompile - END - call v9.CheckScriptFailure(lines, 'E119:') - let lines =<< trim END - def DeferUserFunc2() - defer g:FuncOneArg(1, 2) - enddef - defcompile - END - call v9.CheckScriptFailure(lines, 'E118:') - let lines =<< trim END - def DeferUserFunc1() - defer g:FuncOneArg(1) - enddef - defcompile - END - call v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number') -endfunc - -" Test for calling a deferred function after an exception -func Test_defer_after_exception() - let g:callTrace = [] - func Bar() - let g:callTrace += [1] - throw 'InnerException' - endfunc - - func Defer() - let g:callTrace += [2] - let g:callTrace += [3] - try - call Bar() - catch /InnerException/ - let g:callTrace += [4] - endtry - let g:callTrace += [5] - let g:callTrace += [6] - endfunc - - func Foo() - defer Defer() - throw "TestException" - endfunc - - try - call Foo() - catch /TestException/ - let g:callTrace += [7] - endtry - call assert_equal([2, 3, 1, 4, 5, 6, 7], g:callTrace) - - delfunc Defer - delfunc Foo - delfunc Bar - unlet g:callTrace -endfunc - -" Test for multiple deferred function which throw exceptions. -" Exceptions thrown by deferred functions should result in error messages but -" not propagated into the calling functions. -func Test_multidefer_with_exception() - let g:callTrace = [] - func Except() - let g:callTrace += [1] - throw 'InnerException' - let g:callTrace += [2] - endfunc - - func FirstDefer() - let g:callTrace += [3] - let g:callTrace += [4] - endfunc - - func SecondDeferWithExcept() - let g:callTrace += [5] - call Except() - let g:callTrace += [6] - endfunc - - func ThirdDefer() - let g:callTrace += [7] - let g:callTrace += [8] - endfunc - - func Foo() - let g:callTrace += [9] - defer FirstDefer() - defer SecondDeferWithExcept() - defer ThirdDefer() - let g:callTrace += [10] - endfunc - - let v:errmsg = '' - try - let g:callTrace += [11] - call Foo() - let g:callTrace += [12] - catch /TestException/ - let g:callTrace += [13] - catch - let g:callTrace += [14] - finally - let g:callTrace += [15] - endtry - let g:callTrace += [16] - - call assert_equal('E605: Exception not caught: InnerException', v:errmsg) - call assert_equal([11, 9, 10, 7, 8, 5, 1, 3, 4, 12, 15, 16], g:callTrace) - - unlet g:callTrace - delfunc Except - delfunc FirstDefer - delfunc SecondDeferWithExcept - delfunc ThirdDefer - delfunc Foo -endfunc - -func Test_func_curly_brace_invalid_name() - func Fail() - func Foo{'()'}bar() - endfunc - endfunc - - call assert_fails('call Fail()', 'E475: Invalid argument: Foo()bar') - - silent! call Fail() - call assert_equal([], getcompletion('Foo', 'function')) - - set formatexpr=Fail() - normal! gqq - call assert_equal([], getcompletion('Foo', 'function')) - - set formatexpr& - delfunc Fail -endfunc - -func Test_func_return_in_try_verbose() - func TryReturnList() - try - return [1, 2, 3] - endtry - endfunc - func TryReturnNumber() - try - return 123 - endtry - endfunc - func TryReturnOverlongString() - try - return repeat('a', 9999) - endtry - endfunc - - " This should not cause heap-use-after-free - call assert_match('\n:return \[1, 2, 3\] made pending\n', - \ execute('14verbose call TryReturnList()')) - " This should not cause stack-use-after-scope - call assert_match('\n:return 123 made pending\n', - \ execute('14verbose call TryReturnNumber()')) - " An overlong string is truncated - call assert_match('\n:return a\{100,}\.\.\.', - \ execute('14verbose call TryReturnOverlongString()')) - - delfunc TryReturnList - delfunc TryReturnNumber - delfunc TryReturnOverlongString -endfunc - -" vim: shiftwidth=2 sts=2 expandtab |
