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 function Foo() 226 echo 'hello' 227 endfunction | echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' 228 delfunc Foo 229endfunc 230 231func Test_delfunction_force() 232 delfunc! Xtest 233 delfunc! Xtest 234 func Xtest() 235 echo 'nothing' 236 endfunc 237 delfunc! Xtest 238 delfunc! Xtest 239 240 " Try deleting the current function 241 call assert_fails('delfunc Test_delfunction_force', 'E131:') 242endfunc 243 244func Test_function_defined_line() 245 CheckNotGui 246 247 let lines =<< trim [CODE] 248 " F1 249 func F1() 250 " F2 251 func F2() 252 " 253 " 254 " 255 return 256 endfunc 257 " F3 258 execute "func F3()\n\n\n\nreturn\nendfunc" 259 " F4 260 execute "func F4()\n 261 \\n 262 \\n 263 \\n 264 \return\n 265 \endfunc" 266 endfunc 267 " F5 268 execute "func F5()\n\n\n\nreturn\nendfunc" 269 " F6 270 execute "func F6()\n 271 \\n 272 \\n 273 \\n 274 \return\n 275 \endfunc" 276 call F1() 277 verbose func F1 278 verbose func F2 279 verbose func F3 280 verbose func F4 281 verbose func F5 282 verbose func F6 283 qall! 284 [CODE] 285 286 call writefile(lines, 'Xtest.vim') 287 let res = system(GetVimCommandClean() .. ' -es -X -S Xtest.vim') 288 call assert_equal(0, v:shell_error) 289 290 let m = matchstr(res, 'function F1()[^[:print:]]*[[:print:]]*') 291 call assert_match(' line 2$', m) 292 293 let m = matchstr(res, 'function F2()[^[:print:]]*[[:print:]]*') 294 call assert_match(' line 4$', m) 295 296 let m = matchstr(res, 'function F3()[^[:print:]]*[[:print:]]*') 297 call assert_match(' line 11$', m) 298 299 let m = matchstr(res, 'function F4()[^[:print:]]*[[:print:]]*') 300 call assert_match(' line 13$', m) 301 302 let m = matchstr(res, 'function F5()[^[:print:]]*[[:print:]]*') 303 call assert_match(' line 21$', m) 304 305 let m = matchstr(res, 'function F6()[^[:print:]]*[[:print:]]*') 306 call assert_match(' line 23$', m) 307 308 call delete('Xtest.vim') 309endfunc 310 311" Test for defining a function reference in the global scope 312func Test_add_funcref_to_global_scope() 313 let x = g: 314 let caught_E862 = 0 315 try 316 func x.Xfunc() 317 return 1 318 endfunc 319 catch /E862:/ 320 let caught_E862 = 1 321 endtry 322 call assert_equal(1, caught_E862) 323endfunc 324 325func Test_funccall_garbage_collect() 326 func Func(x, ...) 327 call add(a:x, a:000) 328 endfunc 329 call Func([], []) 330 " Must not crash cause by invalid freeing 331 call test_garbagecollect_now() 332 call assert_true(v:true) 333 delfunc Func 334endfunc 335 336" Test for script-local function 337func <SID>DoLast() 338 call append(line('$'), "last line") 339endfunc 340 341func s:DoNothing() 342 call append(line('$'), "nothing line") 343endfunc 344 345func Test_script_local_func() 346 set nocp nomore viminfo+=nviminfo 347 new 348 nnoremap <buffer> _x :call <SID>DoNothing()<bar>call <SID>DoLast()<bar>delfunc <SID>DoNothing<bar>delfunc <SID>DoLast<cr> 349 350 normal _x 351 call assert_equal('nothing line', getline(2)) 352 call assert_equal('last line', getline(3)) 353 close! 354 355 " Try to call a script local function in global scope 356 let lines =<< trim [CODE] 357 :call assert_fails('call s:Xfunc()', 'E81:') 358 :call assert_fails('let x = call("<SID>Xfunc", [])', 'E120:') 359 :call writefile(v:errors, 'Xresult') 360 :qall 361 362 [CODE] 363 call writefile(lines, 'Xscript') 364 if RunVim([], [], '-s Xscript') 365 call assert_equal([], readfile('Xresult')) 366 endif 367 call delete('Xresult') 368 call delete('Xscript') 369endfunc 370 371" Test for errors in defining new functions 372func Test_func_def_error() 373 call assert_fails('func Xfunc abc ()', 'E124:') 374 call assert_fails('func Xfunc(', 'E125:') 375 call assert_fails('func xfunc()', 'E128:') 376 377 " Try to redefine a function that is in use 378 let caught_E127 = 0 379 try 380 func! Test_func_def_error() 381 endfunc 382 catch /E127:/ 383 let caught_E127 = 1 384 endtry 385 call assert_equal(1, caught_E127) 386 387 " Try to define a function in a dict twice 388 let d = {} 389 let lines =<< trim END 390 func d.F1() 391 return 1 392 endfunc 393 END 394 let l = join(lines, "\n") . "\n" 395 exe l 396 call assert_fails('exe l', 'E717:') 397 398 " Define an autoload function with an incorrect file name 399 call writefile(['func foo#Bar()', 'return 1', 'endfunc'], 'Xscript') 400 call assert_fails('source Xscript', 'E746:') 401 call delete('Xscript') 402endfunc 403 404" Test for deleting a function 405func Test_del_func() 406 call assert_fails('delfunction Xabc', 'E130:') 407 let d = {'a' : 10} 408 call assert_fails('delfunc d.a', 'E718:') 409endfunc 410 411" Test for calling return outside of a function 412func Test_return_outside_func() 413 call writefile(['return 10'], 'Xscript') 414 call assert_fails('source Xscript', 'E133:') 415 call delete('Xscript') 416endfunc 417 418" Test for errors in calling a function 419func Test_func_arg_error() 420 " Too many arguments 421 call assert_fails("call call('min', range(1,20))", 'E118:') 422 call assert_fails("call call('min', range(1,21))", 'E699:') 423 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)', 424 \ 'E740:') 425 426 " Missing dict argument 427 func Xfunc() dict 428 return 1 429 endfunc 430 call assert_fails('call Xfunc()', 'E725:') 431 delfunc Xfunc 432endfunc 433 434" vim: shiftwidth=2 sts=2 expandtab 435