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