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", 'E1068:') 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')) 163 164 " Error in default argument expression 165 let l =<< trim END 166 func F1(x = y) 167 return a:x * 2 168 endfunc 169 echo F1() 170 END 171 let @a = l->join("\n") 172 call assert_fails("exe @a", 'E121:') 173endfunc 174 175func s:addFoo(lead) 176 return a:lead .. 'foo' 177endfunc 178 179func Test_user_method() 180 eval 'bar'->s:addFoo()->assert_equal('barfoo') 181endfunc 182 183func Test_failed_call_in_try() 184 try | call UnknownFunc() | catch | endtry 185endfunc 186 187" Test for listing user-defined functions 188func Test_function_list() 189 call assert_fails("function Xabc", 'E123:') 190endfunc 191 192" Test for <sfile>, <slnum> in a function 193func Test_sfile_in_function() 194 func Xfunc() 195 call assert_match('..Test_sfile_in_function\[5]..Xfunc', expand('<sfile>')) 196 call assert_equal('2', expand('<slnum>')) 197 endfunc 198 call Xfunc() 199 delfunc Xfunc 200endfunc 201 202" Test trailing text after :endfunction {{{1 203func Test_endfunction_trailing() 204 call assert_false(exists('*Xtest')) 205 206 exe "func Xtest()\necho 'hello'\nendfunc\nlet done = 'yes'" 207 call assert_true(exists('*Xtest')) 208 call assert_equal('yes', done) 209 delfunc Xtest 210 unlet done 211 212 exe "func Xtest()\necho 'hello'\nendfunc|let done = 'yes'" 213 call assert_true(exists('*Xtest')) 214 call assert_equal('yes', done) 215 delfunc Xtest 216 unlet done 217 218 " trailing line break 219 exe "func Xtest()\necho 'hello'\nendfunc\n" 220 call assert_true(exists('*Xtest')) 221 delfunc Xtest 222 223 set verbose=1 224 exe "func Xtest()\necho 'hello'\nendfunc \" garbage" 225 call assert_notmatch('W22:', split(execute('1messages'), "\n")[0]) 226 call assert_true(exists('*Xtest')) 227 delfunc Xtest 228 229 exe "func Xtest()\necho 'hello'\nendfunc garbage" 230 call assert_match('W22:', split(execute('1messages'), "\n")[0]) 231 call assert_true(exists('*Xtest')) 232 delfunc Xtest 233 set verbose=0 234 235 func Xtest(a1, a2) 236 echo a:a1 .. a:a2 237 endfunc 238 set verbose=15 239 redir @a 240 call Xtest(123, repeat('x', 100)) 241 redir END 242 call assert_match('calling Xtest(123, ''xxxxxxx.*x\.\.\.x.*xxxx'')', getreg('a')) 243 delfunc Xtest 244 set verbose=0 245 246 function Foo() 247 echo 'hello' 248 endfunction | echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' 249 delfunc Foo 250endfunc 251 252func Test_delfunction_force() 253 delfunc! Xtest 254 delfunc! Xtest 255 func Xtest() 256 echo 'nothing' 257 endfunc 258 delfunc! Xtest 259 delfunc! Xtest 260 261 " Try deleting the current function 262 call assert_fails('delfunc Test_delfunction_force', 'E131:') 263endfunc 264 265func Test_function_defined_line() 266 CheckNotGui 267 268 let lines =<< trim [CODE] 269 " F1 270 func F1() 271 " F2 272 func F2() 273 " 274 " 275 " 276 return 277 endfunc 278 " F3 279 execute "func F3()\n\n\n\nreturn\nendfunc" 280 " F4 281 execute "func F4()\n 282 \\n 283 \\n 284 \\n 285 \return\n 286 \endfunc" 287 endfunc 288 " F5 289 execute "func F5()\n\n\n\nreturn\nendfunc" 290 " F6 291 execute "func F6()\n 292 \\n 293 \\n 294 \\n 295 \return\n 296 \endfunc" 297 call F1() 298 verbose func F1 299 verbose func F2 300 verbose func F3 301 verbose func F4 302 verbose func F5 303 verbose func F6 304 qall! 305 [CODE] 306 307 call writefile(lines, 'Xtest.vim') 308 let res = system(GetVimCommandClean() .. ' -es -X -S Xtest.vim') 309 call assert_equal(0, v:shell_error) 310 311 let m = matchstr(res, 'function F1()[^[:print:]]*[[:print:]]*') 312 call assert_match(' line 2$', m) 313 314 let m = matchstr(res, 'function F2()[^[:print:]]*[[:print:]]*') 315 call assert_match(' line 4$', m) 316 317 let m = matchstr(res, 'function F3()[^[:print:]]*[[:print:]]*') 318 call assert_match(' line 11$', m) 319 320 let m = matchstr(res, 'function F4()[^[:print:]]*[[:print:]]*') 321 call assert_match(' line 13$', m) 322 323 let m = matchstr(res, 'function F5()[^[:print:]]*[[:print:]]*') 324 call assert_match(' line 21$', m) 325 326 let m = matchstr(res, 'function F6()[^[:print:]]*[[:print:]]*') 327 call assert_match(' line 23$', m) 328 329 call delete('Xtest.vim') 330endfunc 331 332" Test for defining a function reference in the global scope 333func Test_add_funcref_to_global_scope() 334 let x = g: 335 let caught_E862 = 0 336 try 337 func x.Xfunc() 338 return 1 339 endfunc 340 catch /E862:/ 341 let caught_E862 = 1 342 endtry 343 call assert_equal(1, caught_E862) 344endfunc 345 346func Test_funccall_garbage_collect() 347 func Func(x, ...) 348 call add(a:x, a:000) 349 endfunc 350 call Func([], []) 351 " Must not crash cause by invalid freeing 352 call test_garbagecollect_now() 353 call assert_true(v:true) 354 delfunc Func 355endfunc 356 357" Test for script-local function 358func <SID>DoLast() 359 call append(line('$'), "last line") 360endfunc 361 362func s:DoNothing() 363 call append(line('$'), "nothing line") 364endfunc 365 366func Test_script_local_func() 367 set nocp nomore viminfo+=nviminfo 368 new 369 nnoremap <buffer> _x :call <SID>DoNothing()<bar>call <SID>DoLast()<bar>delfunc <SID>DoNothing<bar>delfunc <SID>DoLast<cr> 370 371 normal _x 372 call assert_equal('nothing line', getline(2)) 373 call assert_equal('last line', getline(3)) 374 close! 375 376 " Try to call a script local function in global scope 377 let lines =<< trim [CODE] 378 :call assert_fails('call s:Xfunc()', 'E81:') 379 :call assert_fails('let x = call("<SID>Xfunc", [])', 'E120:') 380 :call writefile(v:errors, 'Xresult') 381 :qall 382 383 [CODE] 384 call writefile(lines, 'Xscript') 385 if RunVim([], [], '-s Xscript') 386 call assert_equal([], readfile('Xresult')) 387 endif 388 call delete('Xresult') 389 call delete('Xscript') 390endfunc 391 392" Test for errors in defining new functions 393func Test_func_def_error() 394 call assert_fails('func Xfunc abc ()', 'E124:') 395 call assert_fails('func Xfunc(', 'E125:') 396 call assert_fails('func xfunc()', 'E128:') 397 398 " Try to redefine a function that is in use 399 let caught_E127 = 0 400 try 401 func! Test_func_def_error() 402 endfunc 403 catch /E127:/ 404 let caught_E127 = 1 405 endtry 406 call assert_equal(1, caught_E127) 407 408 " Try to define a function in a dict twice 409 let d = {} 410 let lines =<< trim END 411 func d.F1() 412 return 1 413 endfunc 414 END 415 let l = join(lines, "\n") . "\n" 416 exe l 417 call assert_fails('exe l', 'E717:') 418 call assert_fails('call feedkeys(":func d.F1()\<CR>", "xt")', 'E717:') 419 420 " Define an autoload function with an incorrect file name 421 call writefile(['func foo#Bar()', 'return 1', 'endfunc'], 'Xscript') 422 call assert_fails('source Xscript', 'E746:') 423 call delete('Xscript') 424 425 " Try to list functions using an invalid search pattern 426 call assert_fails('function /\%(/', 'E53:') 427endfunc 428 429" Test for deleting a function 430func Test_del_func() 431 call assert_fails('delfunction Xabc', 'E130:') 432 let d = {'a' : 10} 433 call assert_fails('delfunc d.a', 'E718:') 434 func d.fn() 435 return 1 436 endfunc 437 438 " cannot delete the dict function by number 439 let nr = substitute(execute('echo d'), '.*function(''\(\d\+\)'').*', '\1', '') 440 call assert_fails('delfunction g:' .. nr, 'E475: Invalid argument: g:') 441 442 delfunc d.fn 443 call assert_equal({'a' : 10}, d) 444endfunc 445 446" Test for calling return outside of a function 447func Test_return_outside_func() 448 call writefile(['return 10'], 'Xscript') 449 call assert_fails('source Xscript', 'E133:') 450 call delete('Xscript') 451endfunc 452 453" Test for errors in calling a function 454func Test_func_arg_error() 455 " Too many arguments 456 call assert_fails("call call('min', range(1,20))", 'E118:') 457 call assert_fails("call call('min', range(1,21))", 'E699:') 458 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)', 459 \ 'E740:') 460 461 " Missing dict argument 462 func Xfunc() dict 463 return 1 464 endfunc 465 call assert_fails('call Xfunc()', 'E725:') 466 delfunc Xfunc 467endfunc 468 469func Test_func_dict() 470 let mydict = {'a': 'b'} 471 function mydict.somefunc() dict 472 return len(self) 473 endfunc 474 475 call assert_equal("{'a': 'b', 'somefunc': function('3')}", string(mydict)) 476 call assert_equal(2, mydict.somefunc()) 477 call assert_match("^\n function \\d\\\+() dict" 478 \ .. "\n1 return len(self)" 479 \ .. "\n endfunction$", execute('func mydict.somefunc')) 480 call assert_fails('call mydict.nonexist()', 'E716:') 481endfunc 482 483func Test_func_range() 484 new 485 call setline(1, range(1, 8)) 486 func FuncRange() range 487 echo a:firstline 488 echo a:lastline 489 endfunc 490 3 491 call assert_equal("\n3\n3", execute('call FuncRange()')) 492 call assert_equal("\n4\n6", execute('4,6 call FuncRange()')) 493 call assert_equal("\n function FuncRange() range" 494 \ .. "\n1 echo a:firstline" 495 \ .. "\n2 echo a:lastline" 496 \ .. "\n endfunction", 497 \ execute('function FuncRange')) 498 499 bwipe! 500endfunc 501 502" vim: shiftwidth=2 sts=2 expandtab 503