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'))
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