blob: 747ec486bc714fc63814accf2a0ae5f28e354f5f [file] [log] [blame]
Bram Moolenaar53f0c962017-10-22 14:23:59 +02001" 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
Bram Moolenaar476a6132020-04-08 19:48:56 +02006source check.vim
7source shared.vim
8
Bram Moolenaar53f0c962017-10-22 14:23:59 +02009func 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()
Bram Moolenaarfcfe1a92019-08-04 23:04:39 +020053 let g:FuncRef = function("FuncWithRef")
Bram Moolenaar53f0c962017-10-22 14:23:59 +020054 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
Bram Moolenaarfcfe1a92019-08-04 23:04:39 +020068 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
Bram Moolenaar53f0c962017-10-22 14:23:59 +020076 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
Bram Moolenaar476a6132020-04-08 19:48:56 +020089 " Try to overwrite a function in the global (g:) scope
Bram Moolenaar53f0c962017-10-22 14:23:59 +020090 call assert_equal(3, max([1, 2, 3]))
Bram Moolenaare2e40752020-09-04 21:18:46 +020091 call assert_fails("call extend(g:, {'max': function('min')})", 'E704:')
Bram Moolenaar53f0c962017-10-22 14:23:59 +020092 call assert_equal(3, max([1, 2, 3]))
93
Bram Moolenaar8dfcce32020-03-18 19:32:26 +010094 " Try to overwrite an user defined function with a function reference
95 call assert_fails("let Expr1 = function('min')", 'E705:')
96
Bram Moolenaar53f0c962017-10-22 14:23:59 +020097 " 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
Bram Moolenaar42ae78c2019-05-09 21:08:58 +0200112
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()
Bram Moolenaar5feabe02020-01-30 18:24:53 +0100131 if has('float')
132 call assert_equal(1.0, Log(10))
133 call assert_equal(log(10), Log(10, exp(1)))
Bram Moolenaare2e40752020-09-04 21:18:46 +0200134 call assert_fails("call Log(1,2,3)", 'E118:')
Bram Moolenaar5feabe02020-01-30 18:24:53 +0100135 endif
Bram Moolenaar42ae78c2019-05-09 21:08:58 +0200136
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
Bram Moolenaare2e40752020-09-04 21:18:46 +0200152 call assert_fails("call MakeBadFunc()", 'E989:')
Bram Moolenaare9b8b782021-04-06 20:18:29 +0200153 call assert_fails("fu F(a=1 ,) | endf", 'E1068:')
Bram Moolenaar42ae78c2019-05-09 21:08:58 +0200154
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'))
Yegappan Lakshmanan34fcb692021-05-25 20:14:00 +0200163
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:')
Bram Moolenaar42ae78c2019-05-09 21:08:58 +0200173endfunc
Bram Moolenaarfcfe1a92019-08-04 23:04:39 +0200174
175func s:addFoo(lead)
176 return a:lead .. 'foo'
177endfunc
178
179func Test_user_method()
180 eval 'bar'->s:addFoo()->assert_equal('barfoo')
181endfunc
Bram Moolenaare51bb172020-02-16 19:42:23 +0100182
183func Test_failed_call_in_try()
184 try | call UnknownFunc() | catch | endtry
185endfunc
Bram Moolenaaree4e0c12020-04-06 21:35:05 +0200186
187" Test for listing user-defined functions
188func Test_function_list()
189 call assert_fails("function Xabc", 'E123:')
190endfunc
191
Bram Moolenaar476a6132020-04-08 19:48:56 +0200192" 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
Bram Moolenaara0d072e2020-07-01 20:19:37 +0200235 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
Bram Moolenaar476a6132020-04-08 19:48:56 +0200246 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:')
Yegappan Lakshmanan611728f2021-05-24 15:15:47 +0200418 call assert_fails('call feedkeys(":func d.F1()\<CR>", "xt")', 'E717:')
Bram Moolenaar476a6132020-04-08 19:48:56 +0200419
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')
Bram Moolenaar531be472020-09-23 22:38:05 +0200424
425 " Try to list functions using an invalid search pattern
426 call assert_fails('function /\%(/', 'E53:')
Bram Moolenaar476a6132020-04-08 19:48:56 +0200427endfunc
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:')
Yegappan Lakshmanan611728f2021-05-24 15:15:47 +0200434 func d.fn()
435 return 1
436 endfunc
437 delfunc d.fn
438 call assert_equal({'a' : 10}, d)
Bram Moolenaar476a6132020-04-08 19:48:56 +0200439endfunc
440
441" Test for calling return outside of a function
442func Test_return_outside_func()
443 call writefile(['return 10'], 'Xscript')
444 call assert_fails('source Xscript', 'E133:')
445 call delete('Xscript')
446endfunc
447
448" Test for errors in calling a function
449func Test_func_arg_error()
450 " Too many arguments
451 call assert_fails("call call('min', range(1,20))", 'E118:')
452 call assert_fails("call call('min', range(1,21))", 'E699:')
453 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)',
454 \ 'E740:')
455
456 " Missing dict argument
457 func Xfunc() dict
458 return 1
459 endfunc
460 call assert_fails('call Xfunc()', 'E725:')
461 delfunc Xfunc
462endfunc
463
Bram Moolenaar67322bf2020-12-06 15:03:19 +0100464func Test_func_dict()
465 let mydict = {'a': 'b'}
466 function mydict.somefunc() dict
467 return len(self)
468 endfunc
469
Yegappan Lakshmanan611728f2021-05-24 15:15:47 +0200470 call assert_equal("{'a': 'b', 'somefunc': function('3')}", string(mydict))
Bram Moolenaar67322bf2020-12-06 15:03:19 +0100471 call assert_equal(2, mydict.somefunc())
472 call assert_match("^\n function \\d\\\+() dict"
473 \ .. "\n1 return len(self)"
474 \ .. "\n endfunction$", execute('func mydict.somefunc'))
Yegappan Lakshmanan611728f2021-05-24 15:15:47 +0200475 call assert_fails('call mydict.nonexist()', 'E716:')
Bram Moolenaar67322bf2020-12-06 15:03:19 +0100476endfunc
477
478func Test_func_range()
479 new
480 call setline(1, range(1, 8))
481 func FuncRange() range
482 echo a:firstline
483 echo a:lastline
484 endfunc
485 3
486 call assert_equal("\n3\n3", execute('call FuncRange()'))
487 call assert_equal("\n4\n6", execute('4,6 call FuncRange()'))
488 call assert_equal("\n function FuncRange() range"
489 \ .. "\n1 echo a:firstline"
490 \ .. "\n2 echo a:lastline"
491 \ .. "\n endfunction",
492 \ execute('function FuncRange'))
493
494 bwipe!
495endfunc
496
Bram Moolenaaree4e0c12020-04-06 21:35:05 +0200497" vim: shiftwidth=2 sts=2 expandtab