1" Test various aspects of the Vim9 script language.
2
3source check.vim
4source term_util.vim
5source view_util.vim
6source vim9.vim
7source screendump.vim
8
9func Test_def_basic()
10  def SomeFunc(): string
11    return 'yes'
12  enddef
13  call SomeFunc()->assert_equal('yes')
14endfunc
15
16def ReturnString(): string
17  return 'string'
18enddef
19
20def ReturnNumber(): number
21  return 123
22enddef
23
24let g:notNumber = 'string'
25
26def ReturnGlobal(): number
27  return g:notNumber
28enddef
29
30def Test_return_something()
31  ReturnString()->assert_equal('string')
32  ReturnNumber()->assert_equal(123)
33  assert_fails('ReturnGlobal()', 'E1012: Type mismatch; expected number but got string', '', 1, 'ReturnGlobal')
34enddef
35
36def Test_missing_return()
37  CheckDefFailure(['def Missing(): number',
38                   '  if g:cond',
39                   '    echo "no return"',
40                   '  else',
41                   '    return 0',
42                   '  endif'
43                   'enddef'], 'E1027:')
44  CheckDefFailure(['def Missing(): number',
45                   '  if g:cond',
46                   '    return 1',
47                   '  else',
48                   '    echo "no return"',
49                   '  endif'
50                   'enddef'], 'E1027:')
51  CheckDefFailure(['def Missing(): number',
52                   '  if g:cond',
53                   '    return 1',
54                   '  else',
55                   '    return 2',
56                   '  endif'
57                   '  return 3'
58                   'enddef'], 'E1095:')
59enddef
60
61let s:nothing = 0
62def ReturnNothing()
63  s:nothing = 1
64  if true
65    return
66  endif
67  s:nothing = 2
68enddef
69
70def Test_return_nothing()
71  ReturnNothing()
72  s:nothing->assert_equal(1)
73enddef
74
75func Increment()
76  let g:counter += 1
77endfunc
78
79def Test_call_ufunc_count()
80  g:counter = 1
81  Increment()
82  Increment()
83  Increment()
84  # works with and without :call
85  g:counter->assert_equal(4)
86  eval g:counter->assert_equal(4)
87  unlet g:counter
88enddef
89
90def MyVarargs(arg: string, ...rest: list<string>): string
91  var res = arg
92  for s in rest
93    res ..= ',' .. s
94  endfor
95  return res
96enddef
97
98def Test_call_varargs()
99  MyVarargs('one')->assert_equal('one')
100  MyVarargs('one', 'two')->assert_equal('one,two')
101  MyVarargs('one', 'two', 'three')->assert_equal('one,two,three')
102enddef
103
104def MyDefaultArgs(name = 'string'): string
105  return name
106enddef
107
108def MyDefaultSecond(name: string, second: bool  = true): string
109  return second ? name : 'none'
110enddef
111
112def Test_call_default_args()
113  MyDefaultArgs()->assert_equal('string')
114  MyDefaultArgs('one')->assert_equal('one')
115  assert_fails('MyDefaultArgs("one", "two")', 'E118:', '', 3, 'Test_call_default_args')
116
117  MyDefaultSecond('test')->assert_equal('test')
118  MyDefaultSecond('test', true)->assert_equal('test')
119  MyDefaultSecond('test', false)->assert_equal('none')
120
121  CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef', 'defcompile'], 'E1001:')
122  CheckScriptFailure(['def Func(arg: number = "text")', 'enddef', 'defcompile'], 'E1013: Argument 1: type mismatch, expected number but got string')
123enddef
124
125def Test_nested_function()
126  def Nested(arg: string): string
127    return 'nested ' .. arg
128  enddef
129  Nested('function')->assert_equal('nested function')
130
131  CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:')
132  CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:')
133
134  CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:')
135  CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:')
136  CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:')
137
138  CheckDefFailure([
139        'def Outer()',
140        '  def Inner()',
141        '    # comment',
142        '  enddef',
143        '  def Inner()',
144        '  enddef',
145        'enddef'], 'E1073:')
146  CheckDefFailure([
147        'def Outer()',
148        '  def Inner()',
149        '    # comment',
150        '  enddef',
151        '  def! Inner()',
152        '  enddef',
153        'enddef'], 'E1117:')
154enddef
155
156func Test_call_default_args_from_func()
157  call MyDefaultArgs()->assert_equal('string')
158  call MyDefaultArgs('one')->assert_equal('one')
159  call assert_fails('call MyDefaultArgs("one", "two")', 'E118:', '', 3, 'Test_call_default_args_from_func')
160endfunc
161
162def Test_nested_global_function()
163  var lines =<< trim END
164      vim9script
165      def Outer()
166          def g:Inner(): string
167              return 'inner'
168          enddef
169      enddef
170      defcompile
171      Outer()
172      g:Inner()->assert_equal('inner')
173      delfunc g:Inner
174      Outer()
175      g:Inner()->assert_equal('inner')
176      delfunc g:Inner
177      Outer()
178      g:Inner()->assert_equal('inner')
179      delfunc g:Inner
180  END
181  CheckScriptSuccess(lines)
182
183  lines =<< trim END
184      vim9script
185      def Outer()
186          def g:Inner(): string
187              return 'inner'
188          enddef
189      enddef
190      defcompile
191      Outer()
192      Outer()
193  END
194  CheckScriptFailure(lines, "E122:")
195
196  lines =<< trim END
197      vim9script
198      def Func()
199        echo 'script'
200      enddef
201      def Outer()
202        def Func()
203          echo 'inner'
204        enddef
205      enddef
206      defcompile
207  END
208  CheckScriptFailure(lines, "E1073:")
209enddef
210
211def Test_global_local_function()
212  var lines =<< trim END
213      vim9script
214      def g:Func(): string
215          return 'global'
216      enddef
217      def Func(): string
218          return 'local'
219      enddef
220      g:Func()->assert_equal('global')
221      Func()->assert_equal('local')
222  END
223  CheckScriptSuccess(lines)
224
225  lines =<< trim END
226      vim9script
227      def g:Funcy()
228        echo 'funcy'
229      enddef
230      s:Funcy()
231  END
232  CheckScriptFailure(lines, 'E117:')
233enddef
234
235def Test_local_function_shadows_global()
236  var lines =<< trim END
237      vim9script
238      def g:Gfunc(): string
239        return 'global'
240      enddef
241      def AnotherFunc(): number
242        var Gfunc = function('len')
243        return Gfunc('testing')
244      enddef
245      g:Gfunc()->assert_equal('global')
246      AnotherFunc()->assert_equal(7)
247      delfunc g:Gfunc
248  END
249  CheckScriptSuccess(lines)
250
251  lines =<< trim END
252      vim9script
253      def g:Func(): string
254        return 'global'
255      enddef
256      def AnotherFunc()
257        g:Func = function('len')
258      enddef
259      AnotherFunc()
260  END
261  CheckScriptFailure(lines, 'E705:')
262  delfunc g:Func
263enddef
264
265func TakesOneArg(arg)
266  echo a:arg
267endfunc
268
269def Test_call_wrong_args()
270  CheckDefFailure(['TakesOneArg()'], 'E119:')
271  CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
272  CheckDefFailure(['bufnr(xxx)'], 'E1001:')
273  CheckScriptFailure(['def Func(Ref: func(s: string))'], 'E475:')
274
275  var lines =<< trim END
276    vim9script
277    def Func(s: string)
278      echo s
279    enddef
280    Func([])
281  END
282  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 5)
283
284  lines =<< trim END
285    vim9script
286    def FuncOne(nr: number)
287      echo nr
288    enddef
289    def FuncTwo()
290      FuncOne()
291    enddef
292    defcompile
293  END
294  writefile(lines, 'Xscript')
295  var didCatch = false
296  try
297    source Xscript
298  catch
299    assert_match('E119: Not enough arguments for function: <SNR>\d\+_FuncOne', v:exception)
300    assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint)
301    didCatch = true
302  endtry
303  assert_true(didCatch)
304
305  lines =<< trim END
306    vim9script
307    def FuncOne(nr: number)
308      echo nr
309    enddef
310    def FuncTwo()
311      FuncOne(1, 2)
312    enddef
313    defcompile
314  END
315  writefile(lines, 'Xscript')
316  didCatch = false
317  try
318    source Xscript
319  catch
320    assert_match('E118: Too many arguments for function: <SNR>\d\+_FuncOne', v:exception)
321    assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint)
322    didCatch = true
323  endtry
324  assert_true(didCatch)
325
326  delete('Xscript')
327enddef
328
329" Default arg and varargs
330def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
331  var res = one .. ',' .. two
332  for s in rest
333    res ..= ',' .. s
334  endfor
335  return res
336enddef
337
338def Test_call_def_varargs()
339  assert_fails('MyDefVarargs()', 'E119:', '', 1, 'Test_call_def_varargs')
340  MyDefVarargs('one')->assert_equal('one,foo')
341  MyDefVarargs('one', 'two')->assert_equal('one,two')
342  MyDefVarargs('one', 'two', 'three')->assert_equal('one,two,three')
343  CheckDefFailure(['MyDefVarargs("one", 22)'],
344      'E1013: Argument 2: type mismatch, expected string but got number')
345  CheckDefFailure(['MyDefVarargs("one", "two", 123)'],
346      'E1013: Argument 3: type mismatch, expected string but got number')
347
348  var lines =<< trim END
349      vim9script
350      def Func(...l: list<string>)
351        echo l
352      enddef
353      Func('a', 'b', 'c')
354  END
355  CheckScriptSuccess(lines)
356
357  lines =<< trim END
358      vim9script
359      def Func(...l: list<string>)
360        echo l
361      enddef
362      Func()
363  END
364  CheckScriptSuccess(lines)
365
366  lines =<< trim END
367      vim9script
368      def Func(...l: any)
369        echo l
370      enddef
371      Func(0)
372  END
373  CheckScriptSuccess(lines)
374
375  lines =<< trim END
376      vim9script
377      def Func(..._l: list<string>)
378        echo _l
379      enddef
380      Func('a', 'b', 'c')
381  END
382  CheckScriptSuccess(lines)
383
384  lines =<< trim END
385      vim9script
386      def Func(...l: list<string>)
387        echo l
388      enddef
389      Func(1, 2, 3)
390  END
391  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch')
392
393  lines =<< trim END
394      vim9script
395      def Func(...l: list<string>)
396        echo l
397      enddef
398      Func('a', 9)
399  END
400  CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch')
401
402  lines =<< trim END
403      vim9script
404      def Func(...l: list<string>)
405        echo l
406      enddef
407      Func(1, 'a')
408  END
409  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch')
410enddef
411
412def Test_call_call()
413  var l = [3, 2, 1]
414  call('reverse', [l])
415  l->assert_equal([1, 2, 3])
416enddef
417
418let s:value = ''
419
420def FuncOneDefArg(opt = 'text')
421  s:value = opt
422enddef
423
424def FuncTwoDefArg(nr = 123, opt = 'text'): string
425  return nr .. opt
426enddef
427
428def FuncVarargs(...arg: list<string>): string
429  return join(arg, ',')
430enddef
431
432def Test_func_type_varargs()
433  var RefDefArg: func(?string)
434  RefDefArg = FuncOneDefArg
435  RefDefArg()
436  s:value->assert_equal('text')
437  RefDefArg('some')
438  s:value->assert_equal('some')
439
440  var RefDef2Arg: func(?number, ?string): string
441  RefDef2Arg = FuncTwoDefArg
442  RefDef2Arg()->assert_equal('123text')
443  RefDef2Arg(99)->assert_equal('99text')
444  RefDef2Arg(77, 'some')->assert_equal('77some')
445
446  CheckDefFailure(['var RefWrong: func(string?)'], 'E1010:')
447  CheckDefFailure(['var RefWrong: func(?string, string)'], 'E1007:')
448
449  var RefVarargs: func(...list<string>): string
450  RefVarargs = FuncVarargs
451  RefVarargs()->assert_equal('')
452  RefVarargs('one')->assert_equal('one')
453  RefVarargs('one', 'two')->assert_equal('one,two')
454
455  CheckDefFailure(['var RefWrong: func(...list<string>, string)'], 'E110:')
456  CheckDefFailure(['var RefWrong: func(...list<string>, ?string)'], 'E110:')
457enddef
458
459" Only varargs
460def MyVarargsOnly(...args: list<string>): string
461  return join(args, ',')
462enddef
463
464def Test_call_varargs_only()
465  MyVarargsOnly()->assert_equal('')
466  MyVarargsOnly('one')->assert_equal('one')
467  MyVarargsOnly('one', 'two')->assert_equal('one,two')
468  CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: Argument 1: type mismatch, expected string but got number')
469  CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: Argument 2: type mismatch, expected string but got number')
470enddef
471
472def Test_using_var_as_arg()
473  writefile(['def Func(x: number)',  'var x = 234', 'enddef', 'defcompile'], 'Xdef')
474  assert_fails('so Xdef', 'E1006:', '', 1, 'Func')
475  delete('Xdef')
476enddef
477
478def DictArg(arg: dict<string>)
479  arg['key'] = 'value'
480enddef
481
482def ListArg(arg: list<string>)
483  arg[0] = 'value'
484enddef
485
486def Test_assign_to_argument()
487  # works for dict and list
488  var d: dict<string> = {}
489  DictArg(d)
490  d['key']->assert_equal('value')
491  var l: list<string> = []
492  ListArg(l)
493  l[0]->assert_equal('value')
494
495  CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef', 'defcompile'], 'E1090:')
496enddef
497
498" These argument names are reserved in legacy functions.
499def WithReservedNames(firstline: string, lastline: string): string
500  return firstline .. lastline
501enddef
502
503def Test_argument_names()
504  assert_equal('OK', WithReservedNames('O', 'K'))
505enddef
506
507def Test_call_func_defined_later()
508  g:DefinedLater('one')->assert_equal('one')
509  assert_fails('NotDefined("one")', 'E117:', '', 2, 'Test_call_func_defined_later')
510enddef
511
512func DefinedLater(arg)
513  return a:arg
514endfunc
515
516def Test_call_funcref()
517  g:SomeFunc('abc')->assert_equal(3)
518  assert_fails('NotAFunc()', 'E117:', '', 2, 'Test_call_funcref') # comment after call
519  assert_fails('g:NotAFunc()', 'E117:', '', 3, 'Test_call_funcref')
520
521  var lines =<< trim END
522    vim9script
523    def RetNumber(): number
524      return 123
525    enddef
526    var Funcref: func: number = function('RetNumber')
527    Funcref()->assert_equal(123)
528  END
529  CheckScriptSuccess(lines)
530
531  lines =<< trim END
532    vim9script
533    def RetNumber(): number
534      return 123
535    enddef
536    def Bar(F: func: number): number
537      return F()
538    enddef
539    var Funcref = function('RetNumber')
540    Bar(Funcref)->assert_equal(123)
541  END
542  CheckScriptSuccess(lines)
543
544  lines =<< trim END
545    vim9script
546    def UseNumber(nr: number)
547      echo nr
548    enddef
549    var Funcref: func(number) = function('UseNumber')
550    Funcref(123)
551  END
552  CheckScriptSuccess(lines)
553
554  lines =<< trim END
555    vim9script
556    def UseNumber(nr: number)
557      echo nr
558    enddef
559    var Funcref: func(string) = function('UseNumber')
560  END
561  CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(string) but got func(number)')
562
563  lines =<< trim END
564    vim9script
565    def EchoNr(nr = 34)
566      g:echo = nr
567    enddef
568    var Funcref: func(?number) = function('EchoNr')
569    Funcref()
570    g:echo->assert_equal(34)
571    Funcref(123)
572    g:echo->assert_equal(123)
573  END
574  CheckScriptSuccess(lines)
575
576  lines =<< trim END
577    vim9script
578    def EchoList(...l: list<number>)
579      g:echo = l
580    enddef
581    var Funcref: func(...list<number>) = function('EchoList')
582    Funcref()
583    g:echo->assert_equal([])
584    Funcref(1, 2, 3)
585    g:echo->assert_equal([1, 2, 3])
586  END
587  CheckScriptSuccess(lines)
588
589  lines =<< trim END
590    vim9script
591    def OptAndVar(nr: number, opt = 12, ...l: list<number>): number
592      g:optarg = opt
593      g:listarg = l
594      return nr
595    enddef
596    var Funcref: func(number, ?number, ...list<number>): number = function('OptAndVar')
597    Funcref(10)->assert_equal(10)
598    g:optarg->assert_equal(12)
599    g:listarg->assert_equal([])
600
601    Funcref(11, 22)->assert_equal(11)
602    g:optarg->assert_equal(22)
603    g:listarg->assert_equal([])
604
605    Funcref(17, 18, 1, 2, 3)->assert_equal(17)
606    g:optarg->assert_equal(18)
607    g:listarg->assert_equal([1, 2, 3])
608  END
609  CheckScriptSuccess(lines)
610enddef
611
612let SomeFunc = function('len')
613let NotAFunc = 'text'
614
615def CombineFuncrefTypes()
616  # same arguments, different return type
617  var Ref1: func(bool): string
618  var Ref2: func(bool): number
619  var Ref3: func(bool): any
620  Ref3 = g:cond ? Ref1 : Ref2
621
622  # different number of arguments
623  var Refa1: func(bool): number
624  var Refa2: func(bool, number): number
625  var Refa3: func: number
626  Refa3 = g:cond ? Refa1 : Refa2
627
628  # different argument types
629  var Refb1: func(bool, string): number
630  var Refb2: func(string, number): number
631  var Refb3: func(any, any): number
632  Refb3 = g:cond ? Refb1 : Refb2
633enddef
634
635def FuncWithForwardCall()
636  return g:DefinedEvenLater("yes")
637enddef
638
639def DefinedEvenLater(arg: string): string
640  return arg
641enddef
642
643def Test_error_in_nested_function()
644  # Error in called function requires unwinding the call stack.
645  assert_fails('FuncWithForwardCall()', 'E1096:', '', 1, 'FuncWithForwardCall')
646enddef
647
648def Test_return_type_wrong()
649  CheckScriptFailure([
650        'def Func(): number',
651        'return "a"',
652        'enddef',
653        'defcompile'], 'expected number but got string')
654  CheckScriptFailure([
655        'def Func(): string',
656        'return 1',
657        'enddef',
658        'defcompile'], 'expected string but got number')
659  CheckScriptFailure([
660        'def Func(): void',
661        'return "a"',
662        'enddef',
663        'defcompile'],
664        'E1096: Returning a value in a function without a return type')
665  CheckScriptFailure([
666        'def Func()',
667        'return "a"',
668        'enddef',
669        'defcompile'],
670        'E1096: Returning a value in a function without a return type')
671
672  CheckScriptFailure([
673        'def Func(): number',
674        'return',
675        'enddef',
676        'defcompile'], 'E1003:')
677
678  CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
679  CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
680  CheckScriptFailure(['def Func()', 'return 1'], 'E1057:')
681
682  CheckScriptFailure([
683        'vim9script',
684        'def FuncB()',
685        '  return 123',
686        'enddef',
687        'def FuncA()',
688        '   FuncB()',
689        'enddef',
690        'defcompile'], 'E1096:')
691enddef
692
693def Test_arg_type_wrong()
694  CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
695  CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...')
696  CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:')
697  CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:')
698enddef
699
700def Test_vim9script_call()
701  var lines =<< trim END
702    vim9script
703    var name = ''
704    def MyFunc(arg: string)
705       name = arg
706    enddef
707    MyFunc('foobar')
708    name->assert_equal('foobar')
709
710    var str = 'barfoo'
711    str->MyFunc()
712    name->assert_equal('barfoo')
713
714    g:value = 'value'
715    g:value->MyFunc()
716    name->assert_equal('value')
717
718    var listvar = []
719    def ListFunc(arg: list<number>)
720       listvar = arg
721    enddef
722    [1, 2, 3]->ListFunc()
723    listvar->assert_equal([1, 2, 3])
724
725    var dictvar = {}
726    def DictFunc(arg: dict<number>)
727       dictvar = arg
728    enddef
729    {'a': 1, 'b': 2}->DictFunc()
730    dictvar->assert_equal(#{a: 1, b: 2})
731    def CompiledDict()
732      {'a': 3, 'b': 4}->DictFunc()
733    enddef
734    CompiledDict()
735    dictvar->assert_equal(#{a: 3, b: 4})
736
737    #{a: 3, b: 4}->DictFunc()
738    dictvar->assert_equal(#{a: 3, b: 4})
739
740    ('text')->MyFunc()
741    name->assert_equal('text')
742    ("some")->MyFunc()
743    name->assert_equal('some')
744
745    # line starting with single quote is not a mark
746    # line starting with double quote can be a method call
747    'asdfasdf'->MyFunc()
748    name->assert_equal('asdfasdf')
749    "xyz"->MyFunc()
750    name->assert_equal('xyz')
751
752    def UseString()
753      'xyork'->MyFunc()
754    enddef
755    UseString()
756    name->assert_equal('xyork')
757
758    def UseString2()
759      "knife"->MyFunc()
760    enddef
761    UseString2()
762    name->assert_equal('knife')
763
764    # prepending a colon makes it a mark
765    new
766    setline(1, ['aaa', 'bbb', 'ccc'])
767    normal! 3Gmt1G
768    :'t
769    getcurpos()[1]->assert_equal(3)
770    bwipe!
771
772    MyFunc(
773        'continued'
774        )
775    assert_equal('continued',
776            name
777            )
778
779    call MyFunc(
780        'more'
781          ..
782          'lines'
783        )
784    assert_equal(
785        'morelines',
786        name)
787  END
788  writefile(lines, 'Xcall.vim')
789  source Xcall.vim
790  delete('Xcall.vim')
791enddef
792
793def Test_vim9script_call_fail_decl()
794  var lines =<< trim END
795    vim9script
796    var name = ''
797    def MyFunc(arg: string)
798       var name = 123
799    enddef
800    defcompile
801  END
802  CheckScriptFailure(lines, 'E1054:')
803enddef
804
805def Test_vim9script_call_fail_type()
806  var lines =<< trim END
807    vim9script
808    def MyFunc(arg: string)
809      echo arg
810    enddef
811    MyFunc(1234)
812  END
813  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
814enddef
815
816def Test_vim9script_call_fail_const()
817  var lines =<< trim END
818    vim9script
819    const var = ''
820    def MyFunc(arg: string)
821       var = 'asdf'
822    enddef
823    defcompile
824  END
825  writefile(lines, 'Xcall_const.vim')
826  assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc')
827  delete('Xcall_const.vim')
828enddef
829
830" Test that inside :function a Python function can be defined, :def is not
831" recognized.
832func Test_function_python()
833  CheckFeature python3
834  let py = 'python3'
835  execute py "<< EOF"
836def do_something():
837  return 1
838EOF
839endfunc
840
841def Test_delfunc()
842  var lines =<< trim END
843    vim9script
844    def g:GoneSoon()
845      echo 'hello'
846    enddef
847
848    def CallGoneSoon()
849      GoneSoon()
850    enddef
851    defcompile
852
853    delfunc g:GoneSoon
854    CallGoneSoon()
855  END
856  writefile(lines, 'XToDelFunc')
857  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
858  assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon')
859
860  delete('XToDelFunc')
861enddef
862
863def Test_redef_failure()
864  writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
865  so Xdef
866  writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
867  so Xdef
868  writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef')
869  assert_fails('so Xdef', 'E1027:', '', 1, 'Func0')
870  writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
871  so Xdef
872  delete('Xdef')
873
874  g:Func0()->assert_equal(0)
875  g:Func1()->assert_equal('Func1')
876  g:Func2()->assert_equal('Func2')
877
878  delfunc! Func0
879  delfunc! Func1
880  delfunc! Func2
881enddef
882
883def Test_vim9script_func()
884  var lines =<< trim END
885    vim9script
886    func Func(arg)
887      echo a:arg
888    endfunc
889    Func('text')
890  END
891  writefile(lines, 'XVim9Func')
892  so XVim9Func
893
894  delete('XVim9Func')
895enddef
896
897" Test for internal functions returning different types
898func Test_InternalFuncRetType()
899  let lines =<< trim END
900    def RetFloat(): float
901      return ceil(1.456)
902    enddef
903
904    def RetListAny(): list<any>
905      return items({'k': 'v'})
906    enddef
907
908    def RetListString(): list<string>
909      return split('a:b:c', ':')
910    enddef
911
912    def RetListDictAny(): list<dict<any>>
913      return getbufinfo()
914    enddef
915
916    def RetDictNumber(): dict<number>
917      return wordcount()
918    enddef
919
920    def RetDictString(): dict<string>
921      return environ()
922    enddef
923  END
924  call writefile(lines, 'Xscript')
925  source Xscript
926
927  call RetFloat()->assert_equal(2.0)
928  call RetListAny()->assert_equal([['k', 'v']])
929  call RetListString()->assert_equal(['a', 'b', 'c'])
930  call RetListDictAny()->assert_notequal([])
931  call RetDictNumber()->assert_notequal({})
932  call RetDictString()->assert_notequal({})
933  call delete('Xscript')
934endfunc
935
936" Test for passing too many or too few arguments to internal functions
937func Test_internalfunc_arg_error()
938  let l =<< trim END
939    def! FArgErr(): float
940      return ceil(1.1, 2)
941    enddef
942    defcompile
943  END
944  call writefile(l, 'Xinvalidarg')
945  call assert_fails('so Xinvalidarg', 'E118:', '', 1, 'FArgErr')
946  let l =<< trim END
947    def! FArgErr(): float
948      return ceil()
949    enddef
950    defcompile
951  END
952  call writefile(l, 'Xinvalidarg')
953  call assert_fails('so Xinvalidarg', 'E119:', '', 1, 'FArgErr')
954  call delete('Xinvalidarg')
955endfunc
956
957let s:funcResult = 0
958
959def FuncNoArgNoRet()
960  s:funcResult = 11
961enddef
962
963def FuncNoArgRetNumber(): number
964  s:funcResult = 22
965  return 1234
966enddef
967
968def FuncNoArgRetString(): string
969  s:funcResult = 45
970  return 'text'
971enddef
972
973def FuncOneArgNoRet(arg: number)
974  s:funcResult = arg
975enddef
976
977def FuncOneArgRetNumber(arg: number): number
978  s:funcResult = arg
979  return arg
980enddef
981
982def FuncTwoArgNoRet(one: bool, two: number)
983  s:funcResult = two
984enddef
985
986def FuncOneArgRetString(arg: string): string
987  return arg
988enddef
989
990def FuncOneArgRetAny(arg: any): any
991  return arg
992enddef
993
994def Test_func_type()
995  var Ref1: func()
996  s:funcResult = 0
997  Ref1 = FuncNoArgNoRet
998  Ref1()
999  s:funcResult->assert_equal(11)
1000
1001  var Ref2: func
1002  s:funcResult = 0
1003  Ref2 = FuncNoArgNoRet
1004  Ref2()
1005  s:funcResult->assert_equal(11)
1006
1007  s:funcResult = 0
1008  Ref2 = FuncOneArgNoRet
1009  Ref2(12)
1010  s:funcResult->assert_equal(12)
1011
1012  s:funcResult = 0
1013  Ref2 = FuncNoArgRetNumber
1014  Ref2()->assert_equal(1234)
1015  s:funcResult->assert_equal(22)
1016
1017  s:funcResult = 0
1018  Ref2 = FuncOneArgRetNumber
1019  Ref2(13)->assert_equal(13)
1020  s:funcResult->assert_equal(13)
1021enddef
1022
1023def Test_repeat_return_type()
1024  var res = 0
1025  for n in repeat([1], 3)
1026    res += n
1027  endfor
1028  res->assert_equal(3)
1029
1030  res = 0
1031  for n in add([1, 2], 3)
1032    res += n
1033  endfor
1034  res->assert_equal(6)
1035enddef
1036
1037def Test_argv_return_type()
1038  next fileone filetwo
1039  var res = ''
1040  for name in argv()
1041    res ..= name
1042  endfor
1043  res->assert_equal('fileonefiletwo')
1044enddef
1045
1046def Test_func_type_part()
1047  var RefVoid: func: void
1048  RefVoid = FuncNoArgNoRet
1049  RefVoid = FuncOneArgNoRet
1050  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number')
1051  CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string')
1052
1053  var RefAny: func(): any
1054  RefAny = FuncNoArgRetNumber
1055  RefAny = FuncNoArgRetString
1056  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()')
1057  CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)')
1058
1059  var RefAnyNoArgs: func: any = RefAny
1060
1061  var RefNr: func: number
1062  RefNr = FuncNoArgRetNumber
1063  RefNr = FuncOneArgRetNumber
1064  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()')
1065  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string')
1066
1067  var RefStr: func: string
1068  RefStr = FuncNoArgRetString
1069  RefStr = FuncOneArgRetString
1070  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()')
1071  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number')
1072enddef
1073
1074def Test_func_type_fails()
1075  CheckDefFailure(['var ref1: func()'], 'E704:')
1076
1077  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number')
1078  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)')
1079  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
1080  CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)')
1081  CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)')
1082  CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)')
1083
1084  CheckDefFailure(['var RefWrong: func(string ,number)'], 'E1068:')
1085  CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:')
1086  CheckDefFailure(['var RefWrong: func(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)'], 'E1005:')
1087  CheckDefFailure(['var RefWrong: func(bool):string'], 'E1069:')
1088enddef
1089
1090def Test_func_return_type()
1091  var nr: number
1092  nr = FuncNoArgRetNumber()
1093  nr->assert_equal(1234)
1094
1095  nr = FuncOneArgRetAny(122)
1096  nr->assert_equal(122)
1097
1098  var str: string
1099  str = FuncOneArgRetAny('yes')
1100  str->assert_equal('yes')
1101
1102  CheckDefFailure(['var str: string', 'str = FuncNoArgRetNumber()'], 'E1012: Type mismatch; expected string but got number')
1103enddef
1104
1105def Test_func_common_type()
1106  def FuncOne(n: number): number
1107    return n
1108  enddef
1109  def FuncTwo(s: string): number
1110    return len(s)
1111  enddef
1112  def FuncThree(n: number, s: string): number
1113    return n + len(s)
1114  enddef
1115  var list = [FuncOne, FuncTwo, FuncThree]
1116  assert_equal(8, list[0](8))
1117  assert_equal(4, list[1]('word'))
1118  assert_equal(7, list[2](3, 'word'))
1119enddef
1120
1121def MultiLine(
1122    arg1: string,
1123    arg2 = 1234,
1124    ...rest: list<string>
1125      ): string
1126  return arg1 .. arg2 .. join(rest, '-')
1127enddef
1128
1129def MultiLineComment(
1130    arg1: string, # comment
1131    arg2 = 1234, # comment
1132    ...rest: list<string> # comment
1133      ): string # comment
1134  return arg1 .. arg2 .. join(rest, '-')
1135enddef
1136
1137def Test_multiline()
1138  MultiLine('text')->assert_equal('text1234')
1139  MultiLine('text', 777)->assert_equal('text777')
1140  MultiLine('text', 777, 'one')->assert_equal('text777one')
1141  MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1142enddef
1143
1144func Test_multiline_not_vim9()
1145  call MultiLine('text')->assert_equal('text1234')
1146  call MultiLine('text', 777)->assert_equal('text777')
1147  call MultiLine('text', 777, 'one')->assert_equal('text777one')
1148  call MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1149endfunc
1150
1151
1152" When using CheckScriptFailure() for the below test, E1010 is generated instead
1153" of E1056.
1154func Test_E1056_1059()
1155  let caught_1056 = 0
1156  try
1157    def F():
1158      return 1
1159    enddef
1160  catch /E1056:/
1161    let caught_1056 = 1
1162  endtry
1163  eval caught_1056->assert_equal(1)
1164
1165  let caught_1059 = 0
1166  try
1167    def F5(items : list)
1168      echo 'a'
1169    enddef
1170  catch /E1059:/
1171    let caught_1059 = 1
1172  endtry
1173  eval caught_1059->assert_equal(1)
1174endfunc
1175
1176func DelMe()
1177  echo 'DelMe'
1178endfunc
1179
1180def Test_error_reporting()
1181  # comment lines at the start of the function
1182  var lines =<< trim END
1183    " comment
1184    def Func()
1185      # comment
1186      # comment
1187      invalid
1188    enddef
1189    defcompile
1190  END
1191  writefile(lines, 'Xdef')
1192  try
1193    source Xdef
1194    assert_report('should have failed')
1195  catch /E476:/
1196    v:exception->assert_match('Invalid command: invalid')
1197    v:throwpoint->assert_match(', line 3$')
1198  endtry
1199
1200  # comment lines after the start of the function
1201  lines =<< trim END
1202    " comment
1203    def Func()
1204      var x = 1234
1205      # comment
1206      # comment
1207      invalid
1208    enddef
1209    defcompile
1210  END
1211  writefile(lines, 'Xdef')
1212  try
1213    source Xdef
1214    assert_report('should have failed')
1215  catch /E476:/
1216    v:exception->assert_match('Invalid command: invalid')
1217    v:throwpoint->assert_match(', line 4$')
1218  endtry
1219
1220  lines =<< trim END
1221    vim9script
1222    def Func()
1223      var db = #{foo: 1, bar: 2}
1224      # comment
1225      var x = db.asdf
1226    enddef
1227    defcompile
1228    Func()
1229  END
1230  writefile(lines, 'Xdef')
1231  try
1232    source Xdef
1233    assert_report('should have failed')
1234  catch /E716:/
1235    v:throwpoint->assert_match('_Func, line 3$')
1236  endtry
1237
1238  delete('Xdef')
1239enddef
1240
1241def Test_deleted_function()
1242  CheckDefExecFailure([
1243      'var RefMe: func = function("g:DelMe")',
1244      'delfunc g:DelMe',
1245      'echo RefMe()'], 'E117:')
1246enddef
1247
1248def Test_unknown_function()
1249  CheckDefExecFailure([
1250      'var Ref: func = function("NotExist")',
1251      'delfunc g:NotExist'], 'E700:')
1252enddef
1253
1254def RefFunc(Ref: func(string): string): string
1255  return Ref('more')
1256enddef
1257
1258def Test_closure_simple()
1259  var local = 'some '
1260  RefFunc({s -> local .. s})->assert_equal('some more')
1261enddef
1262
1263def MakeRef()
1264  var local = 'some '
1265  g:Ref = {s -> local .. s}
1266enddef
1267
1268def Test_closure_ref_after_return()
1269  MakeRef()
1270  g:Ref('thing')->assert_equal('some thing')
1271  unlet g:Ref
1272enddef
1273
1274def MakeTwoRefs()
1275  var local = ['some']
1276  g:Extend = {s -> local->add(s)}
1277  g:Read = {-> local}
1278enddef
1279
1280def Test_closure_two_refs()
1281  MakeTwoRefs()
1282  join(g:Read(), ' ')->assert_equal('some')
1283  g:Extend('more')
1284  join(g:Read(), ' ')->assert_equal('some more')
1285  g:Extend('even')
1286  join(g:Read(), ' ')->assert_equal('some more even')
1287
1288  unlet g:Extend
1289  unlet g:Read
1290enddef
1291
1292def ReadRef(Ref: func(): list<string>): string
1293  return join(Ref(), ' ')
1294enddef
1295
1296def ExtendRef(Ref: func(string): list<string>, add: string)
1297  Ref(add)
1298enddef
1299
1300def Test_closure_two_indirect_refs()
1301  MakeTwoRefs()
1302  ReadRef(g:Read)->assert_equal('some')
1303  ExtendRef(g:Extend, 'more')
1304  ReadRef(g:Read)->assert_equal('some more')
1305  ExtendRef(g:Extend, 'even')
1306  ReadRef(g:Read)->assert_equal('some more even')
1307
1308  unlet g:Extend
1309  unlet g:Read
1310enddef
1311
1312def MakeArgRefs(theArg: string)
1313  var local = 'loc_val'
1314  g:UseArg = {s -> theArg .. '/' .. local .. '/' .. s}
1315enddef
1316
1317def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
1318  var local = 'the_loc'
1319  g:UseVararg = {s -> theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)}
1320enddef
1321
1322def Test_closure_using_argument()
1323  MakeArgRefs('arg_val')
1324  g:UseArg('call_val')->assert_equal('arg_val/loc_val/call_val')
1325
1326  MakeArgRefsVarargs('arg_val', 'one', 'two')
1327  g:UseVararg('call_val')->assert_equal('arg_val/the_loc/call_val/one two')
1328
1329  unlet g:UseArg
1330  unlet g:UseVararg
1331enddef
1332
1333def MakeGetAndAppendRefs()
1334  var local = 'a'
1335
1336  def Append(arg: string)
1337    local ..= arg
1338  enddef
1339  g:Append = Append
1340
1341  def Get(): string
1342    return local
1343  enddef
1344  g:Get = Get
1345enddef
1346
1347def Test_closure_append_get()
1348  MakeGetAndAppendRefs()
1349  g:Get()->assert_equal('a')
1350  g:Append('-b')
1351  g:Get()->assert_equal('a-b')
1352  g:Append('-c')
1353  g:Get()->assert_equal('a-b-c')
1354
1355  unlet g:Append
1356  unlet g:Get
1357enddef
1358
1359def Test_nested_closure()
1360  var local = 'text'
1361  def Closure(arg: string): string
1362    return local .. arg
1363  enddef
1364  Closure('!!!')->assert_equal('text!!!')
1365enddef
1366
1367func GetResult(Ref)
1368  return a:Ref('some')
1369endfunc
1370
1371def Test_call_closure_not_compiled()
1372  var text = 'text'
1373  g:Ref = {s ->  s .. text}
1374  GetResult(g:Ref)->assert_equal('sometext')
1375enddef
1376
1377def Test_double_closure_fails()
1378  var lines =<< trim END
1379    vim9script
1380    def Func()
1381      var name = 0
1382      for i in range(2)
1383          timer_start(0, {-> name})
1384      endfor
1385    enddef
1386    Func()
1387  END
1388  CheckScriptSuccess(lines)
1389enddef
1390
1391def Test_nested_closure_used()
1392  var lines =<< trim END
1393      vim9script
1394      def Func()
1395        var x = 'hello'
1396        var Closure = {-> x}
1397        g:Myclosure = {-> Closure()}
1398      enddef
1399      Func()
1400      assert_equal('hello', g:Myclosure())
1401  END
1402  CheckScriptSuccess(lines)
1403enddef
1404
1405def Test_nested_closure_fails()
1406  var lines =<< trim END
1407    vim9script
1408    def FuncA()
1409      FuncB(0)
1410    enddef
1411    def FuncB(n: number): list<string>
1412      return map([0], {_, v -> n})
1413    enddef
1414    FuncA()
1415  END
1416  CheckScriptFailure(lines, 'E1012:')
1417enddef
1418
1419def Test_nested_lambda()
1420  var lines =<< trim END
1421    vim9script
1422    def Func()
1423      var x = 4
1424      var Lambda1 = {-> 7}
1425      var Lambda2 = {-> [Lambda1(), x]}
1426      var res = Lambda2()
1427      assert_equal([7, 4], res)
1428    enddef
1429    Func()
1430  END
1431  CheckScriptSuccess(lines)
1432enddef
1433
1434def Test_sort_return_type()
1435  var res: list<number>
1436  res = [1, 2, 3]->sort()
1437enddef
1438
1439def Test_sort_argument()
1440  var res = ['b', 'a', 'c']->sort('i')
1441  res->assert_equal(['a', 'b', 'c'])
1442enddef
1443
1444def Test_getqflist_return_type()
1445  var l = getqflist()
1446  l->assert_equal([])
1447
1448  var d = getqflist(#{items: 0})
1449  d->assert_equal(#{items: []})
1450enddef
1451
1452def Test_getloclist_return_type()
1453  var l = getloclist(1)
1454  l->assert_equal([])
1455
1456  var d = getloclist(1, #{items: 0})
1457  d->assert_equal(#{items: []})
1458enddef
1459
1460def Test_copy_return_type()
1461  var l = copy([1, 2, 3])
1462  var res = 0
1463  for n in l
1464    res += n
1465  endfor
1466  res->assert_equal(6)
1467
1468  var dl = deepcopy([1, 2, 3])
1469  res = 0
1470  for n in dl
1471    res += n
1472  endfor
1473  res->assert_equal(6)
1474
1475  dl = deepcopy([1, 2, 3], true)
1476enddef
1477
1478def Test_extend_return_type()
1479  var l = extend([1, 2], [3])
1480  var res = 0
1481  for n in l
1482    res += n
1483  endfor
1484  res->assert_equal(6)
1485enddef
1486
1487def Test_garbagecollect()
1488  garbagecollect(true)
1489enddef
1490
1491def Test_insert_return_type()
1492  var l = insert([2, 1], 3)
1493  var res = 0
1494  for n in l
1495    res += n
1496  endfor
1497  res->assert_equal(6)
1498enddef
1499
1500def Test_keys_return_type()
1501  const var: list<string> = #{a: 1, b: 2}->keys()
1502  var->assert_equal(['a', 'b'])
1503enddef
1504
1505def Test_reverse_return_type()
1506  var l = reverse([1, 2, 3])
1507  var res = 0
1508  for n in l
1509    res += n
1510  endfor
1511  res->assert_equal(6)
1512enddef
1513
1514def Test_remove_return_type()
1515  var l = remove(#{one: [1, 2], two: [3, 4]}, 'one')
1516  var res = 0
1517  for n in l
1518    res += n
1519  endfor
1520  res->assert_equal(3)
1521enddef
1522
1523def Test_filter_return_type()
1524  var l = filter([1, 2, 3], {-> 1})
1525  var res = 0
1526  for n in l
1527    res += n
1528  endfor
1529  res->assert_equal(6)
1530enddef
1531
1532def Test_bufnr()
1533  var buf = bufnr()
1534  bufnr('%')->assert_equal(buf)
1535
1536  buf = bufnr('Xdummy', true)
1537  buf->assert_notequal(-1)
1538  exe 'bwipe! ' .. buf
1539enddef
1540
1541def Test_col()
1542  new
1543  setline(1, 'asdf')
1544  col([1, '$'])->assert_equal(5)
1545enddef
1546
1547def Test_char2nr()
1548  char2nr('あ', true)->assert_equal(12354)
1549enddef
1550
1551def Test_getreg_return_type()
1552  var s1: string = getreg('"')
1553  var s2: string = getreg('"', 1)
1554  var s3: list<string> = getreg('"', 1, 1)
1555enddef
1556
1557def Wrong_dict_key_type(items: list<number>): list<number>
1558  return filter(items, {_, val -> get({val: 1}, 'x')})
1559enddef
1560
1561def Test_wrong_dict_key_type()
1562  assert_fails('Wrong_dict_key_type([1, 2, 3])', 'E1012:')
1563enddef
1564
1565def Line_continuation_in_def(dir: string = ''): string
1566  var path: string = empty(dir)
1567          \ ? 'empty'
1568          \ : 'full'
1569  return path
1570enddef
1571
1572def Test_line_continuation_in_def()
1573  Line_continuation_in_def('.')->assert_equal('full')
1574enddef
1575
1576def Line_continuation_in_lambda(): list<string>
1577  var x = range(97, 100)
1578      ->map({_, v -> nr2char(v)
1579          ->toupper()})
1580      ->reverse()
1581  return x
1582enddef
1583
1584def Test_line_continuation_in_lambda()
1585  Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
1586enddef
1587
1588func Test_silent_echo()
1589  CheckScreendump
1590
1591  let lines =<< trim END
1592    vim9script
1593    def EchoNothing()
1594      silent echo ''
1595    enddef
1596    defcompile
1597  END
1598  call writefile(lines, 'XTest_silent_echo')
1599
1600  " Check that the balloon shows up after a mouse move
1601  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
1602  call term_sendkeys(buf, ":abc")
1603  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
1604
1605  " clean up
1606  call StopVimInTerminal(buf)
1607  call delete('XTest_silent_echo')
1608endfunc
1609
1610""""""" builtin functions that behave differently in Vim9
1611
1612def Test_bufname()
1613  split SomeFile
1614  bufname('%')->assert_equal('SomeFile')
1615  edit OtherFile
1616  bufname('#')->assert_equal('SomeFile')
1617  close
1618enddef
1619
1620def Test_bufwinid()
1621  var origwin = win_getid()
1622  below split SomeFile
1623  var SomeFileID = win_getid()
1624  below split OtherFile
1625  below split SomeFile
1626  bufwinid('SomeFile')->assert_equal(SomeFileID)
1627
1628  win_gotoid(origwin)
1629  only
1630  bwipe SomeFile
1631  bwipe OtherFile
1632enddef
1633
1634def Test_count()
1635  count('ABC ABC ABC', 'b', true)->assert_equal(3)
1636  count('ABC ABC ABC', 'b', false)->assert_equal(0)
1637enddef
1638
1639def Test_expand()
1640  split SomeFile
1641  expand('%', true, true)->assert_equal(['SomeFile'])
1642  close
1643enddef
1644
1645def Test_getbufinfo()
1646  var bufinfo = getbufinfo(bufnr())
1647  getbufinfo('%')->assert_equal(bufinfo)
1648
1649  edit Xtestfile1
1650  hide edit Xtestfile2
1651  hide enew
1652  getbufinfo(#{bufloaded: true, buflisted: true, bufmodified: false})
1653      ->len()->assert_equal(3)
1654  bwipe Xtestfile1 Xtestfile2
1655enddef
1656
1657def Test_getbufline()
1658  e SomeFile
1659  var buf = bufnr()
1660  e #
1661  var lines = ['aaa', 'bbb', 'ccc']
1662  setbufline(buf, 1, lines)
1663  getbufline('#', 1, '$')->assert_equal(lines)
1664
1665  bwipe!
1666enddef
1667
1668def Test_getchangelist()
1669  new
1670  setline(1, 'some text')
1671  var changelist = bufnr()->getchangelist()
1672  getchangelist('%')->assert_equal(changelist)
1673  bwipe!
1674enddef
1675
1676def Test_getchar()
1677  while getchar(0)
1678  endwhile
1679  getchar(true)->assert_equal(0)
1680enddef
1681
1682def Test_getcompletion()
1683  set wildignore=*.vim,*~
1684  var l = getcompletion('run', 'file', true)
1685  l->assert_equal([])
1686  set wildignore&
1687enddef
1688
1689def Test_getreg()
1690  var lines = ['aaa', 'bbb', 'ccc']
1691  setreg('a', lines)
1692  getreg('a', true, true)->assert_equal(lines)
1693enddef
1694
1695def Test_glob()
1696  glob('runtest.vim', true, true, true)->assert_equal(['runtest.vim'])
1697enddef
1698
1699def Test_globpath()
1700  globpath('.', 'runtest.vim', true, true, true)->assert_equal(['./runtest.vim'])
1701enddef
1702
1703def Test_has()
1704  has('eval', true)->assert_equal(1)
1705enddef
1706
1707def Test_hasmapto()
1708  hasmapto('foobar', 'i', true)->assert_equal(0)
1709  iabbrev foo foobar
1710  hasmapto('foobar', 'i', true)->assert_equal(1)
1711  iunabbrev foo
1712enddef
1713
1714def Test_index()
1715  index(['a', 'b', 'a', 'B'], 'b', 2, true)->assert_equal(3)
1716enddef
1717
1718def Test_list2str_str2list_utf8()
1719  var s = "\u3042\u3044"
1720  var l = [0x3042, 0x3044]
1721  str2list(s, true)->assert_equal(l)
1722  list2str(l, true)->assert_equal(s)
1723enddef
1724
1725def SID(): number
1726  return expand('<SID>')
1727          ->matchstr('<SNR>\zs\d\+\ze_$')
1728          ->str2nr()
1729enddef
1730
1731def Test_maparg()
1732  var lnum = str2nr(expand('<sflnum>'))
1733  map foo bar
1734  maparg('foo', '', false, true)->assert_equal(#{
1735        lnum: lnum + 1,
1736        script: 0,
1737        mode: ' ',
1738        silent: 0,
1739        noremap: 0,
1740        lhs: 'foo',
1741        lhsraw: 'foo',
1742        nowait: 0,
1743        expr: 0,
1744        sid: SID(),
1745        rhs: 'bar',
1746        buffer: 0})
1747  unmap foo
1748enddef
1749
1750def Test_mapcheck()
1751  iabbrev foo foobar
1752  mapcheck('foo', 'i', true)->assert_equal('foobar')
1753  iunabbrev foo
1754enddef
1755
1756def Test_maparg_mapset()
1757  nnoremap <F3> :echo "hit F3"<CR>
1758  var mapsave = maparg('<F3>', 'n', false, true)
1759  mapset('n', false, mapsave)
1760
1761  nunmap <F3>
1762enddef
1763
1764def Test_nr2char()
1765  nr2char(97, true)->assert_equal('a')
1766enddef
1767
1768def Test_readdir()
1769   eval expand('sautest')->readdir({e -> e[0] !=# '.'})
1770   eval expand('sautest')->readdirex({e -> e.name[0] !=# '.'})
1771enddef
1772
1773def Test_search()
1774  new
1775  setline(1, ['foo', 'bar'])
1776  var val = 0
1777  # skip expr returns boolean
1778  search('bar', 'W', 0, 0, {-> val == 1})->assert_equal(2)
1779  :1
1780  search('bar', 'W', 0, 0, {-> val == 0})->assert_equal(0)
1781  # skip expr returns number, only 0 and 1 are accepted
1782  :1
1783  search('bar', 'W', 0, 0, {-> 0})->assert_equal(2)
1784  :1
1785  search('bar', 'W', 0, 0, {-> 1})->assert_equal(0)
1786  assert_fails("search('bar', '', 0, 0, {-> -1})", 'E1023:')
1787  assert_fails("search('bar', '', 0, 0, {-> -1})", 'E1023:')
1788enddef
1789
1790def Test_searchcount()
1791  new
1792  setline(1, "foo bar")
1793  :/foo
1794  searchcount(#{recompute: true})
1795      ->assert_equal(#{
1796          exact_match: 1,
1797          current: 1,
1798          total: 1,
1799          maxcount: 99,
1800          incomplete: 0})
1801  bwipe!
1802enddef
1803
1804def Test_searchdecl()
1805  searchdecl('blah', true, true)->assert_equal(1)
1806enddef
1807
1808def Test_setbufvar()
1809  setbufvar(bufnr('%'), '&syntax', 'vim')
1810  &syntax->assert_equal('vim')
1811  setbufvar(bufnr('%'), '&ts', 16)
1812  &ts->assert_equal(16)
1813  settabwinvar(1, 1, '&syntax', 'vam')
1814  &syntax->assert_equal('vam')
1815  settabwinvar(1, 1, '&ts', 15)
1816  &ts->assert_equal(15)
1817  setlocal ts=8
1818
1819  setbufvar('%', 'myvar', 123)
1820  getbufvar('%', 'myvar')->assert_equal(123)
1821enddef
1822
1823def Test_setloclist()
1824  var items = [#{filename: '/tmp/file', lnum: 1, valid: true}]
1825  var what = #{items: items}
1826  setqflist([], ' ', what)
1827  setloclist(0, [], ' ', what)
1828enddef
1829
1830def Test_setreg()
1831  setreg('a', ['aaa', 'bbb', 'ccc'])
1832  var reginfo = getreginfo('a')
1833  setreg('a', reginfo)
1834  getreginfo('a')->assert_equal(reginfo)
1835enddef
1836
1837def Test_spellsuggest()
1838  if !has('spell')
1839    MissingFeature 'spell'
1840  else
1841    spellsuggest('marrch', 1, true)->assert_equal(['March'])
1842  endif
1843enddef
1844
1845def Test_split()
1846  split('  aa  bb  ', '\W\+', true)->assert_equal(['', 'aa', 'bb', ''])
1847enddef
1848
1849def Test_str2nr()
1850  str2nr("1'000'000", 10, true)->assert_equal(1000000)
1851enddef
1852
1853def Test_strchars()
1854  strchars("A\u20dd", true)->assert_equal(1)
1855enddef
1856
1857def Test_submatch()
1858  var pat = 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)'
1859  var Rep = {-> range(10)->map({_, v -> submatch(v, true)})->string()}
1860  var actual = substitute('A123456789', pat, Rep, '')
1861  var expected = "[['A123456789'], ['1'], ['2'], ['3'], ['4'], ['5'], ['6'], ['7'], ['8'], ['9']]"
1862  actual->assert_equal(expected)
1863enddef
1864
1865def Test_synID()
1866  new
1867  setline(1, "text")
1868  synID(1, 1, true)->assert_equal(0)
1869  bwipe!
1870enddef
1871
1872def Test_term_gettty()
1873  if !has('terminal')
1874    MissingFeature 'terminal'
1875  else
1876    var buf = Run_shell_in_terminal({})
1877    term_gettty(buf, true)->assert_notequal('')
1878    StopShellInTerminal(buf)
1879  endif
1880enddef
1881
1882def Test_term_start()
1883  if !has('terminal')
1884    MissingFeature 'terminal'
1885  else
1886    botright new
1887    var winnr = winnr()
1888    term_start(&shell, #{curwin: true})
1889    winnr()->assert_equal(winnr)
1890    bwipe!
1891  endif
1892enddef
1893
1894def Test_timer_paused()
1895  var id = timer_start(50, {-> 0})
1896  timer_pause(id, true)
1897  var info = timer_info(id)
1898  info[0]['paused']->assert_equal(1)
1899  timer_stop(id)
1900enddef
1901
1902def Test_win_splitmove()
1903  split
1904  win_splitmove(1, 2, #{vertical: true, rightbelow: true})
1905  close
1906enddef
1907
1908""""""" end of builtin functions
1909
1910def Fibonacci(n: number): number
1911  if n < 2
1912    return n
1913  else
1914    return Fibonacci(n - 1) + Fibonacci(n - 2)
1915  endif
1916enddef
1917
1918def Test_recursive_call()
1919  Fibonacci(20)->assert_equal(6765)
1920enddef
1921
1922def TreeWalk(dir: string): list<any>
1923  return readdir(dir)->map({_, val ->
1924            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
1925               ? {val: TreeWalk(dir .. '/' .. val)}
1926               : val
1927             })
1928enddef
1929
1930def Test_closure_in_map()
1931  mkdir('XclosureDir/tdir', 'p')
1932  writefile(['111'], 'XclosureDir/file1')
1933  writefile(['222'], 'XclosureDir/file2')
1934  writefile(['333'], 'XclosureDir/tdir/file3')
1935
1936  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {'tdir': ['file3']}])
1937
1938  delete('XclosureDir', 'rf')
1939enddef
1940
1941def Test_invalid_function_name()
1942  var lines =<< trim END
1943      vim9script
1944      def s: list<string>
1945  END
1946  CheckScriptFailure(lines, 'E129:')
1947
1948  lines =<< trim END
1949      vim9script
1950      def g: list<string>
1951  END
1952  CheckScriptFailure(lines, 'E129:')
1953
1954  lines =<< trim END
1955      vim9script
1956      def <SID>: list<string>
1957  END
1958  CheckScriptFailure(lines, 'E884:')
1959
1960  lines =<< trim END
1961      vim9script
1962      def F list<string>
1963  END
1964  CheckScriptFailure(lines, 'E488:')
1965enddef
1966
1967def Test_partial_call()
1968  var Xsetlist = function('setloclist', [0])
1969  Xsetlist([], ' ', {'title': 'test'})
1970  getloclist(0, {'title': 1})->assert_equal({'title': 'test'})
1971
1972  Xsetlist = function('setloclist', [0, [], ' '])
1973  Xsetlist({'title': 'test'})
1974  getloclist(0, {'title': 1})->assert_equal({'title': 'test'})
1975
1976  Xsetlist = function('setqflist')
1977  Xsetlist([], ' ', {'title': 'test'})
1978  getqflist({'title': 1})->assert_equal({'title': 'test'})
1979
1980  Xsetlist = function('setqflist', [[], ' '])
1981  Xsetlist({'title': 'test'})
1982  getqflist({'title': 1})->assert_equal({'title': 'test'})
1983
1984  var Len: func: number = function('len', ['word'])
1985  assert_equal(4, Len())
1986enddef
1987
1988def Test_cmd_modifier()
1989  tab echo '0'
1990  CheckDefFailure(['5tab echo 3'], 'E16:')
1991enddef
1992
1993def Test_restore_modifiers()
1994  # check that when compiling a :def function command modifiers are not messed
1995  # up.
1996  var lines =<< trim END
1997      vim9script
1998      set eventignore=
1999      autocmd QuickFixCmdPost * copen
2000      def AutocmdsDisabled()
2001          eval 0
2002      enddef
2003      func Func()
2004        noautocmd call s:AutocmdsDisabled()
2005        let g:ei_after = &eventignore
2006      endfunc
2007      Func()
2008  END
2009  CheckScriptSuccess(lines)
2010  g:ei_after->assert_equal('')
2011enddef
2012
2013def StackTop()
2014  eval 1
2015  eval 2
2016  # call not on fourth line
2017  StackBot()
2018enddef
2019
2020def StackBot()
2021  # throw an error
2022  eval [][0]
2023enddef
2024
2025def Test_callstack_def()
2026  try
2027    StackTop()
2028  catch
2029    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
2030  endtry
2031enddef
2032
2033" Re-using spot for variable used in block
2034def Test_block_scoped_var()
2035  var lines =<< trim END
2036      vim9script
2037      def Func()
2038        var x = ['a', 'b', 'c']
2039        if 1
2040          var y = 'x'
2041          map(x, {-> y})
2042        endif
2043        var z = x
2044        assert_equal(['x', 'x', 'x'], z)
2045      enddef
2046      Func()
2047  END
2048  CheckScriptSuccess(lines)
2049enddef
2050
2051
2052" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
2053