1" Test various aspects of the Vim script language.
2" Most of this was formerly in test49.
3
4source check.vim
5source shared.vim
6
7"-------------------------------------------------------------------------------
8" Test environment							    {{{1
9"-------------------------------------------------------------------------------
10
11com!		   XpathINIT  let g:Xpath = ''
12com! -nargs=1 -bar Xpath      let g:Xpath = g:Xpath . <args>
13
14" Append a message to the "messages" file
15func Xout(text)
16    split messages
17    $put =a:text
18    wq
19endfunc
20
21com! -nargs=1	     Xout     call Xout(<args>)
22
23" MakeScript() - Make a script file from a function.			    {{{2
24"
25" Create a script that consists of the body of the function a:funcname.
26" Replace any ":return" by a ":finish", any argument variable by a global
27" variable, and every ":call" by a ":source" for the next following argument
28" in the variable argument list.  This function is useful if similar tests are
29" to be made for a ":return" from a function call or a ":finish" in a script
30" file.
31func MakeScript(funcname, ...)
32    let script = tempname()
33    execute "redir! >" . script
34    execute "function" a:funcname
35    redir END
36    execute "edit" script
37    " Delete the "function" and the "endfunction" lines.  Do not include the
38    " word "function" in the pattern since it might be translated if LANG is
39    " set.  When MakeScript() is being debugged, this deletes also the debugging
40    " output of its line 3 and 4.
41    exec '1,/.*' . a:funcname . '(.*)/d'
42    /^\d*\s*endfunction\>/,$d
43    %s/^\d*//e
44    %s/return/finish/e
45    %s/\<a:\(\h\w*\)/g:\1/ge
46    normal gg0
47    let cnt = 0
48    while search('\<call\s*\%(\u\|s:\)\w*\s*(.*)', 'W') > 0
49	let cnt = cnt + 1
50	s/\<call\s*\%(\u\|s:\)\w*\s*(.*)/\='source ' . a:{cnt}/
51    endwhile
52    g/^\s*$/d
53    write
54    bwipeout
55    return script
56endfunc
57
58" ExecAsScript - Source a temporary script made from a function.	    {{{2
59"
60" Make a temporary script file from the function a:funcname, ":source" it, and
61" delete it afterwards.  However, if an exception is thrown the file may remain,
62" the caller should call DeleteTheScript() afterwards.
63let s:script_name = ''
64function! ExecAsScript(funcname)
65    " Make a script from the function passed as argument.
66    let s:script_name = MakeScript(a:funcname)
67
68    " Source and delete the script.
69    exec "source" s:script_name
70    call delete(s:script_name)
71    let s:script_name = ''
72endfunction
73
74function! DeleteTheScript()
75    if s:script_name
76	call delete(s:script_name)
77	let s:script_name = ''
78    endif
79endfunc
80
81com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
82
83
84"-------------------------------------------------------------------------------
85" Test 1:   :endwhile in function					    {{{1
86"
87"	    Detect if a broken loop is (incorrectly) reactivated by the
88"	    :endwhile.  Use a :return to prevent an endless loop, and make
89"	    this test first to get a meaningful result on an error before other
90"	    tests will hang.
91"-------------------------------------------------------------------------------
92
93function! T1_F()
94    Xpath 'a'
95    let first = 1
96    while 1
97	Xpath 'b'
98	if first
99	    Xpath 'c'
100	    let first = 0
101	    break
102	else
103	    Xpath 'd'
104	    return
105	endif
106    endwhile
107endfunction
108
109function! T1_G()
110    Xpath 'h'
111    let first = 1
112    while 1
113	Xpath 'i'
114	if first
115	    Xpath 'j'
116	    let first = 0
117	    break
118	else
119	    Xpath 'k'
120	    return
121	endif
122	if 1	" unmatched :if
123    endwhile
124endfunction
125
126func Test_endwhile_function()
127  XpathINIT
128  call T1_F()
129  Xpath 'F'
130
131  try
132    call T1_G()
133  catch
134    " Catch missing :endif
135    call assert_true(v:exception =~ 'E171')
136    Xpath 'x'
137  endtry
138  Xpath 'G'
139
140  call assert_equal('abcFhijxG', g:Xpath)
141endfunc
142
143"-------------------------------------------------------------------------------
144" Test 2:   :endwhile in script						    {{{1
145"
146"	    Detect if a broken loop is (incorrectly) reactivated by the
147"	    :endwhile.  Use a :finish to prevent an endless loop, and place
148"	    this test before others that might hang to get a meaningful result
149"	    on an error.
150"
151"	    This test executes the bodies of the functions T1_F and T1_G from
152"	    the previous test as script files (:return replaced by :finish).
153"-------------------------------------------------------------------------------
154
155func Test_endwhile_script()
156  XpathINIT
157  ExecAsScript T1_F
158  Xpath 'F'
159  call DeleteTheScript()
160
161  try
162    ExecAsScript T1_G
163  catch
164    " Catch missing :endif
165    call assert_true(v:exception =~ 'E171')
166    Xpath 'x'
167  endtry
168  Xpath 'G'
169  call DeleteTheScript()
170
171  call assert_equal('abcFhijxG', g:Xpath)
172endfunc
173
174"-------------------------------------------------------------------------------
175" Test 3:   :if, :elseif, :while, :continue, :break			    {{{1
176"-------------------------------------------------------------------------------
177
178function Test_if_while()
179    XpathINIT
180    if 1
181	Xpath 'a'
182	let loops = 3
183	while loops > -1	    " main loop: loops == 3, 2, 1 (which breaks)
184	    if loops <= 0
185		let break_err = 1
186		let loops = -1
187	    else
188		Xpath 'b' . loops
189	    endif
190	    if (loops == 2)
191		while loops == 2 " dummy loop
192		    Xpath 'c' . loops
193		    let loops = loops - 1
194		    continue    " stop dummy loop
195		    Xpath 'd' . loops
196		endwhile
197		continue	    " continue main loop
198		Xpath 'e' . loops
199	    elseif (loops == 1)
200		let p = 1
201		while p	    " dummy loop
202		    Xpath 'f' . loops
203		    let p = 0
204		    break	    " break dummy loop
205		    Xpath 'g' . loops
206		endwhile
207		Xpath 'h' . loops
208		unlet p
209		break	    " break main loop
210		Xpath 'i' . loops
211	    endif
212	    if (loops > 0)
213		Xpath 'j' . loops
214	    endif
215	    while loops == 3    " dummy loop
216		let loops = loops - 1
217	    endwhile	    " end dummy loop
218	endwhile		    " end main loop
219	Xpath 'k'
220    else
221	Xpath 'l'
222    endif
223    Xpath 'm'
224    if exists("break_err")
225	Xpath 'm'
226	unlet break_err
227    endif
228
229    unlet loops
230
231    call assert_equal('ab3j3b2c2b1f1h1km', g:Xpath)
232endfunc
233
234"-------------------------------------------------------------------------------
235" Test 4:   :return							    {{{1
236"-------------------------------------------------------------------------------
237
238function! T4_F()
239    if 1
240	Xpath 'a'
241	let loops = 3
242	while loops > 0				"    3:  2:     1:
243	    Xpath 'b' . loops
244	    if (loops == 2)
245		Xpath 'c' . loops
246		return
247		Xpath 'd' . loops
248	    endif
249	    Xpath 'e' . loops
250	    let loops = loops - 1
251	endwhile
252	Xpath 'f'
253    else
254	Xpath 'g'
255    endif
256endfunction
257
258function Test_return()
259    XpathINIT
260    call T4_F()
261    Xpath '4'
262
263    call assert_equal('ab3e3b2c24', g:Xpath)
264endfunction
265
266
267"-------------------------------------------------------------------------------
268" Test 5:   :finish							    {{{1
269"
270"	    This test executes the body of the function T4_F from the previous
271"	    test as a script file (:return replaced by :finish).
272"-------------------------------------------------------------------------------
273
274function Test_finish()
275    XpathINIT
276    ExecAsScript T4_F
277    Xpath '5'
278    call DeleteTheScript()
279
280    call assert_equal('ab3e3b2c25', g:Xpath)
281endfunction
282
283
284
285"-------------------------------------------------------------------------------
286" Test 6:   Defining functions in :while loops				    {{{1
287"
288"	     Functions can be defined inside other functions.  An inner function
289"	     gets defined when the outer function is executed.  Functions may
290"	     also be defined inside while loops.  Expressions in braces for
291"	     defining the function name are allowed.
292"
293"	     The functions are defined when sourcing the script, only the
294"	     resulting path is checked in the test function.
295"-------------------------------------------------------------------------------
296
297XpathINIT
298
299" The command CALL collects the argument of all its invocations in "calls"
300" when used from a function (that is, when the global variable "calls" needs
301" the "g:" prefix).  This is to check that the function code is skipped when
302" the function is defined.  For inner functions, do so only if the outer
303" function is not being executed.
304"
305let calls = ""
306com! -nargs=1 CALL
307	    \ if !exists("calls") && !exists("outer") |
308	    \ let g:calls = g:calls . <args> |
309	    \ endif
310
311let i = 0
312while i < 3
313    let i = i + 1
314    if i == 1
315	Xpath 'a'
316	function! F1(arg)
317	    CALL a:arg
318	    let outer = 1
319
320	    let j = 0
321	    while j < 1
322		Xpath 'b'
323		let j = j + 1
324		function! G1(arg)
325		    CALL a:arg
326		endfunction
327		Xpath 'c'
328	    endwhile
329	endfunction
330	Xpath 'd'
331
332	continue
333    endif
334
335    Xpath 'e' . i
336    function! F{i}(i, arg)
337	CALL a:arg
338	let outer = 1
339
340	if a:i == 3
341	    Xpath 'f'
342	endif
343	let k = 0
344	while k < 3
345	    Xpath 'g' . k
346	    let k = k + 1
347	    function! G{a:i}{k}(arg)
348		CALL a:arg
349	    endfunction
350	    Xpath 'h' . k
351	endwhile
352    endfunction
353    Xpath 'i'
354
355endwhile
356
357if exists("*G1")
358    Xpath 'j'
359endif
360if exists("*F1")
361    call F1("F1")
362    if exists("*G1")
363       call G1("G1")
364    endif
365endif
366
367if exists("G21") || exists("G22") || exists("G23")
368    Xpath 'k'
369endif
370if exists("*F2")
371    call F2(2, "F2")
372    if exists("*G21")
373       call G21("G21")
374    endif
375    if exists("*G22")
376       call G22("G22")
377    endif
378    if exists("*G23")
379       call G23("G23")
380    endif
381endif
382
383if exists("G31") || exists("G32") || exists("G33")
384    Xpath 'l'
385endif
386if exists("*F3")
387    call F3(3, "F3")
388    if exists("*G31")
389       call G31("G31")
390    endif
391    if exists("*G32")
392       call G32("G32")
393    endif
394    if exists("*G33")
395       call G33("G33")
396    endif
397endif
398
399Xpath 'm'
400
401let g:test6_result = g:Xpath
402let g:test6_calls = calls
403
404unlet calls
405delfunction F1
406delfunction G1
407delfunction F2
408delfunction G21
409delfunction G22
410delfunction G23
411delfunction G31
412delfunction G32
413delfunction G33
414
415function Test_defining_functions()
416    call assert_equal('ade2ie3ibcg0h1g1h2g2h3fg0h1g1h2g2h3m', g:test6_result)
417    call assert_equal('F1G1F2G21G22G23F3G31G32G33', g:test6_calls)
418endfunc
419
420"-------------------------------------------------------------------------------
421" Test 7:   Continuing on errors outside functions			    {{{1
422"
423"	    On an error outside a function, the script processing continues
424"	    at the line following the outermost :endif or :endwhile.  When not
425"	    inside an :if or :while, the script processing continues at the next
426"	    line.
427"-------------------------------------------------------------------------------
428
429XpathINIT
430
431if 1
432    Xpath 'a'
433    while 1
434	Xpath 'b'
435	asdf
436	Xpath 'c'
437	break
438    endwhile | Xpath 'd'
439    Xpath 'e'
440endif | Xpath 'f'
441Xpath 'g'
442
443while 1
444    Xpath 'h'
445    if 1
446	Xpath 'i'
447	asdf
448	Xpath 'j'
449    endif | Xpath 'k'
450    Xpath 'l'
451    break
452endwhile | Xpath 'm'
453Xpath 'n'
454
455asdf
456Xpath 'o'
457
458asdf | Xpath 'p'
459Xpath 'q'
460
461let g:test7_result = g:Xpath
462
463func Test_error_in_script()
464    call assert_equal('abghinoq', g:test7_result)
465endfunc
466
467"-------------------------------------------------------------------------------
468" Test 8:   Aborting and continuing on errors inside functions		    {{{1
469"
470"	    On an error inside a function without the "abort" attribute, the
471"	    script processing continues at the next line (unless the error was
472"	    in a :return command).  On an error inside a function with the
473"	    "abort" attribute, the function is aborted and the script processing
474"	    continues after the function call; the value -1 is returned then.
475"-------------------------------------------------------------------------------
476
477XpathINIT
478
479function! T8_F()
480    if 1
481	Xpath 'a'
482	while 1
483	    Xpath 'b'
484	    asdf
485	    Xpath 'c'
486	    asdf | Xpath 'd'
487	    Xpath 'e'
488	    break
489	endwhile
490	Xpath 'f'
491    endif | Xpath 'g'
492    Xpath 'h'
493
494    while 1
495	Xpath 'i'
496	if 1
497	    Xpath 'j'
498	    asdf
499	    Xpath 'k'
500	    asdf | Xpath 'l'
501	    Xpath 'm'
502	endif
503	Xpath 'n'
504	break
505    endwhile | Xpath 'o'
506    Xpath 'p'
507
508    return novar		" returns (default return value 0)
509    Xpath 'q'
510    return 1			" not reached
511endfunction
512
513function! T8_G() abort
514    if 1
515	Xpath 'r'
516	while 1
517	    Xpath 's'
518	    asdf		" returns -1
519	    Xpath 't'
520	    break
521	endwhile
522	Xpath 'v'
523    endif | Xpath 'w'
524    Xpath 'x'
525
526    return -4			" not reached
527endfunction
528
529function! T8_H() abort
530    while 1
531	Xpath 'A'
532	if 1
533	    Xpath 'B'
534	    asdf		" returns -1
535	    Xpath 'C'
536	endif
537	Xpath 'D'
538	break
539    endwhile | Xpath 'E'
540    Xpath 'F'
541
542    return -4			" not reached
543endfunction
544
545" Aborted functions (T8_G and T8_H) return -1.
546let g:test8_sum = (T8_F() + 1) - 4 * T8_G() - 8 * T8_H()
547Xpath 'X'
548let g:test8_result = g:Xpath
549
550func Test_error_in_function()
551    call assert_equal(13, g:test8_sum)
552    call assert_equal('abcefghijkmnoprsABX', g:test8_result)
553
554    delfunction T8_F
555    delfunction T8_G
556    delfunction T8_H
557endfunc
558
559
560"-------------------------------------------------------------------------------
561" Test 9:   Continuing after aborted functions				    {{{1
562"
563"	    When a function with the "abort" attribute is aborted due to an
564"	    error, the next function back in the call hierarchy without an
565"	    "abort" attribute continues; the value -1 is returned then.
566"-------------------------------------------------------------------------------
567
568XpathINIT
569
570function! F() abort
571    Xpath 'a'
572    let result = G()	" not aborted
573    Xpath 'b'
574    if result != 2
575	Xpath 'c'
576    endif
577    return 1
578endfunction
579
580function! G()		" no abort attribute
581    Xpath 'd'
582    if H() != -1	" aborted
583	Xpath 'e'
584    endif
585    Xpath 'f'
586    return 2
587endfunction
588
589function! H() abort
590    Xpath 'g'
591    call I()		" aborted
592    Xpath 'h'
593    return 4
594endfunction
595
596function! I() abort
597    Xpath 'i'
598    asdf		" error
599    Xpath 'j'
600    return 8
601endfunction
602
603if F() != 1
604    Xpath 'k'
605endif
606
607let g:test9_result = g:Xpath
608
609delfunction F
610delfunction G
611delfunction H
612delfunction I
613
614func Test_func_abort()
615    call assert_equal('adgifb', g:test9_result)
616endfunc
617
618
619"-------------------------------------------------------------------------------
620" Test 10:  :if, :elseif, :while argument parsing			    {{{1
621"
622"	    A '"' or '|' in an argument expression must not be mixed up with
623"	    a comment or a next command after a bar.  Parsing errors should
624"	    be recognized.
625"-------------------------------------------------------------------------------
626
627XpathINIT
628
629function! MSG(enr, emsg)
630    let english = v:lang == "C" || v:lang =~ '^[Ee]n'
631    if a:enr == ""
632	Xout "TODO: Add message number for:" a:emsg
633	let v:errmsg = ":" . v:errmsg
634    endif
635    let match = 1
636    if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
637	let match = 0
638	if v:errmsg == ""
639	    Xout "Message missing."
640	else
641	    let v:errmsg = v:errmsg->escape('"')
642	    Xout "Unexpected message:" v:errmsg
643	endif
644    endif
645    return match
646endfunc
647
648if 1 || strlen("\"") | Xpath 'a'
649    Xpath 'b'
650endif
651Xpath 'c'
652
653if 0
654elseif 1 || strlen("\"") | Xpath 'd'
655    Xpath 'e'
656endif
657Xpath 'f'
658
659while 1 || strlen("\"") | Xpath 'g'
660    Xpath 'h'
661    break
662endwhile
663Xpath 'i'
664
665let v:errmsg = ""
666if 1 ||| strlen("\"") | Xpath 'j'
667    Xpath 'k'
668endif
669Xpath 'l'
670if !MSG('E15', "Invalid expression")
671    Xpath 'm'
672endif
673
674let v:errmsg = ""
675if 0
676elseif 1 ||| strlen("\"") | Xpath 'n'
677    Xpath 'o'
678endif
679Xpath 'p'
680if !MSG('E15', "Invalid expression")
681    Xpath 'q'
682endif
683
684let v:errmsg = ""
685while 1 ||| strlen("\"") | Xpath 'r'
686    Xpath 's'
687    break
688endwhile
689Xpath 't'
690if !MSG('E15', "Invalid expression")
691    Xpath 'u'
692endif
693
694let g:test10_result = g:Xpath
695delfunction MSG
696
697func Test_expr_parsing()
698    call assert_equal('abcdefghilpt', g:test10_result)
699endfunc
700
701
702"-------------------------------------------------------------------------------
703" Test 11:  :if, :elseif, :while argument evaluation after abort	    {{{1
704"
705"	    When code is skipped over due to an error, the boolean argument to
706"	    an :if, :elseif, or :while must not be evaluated.
707"-------------------------------------------------------------------------------
708
709XpathINIT
710
711let calls = 0
712
713function! P(num)
714    let g:calls = g:calls + a:num   " side effect on call
715    return 0
716endfunction
717
718if 1
719    Xpath 'a'
720    asdf		" error
721    Xpath 'b'
722    if P(1)		" should not be called
723	Xpath 'c'
724    elseif !P(2)	" should not be called
725	Xpath 'd'
726    else
727	Xpath 'e'
728    endif
729    Xpath 'f'
730    while P(4)		" should not be called
731	Xpath 'g'
732    endwhile
733    Xpath 'h'
734endif
735Xpath 'x'
736
737let g:test11_calls = calls
738let g:test11_result = g:Xpath
739
740unlet calls
741delfunction P
742
743func Test_arg_abort()
744    call assert_equal(0, g:test11_calls)
745    call assert_equal('ax', g:test11_result)
746endfunc
747
748
749"-------------------------------------------------------------------------------
750" Test 12:  Expressions in braces in skipped code			    {{{1
751"
752"	    In code skipped over due to an error or inactive conditional,
753"	    an expression in braces as part of a variable or function name
754"	    should not be evaluated.
755"-------------------------------------------------------------------------------
756
757XpathINIT
758
759function! NULL()
760    Xpath 'a'
761    return 0
762endfunction
763
764function! ZERO()
765    Xpath 'b'
766    return 0
767endfunction
768
769function! F0()
770    Xpath 'c'
771endfunction
772
773function! F1(arg)
774    Xpath 'e'
775endfunction
776
777let V0 = 1
778
779Xpath 'f'
780echo 0 ? F{NULL() + V{ZERO()}}() : 1
781
782Xpath 'g'
783if 0
784    Xpath 'h'
785    call F{NULL() + V{ZERO()}}()
786endif
787
788Xpath 'i'
789if 1
790    asdf		" error
791    Xpath 'j'
792    call F1(F{NULL() + V{ZERO()}}())
793endif
794
795Xpath 'k'
796if 1
797    asdf		" error
798    Xpath 'l'
799    call F{NULL() + V{ZERO()}}()
800endif
801
802let g:test12_result = g:Xpath
803
804func Test_braces_skipped()
805    call assert_equal('fgik', g:test12_result)
806endfunc
807
808
809"-------------------------------------------------------------------------------
810" Test 13:  Failure in argument evaluation for :while			    {{{1
811"
812"	    A failure in the expression evaluation for the condition of a :while
813"	    causes the whole :while loop until the matching :endwhile being
814"	    ignored.  Continuation is at the next following line.
815"-------------------------------------------------------------------------------
816
817XpathINIT
818
819Xpath 'a'
820while asdf
821    Xpath 'b'
822    while 1
823	Xpath 'c'
824	break
825    endwhile
826    Xpath 'd'
827    break
828endwhile
829Xpath 'e'
830
831while asdf | Xpath 'f' | endwhile | Xpath 'g'
832Xpath 'h'
833let g:test13_result = g:Xpath
834
835func Test_while_fail()
836    call assert_equal('aeh', g:test13_result)
837endfunc
838
839
840"-------------------------------------------------------------------------------
841" Test 14:  Failure in argument evaluation for :if			    {{{1
842"
843"	    A failure in the expression evaluation for the condition of an :if
844"	    does not cause the corresponding :else or :endif being matched to
845"	    a previous :if/:elseif.  Neither of both branches of the failed :if
846"	    are executed.
847"-------------------------------------------------------------------------------
848
849XpathINIT
850
851function! F()
852    Xpath 'a'
853    let x = 0
854    if x		" false
855	Xpath 'b'
856    elseif !x		" always true
857	Xpath 'c'
858	let x = 1
859	if g:boolvar	" possibly undefined
860	    Xpath 'd'
861	else
862	    Xpath 'e'
863	endif
864	Xpath 'f'
865    elseif x		" never executed
866	Xpath 'g'
867    endif
868    Xpath 'h'
869endfunction
870
871let boolvar = 1
872call F()
873Xpath '-'
874
875unlet boolvar
876call F()
877let g:test14_result = g:Xpath
878
879delfunction F
880
881func Test_if_fail()
882    call assert_equal('acdfh-acfh', g:test14_result)
883endfunc
884
885
886"-------------------------------------------------------------------------------
887" Test 15:  Failure in argument evaluation for :if (bar)		    {{{1
888"
889"	    Like previous test, except that the failing :if ... | ... | :endif
890"	    is in a single line.
891"-------------------------------------------------------------------------------
892
893XpathINIT
894
895function! F()
896    Xpath 'a'
897    let x = 0
898    if x		" false
899	Xpath 'b'
900    elseif !x		" always true
901	Xpath 'c'
902	let x = 1
903	if g:boolvar | Xpath 'd' | else | Xpath 'e' | endif
904	Xpath 'f'
905    elseif x		" never executed
906	Xpath 'g'
907    endif
908    Xpath 'h'
909endfunction
910
911let boolvar = 1
912call F()
913Xpath '-'
914
915unlet boolvar
916call F()
917let g:test15_result = g:Xpath
918
919delfunction F
920
921func Test_if_bar_fail()
922    call assert_equal('acdfh-acfh', g:test15_result)
923endfunc
924
925"-------------------------------------------------------------------------------
926" Test 16:  Double :else or :elseif after :else				    {{{1
927"
928"	    Multiple :elses or an :elseif after an :else are forbidden.
929"-------------------------------------------------------------------------------
930
931func T16_F() abort
932  if 0
933    Xpath 'a'
934  else
935    Xpath 'b'
936  else		" aborts function
937    Xpath 'c'
938  endif
939  Xpath 'd'
940endfunc
941
942func T16_G() abort
943  if 0
944    Xpath 'a'
945  else
946    Xpath 'b'
947  elseif 1		" aborts function
948    Xpath 'c'
949  else
950    Xpath 'd'
951  endif
952  Xpath 'e'
953endfunc
954
955func T16_H() abort
956  if 0
957    Xpath 'a'
958  elseif 0
959    Xpath 'b'
960  else
961    Xpath 'c'
962  else		" aborts function
963    Xpath 'd'
964  endif
965  Xpath 'e'
966endfunc
967
968func T16_I() abort
969  if 0
970    Xpath 'a'
971  elseif 0
972    Xpath 'b'
973  else
974    Xpath 'c'
975  elseif 1		" aborts function
976    Xpath 'd'
977  else
978    Xpath 'e'
979  endif
980  Xpath 'f'
981endfunc
982
983func Test_Multi_Else()
984  XpathINIT
985  try
986    call T16_F()
987  catch /E583:/
988    Xpath 'e'
989  endtry
990  call assert_equal('be', g:Xpath)
991
992  XpathINIT
993  try
994    call T16_G()
995  catch /E584:/
996    Xpath 'f'
997  endtry
998  call assert_equal('bf', g:Xpath)
999
1000  XpathINIT
1001  try
1002    call T16_H()
1003  catch /E583:/
1004    Xpath 'f'
1005  endtry
1006  call assert_equal('cf', g:Xpath)
1007
1008  XpathINIT
1009  try
1010    call T16_I()
1011  catch /E584:/
1012    Xpath 'g'
1013  endtry
1014  call assert_equal('cg', g:Xpath)
1015endfunc
1016
1017"-------------------------------------------------------------------------------
1018" Test 17:  Nesting of unmatched :if or :endif inside a :while		    {{{1
1019"
1020"	    The :while/:endwhile takes precedence in nesting over an unclosed
1021"	    :if or an unopened :endif.
1022"-------------------------------------------------------------------------------
1023
1024" While loops inside a function are continued on error.
1025func T17_F()
1026  let loops = 3
1027  while loops > 0
1028    let loops -= 1
1029    Xpath 'a' . loops
1030    if (loops == 1)
1031      Xpath 'b' . loops
1032      continue
1033    elseif (loops == 0)
1034      Xpath 'c' . loops
1035      break
1036    elseif 1
1037      Xpath 'd' . loops
1038    " endif missing!
1039  endwhile	" :endwhile after :if 1
1040  Xpath 'e'
1041endfunc
1042
1043func T17_G()
1044  let loops = 2
1045  while loops > 0
1046    let loops -= 1
1047    Xpath 'a' . loops
1048    if 0
1049      Xpath 'b' . loops
1050    " endif missing
1051  endwhile	" :endwhile after :if 0
1052endfunc
1053
1054func T17_H()
1055  let loops = 2
1056  while loops > 0
1057    let loops -= 1
1058    Xpath 'a' . loops
1059    " if missing!
1060    endif	" :endif without :if in while
1061    Xpath 'b' . loops
1062  endwhile
1063endfunc
1064
1065" Error continuation outside a function is at the outermost :endwhile or :endif.
1066XpathINIT
1067let v:errmsg = ''
1068let loops = 2
1069while loops > 0
1070    let loops -= 1
1071    Xpath 'a' . loops
1072    if 0
1073	Xpath 'b' . loops
1074    " endif missing! Following :endwhile fails.
1075endwhile | Xpath 'c'
1076Xpath 'd'
1077call assert_match('E171:', v:errmsg)
1078call assert_equal('a1d', g:Xpath)
1079
1080func Test_unmatched_if_in_while()
1081  XpathINIT
1082  call assert_fails('call T17_F()', 'E171:')
1083  call assert_equal('a2d2a1b1a0c0e', g:Xpath)
1084
1085  XpathINIT
1086  call assert_fails('call T17_G()', 'E171:')
1087  call assert_equal('a1a0', g:Xpath)
1088
1089  XpathINIT
1090  call assert_fails('call T17_H()', 'E580:')
1091  call assert_equal('a1b1a0b0', g:Xpath)
1092endfunc
1093
1094"-------------------------------------------------------------------------------
1095"-------------------------------------------------------------------------------
1096"-------------------------------------------------------------------------------
1097" Test 87   using (expr) ? funcref : funcref				    {{{1
1098"
1099"	    Vim needs to correctly parse the funcref and even when it does
1100"	    not execute the funcref, it needs to consume the trailing ()
1101"-------------------------------------------------------------------------------
1102
1103func Add2(x1, x2)
1104  return a:x1 + a:x2
1105endfu
1106
1107func GetStr()
1108  return "abcdefghijklmnopqrstuvwxyp"
1109endfu
1110
1111func Test_funcref_with_condexpr()
1112  call assert_equal(5, function('Add2')(2,3))
1113
1114  call assert_equal(3, 1 ? function('Add2')(1,2) : function('Add2')(2,3))
1115  call assert_equal(5, 0 ? function('Add2')(1,2) : function('Add2')(2,3))
1116  " Make sure, GetStr() still works.
1117  call assert_equal('abcdefghijk', GetStr()[0:10])
1118endfunc
1119
1120" Test 90:  Recognizing {} in variable name.			    {{{1
1121"-------------------------------------------------------------------------------
1122
1123func Test_curlies()
1124    let s:var = 66
1125    let ns = 's'
1126    call assert_equal(66, {ns}:var)
1127
1128    let g:a = {}
1129    let g:b = 't'
1130    let g:a[g:b] = 77
1131    call assert_equal(77, g:a['t'])
1132endfunc
1133
1134"-------------------------------------------------------------------------------
1135" Test 91:  using type().					    {{{1
1136"-------------------------------------------------------------------------------
1137
1138func Test_type()
1139    call assert_equal(0, type(0))
1140    call assert_equal(1, type(""))
1141    call assert_equal(2, type(function("tr")))
1142    call assert_equal(2, type(function("tr", [8])))
1143    call assert_equal(3, type([]))
1144    call assert_equal(4, type({}))
1145    if has('float')
1146      call assert_equal(5, type(0.0))
1147    endif
1148    call assert_equal(6, type(v:false))
1149    call assert_equal(6, type(v:true))
1150    call assert_equal(7, type(v:none))
1151    call assert_equal(7, type(v:null))
1152    call assert_equal(8, v:t_job)
1153    call assert_equal(9, v:t_channel)
1154    call assert_equal(v:t_number, type(0))
1155    call assert_equal(v:t_string, type(""))
1156    call assert_equal(v:t_func, type(function("tr")))
1157    call assert_equal(v:t_func, type(function("tr", [8])))
1158    call assert_equal(v:t_list, type([]))
1159    call assert_equal(v:t_dict, type({}))
1160    if has('float')
1161      call assert_equal(v:t_float, type(0.0))
1162    endif
1163    call assert_equal(v:t_bool, type(v:false))
1164    call assert_equal(v:t_bool, type(v:true))
1165    call assert_equal(v:t_none, type(v:none))
1166    call assert_equal(v:t_none, type(v:null))
1167    call assert_equal(v:t_string, type(test_null_string()))
1168    call assert_equal(v:t_func, type(test_null_function()))
1169    call assert_equal(v:t_func, type(test_null_partial()))
1170    call assert_equal(v:t_list, type(test_null_list()))
1171    call assert_equal(v:t_dict, type(test_null_dict()))
1172    if has('job')
1173      call assert_equal(v:t_job, type(test_null_job()))
1174    endif
1175    if has('channel')
1176      call assert_equal(v:t_channel, type(test_null_channel()))
1177    endif
1178    call assert_equal(v:t_blob, type(test_null_blob()))
1179
1180    call assert_fails("call type(test_void())", 'E685:')
1181    call assert_fails("call type(test_unknown())", 'E685:')
1182
1183    call assert_equal(0, 0 + v:false)
1184    call assert_equal(1, 0 + v:true)
1185    call assert_equal(0, 0 + v:none)
1186    call assert_equal(0, 0 + v:null)
1187
1188    call assert_equal('v:false', '' . v:false)
1189    call assert_equal('v:true', '' . v:true)
1190    call assert_equal('v:none', '' . v:none)
1191    call assert_equal('v:null', '' . v:null)
1192
1193    call assert_true(v:false == 0)
1194    call assert_false(v:false != 0)
1195    call assert_true(v:true == 1)
1196    call assert_false(v:true != 1)
1197    call assert_false(v:true == v:false)
1198    call assert_true(v:true != v:false)
1199
1200    call assert_true(v:null == 0)
1201    call assert_false(v:null != 0)
1202    call assert_true(v:none == 0)
1203    call assert_false(v:none != 0)
1204
1205    call assert_true(v:false is v:false)
1206    call assert_true(v:true is v:true)
1207    call assert_true(v:none is v:none)
1208    call assert_true(v:null is v:null)
1209
1210    call assert_false(v:false isnot v:false)
1211    call assert_false(v:true isnot v:true)
1212    call assert_false(v:none isnot v:none)
1213    call assert_false(v:null isnot v:null)
1214
1215    call assert_false(v:false is 0)
1216    call assert_false(v:true is 1)
1217    call assert_false(v:true is v:false)
1218    call assert_false(v:none is 0)
1219    call assert_false(v:null is 0)
1220    call assert_false(v:null is v:none)
1221
1222    call assert_true(v:false isnot 0)
1223    call assert_true(v:true isnot 1)
1224    call assert_true(v:true isnot v:false)
1225    call assert_true(v:none isnot 0)
1226    call assert_true(v:null isnot 0)
1227    call assert_true(v:null isnot v:none)
1228
1229    call assert_equal(v:false, eval(string(v:false)))
1230    call assert_equal(v:true, eval(string(v:true)))
1231    call assert_equal(v:none, eval(string(v:none)))
1232    call assert_equal(v:null, eval(string(v:null)))
1233
1234    call assert_equal(v:false, copy(v:false))
1235    call assert_equal(v:true, copy(v:true))
1236    call assert_equal(v:none, copy(v:none))
1237    call assert_equal(v:null, copy(v:null))
1238
1239    call assert_equal([v:false], deepcopy([v:false]))
1240    call assert_equal([v:true], deepcopy([v:true]))
1241    call assert_equal([v:none], deepcopy([v:none]))
1242    call assert_equal([v:null], deepcopy([v:null]))
1243
1244    call assert_true(empty(v:false))
1245    call assert_false(empty(v:true))
1246    call assert_true(empty(v:null))
1247    call assert_true(empty(v:none))
1248
1249    func ChangeYourMind()
1250	try
1251	    return v:true
1252	finally
1253	    return 'something else'
1254	endtry
1255    endfunc
1256
1257    call ChangeYourMind()
1258endfunc
1259
1260"-------------------------------------------------------------------------------
1261" Test 92:  skipping code					    {{{1
1262"-------------------------------------------------------------------------------
1263
1264func Test_skip()
1265    let Fn = function('Test_type')
1266    call assert_false(0 && Fn[1])
1267    call assert_false(0 && string(Fn))
1268    call assert_false(0 && len(Fn))
1269    let l = []
1270    call assert_false(0 && l[1])
1271    call assert_false(0 && string(l))
1272    call assert_false(0 && len(l))
1273    let f = 1.0
1274    call assert_false(0 && f[1])
1275    call assert_false(0 && string(f))
1276    call assert_false(0 && len(f))
1277    let sp = v:null
1278    call assert_false(0 && sp[1])
1279    call assert_false(0 && string(sp))
1280    call assert_false(0 && len(sp))
1281
1282endfunc
1283
1284"-------------------------------------------------------------------------------
1285" Test 93:  :echo and string()					    {{{1
1286"-------------------------------------------------------------------------------
1287
1288func Test_echo_and_string()
1289    " String
1290    let a = 'foo bar'
1291    redir => result
1292    echo a
1293    echo string(a)
1294    redir END
1295    let l = split(result, "\n")
1296    call assert_equal(["foo bar",
1297		     \ "'foo bar'"], l)
1298
1299    " Float
1300    if has('float')
1301	let a = -1.2e0
1302	redir => result
1303	echo a
1304	echo string(a)
1305	redir END
1306	let l = split(result, "\n")
1307	call assert_equal(["-1.2",
1308			 \ "-1.2"], l)
1309    endif
1310
1311    " Funcref
1312    redir => result
1313    echo function('string')
1314    echo string(function('string'))
1315    redir END
1316    let l = split(result, "\n")
1317    call assert_equal(["string",
1318		     \ "function('string')"], l)
1319
1320    " Recursive dictionary
1321    let a = {}
1322    let a["a"] = a
1323    redir => result
1324    echo a
1325    echo string(a)
1326    redir END
1327    let l = split(result, "\n")
1328    call assert_equal(["{'a': {...}}",
1329		     \ "{'a': {...}}"], l)
1330
1331    " Recursive list
1332    let a = [0]
1333    let a[0] = a
1334    redir => result
1335    echo a
1336    echo string(a)
1337    redir END
1338    let l = split(result, "\n")
1339    call assert_equal(["[[...]]",
1340		     \ "[[...]]"], l)
1341
1342    " Empty dictionaries in a list
1343    let a = {}
1344    redir => result
1345    echo [a, a, a]
1346    echo string([a, a, a])
1347    redir END
1348    let l = split(result, "\n")
1349    call assert_equal(["[{}, {}, {}]",
1350		     \ "[{}, {}, {}]"], l)
1351
1352    " Empty dictionaries in a dictionary
1353    let a = {}
1354    let b = {"a": a, "b": a}
1355    redir => result
1356    echo b
1357    echo string(b)
1358    redir END
1359    let l = split(result, "\n")
1360    call assert_equal(["{'a': {}, 'b': {}}",
1361		     \ "{'a': {}, 'b': {}}"], l)
1362
1363    " Empty lists in a list
1364    let a = []
1365    redir => result
1366    echo [a, a, a]
1367    echo string([a, a, a])
1368    redir END
1369    let l = split(result, "\n")
1370    call assert_equal(["[[], [], []]",
1371		     \ "[[], [], []]"], l)
1372
1373    " Empty lists in a dictionary
1374    let a = []
1375    let b = {"a": a, "b": a}
1376    redir => result
1377    echo b
1378    echo string(b)
1379    redir END
1380    let l = split(result, "\n")
1381    call assert_equal(["{'a': [], 'b': []}",
1382		     \ "{'a': [], 'b': []}"], l)
1383
1384    " Dictionaries in a list
1385    let a = {"one": "yes", "two": "yes", "three": "yes"}
1386    redir => result
1387    echo [a, a, a]
1388    echo string([a, a, a])
1389    redir END
1390    let l = split(result, "\n")
1391    call assert_equal(["[{'one': 'yes', 'two': 'yes', 'three': 'yes'}, {...}, {...}]",
1392		     \ "[{'one': 'yes', 'two': 'yes', 'three': 'yes'}, {'one': 'yes', 'two': 'yes', 'three': 'yes'}, {'one': 'yes', 'two': 'yes', 'three': 'yes'}]"], l)
1393
1394    " Dictionaries in a dictionary
1395    let a = {"one": "yes", "two": "yes", "three": "yes"}
1396    let b = {"a": a, "b": a}
1397    redir => result
1398    echo b
1399    echo string(b)
1400    redir END
1401    let l = split(result, "\n")
1402    call assert_equal(["{'a': {'one': 'yes', 'two': 'yes', 'three': 'yes'}, 'b': {...}}",
1403		     \ "{'a': {'one': 'yes', 'two': 'yes', 'three': 'yes'}, 'b': {'one': 'yes', 'two': 'yes', 'three': 'yes'}}"], l)
1404
1405    " Lists in a list
1406    let a = [1, 2, 3]
1407    redir => result
1408    echo [a, a, a]
1409    echo string([a, a, a])
1410    redir END
1411    let l = split(result, "\n")
1412    call assert_equal(["[[1, 2, 3], [...], [...]]",
1413		     \ "[[1, 2, 3], [1, 2, 3], [1, 2, 3]]"], l)
1414
1415    " Lists in a dictionary
1416    let a = [1, 2, 3]
1417    let b = {"a": a, "b": a}
1418    redir => result
1419    echo b
1420    echo string(b)
1421    redir END
1422    let l = split(result, "\n")
1423    call assert_equal(["{'a': [1, 2, 3], 'b': [...]}",
1424		     \ "{'a': [1, 2, 3], 'b': [1, 2, 3]}"], l)
1425
1426    call assert_fails('echo &:', 'E112:')
1427    call assert_fails('echo &g:', 'E112:')
1428    call assert_fails('echo &l:', 'E112:')
1429
1430endfunc
1431
1432"-------------------------------------------------------------------------------
1433" Test 94:  64-bit Numbers					    {{{1
1434"-------------------------------------------------------------------------------
1435
1436func Test_num64()
1437    call assert_notequal( 4294967296, 0)
1438    call assert_notequal(-4294967296, 0)
1439    call assert_equal( 4294967296,  0xFFFFffff + 1)
1440    call assert_equal(-4294967296, -0xFFFFffff - 1)
1441
1442    call assert_equal( 9223372036854775807,  1 / 0)
1443    call assert_equal(-9223372036854775807, -1 / 0)
1444    call assert_equal(-9223372036854775807 - 1,  0 / 0)
1445
1446    if has('float')
1447      call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150))
1448      call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150))
1449    endif
1450
1451    let rng = range(0xFFFFffff, 0x100000001)
1452    call assert_equal([0xFFFFffff, 0x100000000, 0x100000001], rng)
1453    call assert_equal(0x100000001, max(rng))
1454    call assert_equal(0xFFFFffff, min(rng))
1455    call assert_equal(rng, sort(range(0x100000001, 0xFFFFffff, -1), 'N'))
1456endfunc
1457
1458"-------------------------------------------------------------------------------
1459" Test 95:  lines of :append, :change, :insert			    {{{1
1460"-------------------------------------------------------------------------------
1461
1462function! DefineFunction(name, body)
1463    let func = join(['function! ' . a:name . '()'] + a:body + ['endfunction'], "\n")
1464    exec func
1465endfunction
1466
1467func Test_script_lines()
1468    " :append
1469    try
1470	call DefineFunction('T_Append', [
1471		    \ 'append',
1472		    \ 'py <<EOS',
1473		    \ '.',
1474		    \ ])
1475    catch
1476	call assert_report("Can't define function")
1477    endtry
1478    try
1479	call DefineFunction('T_Append', [
1480		    \ 'append',
1481		    \ 'abc',
1482		    \ ])
1483	call assert_report("Shouldn't be able to define function")
1484    catch
1485	call assert_exception('Vim(function):E126: Missing :endfunction')
1486    endtry
1487
1488    " :change
1489    try
1490	call DefineFunction('T_Change', [
1491		    \ 'change',
1492		    \ 'py <<EOS',
1493		    \ '.',
1494		    \ ])
1495    catch
1496	call assert_report("Can't define function")
1497    endtry
1498    try
1499	call DefineFunction('T_Change', [
1500		    \ 'change',
1501		    \ 'abc',
1502		    \ ])
1503	call assert_report("Shouldn't be able to define function")
1504    catch
1505	call assert_exception('Vim(function):E126: Missing :endfunction')
1506    endtry
1507
1508    " :insert
1509    try
1510	call DefineFunction('T_Insert', [
1511		    \ 'insert',
1512		    \ 'py <<EOS',
1513		    \ '.',
1514		    \ ])
1515    catch
1516	call assert_report("Can't define function")
1517    endtry
1518    try
1519	call DefineFunction('T_Insert', [
1520		    \ 'insert',
1521		    \ 'abc',
1522		    \ ])
1523	call assert_report("Shouldn't be able to define function")
1524    catch
1525	call assert_exception('Vim(function):E126: Missing :endfunction')
1526    endtry
1527endfunc
1528
1529"-------------------------------------------------------------------------------
1530" Test 96:  line continuation						    {{{1
1531"
1532"	    Undefined behavior was detected by ubsan with line continuation
1533"	    after an empty line.
1534"-------------------------------------------------------------------------------
1535func Test_script_emty_line_continuation()
1536
1537    \
1538endfunc
1539
1540"-------------------------------------------------------------------------------
1541" Test 97:  bitwise functions						    {{{1
1542"-------------------------------------------------------------------------------
1543func Test_bitwise_functions()
1544    " and
1545    call assert_equal(127, and(127, 127))
1546    call assert_equal(16, and(127, 16))
1547    eval 127->and(16)->assert_equal(16)
1548    call assert_equal(0, and(127, 128))
1549    call assert_fails("call and([], 1)", 'E745:')
1550    call assert_fails("call and({}, 1)", 'E728:')
1551    if has('float')
1552      call assert_fails("call and(1.0, 1)", 'E805:')
1553      call assert_fails("call and(1, 1.0)", 'E805:')
1554    endif
1555    call assert_fails("call and(1, [])", 'E745:')
1556    call assert_fails("call and(1, {})", 'E728:')
1557    " or
1558    call assert_equal(23, or(16, 7))
1559    call assert_equal(15, or(8, 7))
1560    eval 8->or(7)->assert_equal(15)
1561    call assert_equal(123, or(0, 123))
1562    call assert_fails("call or([], 1)", 'E745:')
1563    call assert_fails("call or({}, 1)", 'E728:')
1564    if has('float')
1565      call assert_fails("call or(1.0, 1)", 'E805:')
1566      call assert_fails("call or(1, 1.0)", 'E805:')
1567    endif
1568    call assert_fails("call or(1, [])", 'E745:')
1569    call assert_fails("call or(1, {})", 'E728:')
1570    " xor
1571    call assert_equal(0, xor(127, 127))
1572    call assert_equal(111, xor(127, 16))
1573    eval 127->xor(16)->assert_equal(111)
1574    call assert_equal(255, xor(127, 128))
1575    if has('float')
1576      call assert_fails("call xor(1.0, 1)", 'E805:')
1577      call assert_fails("call xor(1, 1.0)", 'E805:')
1578    endif
1579    call assert_fails("call xor([], 1)", 'E745:')
1580    call assert_fails("call xor({}, 1)", 'E728:')
1581    call assert_fails("call xor(1, [])", 'E745:')
1582    call assert_fails("call xor(1, {})", 'E728:')
1583    " invert
1584    call assert_equal(65408, and(invert(127), 65535))
1585    eval 127->invert()->and(65535)->assert_equal(65408)
1586    call assert_equal(65519, and(invert(16), 65535))
1587    call assert_equal(65407, and(invert(128), 65535))
1588    if has('float')
1589      call assert_fails("call invert(1.0)", 'E805:')
1590    endif
1591    call assert_fails("call invert([])", 'E745:')
1592    call assert_fails("call invert({})", 'E728:')
1593endfunc
1594
1595" Test using bang after user command				    {{{1
1596func Test_user_command_with_bang()
1597    command -bang Nieuw let nieuw = 1
1598    Ni!
1599    call assert_equal(1, nieuw)
1600    unlet nieuw
1601    delcommand Nieuw
1602endfunc
1603
1604func Test_script_expand_sfile()
1605  let lines =<< trim END
1606    func s:snr()
1607      return expand('<sfile>')
1608    endfunc
1609    let g:result = s:snr()
1610  END
1611  call writefile(lines, 'Xexpand')
1612  source Xexpand
1613  call assert_match('<SNR>\d\+_snr', g:result)
1614  source Xexpand
1615  call assert_match('<SNR>\d\+_snr', g:result)
1616
1617  call delete('Xexpand')
1618  unlet g:result
1619endfunc
1620
1621func Test_compound_assignment_operators()
1622    " Test for number
1623    let x = 1
1624    let x += 10
1625    call assert_equal(11, x)
1626    let x -= 5
1627    call assert_equal(6, x)
1628    let x *= 4
1629    call assert_equal(24, x)
1630    let x /= 3
1631    call assert_equal(8, x)
1632    let x %= 3
1633    call assert_equal(2, x)
1634    let x .= 'n'
1635    call assert_equal('2n', x)
1636
1637    " Test special cases: division or modulus with 0.
1638    let x = 1
1639    let x /= 0
1640    call assert_equal(0x7FFFFFFFFFFFFFFF, x)
1641
1642    let x = -1
1643    let x /= 0
1644    call assert_equal(-0x7FFFFFFFFFFFFFFF, x)
1645
1646    let x = 0
1647    let x /= 0
1648    call assert_equal(-0x7FFFFFFFFFFFFFFF - 1, x)
1649
1650    let x = 1
1651    let x %= 0
1652    call assert_equal(0, x)
1653
1654    let x = -1
1655    let x %= 0
1656    call assert_equal(0, x)
1657
1658    let x = 0
1659    let x %= 0
1660    call assert_equal(0, x)
1661
1662    " Test for string
1663    let x = 'str'
1664    let x .= 'ing'
1665    call assert_equal('string', x)
1666    let x += 1
1667    call assert_equal(1, x)
1668
1669    if has('float')
1670      " Test for float
1671      let x -= 1.5
1672      call assert_equal(-0.5, x)
1673      let x = 0.5
1674      let x += 4.5
1675      call assert_equal(5.0, x)
1676      let x -= 1.5
1677      call assert_equal(3.5, x)
1678      let x *= 3.0
1679      call assert_equal(10.5, x)
1680      let x /= 2.5
1681      call assert_equal(4.2, x)
1682      call assert_fails('let x %= 0.5', 'E734')
1683      call assert_fails('let x .= "f"', 'E734')
1684      let x = !3.14
1685      call assert_equal(0.0, x)
1686
1687      " integer and float operations
1688      let x = 1
1689      let x *= 2.1
1690      call assert_equal(2.1, x)
1691      let x = 1
1692      let x /= 0.25
1693      call assert_equal(4.0, x)
1694      let x = 1
1695      call assert_fails('let x %= 0.25', 'E734:')
1696      let x = 1
1697      call assert_fails('let x .= 0.25', 'E734:')
1698      let x = 1.0
1699      call assert_fails('let x += [1.1]', 'E734:')
1700    endif
1701
1702    " Test for environment variable
1703    let $FOO = 1
1704    call assert_fails('let $FOO += 1', 'E734')
1705    call assert_fails('let $FOO -= 1', 'E734')
1706    call assert_fails('let $FOO *= 1', 'E734')
1707    call assert_fails('let $FOO /= 1', 'E734')
1708    call assert_fails('let $FOO %= 1', 'E734')
1709    let $FOO .= 's'
1710    call assert_equal('1s', $FOO)
1711    unlet $FOO
1712
1713    " Test for option variable (type: number)
1714    let &scrolljump = 1
1715    let &scrolljump += 5
1716    call assert_equal(6, &scrolljump)
1717    let &scrolljump -= 2
1718    call assert_equal(4, &scrolljump)
1719    let &scrolljump *= 3
1720    call assert_equal(12, &scrolljump)
1721    let &scrolljump /= 2
1722    call assert_equal(6, &scrolljump)
1723    let &scrolljump %= 5
1724    call assert_equal(1, &scrolljump)
1725    call assert_fails('let &scrolljump .= "j"', 'E734')
1726    set scrolljump&vim
1727
1728    " Test for register
1729    let @/ = 1
1730    call assert_fails('let @/ += 1', 'E734')
1731    call assert_fails('let @/ -= 1', 'E734')
1732    call assert_fails('let @/ *= 1', 'E734')
1733    call assert_fails('let @/ /= 1', 'E734')
1734    call assert_fails('let @/ %= 1', 'E734')
1735    let @/ .= 's'
1736    call assert_equal('1s', @/)
1737    let @/ = ''
1738endfunc
1739
1740func Test_unlet_env()
1741  let $TESTVAR = 'yes'
1742  call assert_equal('yes', $TESTVAR)
1743  call assert_fails('lockvar $TESTVAR', 'E940')
1744  call assert_fails('unlockvar $TESTVAR', 'E940')
1745  call assert_equal('yes', $TESTVAR)
1746  if 0
1747    unlet $TESTVAR
1748  endif
1749  call assert_equal('yes', $TESTVAR)
1750  unlet $TESTVAR
1751  call assert_equal('', $TESTVAR)
1752endfunc
1753
1754func Test_refcount()
1755    " Immediate values
1756    call assert_equal(-1, test_refcount(1))
1757    call assert_equal(-1, test_refcount('s'))
1758    call assert_equal(-1, test_refcount(v:true))
1759    call assert_equal(0, test_refcount([]))
1760    call assert_equal(0, test_refcount({}))
1761    call assert_equal(0, test_refcount(0zff))
1762    call assert_equal(0, test_refcount({-> line('.')}))
1763    if has('float')
1764        call assert_equal(-1, test_refcount(0.1))
1765    endif
1766    if has('job')
1767        call assert_equal(0, test_refcount(job_start([&shell, &shellcmdflag, 'echo .'])))
1768    endif
1769
1770    " No refcount types
1771    let x = 1
1772    call assert_equal(-1, test_refcount(x))
1773    let x = 's'
1774    call assert_equal(-1, test_refcount(x))
1775    let x = v:true
1776    call assert_equal(-1, test_refcount(x))
1777    if has('float')
1778        let x = 0.1
1779        call assert_equal(-1, test_refcount(x))
1780    endif
1781
1782    " Check refcount
1783    let x = []
1784    call assert_equal(1, test_refcount(x))
1785
1786    let x = {}
1787    call assert_equal(1, x->test_refcount())
1788
1789    let x = 0zff
1790    call assert_equal(1, test_refcount(x))
1791
1792    let X = {-> line('.')}
1793    call assert_equal(1, test_refcount(X))
1794    let Y = X
1795    call assert_equal(2, test_refcount(X))
1796
1797    if has('job')
1798        let job = job_start([&shell, &shellcmdflag, 'echo .'])
1799        call assert_equal(1, test_refcount(job))
1800        call assert_equal(1, test_refcount(job_getchannel(job)))
1801        call assert_equal(1, test_refcount(job))
1802    endif
1803
1804    " Function arguments, copying and unassigning
1805    func ExprCheck(x, i)
1806        let i = a:i + 1
1807        call assert_equal(i, test_refcount(a:x))
1808        let Y = a:x
1809        call assert_equal(i + 1, test_refcount(a:x))
1810        call assert_equal(test_refcount(a:x), test_refcount(Y))
1811        let Y = 0
1812        call assert_equal(i, test_refcount(a:x))
1813    endfunc
1814    call ExprCheck([], 0)
1815    call ExprCheck({}, 0)
1816    call ExprCheck(0zff, 0)
1817    call ExprCheck({-> line('.')}, 0)
1818    if has('job')
1819	call ExprCheck(job, 1)
1820	call ExprCheck(job_getchannel(job), 1)
1821	call job_stop(job)
1822    endif
1823    delfunc ExprCheck
1824
1825    " Regarding function
1826    func Func(x) abort
1827        call assert_equal(2, test_refcount(function('Func')))
1828        call assert_equal(0, test_refcount(funcref('Func')))
1829    endfunc
1830    call assert_equal(1, test_refcount(function('Func')))
1831    call assert_equal(0, test_refcount(function('Func', [1])))
1832    call assert_equal(0, test_refcount(funcref('Func')))
1833    call assert_equal(0, test_refcount(funcref('Func', [1])))
1834    let X = function('Func')
1835    let Y = X
1836    call assert_equal(1, test_refcount(X))
1837    let X = function('Func', [1])
1838    let Y = X
1839    call assert_equal(2, test_refcount(X))
1840    let X = funcref('Func')
1841    let Y = X
1842    call assert_equal(2, test_refcount(X))
1843    let X = funcref('Func', [1])
1844    let Y = X
1845    call assert_equal(2, test_refcount(X))
1846    unlet X
1847    unlet Y
1848    call Func(1)
1849    delfunc Func
1850
1851    " Function with dict
1852    func DictFunc() dict
1853        call assert_equal(3, test_refcount(self))
1854    endfunc
1855    let d = {'Func': function('DictFunc')}
1856    call assert_equal(1, test_refcount(d))
1857    call assert_equal(0, test_refcount(d.Func))
1858    call d.Func()
1859    unlet d
1860    delfunc DictFunc
1861endfunc
1862
1863" Test for missing :endif, :endfor, :endwhile and :endtry           {{{1
1864func Test_missing_end()
1865  call writefile(['if 2 > 1', 'echo ">"'], 'Xscript')
1866  call assert_fails('source Xscript', 'E171:')
1867  call writefile(['for i in range(5)', 'echo i'], 'Xscript')
1868  call assert_fails('source Xscript', 'E170:')
1869  call writefile(['while v:true', 'echo "."'], 'Xscript')
1870  call assert_fails('source Xscript', 'E170:')
1871  call writefile(['try', 'echo "."'], 'Xscript')
1872  call assert_fails('source Xscript', 'E600:')
1873  call delete('Xscript')
1874
1875  " Using endfor with :while
1876  let caught_e732 = 0
1877  try
1878    while v:true
1879    endfor
1880  catch /E732:/
1881    let caught_e732 = 1
1882  endtry
1883  call assert_equal(1, caught_e732)
1884
1885  " Using endwhile with :for
1886  let caught_e733 = 0
1887  try
1888    for i in range(1)
1889    endwhile
1890  catch /E733:/
1891    let caught_e733 = 1
1892  endtry
1893  call assert_equal(1, caught_e733)
1894
1895  " Using endfunc with :if
1896  call assert_fails('exe "if 1 | endfunc | endif"', 'E193:')
1897
1898  " Missing 'in' in a :for statement
1899  call assert_fails('for i range(1) | endfor', 'E690:')
1900
1901  " Incorrect number of variables in for
1902  call assert_fails('for [i,] in range(3) | endfor', 'E475:')
1903endfunc
1904
1905" Test for deep nesting of if/for/while/try statements              {{{1
1906func Test_deep_nest()
1907  CheckRunVimInTerminal
1908
1909  let lines =<< trim [SCRIPT]
1910    " Deep nesting of if ... endif
1911    func Test1()
1912      let @a = join(repeat(['if v:true'], 51), "\n")
1913      let @a ..= "\n"
1914      let @a ..= join(repeat(['endif'], 51), "\n")
1915      @a
1916      let @a = ''
1917    endfunc
1918
1919    " Deep nesting of for ... endfor
1920    func Test2()
1921      let @a = join(repeat(['for i in [1]'], 51), "\n")
1922      let @a ..= "\n"
1923      let @a ..= join(repeat(['endfor'], 51), "\n")
1924      @a
1925      let @a = ''
1926    endfunc
1927
1928    " Deep nesting of while ... endwhile
1929    func Test3()
1930      let @a = join(repeat(['while v:true'], 51), "\n")
1931      let @a ..= "\n"
1932      let @a ..= join(repeat(['endwhile'], 51), "\n")
1933      @a
1934      let @a = ''
1935    endfunc
1936
1937    " Deep nesting of try ... endtry
1938    func Test4()
1939      let @a = join(repeat(['try'], 51), "\n")
1940      let @a ..= "\necho v:true\n"
1941      let @a ..= join(repeat(['endtry'], 51), "\n")
1942      @a
1943      let @a = ''
1944    endfunc
1945
1946    " Deep nesting of function ... endfunction
1947    func Test5()
1948      let @a = join(repeat(['function X()'], 51), "\n")
1949      let @a ..= "\necho v:true\n"
1950      let @a ..= join(repeat(['endfunction'], 51), "\n")
1951      @a
1952      let @a = ''
1953    endfunc
1954  [SCRIPT]
1955  call writefile(lines, 'Xscript')
1956
1957  let buf = RunVimInTerminal('-S Xscript', {'rows': 6})
1958
1959  " Deep nesting of if ... endif
1960  call term_sendkeys(buf, ":call Test1()\n")
1961  call TermWait(buf)
1962  call WaitForAssert({-> assert_match('^E579:', term_getline(buf, 5))})
1963
1964  " Deep nesting of for ... endfor
1965  call term_sendkeys(buf, ":call Test2()\n")
1966  call TermWait(buf)
1967  call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
1968
1969  " Deep nesting of while ... endwhile
1970  call term_sendkeys(buf, ":call Test3()\n")
1971  call TermWait(buf)
1972  call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
1973
1974  " Deep nesting of try ... endtry
1975  call term_sendkeys(buf, ":call Test4()\n")
1976  call TermWait(buf)
1977  call WaitForAssert({-> assert_match('^E601:', term_getline(buf, 5))})
1978
1979  " Deep nesting of function ... endfunction
1980  call term_sendkeys(buf, ":call Test5()\n")
1981  call TermWait(buf)
1982  call WaitForAssert({-> assert_match('^E1058:', term_getline(buf, 4))})
1983  call term_sendkeys(buf, "\<C-C>\n")
1984  call TermWait(buf)
1985
1986  "let l = ''
1987  "for i in range(1, 6)
1988  "  let l ..= term_getline(buf, i) . "\n"
1989  "endfor
1990  "call assert_report(l)
1991
1992  call StopVimInTerminal(buf)
1993  call delete('Xscript')
1994endfunc
1995
1996" Test for errors in converting to float from various types         {{{1
1997func Test_float_conversion_errors()
1998  if has('float')
1999    call assert_fails('let x = 4.0 % 2.0', 'E804')
2000    call assert_fails('echo 1.1[0]', 'E806')
2001    call assert_fails('echo sort([function("min"), 1], "f")', 'E891:')
2002    call assert_fails('echo 3.2 == "vim"', 'E892:')
2003    call assert_fails('echo sort([[], 1], "f")', 'E893:')
2004    call assert_fails('echo sort([{}, 1], "f")', 'E894:')
2005    call assert_fails('echo 3.2 == v:true', 'E362:')
2006    call assert_fails('echo 3.2 == v:none', 'E907:')
2007  endif
2008endfunc
2009
2010" invalid function names               {{{1
2011func Test_invalid_function_names()
2012  " function name not starting with capital
2013  let caught_e128 = 0
2014  try
2015    func! g:test()
2016      echo "test"
2017    endfunc
2018  catch /E128:/
2019    let caught_e128 = 1
2020  endtry
2021  call assert_equal(1, caught_e128)
2022
2023  " function name includes a colon
2024  let caught_e884 = 0
2025  try
2026    func! b:test()
2027      echo "test"
2028    endfunc
2029  catch /E884:/
2030    let caught_e884 = 1
2031  endtry
2032  call assert_equal(1, caught_e884)
2033
2034  " function name folowed by #
2035  let caught_e128 = 0
2036  try
2037    func! test2() "#
2038      echo "test2"
2039    endfunc
2040  catch /E128:/
2041    let caught_e128 = 1
2042  endtry
2043  call assert_equal(1, caught_e128)
2044
2045  " function name starting with/without "g:", buffer-local funcref.
2046  function! g:Foo(n)
2047    return 'called Foo(' . a:n . ')'
2048  endfunction
2049  let b:my_func = function('Foo')
2050  call assert_equal('called Foo(1)', b:my_func(1))
2051  call assert_equal('called Foo(2)', g:Foo(2))
2052  call assert_equal('called Foo(3)', Foo(3))
2053  delfunc g:Foo
2054
2055  " script-local function used in Funcref must exist.
2056  let lines =<< trim END
2057    func s:Testje()
2058      return "foo"
2059    endfunc
2060    let Bar = function('s:Testje')
2061    call assert_equal(0, exists('s:Testje'))
2062    call assert_equal(1, exists('*s:Testje'))
2063    call assert_equal(1, exists('Bar'))
2064    call assert_equal(1, exists('*Bar'))
2065  END
2066  call writefile(lines, 'Xscript')
2067  source Xscript
2068  call delete('Xscript')
2069endfunc
2070
2071" substring and variable name              {{{1
2072func Test_substring_var()
2073  let str = 'abcdef'
2074  let n = 3
2075  call assert_equal('def', str[n:])
2076  call assert_equal('abcd', str[:n])
2077  call assert_equal('d', str[n:n])
2078  unlet n
2079  let nn = 3
2080  call assert_equal('def', str[nn:])
2081  call assert_equal('abcd', str[:nn])
2082  call assert_equal('d', str[nn:nn])
2083  unlet nn
2084  let b:nn = 4
2085  call assert_equal('ef', str[b:nn:])
2086  call assert_equal('abcde', str[:b:nn])
2087  call assert_equal('e', str[b:nn:b:nn])
2088  unlet b:nn
2089endfunc
2090
2091" Test using s: with a typed command              {{{1
2092func Test_typed_script_var()
2093  CheckRunVimInTerminal
2094
2095  let buf = RunVimInTerminal('', {'rows': 6})
2096
2097  " Deep nesting of if ... endif
2098  call term_sendkeys(buf, ":echo get(s:, 'foo', 'x')\n")
2099  call TermWait(buf)
2100  call WaitForAssert({-> assert_match('^E116:', term_getline(buf, 5))})
2101
2102  call StopVimInTerminal(buf)
2103endfunc
2104
2105"-------------------------------------------------------------------------------
2106" Modelines								    {{{1
2107" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
2108"-------------------------------------------------------------------------------
2109