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 RefNr: func: number
1060  RefNr = FuncNoArgRetNumber
1061  RefNr = FuncOneArgRetNumber
1062  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()')
1063  CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string')
1064
1065  var RefStr: func: string
1066  RefStr = FuncNoArgRetString
1067  RefStr = FuncOneArgRetString
1068  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()')
1069  CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number')
1070enddef
1071
1072def Test_func_type_fails()
1073  CheckDefFailure(['var ref1: func()'], 'E704:')
1074
1075  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number')
1076  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)')
1077  CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
1078  CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)')
1079  CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)')
1080  CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)')
1081
1082  CheckDefFailure(['var RefWrong: func(string ,number)'], 'E1068:')
1083  CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:')
1084  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:')
1085  CheckDefFailure(['var RefWrong: func(bool):string'], 'E1069:')
1086enddef
1087
1088def Test_func_return_type()
1089  var nr: number
1090  nr = FuncNoArgRetNumber()
1091  nr->assert_equal(1234)
1092
1093  nr = FuncOneArgRetAny(122)
1094  nr->assert_equal(122)
1095
1096  var str: string
1097  str = FuncOneArgRetAny('yes')
1098  str->assert_equal('yes')
1099
1100  CheckDefFailure(['var str: string', 'str = FuncNoArgRetNumber()'], 'E1012: Type mismatch; expected string but got number')
1101enddef
1102
1103def MultiLine(
1104    arg1: string,
1105    arg2 = 1234,
1106    ...rest: list<string>
1107      ): string
1108  return arg1 .. arg2 .. join(rest, '-')
1109enddef
1110
1111def MultiLineComment(
1112    arg1: string, # comment
1113    arg2 = 1234, # comment
1114    ...rest: list<string> # comment
1115      ): string # comment
1116  return arg1 .. arg2 .. join(rest, '-')
1117enddef
1118
1119def Test_multiline()
1120  MultiLine('text')->assert_equal('text1234')
1121  MultiLine('text', 777)->assert_equal('text777')
1122  MultiLine('text', 777, 'one')->assert_equal('text777one')
1123  MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1124enddef
1125
1126func Test_multiline_not_vim9()
1127  call MultiLine('text')->assert_equal('text1234')
1128  call MultiLine('text', 777)->assert_equal('text777')
1129  call MultiLine('text', 777, 'one')->assert_equal('text777one')
1130  call MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two')
1131endfunc
1132
1133
1134" When using CheckScriptFailure() for the below test, E1010 is generated instead
1135" of E1056.
1136func Test_E1056_1059()
1137  let caught_1056 = 0
1138  try
1139    def F():
1140      return 1
1141    enddef
1142  catch /E1056:/
1143    let caught_1056 = 1
1144  endtry
1145  eval caught_1056->assert_equal(1)
1146
1147  let caught_1059 = 0
1148  try
1149    def F5(items : list)
1150      echo 'a'
1151    enddef
1152  catch /E1059:/
1153    let caught_1059 = 1
1154  endtry
1155  eval caught_1059->assert_equal(1)
1156endfunc
1157
1158func DelMe()
1159  echo 'DelMe'
1160endfunc
1161
1162def Test_error_reporting()
1163  # comment lines at the start of the function
1164  var lines =<< trim END
1165    " comment
1166    def Func()
1167      # comment
1168      # comment
1169      invalid
1170    enddef
1171    defcompile
1172  END
1173  writefile(lines, 'Xdef')
1174  try
1175    source Xdef
1176    assert_report('should have failed')
1177  catch /E476:/
1178    v:exception->assert_match('Invalid command: invalid')
1179    v:throwpoint->assert_match(', line 3$')
1180  endtry
1181
1182  # comment lines after the start of the function
1183  lines =<< trim END
1184    " comment
1185    def Func()
1186      var x = 1234
1187      # comment
1188      # comment
1189      invalid
1190    enddef
1191    defcompile
1192  END
1193  writefile(lines, 'Xdef')
1194  try
1195    source Xdef
1196    assert_report('should have failed')
1197  catch /E476:/
1198    v:exception->assert_match('Invalid command: invalid')
1199    v:throwpoint->assert_match(', line 4$')
1200  endtry
1201
1202  lines =<< trim END
1203    vim9script
1204    def Func()
1205      var db = #{foo: 1, bar: 2}
1206      # comment
1207      var x = db.asdf
1208    enddef
1209    defcompile
1210    Func()
1211  END
1212  writefile(lines, 'Xdef')
1213  try
1214    source Xdef
1215    assert_report('should have failed')
1216  catch /E716:/
1217    v:throwpoint->assert_match('_Func, line 3$')
1218  endtry
1219
1220  delete('Xdef')
1221enddef
1222
1223def Test_deleted_function()
1224  CheckDefExecFailure([
1225      'var RefMe: func = function("g:DelMe")',
1226      'delfunc g:DelMe',
1227      'echo RefMe()'], 'E117:')
1228enddef
1229
1230def Test_unknown_function()
1231  CheckDefExecFailure([
1232      'var Ref: func = function("NotExist")',
1233      'delfunc g:NotExist'], 'E700:')
1234enddef
1235
1236def RefFunc(Ref: func(string): string): string
1237  return Ref('more')
1238enddef
1239
1240def Test_closure_simple()
1241  var local = 'some '
1242  RefFunc({s -> local .. s})->assert_equal('some more')
1243enddef
1244
1245def MakeRef()
1246  var local = 'some '
1247  g:Ref = {s -> local .. s}
1248enddef
1249
1250def Test_closure_ref_after_return()
1251  MakeRef()
1252  g:Ref('thing')->assert_equal('some thing')
1253  unlet g:Ref
1254enddef
1255
1256def MakeTwoRefs()
1257  var local = ['some']
1258  g:Extend = {s -> local->add(s)}
1259  g:Read = {-> local}
1260enddef
1261
1262def Test_closure_two_refs()
1263  MakeTwoRefs()
1264  join(g:Read(), ' ')->assert_equal('some')
1265  g:Extend('more')
1266  join(g:Read(), ' ')->assert_equal('some more')
1267  g:Extend('even')
1268  join(g:Read(), ' ')->assert_equal('some more even')
1269
1270  unlet g:Extend
1271  unlet g:Read
1272enddef
1273
1274def ReadRef(Ref: func(): list<string>): string
1275  return join(Ref(), ' ')
1276enddef
1277
1278def ExtendRef(Ref: func(string): list<string>, add: string)
1279  Ref(add)
1280enddef
1281
1282def Test_closure_two_indirect_refs()
1283  MakeTwoRefs()
1284  ReadRef(g:Read)->assert_equal('some')
1285  ExtendRef(g:Extend, 'more')
1286  ReadRef(g:Read)->assert_equal('some more')
1287  ExtendRef(g:Extend, 'even')
1288  ReadRef(g:Read)->assert_equal('some more even')
1289
1290  unlet g:Extend
1291  unlet g:Read
1292enddef
1293
1294def MakeArgRefs(theArg: string)
1295  var local = 'loc_val'
1296  g:UseArg = {s -> theArg .. '/' .. local .. '/' .. s}
1297enddef
1298
1299def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
1300  var local = 'the_loc'
1301  g:UseVararg = {s -> theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)}
1302enddef
1303
1304def Test_closure_using_argument()
1305  MakeArgRefs('arg_val')
1306  g:UseArg('call_val')->assert_equal('arg_val/loc_val/call_val')
1307
1308  MakeArgRefsVarargs('arg_val', 'one', 'two')
1309  g:UseVararg('call_val')->assert_equal('arg_val/the_loc/call_val/one two')
1310
1311  unlet g:UseArg
1312  unlet g:UseVararg
1313enddef
1314
1315def MakeGetAndAppendRefs()
1316  var local = 'a'
1317
1318  def Append(arg: string)
1319    local ..= arg
1320  enddef
1321  g:Append = Append
1322
1323  def Get(): string
1324    return local
1325  enddef
1326  g:Get = Get
1327enddef
1328
1329def Test_closure_append_get()
1330  MakeGetAndAppendRefs()
1331  g:Get()->assert_equal('a')
1332  g:Append('-b')
1333  g:Get()->assert_equal('a-b')
1334  g:Append('-c')
1335  g:Get()->assert_equal('a-b-c')
1336
1337  unlet g:Append
1338  unlet g:Get
1339enddef
1340
1341def Test_nested_closure()
1342  var local = 'text'
1343  def Closure(arg: string): string
1344    return local .. arg
1345  enddef
1346  Closure('!!!')->assert_equal('text!!!')
1347enddef
1348
1349func GetResult(Ref)
1350  return a:Ref('some')
1351endfunc
1352
1353def Test_call_closure_not_compiled()
1354  var text = 'text'
1355  g:Ref = {s ->  s .. text}
1356  GetResult(g:Ref)->assert_equal('sometext')
1357enddef
1358
1359def Test_double_closure_fails()
1360  var lines =<< trim END
1361    vim9script
1362    def Func()
1363      var name = 0
1364      for i in range(2)
1365          timer_start(0, {-> name})
1366      endfor
1367    enddef
1368    Func()
1369  END
1370  CheckScriptSuccess(lines)
1371enddef
1372
1373def Test_nested_closure_fails()
1374  var lines =<< trim END
1375    vim9script
1376    def FuncA()
1377      FuncB(0)
1378    enddef
1379    def FuncB(n: number): list<string>
1380      return map([0], {_, v -> n})
1381    enddef
1382    FuncA()
1383  END
1384  CheckScriptFailure(lines, 'E1012:')
1385enddef
1386
1387def Test_sort_return_type()
1388  var res: list<number>
1389  res = [1, 2, 3]->sort()
1390enddef
1391
1392def Test_sort_argument()
1393  var res = ['b', 'a', 'c']->sort('i')
1394  res->assert_equal(['a', 'b', 'c'])
1395enddef
1396
1397def Test_getqflist_return_type()
1398  var l = getqflist()
1399  l->assert_equal([])
1400
1401  var d = getqflist(#{items: 0})
1402  d->assert_equal(#{items: []})
1403enddef
1404
1405def Test_getloclist_return_type()
1406  var l = getloclist(1)
1407  l->assert_equal([])
1408
1409  var d = getloclist(1, #{items: 0})
1410  d->assert_equal(#{items: []})
1411enddef
1412
1413def Test_copy_return_type()
1414  var l = copy([1, 2, 3])
1415  var res = 0
1416  for n in l
1417    res += n
1418  endfor
1419  res->assert_equal(6)
1420
1421  var dl = deepcopy([1, 2, 3])
1422  res = 0
1423  for n in dl
1424    res += n
1425  endfor
1426  res->assert_equal(6)
1427
1428  dl = deepcopy([1, 2, 3], true)
1429enddef
1430
1431def Test_extend_return_type()
1432  var l = extend([1, 2], [3])
1433  var res = 0
1434  for n in l
1435    res += n
1436  endfor
1437  res->assert_equal(6)
1438enddef
1439
1440def Test_garbagecollect()
1441  garbagecollect(true)
1442enddef
1443
1444def Test_insert_return_type()
1445  var l = insert([2, 1], 3)
1446  var res = 0
1447  for n in l
1448    res += n
1449  endfor
1450  res->assert_equal(6)
1451enddef
1452
1453def Test_keys_return_type()
1454  const var: list<string> = #{a: 1, b: 2}->keys()
1455  var->assert_equal(['a', 'b'])
1456enddef
1457
1458def Test_reverse_return_type()
1459  var l = reverse([1, 2, 3])
1460  var res = 0
1461  for n in l
1462    res += n
1463  endfor
1464  res->assert_equal(6)
1465enddef
1466
1467def Test_remove_return_type()
1468  var l = remove(#{one: [1, 2], two: [3, 4]}, 'one')
1469  var res = 0
1470  for n in l
1471    res += n
1472  endfor
1473  res->assert_equal(3)
1474enddef
1475
1476def Test_filter_return_type()
1477  var l = filter([1, 2, 3], {-> 1})
1478  var res = 0
1479  for n in l
1480    res += n
1481  endfor
1482  res->assert_equal(6)
1483enddef
1484
1485def Test_bufnr()
1486  var buf = bufnr()
1487  bufnr('%')->assert_equal(buf)
1488
1489  buf = bufnr('Xdummy', true)
1490  buf->assert_notequal(-1)
1491  exe 'bwipe! ' .. buf
1492enddef
1493
1494def Test_col()
1495  new
1496  setline(1, 'asdf')
1497  col([1, '$'])->assert_equal(5)
1498enddef
1499
1500def Test_char2nr()
1501  char2nr('あ', true)->assert_equal(12354)
1502enddef
1503
1504def Test_getreg_return_type()
1505  var s1: string = getreg('"')
1506  var s2: string = getreg('"', 1)
1507  var s3: list<string> = getreg('"', 1, 1)
1508enddef
1509
1510def Wrong_dict_key_type(items: list<number>): list<number>
1511  return filter(items, {_, val -> get({val: 1}, 'x')})
1512enddef
1513
1514def Test_wrong_dict_key_type()
1515  assert_fails('Wrong_dict_key_type([1, 2, 3])', 'E1012:')
1516enddef
1517
1518def Line_continuation_in_def(dir: string = ''): string
1519  var path: string = empty(dir)
1520          \ ? 'empty'
1521          \ : 'full'
1522  return path
1523enddef
1524
1525def Test_line_continuation_in_def()
1526  Line_continuation_in_def('.')->assert_equal('full')
1527enddef
1528
1529def Line_continuation_in_lambda(): list<string>
1530  var x = range(97, 100)
1531      ->map({_, v -> nr2char(v)
1532          ->toupper()})
1533      ->reverse()
1534  return x
1535enddef
1536
1537def Test_line_continuation_in_lambda()
1538  Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
1539enddef
1540
1541func Test_silent_echo()
1542  CheckScreendump
1543
1544  let lines =<< trim END
1545    vim9script
1546    def EchoNothing()
1547      silent echo ''
1548    enddef
1549    defcompile
1550  END
1551  call writefile(lines, 'XTest_silent_echo')
1552
1553  " Check that the balloon shows up after a mouse move
1554  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
1555  call term_sendkeys(buf, ":abc")
1556  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
1557
1558  " clean up
1559  call StopVimInTerminal(buf)
1560  call delete('XTest_silent_echo')
1561endfunc
1562
1563""""""" builtin functions that behave differently in Vim9
1564
1565def Test_bufname()
1566  split SomeFile
1567  bufname('%')->assert_equal('SomeFile')
1568  edit OtherFile
1569  bufname('#')->assert_equal('SomeFile')
1570  close
1571enddef
1572
1573def Test_bufwinid()
1574  var origwin = win_getid()
1575  below split SomeFile
1576  var SomeFileID = win_getid()
1577  below split OtherFile
1578  below split SomeFile
1579  bufwinid('SomeFile')->assert_equal(SomeFileID)
1580
1581  win_gotoid(origwin)
1582  only
1583  bwipe SomeFile
1584  bwipe OtherFile
1585enddef
1586
1587def Test_count()
1588  count('ABC ABC ABC', 'b', true)->assert_equal(3)
1589  count('ABC ABC ABC', 'b', false)->assert_equal(0)
1590enddef
1591
1592def Test_expand()
1593  split SomeFile
1594  expand('%', true, true)->assert_equal(['SomeFile'])
1595  close
1596enddef
1597
1598def Test_getbufinfo()
1599  var bufinfo = getbufinfo(bufnr())
1600  getbufinfo('%')->assert_equal(bufinfo)
1601
1602  edit Xtestfile1
1603  hide edit Xtestfile2
1604  hide enew
1605  getbufinfo(#{bufloaded: true, buflisted: true, bufmodified: false})
1606      ->len()->assert_equal(3)
1607  bwipe Xtestfile1 Xtestfile2
1608enddef
1609
1610def Test_getbufline()
1611  e SomeFile
1612  var buf = bufnr()
1613  e #
1614  var lines = ['aaa', 'bbb', 'ccc']
1615  setbufline(buf, 1, lines)
1616  getbufline('#', 1, '$')->assert_equal(lines)
1617
1618  bwipe!
1619enddef
1620
1621def Test_getchangelist()
1622  new
1623  setline(1, 'some text')
1624  var changelist = bufnr()->getchangelist()
1625  getchangelist('%')->assert_equal(changelist)
1626  bwipe!
1627enddef
1628
1629def Test_getchar()
1630  while getchar(0)
1631  endwhile
1632  getchar(true)->assert_equal(0)
1633enddef
1634
1635def Test_getcompletion()
1636  set wildignore=*.vim,*~
1637  var l = getcompletion('run', 'file', true)
1638  l->assert_equal([])
1639  set wildignore&
1640enddef
1641
1642def Test_getreg()
1643  var lines = ['aaa', 'bbb', 'ccc']
1644  setreg('a', lines)
1645  getreg('a', true, true)->assert_equal(lines)
1646enddef
1647
1648def Test_glob()
1649  glob('runtest.vim', true, true, true)->assert_equal(['runtest.vim'])
1650enddef
1651
1652def Test_globpath()
1653  globpath('.', 'runtest.vim', true, true, true)->assert_equal(['./runtest.vim'])
1654enddef
1655
1656def Test_has()
1657  has('eval', true)->assert_equal(1)
1658enddef
1659
1660def Test_hasmapto()
1661  hasmapto('foobar', 'i', true)->assert_equal(0)
1662  iabbrev foo foobar
1663  hasmapto('foobar', 'i', true)->assert_equal(1)
1664  iunabbrev foo
1665enddef
1666
1667def Test_index()
1668  index(['a', 'b', 'a', 'B'], 'b', 2, true)->assert_equal(3)
1669enddef
1670
1671def Test_list2str_str2list_utf8()
1672  var s = "\u3042\u3044"
1673  var l = [0x3042, 0x3044]
1674  str2list(s, true)->assert_equal(l)
1675  list2str(l, true)->assert_equal(s)
1676enddef
1677
1678def SID(): number
1679  return expand('<SID>')
1680          ->matchstr('<SNR>\zs\d\+\ze_$')
1681          ->str2nr()
1682enddef
1683
1684def Test_maparg()
1685  var lnum = str2nr(expand('<sflnum>'))
1686  map foo bar
1687  maparg('foo', '', false, true)->assert_equal(#{
1688        lnum: lnum + 1,
1689        script: 0,
1690        mode: ' ',
1691        silent: 0,
1692        noremap: 0,
1693        lhs: 'foo',
1694        lhsraw: 'foo',
1695        nowait: 0,
1696        expr: 0,
1697        sid: SID(),
1698        rhs: 'bar',
1699        buffer: 0})
1700  unmap foo
1701enddef
1702
1703def Test_mapcheck()
1704  iabbrev foo foobar
1705  mapcheck('foo', 'i', true)->assert_equal('foobar')
1706  iunabbrev foo
1707enddef
1708
1709def Test_nr2char()
1710  nr2char(97, true)->assert_equal('a')
1711enddef
1712
1713def Test_readdir()
1714   eval expand('sautest')->readdir({e -> e[0] !=# '.'})
1715   eval expand('sautest')->readdirex({e -> e.name[0] !=# '.'})
1716enddef
1717
1718def Test_search()
1719  new
1720  setline(1, ['foo', 'bar'])
1721  var val = 0
1722  # skip expr returns boolean
1723  search('bar', 'W', 0, 0, {-> val == 1})->assert_equal(2)
1724  :1
1725  search('bar', 'W', 0, 0, {-> val == 0})->assert_equal(0)
1726  # skip expr returns number, only 0 and 1 are accepted
1727  :1
1728  search('bar', 'W', 0, 0, {-> 0})->assert_equal(2)
1729  :1
1730  search('bar', 'W', 0, 0, {-> 1})->assert_equal(0)
1731  assert_fails("search('bar', '', 0, 0, {-> -1})", 'E1023:')
1732  assert_fails("search('bar', '', 0, 0, {-> -1})", 'E1023:')
1733enddef
1734
1735def Test_searchcount()
1736  new
1737  setline(1, "foo bar")
1738  :/foo
1739  searchcount(#{recompute: true})
1740      ->assert_equal(#{
1741          exact_match: 1,
1742          current: 1,
1743          total: 1,
1744          maxcount: 99,
1745          incomplete: 0})
1746  bwipe!
1747enddef
1748
1749def Test_searchdecl()
1750  searchdecl('blah', true, true)->assert_equal(1)
1751enddef
1752
1753def Test_setbufvar()
1754  setbufvar(bufnr('%'), '&syntax', 'vim')
1755  &syntax->assert_equal('vim')
1756  setbufvar(bufnr('%'), '&ts', 16)
1757  &ts->assert_equal(16)
1758  settabwinvar(1, 1, '&syntax', 'vam')
1759  &syntax->assert_equal('vam')
1760  settabwinvar(1, 1, '&ts', 15)
1761  &ts->assert_equal(15)
1762  setlocal ts=8
1763
1764  setbufvar('%', 'myvar', 123)
1765  getbufvar('%', 'myvar')->assert_equal(123)
1766enddef
1767
1768def Test_setloclist()
1769  var items = [#{filename: '/tmp/file', lnum: 1, valid: true}]
1770  var what = #{items: items}
1771  setqflist([], ' ', what)
1772  setloclist(0, [], ' ', what)
1773enddef
1774
1775def Test_setreg()
1776  setreg('a', ['aaa', 'bbb', 'ccc'])
1777  var reginfo = getreginfo('a')
1778  setreg('a', reginfo)
1779  getreginfo('a')->assert_equal(reginfo)
1780enddef
1781
1782def Test_spellsuggest()
1783  if !has('spell')
1784    MissingFeature 'spell'
1785  else
1786    spellsuggest('marrch', 1, true)->assert_equal(['March'])
1787  endif
1788enddef
1789
1790def Test_split()
1791  split('  aa  bb  ', '\W\+', true)->assert_equal(['', 'aa', 'bb', ''])
1792enddef
1793
1794def Test_str2nr()
1795  str2nr("1'000'000", 10, true)->assert_equal(1000000)
1796enddef
1797
1798def Test_strchars()
1799  strchars("A\u20dd", true)->assert_equal(1)
1800enddef
1801
1802def Test_submatch()
1803  var pat = 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)'
1804  var Rep = {-> range(10)->map({_, v -> submatch(v, true)})->string()}
1805  var actual = substitute('A123456789', pat, Rep, '')
1806  var expected = "[['A123456789'], ['1'], ['2'], ['3'], ['4'], ['5'], ['6'], ['7'], ['8'], ['9']]"
1807  actual->assert_equal(expected)
1808enddef
1809
1810def Test_synID()
1811  new
1812  setline(1, "text")
1813  synID(1, 1, true)->assert_equal(0)
1814  bwipe!
1815enddef
1816
1817def Test_term_gettty()
1818  if !has('terminal')
1819    MissingFeature 'terminal'
1820  else
1821    var buf = Run_shell_in_terminal({})
1822    term_gettty(buf, true)->assert_notequal('')
1823    StopShellInTerminal(buf)
1824  endif
1825enddef
1826
1827def Test_term_start()
1828  if !has('terminal')
1829    MissingFeature 'terminal'
1830  else
1831    botright new
1832    var winnr = winnr()
1833    term_start(&shell, #{curwin: true})
1834    winnr()->assert_equal(winnr)
1835    bwipe!
1836  endif
1837enddef
1838
1839def Test_timer_paused()
1840  var id = timer_start(50, {-> 0})
1841  timer_pause(id, true)
1842  var info = timer_info(id)
1843  info[0]['paused']->assert_equal(1)
1844  timer_stop(id)
1845enddef
1846
1847def Test_win_splitmove()
1848  split
1849  win_splitmove(1, 2, #{vertical: true, rightbelow: true})
1850  close
1851enddef
1852
1853""""""" end of builtin functions
1854
1855def Fibonacci(n: number): number
1856  if n < 2
1857    return n
1858  else
1859    return Fibonacci(n - 1) + Fibonacci(n - 2)
1860  endif
1861enddef
1862
1863def Test_recursive_call()
1864  Fibonacci(20)->assert_equal(6765)
1865enddef
1866
1867def TreeWalk(dir: string): list<any>
1868  return readdir(dir)->map({_, val ->
1869            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
1870               ? {val: TreeWalk(dir .. '/' .. val)}
1871               : val
1872             })
1873enddef
1874
1875def Test_closure_in_map()
1876  mkdir('XclosureDir/tdir', 'p')
1877  writefile(['111'], 'XclosureDir/file1')
1878  writefile(['222'], 'XclosureDir/file2')
1879  writefile(['333'], 'XclosureDir/tdir/file3')
1880
1881  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {'tdir': ['file3']}])
1882
1883  delete('XclosureDir', 'rf')
1884enddef
1885
1886def Test_partial_call()
1887  var Xsetlist = function('setloclist', [0])
1888  Xsetlist([], ' ', {'title': 'test'})
1889  getloclist(0, {'title': 1})->assert_equal({'title': 'test'})
1890
1891  Xsetlist = function('setloclist', [0, [], ' '])
1892  Xsetlist({'title': 'test'})
1893  getloclist(0, {'title': 1})->assert_equal({'title': 'test'})
1894
1895  Xsetlist = function('setqflist')
1896  Xsetlist([], ' ', {'title': 'test'})
1897  getqflist({'title': 1})->assert_equal({'title': 'test'})
1898
1899  Xsetlist = function('setqflist', [[], ' '])
1900  Xsetlist({'title': 'test'})
1901  getqflist({'title': 1})->assert_equal({'title': 'test'})
1902enddef
1903
1904def Test_cmd_modifier()
1905  tab echo '0'
1906  CheckDefFailure(['5tab echo 3'], 'E16:')
1907enddef
1908
1909def Test_restore_modifiers()
1910  # check that when compiling a :def function command modifiers are not messed
1911  # up.
1912  var lines =<< trim END
1913      vim9script
1914      set eventignore=
1915      autocmd QuickFixCmdPost * copen
1916      def AutocmdsDisabled()
1917          eval 0
1918      enddef
1919      func Func()
1920        noautocmd call s:AutocmdsDisabled()
1921        let g:ei_after = &eventignore
1922      endfunc
1923      Func()
1924  END
1925  CheckScriptSuccess(lines)
1926  g:ei_after->assert_equal('')
1927enddef
1928
1929def StackTop()
1930  eval 1
1931  eval 2
1932  # call not on fourth line
1933  StackBot()
1934enddef
1935
1936def StackBot()
1937  # throw an error
1938  eval [][0]
1939enddef
1940
1941def Test_callstack_def()
1942  try
1943    StackTop()
1944  catch
1945    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
1946  endtry
1947enddef
1948
1949
1950" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
1951