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  let 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  let 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  let 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  let lines =<< trim END
237      vim9script
238      def g:Gfunc(): string
239        return 'global'
240      enddef
241      def AnotherFunc(): number
242        let 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  let 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  let 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  let 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  let 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  let 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  let 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  let 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(['let RefWrong: func(string?)'], 'E1010:')
447  CheckDefFailure(['let RefWrong: func(?string, string)'], 'E1007:')
448
449  let 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(['let RefWrong: func(...list<string>, string)'], 'E110:')
456  CheckDefFailure(['let 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)',  'let 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  let d: dict<string> = {}
489  DictArg(d)
490  d['key']->assert_equal('value')
491  let 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  let lines =<< trim END
522    vim9script
523    def RetNumber(): number
524      return 123
525    enddef
526    let 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    let 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    let 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    let 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    let 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    let 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    let 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  let Ref1: func(bool): string
618  let Ref2: func(bool): number
619  let Ref3: func(bool): any
620  Ref3 = g:cond ? Ref1 : Ref2
621
622  # different number of arguments
623  let Refa1: func(bool): number
624  let Refa2: func(bool, number): number
625  let Refa3: func: number
626  Refa3 = g:cond ? Refa1 : Refa2
627
628  # different argument types
629  let Refb1: func(bool, string): number
630  let Refb2: func(string, number): number
631  let 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  let lines =<< trim END
702    vim9script
703    let var = ''
704    def MyFunc(arg: string)
705       var = arg
706    enddef
707    MyFunc('foobar')
708    var->assert_equal('foobar')
709
710    let str = 'barfoo'
711    str->MyFunc()
712    var->assert_equal('barfoo')
713
714    g:value = 'value'
715    g:value->MyFunc()
716    var->assert_equal('value')
717
718    let 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    let 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    var->assert_equal('text')
742    ("some")->MyFunc()
743    var->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    var->assert_equal('asdfasdf')
749    "xyz"->MyFunc()
750    var->assert_equal('xyz')
751
752    def UseString()
753      'xyork'->MyFunc()
754    enddef
755    UseString()
756    var->assert_equal('xyork')
757
758    def UseString2()
759      "knife"->MyFunc()
760    enddef
761    UseString2()
762    var->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            var
777            )
778
779    call MyFunc(
780        'more'
781          ..
782          'lines'
783        )
784    assert_equal(
785        'morelines',
786        var)
787  END
788  writefile(lines, 'Xcall.vim')
789  source Xcall.vim
790  delete('Xcall.vim')
791enddef
792
793def Test_vim9script_call_fail_decl()
794  let lines =<< trim END
795    vim9script
796    let var = ''
797    def MyFunc(arg: string)
798       let var = 123
799    enddef
800    defcompile
801  END
802  CheckScriptFailure(lines, 'E1054:')
803enddef
804
805def Test_vim9script_call_fail_type()
806  let 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  let 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  let 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  let 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  let Ref1: func()
996  s:funcResult = 0
997  Ref1 = FuncNoArgNoRet
998  Ref1()
999  s:funcResult->assert_equal(11)
1000
1001  let 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  let 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  let res = ''
1040  for name in argv()
1041    res ..= name
1042  endfor
1043  res->assert_equal('fileonefiletwo')
1044enddef
1045
1046def Test_func_type_part()
1047  let RefVoid: func: void
1048  RefVoid = FuncNoArgNoRet
1049  RefVoid = FuncOneArgNoRet
1050  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number')
1051  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string')
1052
1053  let RefAny: func(): any
1054  RefAny = FuncNoArgRetNumber
1055  RefAny = FuncNoArgRetString
1056  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()')
1057  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)')
1058
1059  let RefNr: func: number
1060  RefNr = FuncNoArgRetNumber
1061  RefNr = FuncOneArgRetNumber
1062  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()')
1063  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string')
1064
1065  let RefStr: func: string
1066  RefStr = FuncNoArgRetString
1067  RefStr = FuncOneArgRetString
1068  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()')
1069  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number')
1070enddef
1071
1072def Test_func_type_fails()
1073  CheckDefFailure(['let ref1: func()'], 'E704:')
1074
1075  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number')
1076  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)')
1077  CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
1078  CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)')
1079  CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)')
1080  CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)')
1081
1082  CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:')
1083  CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:')
1084  CheckDefFailure(['let 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(['let RefWrong: func(bool):string'], 'E1069:')
1086enddef
1087
1088def Test_func_return_type()
1089  let nr: number
1090  nr = FuncNoArgRetNumber()
1091  nr->assert_equal(1234)
1092
1093  nr = FuncOneArgRetAny(122)
1094  nr->assert_equal(122)
1095
1096  let str: string
1097  str = FuncOneArgRetAny('yes')
1098  str->assert_equal('yes')
1099
1100  CheckDefFailure(['let 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  let 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      let 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      let db = #{foo: 1, bar: 2}
1206      # comment
1207      let 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      'let RefMe: func = function("g:DelMe")',
1226      'delfunc g:DelMe',
1227      'echo RefMe()'], 'E117:')
1228enddef
1229
1230def Test_unknown_function()
1231  CheckDefExecFailure([
1232      'let 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  let local = 'some '
1242  RefFunc({s -> local .. s})->assert_equal('some more')
1243enddef
1244
1245def MakeRef()
1246  let 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  let 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  let local = 'loc_val'
1296  g:UseArg = {s -> theArg .. '/' .. local .. '/' .. s}
1297enddef
1298
1299def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
1300  let 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  let 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  let 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  let text = 'text'
1355  g:Ref = {s ->  s .. text}
1356  GetResult(g:Ref)->assert_equal('sometext')
1357enddef
1358
1359def Test_double_closure_fails()
1360  let lines =<< trim END
1361    vim9script
1362    def Func()
1363    let var = 0
1364    for i in range(2)
1365	timer_start(0, {-> var})
1366    endfor
1367    enddef
1368    Func()
1369  END
1370  CheckScriptSuccess(lines)
1371enddef
1372
1373def Test_sort_return_type()
1374  let res: list<number>
1375  res = [1, 2, 3]->sort()
1376enddef
1377
1378def Test_sort_argument()
1379  let res = ['b', 'a', 'c']->sort('i')
1380  res->assert_equal(['a', 'b', 'c'])
1381enddef
1382
1383def Test_getqflist_return_type()
1384  let l = getqflist()
1385  l->assert_equal([])
1386
1387  let d = getqflist(#{items: 0})
1388  d->assert_equal(#{items: []})
1389enddef
1390
1391def Test_getloclist_return_type()
1392  let l = getloclist(1)
1393  l->assert_equal([])
1394
1395  let d = getloclist(1, #{items: 0})
1396  d->assert_equal(#{items: []})
1397enddef
1398
1399def Test_copy_return_type()
1400  let l = copy([1, 2, 3])
1401  let res = 0
1402  for n in l
1403    res += n
1404  endfor
1405  res->assert_equal(6)
1406
1407  let dl = deepcopy([1, 2, 3])
1408  res = 0
1409  for n in dl
1410    res += n
1411  endfor
1412  res->assert_equal(6)
1413
1414  dl = deepcopy([1, 2, 3], true)
1415enddef
1416
1417def Test_extend_return_type()
1418  let l = extend([1, 2], [3])
1419  let res = 0
1420  for n in l
1421    res += n
1422  endfor
1423  res->assert_equal(6)
1424enddef
1425
1426def Test_garbagecollect()
1427  garbagecollect(true)
1428enddef
1429
1430def Test_insert_return_type()
1431  let l = insert([2, 1], 3)
1432  let res = 0
1433  for n in l
1434    res += n
1435  endfor
1436  res->assert_equal(6)
1437enddef
1438
1439def Test_keys_return_type()
1440  const var: list<string> = #{a: 1, b: 2}->keys()
1441  var->assert_equal(['a', 'b'])
1442enddef
1443
1444def Test_reverse_return_type()
1445  let l = reverse([1, 2, 3])
1446  let res = 0
1447  for n in l
1448    res += n
1449  endfor
1450  res->assert_equal(6)
1451enddef
1452
1453def Test_remove_return_type()
1454  let l = remove(#{one: [1, 2], two: [3, 4]}, 'one')
1455  let res = 0
1456  for n in l
1457    res += n
1458  endfor
1459  res->assert_equal(3)
1460enddef
1461
1462def Test_filter_return_type()
1463  let l = filter([1, 2, 3], {-> 1})
1464  let res = 0
1465  for n in l
1466    res += n
1467  endfor
1468  res->assert_equal(6)
1469enddef
1470
1471def Test_bufnr()
1472  let buf = bufnr()
1473  bufnr('%')->assert_equal(buf)
1474
1475  buf = bufnr('Xdummy', true)
1476  buf->assert_notequal(-1)
1477  exe 'bwipe! ' .. buf
1478enddef
1479
1480def Test_col()
1481  new
1482  setline(1, 'asdf')
1483  col([1, '$'])->assert_equal(5)
1484enddef
1485
1486def Test_char2nr()
1487  char2nr('あ', true)->assert_equal(12354)
1488enddef
1489
1490def Test_getreg_return_type()
1491  let s1: string = getreg('"')
1492  let s2: string = getreg('"', 1)
1493  let s3: list<string> = getreg('"', 1, 1)
1494enddef
1495
1496def Wrong_dict_key_type(items: list<number>): list<number>
1497  return filter(items, {_, val -> get({val: 1}, 'x')})
1498enddef
1499
1500def Test_wrong_dict_key_type()
1501  assert_fails('Wrong_dict_key_type([1, 2, 3])', 'E1012:')
1502enddef
1503
1504def Line_continuation_in_def(dir: string = ''): string
1505    let path: string = empty(dir)
1506            \ ? 'empty'
1507            \ : 'full'
1508    return path
1509enddef
1510
1511def Test_line_continuation_in_def()
1512  Line_continuation_in_def('.')->assert_equal('full')
1513enddef
1514
1515def Line_continuation_in_lambda(): list<string>
1516  let x = range(97, 100)
1517      ->map({_, v -> nr2char(v)
1518          ->toupper()})
1519      ->reverse()
1520  return x
1521enddef
1522
1523def Test_line_continuation_in_lambda()
1524  Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
1525enddef
1526
1527func Test_silent_echo()
1528  CheckScreendump
1529
1530  let lines =<< trim END
1531    vim9script
1532    def EchoNothing()
1533      silent echo ''
1534    enddef
1535    defcompile
1536  END
1537  call writefile(lines, 'XTest_silent_echo')
1538
1539  " Check that the balloon shows up after a mouse move
1540  let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6})
1541  call term_sendkeys(buf, ":abc")
1542  call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {})
1543
1544  " clean up
1545  call StopVimInTerminal(buf)
1546  call delete('XTest_silent_echo')
1547endfunc
1548
1549""""""" builtin functions that behave differently in Vim9
1550
1551def Test_bufname()
1552  split SomeFile
1553  bufname('%')->assert_equal('SomeFile')
1554  edit OtherFile
1555  bufname('#')->assert_equal('SomeFile')
1556  close
1557enddef
1558
1559def Test_bufwinid()
1560  let origwin = win_getid()
1561  below split SomeFile
1562  let SomeFileID = win_getid()
1563  below split OtherFile
1564  below split SomeFile
1565  bufwinid('SomeFile')->assert_equal(SomeFileID)
1566
1567  win_gotoid(origwin)
1568  only
1569  bwipe SomeFile
1570  bwipe OtherFile
1571enddef
1572
1573def Test_count()
1574  count('ABC ABC ABC', 'b', true)->assert_equal(3)
1575  count('ABC ABC ABC', 'b', false)->assert_equal(0)
1576enddef
1577
1578def Test_expand()
1579  split SomeFile
1580  expand('%', true, true)->assert_equal(['SomeFile'])
1581  close
1582enddef
1583
1584def Test_getbufinfo()
1585  let bufinfo = getbufinfo(bufnr())
1586  getbufinfo('%')->assert_equal(bufinfo)
1587
1588  edit Xtestfile1
1589  hide edit Xtestfile2
1590  hide enew
1591  getbufinfo(#{bufloaded: true, buflisted: true, bufmodified: false})
1592      ->len()->assert_equal(3)
1593  bwipe Xtestfile1 Xtestfile2
1594enddef
1595
1596def Test_getbufline()
1597  e SomeFile
1598  let buf = bufnr()
1599  e #
1600  let lines = ['aaa', 'bbb', 'ccc']
1601  setbufline(buf, 1, lines)
1602  getbufline('#', 1, '$')->assert_equal(lines)
1603
1604  bwipe!
1605enddef
1606
1607def Test_getchangelist()
1608  new
1609  setline(1, 'some text')
1610  let changelist = bufnr()->getchangelist()
1611  getchangelist('%')->assert_equal(changelist)
1612  bwipe!
1613enddef
1614
1615def Test_getchar()
1616  while getchar(0)
1617  endwhile
1618  getchar(true)->assert_equal(0)
1619enddef
1620
1621def Test_getcompletion()
1622  set wildignore=*.vim,*~
1623  let l = getcompletion('run', 'file', true)
1624  l->assert_equal([])
1625  set wildignore&
1626enddef
1627
1628def Test_getreg()
1629  let lines = ['aaa', 'bbb', 'ccc']
1630  setreg('a', lines)
1631  getreg('a', true, true)->assert_equal(lines)
1632enddef
1633
1634def Test_glob()
1635  glob('runtest.vim', true, true, true)->assert_equal(['runtest.vim'])
1636enddef
1637
1638def Test_globpath()
1639  globpath('.', 'runtest.vim', true, true, true)->assert_equal(['./runtest.vim'])
1640enddef
1641
1642def Test_has()
1643  has('eval', true)->assert_equal(1)
1644enddef
1645
1646def Test_hasmapto()
1647  hasmapto('foobar', 'i', true)->assert_equal(0)
1648  iabbrev foo foobar
1649  hasmapto('foobar', 'i', true)->assert_equal(1)
1650  iunabbrev foo
1651enddef
1652
1653def Test_index()
1654  index(['a', 'b', 'a', 'B'], 'b', 2, true)->assert_equal(3)
1655enddef
1656
1657def Test_list2str_str2list_utf8()
1658  let s = "\u3042\u3044"
1659  let l = [0x3042, 0x3044]
1660  str2list(s, true)->assert_equal(l)
1661  list2str(l, true)->assert_equal(s)
1662enddef
1663
1664def SID(): number
1665  return expand('<SID>')
1666          ->matchstr('<SNR>\zs\d\+\ze_$')
1667          ->str2nr()
1668enddef
1669
1670def Test_maparg()
1671  let lnum = str2nr(expand('<sflnum>'))
1672  map foo bar
1673  maparg('foo', '', false, true)->assert_equal(#{
1674        lnum: lnum + 1,
1675        script: 0,
1676        mode: ' ',
1677        silent: 0,
1678        noremap: 0,
1679        lhs: 'foo',
1680        lhsraw: 'foo',
1681        nowait: 0,
1682        expr: 0,
1683        sid: SID(),
1684        rhs: 'bar',
1685        buffer: 0})
1686  unmap foo
1687enddef
1688
1689def Test_mapcheck()
1690  iabbrev foo foobar
1691  mapcheck('foo', 'i', true)->assert_equal('foobar')
1692  iunabbrev foo
1693enddef
1694
1695def Test_nr2char()
1696  nr2char(97, true)->assert_equal('a')
1697enddef
1698
1699def Test_readdir()
1700   eval expand('sautest')->readdir({e -> e[0] !=# '.'})
1701   eval expand('sautest')->readdirex({e -> e.name[0] !=# '.'})
1702enddef
1703
1704def Test_search()
1705  new
1706  setline(1, ['foo', 'bar'])
1707  let val = 0
1708  # skip expr returns boolean
1709  search('bar', 'W', 0, 0, {-> val == 1})->assert_equal(2)
1710  :1
1711  search('bar', 'W', 0, 0, {-> val == 0})->assert_equal(0)
1712  # skip expr returns number, only 0 and 1 are accepted
1713  :1
1714  search('bar', 'W', 0, 0, {-> 0})->assert_equal(2)
1715  :1
1716  search('bar', 'W', 0, 0, {-> 1})->assert_equal(0)
1717  assert_fails("search('bar', '', 0, 0, {-> -1})", 'E1023:')
1718  assert_fails("search('bar', '', 0, 0, {-> -1})", 'E1023:')
1719enddef
1720
1721def Test_searchcount()
1722  new
1723  setline(1, "foo bar")
1724  :/foo
1725  searchcount(#{recompute: true})
1726      ->assert_equal(#{
1727          exact_match: 1,
1728          current: 1,
1729          total: 1,
1730          maxcount: 99,
1731          incomplete: 0})
1732  bwipe!
1733enddef
1734
1735def Test_searchdecl()
1736  searchdecl('blah', true, true)->assert_equal(1)
1737enddef
1738
1739def Test_setbufvar()
1740  setbufvar(bufnr('%'), '&syntax', 'vim')
1741  &syntax->assert_equal('vim')
1742  setbufvar(bufnr('%'), '&ts', 16)
1743  &ts->assert_equal(16)
1744  settabwinvar(1, 1, '&syntax', 'vam')
1745  &syntax->assert_equal('vam')
1746  settabwinvar(1, 1, '&ts', 15)
1747  &ts->assert_equal(15)
1748  setlocal ts=8
1749
1750  setbufvar('%', 'myvar', 123)
1751  getbufvar('%', 'myvar')->assert_equal(123)
1752enddef
1753
1754def Test_setloclist()
1755  let items = [#{filename: '/tmp/file', lnum: 1, valid: true}]
1756  let what = #{items: items}
1757  setqflist([], ' ', what)
1758  setloclist(0, [], ' ', what)
1759enddef
1760
1761def Test_setreg()
1762  setreg('a', ['aaa', 'bbb', 'ccc'])
1763  let reginfo = getreginfo('a')
1764  setreg('a', reginfo)
1765  getreginfo('a')->assert_equal(reginfo)
1766enddef
1767
1768def Test_spellsuggest()
1769  if !has('spell')
1770    MissingFeature 'spell'
1771  else
1772    spellsuggest('marrch', 1, true)->assert_equal(['March'])
1773  endif
1774enddef
1775
1776def Test_split()
1777  split('  aa  bb  ', '\W\+', true)->assert_equal(['', 'aa', 'bb', ''])
1778enddef
1779
1780def Test_str2nr()
1781  str2nr("1'000'000", 10, true)->assert_equal(1000000)
1782enddef
1783
1784def Test_strchars()
1785  strchars("A\u20dd", true)->assert_equal(1)
1786enddef
1787
1788def Test_submatch()
1789  let pat = 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)'
1790  let Rep = {-> range(10)->map({_, v -> submatch(v, true)})->string()}
1791  let actual = substitute('A123456789', pat, Rep, '')
1792  let expected = "[['A123456789'], ['1'], ['2'], ['3'], ['4'], ['5'], ['6'], ['7'], ['8'], ['9']]"
1793  actual->assert_equal(expected)
1794enddef
1795
1796def Test_synID()
1797  new
1798  setline(1, "text")
1799  synID(1, 1, true)->assert_equal(0)
1800  bwipe!
1801enddef
1802
1803def Test_term_gettty()
1804  if !has('terminal')
1805    MissingFeature 'terminal'
1806  else
1807    let buf = Run_shell_in_terminal({})
1808    term_gettty(buf, true)->assert_notequal('')
1809    StopShellInTerminal(buf)
1810  endif
1811enddef
1812
1813def Test_term_start()
1814  if !has('terminal')
1815    MissingFeature 'terminal'
1816  else
1817    botright new
1818    let winnr = winnr()
1819    term_start(&shell, #{curwin: true})
1820    winnr()->assert_equal(winnr)
1821    bwipe!
1822  endif
1823enddef
1824
1825def Test_timer_paused()
1826  let id = timer_start(50, {-> 0})
1827  timer_pause(id, true)
1828  let info = timer_info(id)
1829  info[0]['paused']->assert_equal(1)
1830  timer_stop(id)
1831enddef
1832
1833def Test_win_splitmove()
1834  split
1835  win_splitmove(1, 2, #{vertical: true, rightbelow: true})
1836  close
1837enddef
1838
1839""""""" end of builtin functions
1840
1841def Fibonacci(n: number): number
1842  if n < 2
1843    return n
1844  else
1845    return Fibonacci(n - 1) + Fibonacci(n - 2)
1846  endif
1847enddef
1848
1849def Test_recursive_call()
1850  Fibonacci(20)->assert_equal(6765)
1851enddef
1852
1853def TreeWalk(dir: string): list<any>
1854  return readdir(dir)->map({_, val ->
1855            fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
1856               ? {val: TreeWalk(dir .. '/' .. val)}
1857               : val
1858             })
1859enddef
1860
1861def Test_closure_in_map()
1862  mkdir('XclosureDir/tdir', 'p')
1863  writefile(['111'], 'XclosureDir/file1')
1864  writefile(['222'], 'XclosureDir/file2')
1865  writefile(['333'], 'XclosureDir/tdir/file3')
1866
1867  TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {'tdir': ['file3']}])
1868
1869  delete('XclosureDir', 'rf')
1870enddef
1871
1872def Test_partial_call()
1873  let Xsetlist = function('setloclist', [0])
1874  Xsetlist([], ' ', {'title': 'test'})
1875  getloclist(0, {'title': 1})->assert_equal({'title': 'test'})
1876
1877  Xsetlist = function('setloclist', [0, [], ' '])
1878  Xsetlist({'title': 'test'})
1879  getloclist(0, {'title': 1})->assert_equal({'title': 'test'})
1880
1881  Xsetlist = function('setqflist')
1882  Xsetlist([], ' ', {'title': 'test'})
1883  getqflist({'title': 1})->assert_equal({'title': 'test'})
1884
1885  Xsetlist = function('setqflist', [[], ' '])
1886  Xsetlist({'title': 'test'})
1887  getqflist({'title': 1})->assert_equal({'title': 'test'})
1888enddef
1889
1890def Test_cmd_modifier()
1891  tab echo '0'
1892  CheckDefFailure(['5tab echo 3'], 'E16:')
1893enddef
1894
1895def Test_restore_modifiers()
1896  # check that when compiling a :def function command modifiers are not messed
1897  # up.
1898  let lines =<< trim END
1899      vim9script
1900      set eventignore=
1901      autocmd QuickFixCmdPost * copen
1902      def AutocmdsDisabled()
1903          eval 0
1904      enddef
1905      func Func()
1906        noautocmd call s:AutocmdsDisabled()
1907        let g:ei_after = &eventignore
1908      endfunc
1909      Func()
1910  END
1911  CheckScriptSuccess(lines)
1912  g:ei_after->assert_equal('')
1913enddef
1914
1915def StackTop()
1916  eval 1
1917  eval 2
1918  # call not on fourth line
1919  StackBot()
1920enddef
1921
1922def StackBot()
1923  # throw an error
1924  eval [][0]
1925enddef
1926
1927def Test_callstack_def()
1928  try
1929    StackTop()
1930  catch
1931    v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2')
1932  endtry
1933enddef
1934
1935
1936" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
1937