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 6source check.vim 7source shared.vim 8 9func Table(title, ...) 10 let ret = a:title 11 let idx = 1 12 while idx <= a:0 13 exe "let ret = ret . a:" . idx 14 let idx = idx + 1 15 endwhile 16 return ret 17endfunc 18 19func Compute(n1, n2, divname) 20 if a:n2 == 0 21 return "fail" 22 endif 23 exe "let g:" . a:divname . " = ". a:n1 / a:n2 24 return "ok" 25endfunc 26 27func Expr1() 28 silent! normal! v 29 return "111" 30endfunc 31 32func Expr2() 33 call search('XX', 'b') 34 return "222" 35endfunc 36 37func ListItem() 38 let g:counter += 1 39 return g:counter . '. ' 40endfunc 41 42func ListReset() 43 let g:counter = 0 44 return '' 45endfunc 46 47func FuncWithRef(a) 48 unlet g:FuncRef 49 return a:a 50endfunc 51 52func Test_user_func() 53 let g:FuncRef = function("FuncWithRef") 54 let g:counter = 0 55 inoremap <expr> ( ListItem() 56 inoremap <expr> [ ListReset() 57 imap <expr> + Expr1() 58 imap <expr> * Expr2() 59 let g:retval = "nop" 60 61 call assert_equal('xxx4asdf', Table("xxx", 4, "asdf")) 62 call assert_equal('fail', Compute(45, 0, "retval")) 63 call assert_equal('nop', g:retval) 64 call assert_equal('ok', Compute(45, 5, "retval")) 65 call assert_equal(9, g:retval) 66 call assert_equal(333, g:FuncRef(333)) 67 68 let g:retval = "nop" 69 call assert_equal('xxx4asdf', "xxx"->Table(4, "asdf")) 70 call assert_equal('fail', 45->Compute(0, "retval")) 71 call assert_equal('nop', g:retval) 72 call assert_equal('ok', 45->Compute(5, "retval")) 73 call assert_equal(9, g:retval) 74 " call assert_equal(333, 333->g:FuncRef()) 75 76 enew 77 78 normal oXX+-XX 79 call assert_equal('XX111-XX', getline('.')) 80 normal o---*--- 81 call assert_equal('---222---', getline('.')) 82 normal o(one 83 call assert_equal('1. one', getline('.')) 84 normal o(two 85 call assert_equal('2. two', getline('.')) 86 normal o[(one again 87 call assert_equal('1. one again', getline('.')) 88 89 " Try to overwrite a function in the global (g:) scope 90 call assert_equal(3, max([1, 2, 3])) 91 call assert_fails("call extend(g:, {'max': function('min')})", 'E704:') 92 call assert_equal(3, max([1, 2, 3])) 93 94 " Try to overwrite an user defined function with a function reference 95 call assert_fails("let Expr1 = function('min')", 'E705:') 96 97 " Regression: the first line below used to throw ?E110: Missing ')'? 98 " Second is here just to prove that this line is correct when not skipping 99 " rhs of &&. 100 call assert_equal(0, (0 && (function('tr'))(1, 2, 3))) 101 call assert_equal(1, (1 && (function('tr'))(1, 2, 3))) 102 103 delfunc Table 104 delfunc Compute 105 delfunc Expr1 106 delfunc Expr2 107 delfunc ListItem 108 delfunc ListReset 109 unlet g:retval g:counter 110 enew! 111endfunc 112 113func Log(val, base = 10) 114 return log(a:val) / log(a:base) 115endfunc 116 117func Args(mandatory, optional = v:null, ...) 118 return deepcopy(a:) 119endfunc 120 121func Args2(a = 1, b = 2, c = 3) 122 return deepcopy(a:) 123endfunc 124 125func MakeBadFunc() 126 func s:fcn(a, b=1, c) 127 endfunc 128endfunc 129 130func Test_default_arg() 131 if has('float') 132 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:') 135 endif 136 137 let res = Args(1) 138 call assert_equal(res.mandatory, 1) 139 call assert_equal(res.optional, v:null) 140 call assert_equal(res['0'], 0) 141 142 let res = Args(1,2) 143 call assert_equal(res.mandatory, 1) 144 call assert_equal(res.optional, 2) 145 call assert_equal(res['0'], 0) 146 147 let res = Args(1,2,3) 148 call assert_equal(res.mandatory, 1) 149 call assert_equal(res.optional, 2) 150 call assert_equal(res['0'], 1) 151 152 call assert_fails("call MakeBadFunc()", 'E989:') 153 call assert_fails("fu F(a=1 ,) | endf", 'E475:') 154 155 let d = Args2(7, v:none, 9) 156 call assert_equal([7, 2, 9], [d.a, d.b, d.c]) 157 158 call assert_equal("\n" 159 \ .. " function Args2(a = 1, b = 2, c = 3)\n" 160 \ .. "1 return deepcopy(a:)\n" 161 \ .. " endfunction", 162 \ execute('func Args2')) 163endfunc 164 165func s:addFoo(lead) 166 return a:lead .. 'foo' 167endfunc 168 169func Test_user_method() 170 eval 'bar'->s:addFoo()->assert_equal('barfoo') 171endfunc 172 173func Test_failed_call_in_try() 174 try | call UnknownFunc() | catch | endtry 175endfunc 176 177" Test for listing user-defined functions 178func Test_function_list() 179 call assert_fails("function Xabc", 'E123:') 180endfunc 181 182" Test for <sfile>, <slnum> in a function 183func Test_sfile_in_function() 184 func Xfunc() 185 call assert_match('..Test_sfile_in_function\[5]..Xfunc', expand('<sfile>')) 186 call assert_equal('2', expand('<slnum>')) 187 endfunc 188 call Xfunc() 189 delfunc Xfunc 190endfunc 191 192" Test trailing text after :endfunction {{{1 193func Test_endfunction_trailing() 194 call assert_false(exists('*Xtest')) 195 196 exe "func Xtest()\necho 'hello'\nendfunc\nlet done = 'yes'" 197 call assert_true(exists('*Xtest')) 198 call assert_equal('yes', done) 199 delfunc Xtest 200 unlet done 201 202 exe "func Xtest()\necho 'hello'\nendfunc|let done = 'yes'" 203 call assert_true(exists('*Xtest')) 204 call assert_equal('yes', done) 205 delfunc Xtest 206 unlet done 207 208 " trailing line break 209 exe "func Xtest()\necho 'hello'\nendfunc\n" 210 call assert_true(exists('*Xtest')) 211 delfunc Xtest 212 213 set verbose=1 214 exe "func Xtest()\necho 'hello'\nendfunc \" garbage" 215 call assert_notmatch('W22:', split(execute('1messages'), "\n")[0]) 216 call assert_true(exists('*Xtest')) 217 delfunc Xtest 218 219 exe "func Xtest()\necho 'hello'\nendfunc garbage" 220 call assert_match('W22:', split(execute('1messages'), "\n")[0]) 221 call assert_true(exists('*Xtest')) 222 delfunc Xtest 223 set verbose=0 224 225 func Xtest(a1, a2) 226 echo a:a1 .. a:a2 227 endfunc 228 set verbose=15 229 redir @a 230 call Xtest(123, repeat('x', 100)) 231 redir END 232 call assert_match('calling Xtest(123, ''xxxxxxx.*x\.\.\.x.*xxxx'')', getreg('a')) 233 delfunc Xtest 234 set verbose=0 235 236 function Foo() 237 echo 'hello' 238 endfunction | echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' 239 delfunc Foo 240endfunc 241 242func Test_delfunction_force() 243 delfunc! Xtest 244 delfunc! Xtest 245 func Xtest() 246 echo 'nothing' 247 endfunc 248 delfunc! Xtest 249 delfunc! Xtest 250 251 " Try deleting the current function 252 call assert_fails('delfunc Test_delfunction_force', 'E131:') 253endfunc 254 255func Test_function_defined_line() 256 CheckNotGui 257 258 let lines =<< trim [CODE] 259 " F1 260 func F1() 261 " F2 262 func F2() 263 " 264 " 265 " 266 return 267 endfunc 268 " F3 269 execute "func F3()\n\n\n\nreturn\nendfunc" 270 " F4 271 execute "func F4()\n 272 \\n 273 \\n 274 \\n 275 \return\n 276 \endfunc" 277 endfunc 278 " F5 279 execute "func F5()\n\n\n\nreturn\nendfunc" 280 " F6 281 execute "func F6()\n 282 \\n 283 \\n 284 \\n 285 \return\n 286 \endfunc" 287 call F1() 288 verbose func F1 289 verbose func F2 290 verbose func F3 291 verbose func F4 292 verbose func F5 293 verbose func F6 294 qall! 295 [CODE] 296 297 call writefile(lines, 'Xtest.vim') 298 let res = system(GetVimCommandClean() .. ' -es -X -S Xtest.vim') 299 call assert_equal(0, v:shell_error) 300 301 let m = matchstr(res, 'function F1()[^[:print:]]*[[:print:]]*') 302 call assert_match(' line 2$', m) 303 304 let m = matchstr(res, 'function F2()[^[:print:]]*[[:print:]]*') 305 call assert_match(' line 4$', m) 306 307 let m = matchstr(res, 'function F3()[^[:print:]]*[[:print:]]*') 308 call assert_match(' line 11$', m) 309 310 let m = matchstr(res, 'function F4()[^[:print:]]*[[:print:]]*') 311 call assert_match(' line 13$', m) 312 313 let m = matchstr(res, 'function F5()[^[:print:]]*[[:print:]]*') 314 call assert_match(' line 21$', m) 315 316 let m = matchstr(res, 'function F6()[^[:print:]]*[[:print:]]*') 317 call assert_match(' line 23$', m) 318 319 call delete('Xtest.vim') 320endfunc 321 322" Test for defining a function reference in the global scope 323func Test_add_funcref_to_global_scope() 324 let x = g: 325 let caught_E862 = 0 326 try 327 func x.Xfunc() 328 return 1 329 endfunc 330 catch /E862:/ 331 let caught_E862 = 1 332 endtry 333 call assert_equal(1, caught_E862) 334endfunc 335 336func Test_funccall_garbage_collect() 337 func Func(x, ...) 338 call add(a:x, a:000) 339 endfunc 340 call Func([], []) 341 " Must not crash cause by invalid freeing 342 call test_garbagecollect_now() 343 call assert_true(v:true) 344 delfunc Func 345endfunc 346 347" Test for script-local function 348func <SID>DoLast() 349 call append(line('$'), "last line") 350endfunc 351 352func s:DoNothing() 353 call append(line('$'), "nothing line") 354endfunc 355 356func Test_script_local_func() 357 set nocp nomore viminfo+=nviminfo 358 new 359 nnoremap <buffer> _x :call <SID>DoNothing()<bar>call <SID>DoLast()<bar>delfunc <SID>DoNothing<bar>delfunc <SID>DoLast<cr> 360 361 normal _x 362 call assert_equal('nothing line', getline(2)) 363 call assert_equal('last line', getline(3)) 364 close! 365 366 " Try to call a script local function in global scope 367 let lines =<< trim [CODE] 368 :call assert_fails('call s:Xfunc()', 'E81:') 369 :call assert_fails('let x = call("<SID>Xfunc", [])', 'E120:') 370 :call writefile(v:errors, 'Xresult') 371 :qall 372 373 [CODE] 374 call writefile(lines, 'Xscript') 375 if RunVim([], [], '-s Xscript') 376 call assert_equal([], readfile('Xresult')) 377 endif 378 call delete('Xresult') 379 call delete('Xscript') 380endfunc 381 382" Test for errors in defining new functions 383func Test_func_def_error() 384 call assert_fails('func Xfunc abc ()', 'E124:') 385 call assert_fails('func Xfunc(', 'E125:') 386 call assert_fails('func xfunc()', 'E128:') 387 388 " Try to redefine a function that is in use 389 let caught_E127 = 0 390 try 391 func! Test_func_def_error() 392 endfunc 393 catch /E127:/ 394 let caught_E127 = 1 395 endtry 396 call assert_equal(1, caught_E127) 397 398 " Try to define a function in a dict twice 399 let d = {} 400 let lines =<< trim END 401 func d.F1() 402 return 1 403 endfunc 404 END 405 let l = join(lines, "\n") . "\n" 406 exe l 407 call assert_fails('exe l', 'E717:') 408 409 " Define an autoload function with an incorrect file name 410 call writefile(['func foo#Bar()', 'return 1', 'endfunc'], 'Xscript') 411 call assert_fails('source Xscript', 'E746:') 412 call delete('Xscript') 413 414 " Try to list functions using an invalid search pattern 415 call assert_fails('function /\%(/', 'E53:') 416endfunc 417 418" Test for deleting a function 419func Test_del_func() 420 call assert_fails('delfunction Xabc', 'E130:') 421 let d = {'a' : 10} 422 call assert_fails('delfunc d.a', 'E718:') 423endfunc 424 425" Test for calling return outside of a function 426func Test_return_outside_func() 427 call writefile(['return 10'], 'Xscript') 428 call assert_fails('source Xscript', 'E133:') 429 call delete('Xscript') 430endfunc 431 432" Test for errors in calling a function 433func Test_func_arg_error() 434 " Too many arguments 435 call assert_fails("call call('min', range(1,20))", 'E118:') 436 call assert_fails("call call('min', range(1,21))", 'E699:') 437 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)', 438 \ 'E740:') 439 440 " Missing dict argument 441 func Xfunc() dict 442 return 1 443 endfunc 444 call assert_fails('call Xfunc()', 'E725:') 445 delfunc Xfunc 446endfunc 447 448func Test_func_dict() 449 let mydict = {'a': 'b'} 450 function mydict.somefunc() dict 451 return len(self) 452 endfunc 453 454 call assert_equal("{'a': 'b', 'somefunc': function('2')}", string(mydict)) 455 call assert_equal(2, mydict.somefunc()) 456 call assert_match("^\n function \\d\\\+() dict" 457 \ .. "\n1 return len(self)" 458 \ .. "\n endfunction$", execute('func mydict.somefunc')) 459endfunc 460 461func Test_func_range() 462 new 463 call setline(1, range(1, 8)) 464 func FuncRange() range 465 echo a:firstline 466 echo a:lastline 467 endfunc 468 3 469 call assert_equal("\n3\n3", execute('call FuncRange()')) 470 call assert_equal("\n4\n6", execute('4,6 call FuncRange()')) 471 call assert_equal("\n function FuncRange() range" 472 \ .. "\n1 echo a:firstline" 473 \ .. "\n2 echo a:lastline" 474 \ .. "\n endfunction", 475 \ execute('function FuncRange')) 476 477 bwipe! 478endfunc 479 480" vim: shiftwidth=2 sts=2 expandtab 481