blob: b5ad14c2a57dfe5ef8747a5ceb355bf518ca33b3 [file] [log] [blame]
Bram Moolenaar1f068232019-11-03 16:17:26 +01001" Test try-catch-finally exception handling
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" Test 25: Executing :finally clauses on normal control flow {{{1
15"
16" Control flow in a :try conditional should always fall through to its
17" :finally clause. A :finally clause of a :try conditional inside an
18" inactive conditional should never be executed.
19"-------------------------------------------------------------------------------
20
21func T25_F()
22 let loops = 3
23 while loops > 0
24 Xpath 'a' . loops
25 if loops >= 2
26 try
27 Xpath 'b' . loops
28 if loops == 2
29 try
30 Xpath 'c' . loops
31 finally
32 Xpath 'd' . loops
33 endtry
34 endif
35 finally
36 Xpath 'e' . loops
37 if loops == 2
38 try
39 Xpath 'f' . loops
Bram Moolenaar373863e2020-09-26 17:20:53 +020040 final
Bram Moolenaar1f068232019-11-03 16:17:26 +010041 Xpath 'g' . loops
42 endtry
43 endif
44 endtry
45 endif
46 Xpath 'h' . loops
47 let loops = loops - 1
48 endwhile
49 Xpath 'i'
50endfunc
51
Bram Moolenaar373863e2020-09-26 17:20:53 +020052" Also try using "fina" and "final" and "finall" as abbraviations.
Bram Moolenaar1f068232019-11-03 16:17:26 +010053func T25_G()
54 if 1
55 try
56 Xpath 'A'
57 call T25_F()
58 Xpath 'B'
Bram Moolenaar373863e2020-09-26 17:20:53 +020059 fina
Bram Moolenaar1f068232019-11-03 16:17:26 +010060 Xpath 'C'
61 endtry
62 else
63 try
64 Xpath 'D'
Bram Moolenaar373863e2020-09-26 17:20:53 +020065 finall
Bram Moolenaar1f068232019-11-03 16:17:26 +010066 Xpath 'E'
67 endtry
68 endif
69endfunc
70
71func Test_finally()
72 XpathINIT
73 call T25_G()
74 call assert_equal('Aa3b3e3h3a2b2c2d2e2f2g2h2a1h1iBC', g:Xpath)
75endfunc
76
77
78"-------------------------------------------------------------------------------
79" Test 26: Executing :finally clauses after :continue or :break {{{1
80"
81" For a :continue or :break dynamically enclosed in a :try/:endtry
82" region inside the next surrounding :while/:endwhile, if the
83" :continue/:break is before the :finally, the :finally clause is
84" executed first. If the :continue/:break is after the :finally, the
85" :finally clause is broken (like an :if/:endif region).
86"-------------------------------------------------------------------------------
87
88func T26_F()
89 try
90 let loops = 3
91 while loops > 0
92 try
93 try
94 if loops == 2
95 Xpath 'a' . loops
96 let loops = loops - 1
97 continue
98 elseif loops == 1
99 Xpath 'b' . loops
100 break
101 finish
102 endif
103 Xpath 'c' . loops
104 endtry
105 finally
106 Xpath 'd' . loops
107 endtry
108 Xpath 'e' . loops
109 let loops = loops - 1
110 endwhile
111 Xpath 'f'
112 finally
113 Xpath 'g'
114 let loops = 3
115 while loops > 0
116 try
117 finally
118 try
119 if loops == 2
120 Xpath 'h' . loops
121 let loops = loops - 1
122 continue
123 elseif loops == 1
124 Xpath 'i' . loops
125 break
126 finish
127 endif
128 endtry
129 Xpath 'j' . loops
130 endtry
131 Xpath 'k' . loops
132 let loops = loops - 1
133 endwhile
134 Xpath 'l'
135 endtry
136 Xpath 'm'
137endfunc
138
139func Test_finally_after_continue()
140 XpathINIT
141 call T26_F()
142 call assert_equal('c3d3e3a2d1b1d1fgj3k3h2i1lm', g:Xpath)
143endfunc
144
145
146"-------------------------------------------------------------------------------
147" Test 32: Remembering the :return value on :finally {{{1
148"
149" If a :finally clause is executed due to a :return specifying
150" a value, this is the value visible to the caller if not overwritten
151" by a new :return in the :finally clause. A :return without a value
152" in the :finally clause overwrites with value 0.
153"-------------------------------------------------------------------------------
154
155func T32_F()
156 try
157 Xpath 'a'
158 try
159 Xpath 'b'
160 return "ABCD"
161 Xpath 'c'
162 finally
163 Xpath 'd'
164 endtry
165 Xpath 'e'
166 finally
167 Xpath 'f'
168 endtry
169 Xpath 'g'
170endfunc
171
172func T32_G()
173 try
174 Xpath 'h'
175 return 8
176 Xpath 'i'
177 finally
178 Xpath 'j'
179 return 16 + strlen(T32_F())
180 Xpath 'k'
181 endtry
182 Xpath 'l'
183endfunc
184
185func T32_H()
186 try
187 Xpath 'm'
188 return 32
189 Xpath 'n'
190 finally
191 Xpath 'o'
192 return
193 Xpath 'p'
194 endtry
195 Xpath 'q'
196endfunc
197
198func T32_I()
199 try
200 Xpath 'r'
201 finally
202 Xpath 's'
203 return T32_G() + T32_H() + 64
204 Xpath 't'
205 endtry
206 Xpath 'u'
207endfunc
208
209func Test_finally_return()
210 XpathINIT
211 call assert_equal(84, T32_I())
212 call assert_equal('rshjabdfmo', g:Xpath)
213endfunc
214
215"-------------------------------------------------------------------------------
216" Test 33: :return under :execute or user command and :finally {{{1
217"
218" A :return command may be executed under an ":execute" or from
219" a user command. Executing of :finally clauses and passing through
220" the return code works also then.
221"-------------------------------------------------------------------------------
222
223func T33_F()
224 try
225 RETURN 10
226 Xpath 'a'
227 finally
228 Xpath 'b'
229 endtry
230 Xpath 'c'
231endfunc
232
233func T33_G()
234 try
235 RETURN 20
236 Xpath 'd'
237 finally
238 Xpath 'e'
239 RETURN 30
240 Xpath 'f'
241 endtry
242 Xpath 'g'
243endfunc
244
245func T33_H()
246 try
247 execute "try | return 40 | finally | return 50 | endtry"
248 Xpath 'h'
249 finally
250 Xpath 'i'
251 endtry
252 Xpath 'j'
253endfunc
254
255func T33_I()
256 try
257 execute "try | return 60 | finally | return 70 | endtry"
258 Xpath 'k'
259 finally
260 Xpath 'l'
261 execute "try | return 80 | finally | return 90 | endtry"
262 Xpath 'm'
263 endtry
264 Xpath 'n'
265endfunc
266
267func T33_J()
268 try
269 RETURN 100
270 Xpath 'o'
271 finally
272 Xpath 'p'
273 return
274 Xpath 'q'
275 endtry
276 Xpath 'r'
277endfunc
278
279func T33_K()
280 try
281 execute "try | return 110 | finally | return 120 | endtry"
282 Xpath 's'
283 finally
284 Xpath 't'
285 execute "try | return 130 | finally | return | endtry"
286 Xpath 'u'
287 endtry
288 Xpath 'v'
289endfunc
290
291func T33_L()
292 try
293 return
294 Xpath 'w'
295 finally
296 Xpath 'x'
297 RETURN 140
298 Xpath 'y'
299 endtry
300 Xpath 'z'
301endfunc
302
303func T33_M()
304 try
305 return
306 Xpath 'A'
307 finally
308 Xpath 'B'
309 execute "try | return 150 | finally | return 160 | endtry"
310 Xpath 'C'
311 endtry
312 Xpath 'D'
313endfunc
314
315func T33_N()
316 RETURN 170
317endfunc
318
319func T33_O()
320 execute "try | return 180 | finally | return 190 | endtry"
321endfunc
322
323func Test_finally_cmd_return()
324 command! -nargs=? RETURN
325 \ try | return <args> | finally | return <args> * 2 | endtry
326 XpathINIT
327 call assert_equal(20, T33_F())
328 call assert_equal(60, T33_G())
329 call assert_equal(50, T33_H())
330 call assert_equal(90, T33_I())
331 call assert_equal(0, T33_J())
332 call assert_equal(0, T33_K())
333 call assert_equal(280, T33_L())
334 call assert_equal(160, T33_M())
335 call assert_equal(340, T33_N())
336 call assert_equal(190, T33_O())
337 call assert_equal('beilptxB', g:Xpath)
338 delcommand RETURN
339endfunc
340
341
342"-------------------------------------------------------------------------------
343" Test 41: Skipped :throw finding next command {{{1
344"
345" A :throw in an inactive conditional must not hide a following
346" command.
347"-------------------------------------------------------------------------------
348
349func T41_F()
350 Xpath 'a'
351 if 0 | throw 'never' | endif | Xpath 'b'
352 Xpath 'c'
353endfunc
354
355func T41_G()
356 Xpath 'd'
357 while 0 | throw 'never' | endwhile | Xpath 'e'
358 Xpath 'f'
359endfunc
360
361func T41_H()
362 Xpath 'g'
363 if 0 | try | throw 'never' | endtry | endif | Xpath 'h'
364 Xpath 'i'
365endfunc
366
367func Test_throw_inactive_cond()
368 XpathINIT
369 try
370 Xpath 'j'
371 call T41_F()
372 Xpath 'k'
373 catch /.*/
374 Xpath 'l'
375 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
376 endtry
377
378 try
379 Xpath 'm'
380 call T41_G()
381 Xpath 'n'
382 catch /.*/
383 Xpath 'o'
384 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
385 endtry
386
387 try
388 Xpath 'p'
389 call T41_H()
390 Xpath 'q'
391 catch /.*/
392 Xpath 'r'
393 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
394 endtry
395
396 call assert_equal('jabckmdefnpghiq', g:Xpath)
397endfunc
398
399
400"-------------------------------------------------------------------------------
401" Test 42: Catching number and string exceptions {{{1
402"
403" When a number is thrown, it is converted to a string exception.
404" Numbers and strings may be caught by specifying a regular exception
405" as argument to the :catch command.
406"-------------------------------------------------------------------------------
407
408
409func T42_F()
410 try
411
412 try
413 Xpath 'a'
414 throw 4711
415 Xpath 'b'
416 catch /4711/
417 Xpath 'c'
418 endtry
419
420 try
421 Xpath 'd'
422 throw 4711
423 Xpath 'e'
424 catch /^4711$/
425 Xpath 'f'
426 endtry
427
428 try
429 Xpath 'g'
430 throw 4711
431 Xpath 'h'
432 catch /\d/
433 Xpath 'i'
434 endtry
435
436 try
437 Xpath 'j'
438 throw 4711
439 Xpath 'k'
440 catch /^\d\+$/
441 Xpath 'l'
442 endtry
443
444 try
445 Xpath 'm'
446 throw "arrgh"
447 Xpath 'n'
448 catch /arrgh/
449 Xpath 'o'
450 endtry
451
452 try
453 Xpath 'p'
454 throw "arrgh"
455 Xpath 'q'
456 catch /^arrgh$/
457 Xpath 'r'
458 endtry
459
460 try
461 Xpath 's'
462 throw "arrgh"
463 Xpath 't'
464 catch /\l/
465 Xpath 'u'
466 endtry
467
468 try
469 Xpath 'v'
470 throw "arrgh"
471 Xpath 'w'
472 catch /^\l\+$/
473 Xpath 'x'
474 endtry
475
476 try
477 try
478 Xpath 'y'
479 throw "ARRGH"
480 Xpath 'z'
481 catch /^arrgh$/
482 Xpath 'A'
483 endtry
484 catch /^\carrgh$/
485 Xpath 'B'
486 endtry
487
488 try
489 Xpath 'C'
490 throw ""
491 Xpath 'D'
492 catch /^$/
493 Xpath 'E'
494 endtry
495
496 catch /.*/
497 Xpath 'F'
498 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
499 endtry
500endfunc
501
502func Test_catch_number_string()
503 XpathINIT
504 call T42_F()
505 call assert_equal('acdfgijlmoprsuvxyBCE', g:Xpath)
506endfunc
507
508
509"-------------------------------------------------------------------------------
510" Test 43: Selecting the correct :catch clause {{{1
511"
512" When an exception is thrown and there are multiple :catch clauses,
513" the first matching one is taken.
514"-------------------------------------------------------------------------------
515
516func T43_F()
517 let loops = 3
518 while loops > 0
519 try
520 if loops == 3
521 Xpath 'a' . loops
522 throw "a"
523 Xpath 'b' . loops
524 elseif loops == 2
525 Xpath 'c' . loops
526 throw "ab"
527 Xpath 'd' . loops
528 elseif loops == 1
529 Xpath 'e' . loops
530 throw "abc"
531 Xpath 'f' . loops
532 endif
533 catch /abc/
534 Xpath 'g' . loops
535 catch /ab/
536 Xpath 'h' . loops
537 catch /.*/
538 Xpath 'i' . loops
539 catch /a/
540 Xpath 'j' . loops
541 endtry
542
543 let loops = loops - 1
544 endwhile
545 Xpath 'k'
546endfunc
547
548func Test_multi_catch()
549 XpathINIT
550 call T43_F()
551 call assert_equal('a3i3c2h2e1g1k', g:Xpath)
552endfunc
553
554
555"-------------------------------------------------------------------------------
556" Test 44: Missing or empty :catch patterns {{{1
557"
558" A missing or empty :catch pattern means the same as /.*/, that is,
559" catches everything. To catch only empty exceptions, /^$/ must be
560" used. A :catch with missing, empty, or /.*/ argument also works
561" when followed by another command separated by a bar on the same
562" line. :catch patterns cannot be specified between ||. But other
563" pattern separators can be used instead of //.
564"-------------------------------------------------------------------------------
565
566func T44_F()
567 try
568 try
569 Xpath 'a'
570 throw ""
571 catch /^$/
572 Xpath 'b'
573 endtry
574
575 try
576 Xpath 'c'
577 throw ""
578 catch /.*/
579 Xpath 'd'
580 endtry
581
582 try
583 Xpath 'e'
584 throw ""
585 catch //
586 Xpath 'f'
587 endtry
588
589 try
590 Xpath 'g'
591 throw ""
592 catch
593 Xpath 'h'
594 endtry
595
596 try
597 Xpath 'i'
598 throw "oops"
599 catch /^$/
600 Xpath 'j'
601 catch /.*/
602 Xpath 'k'
603 endtry
604
605 try
606 Xpath 'l'
607 throw "arrgh"
608 catch /^$/
609 Xpath 'm'
610 catch //
611 Xpath 'n'
612 endtry
613
614 try
615 Xpath 'o'
616 throw "brrr"
617 catch /^$/
618 Xpath 'p'
619 catch
620 Xpath 'q'
621 endtry
622
623 try | Xpath 'r' | throw "x" | catch /.*/ | Xpath 's' | endtry
624
625 try | Xpath 't' | throw "y" | catch // | Xpath 'u' | endtry
626
627 while 1
628 try
629 let caught = 0
630 let v:errmsg = ""
631 " Extra try level: if ":catch" without arguments below raises
632 " a syntax error because it misinterprets the "Xpath" as a pattern,
633 " let it be caught by the ":catch /.*/" below.
634 try
635 try | Xpath 'v' | throw "z" | catch | Xpath 'w' | :
636 endtry
637 endtry
638 catch /.*/
639 let caught = 1
640 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
641 finally
642 if $VIMNOERRTHROW && v:errmsg != ""
643 call assert_report(v:errmsg)
644 endif
645 if caught || $VIMNOERRTHROW && v:errmsg != ""
646 Xpath 'x'
647 endif
648 break " discard error for $VIMNOERRTHROW
649 endtry
650 endwhile
651
652 let cologne = 4711
653 try
654 try
655 Xpath 'y'
656 throw "throw cologne"
657 " Next lines catches all and throws 4711:
658 catch |throw cologne|
659 Xpath 'z'
660 endtry
661 catch /4711/
662 Xpath 'A'
663 endtry
664
665 try
666 Xpath 'B'
667 throw "plus"
668 catch +plus+
669 Xpath 'C'
670 endtry
671
672 Xpath 'D'
673 catch /.*/
674 Xpath 'E'
675 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
676 endtry
677endfunc
678
679func Test_empty_catch()
680 XpathINIT
681 call T44_F()
682 call assert_equal('abcdefghiklnoqrstuvwyABCD', g:Xpath)
683endfunc
684
685
686"-------------------------------------------------------------------------------
687" Test 45: Catching exceptions from nested :try blocks {{{1
688"
689" When :try blocks are nested, an exception is caught by the innermost
690" try conditional that has a matching :catch clause.
691"-------------------------------------------------------------------------------
692
693func T45_F()
694 let loops = 3
695 while loops > 0
696 try
697 try
698 try
699 try
700 if loops == 3
701 Xpath 'a' . loops
702 throw "a"
703 Xpath 'b' . loops
704 elseif loops == 2
705 Xpath 'c' . loops
706 throw "ab"
707 Xpath 'd' . loops
708 elseif loops == 1
709 Xpath 'e' . loops
710 throw "abc"
711 Xpath 'f' . loops
712 endif
713 catch /abc/
714 Xpath 'g' . loops
715 endtry
716 catch /ab/
717 Xpath 'h' . loops
718 endtry
719 catch /.*/
720 Xpath 'i' . loops
721 endtry
722 catch /a/
723 Xpath 'j' . loops
724 endtry
725
726 let loops = loops - 1
727 endwhile
728 Xpath 'k'
729endfunc
730
731func Test_catch_from_nested_try()
732 XpathINIT
733 call T45_F()
734 call assert_equal('a3i3c2h2e1g1k', g:Xpath)
735endfunc
736
737
738"-------------------------------------------------------------------------------
739" Test 46: Executing :finally after a :throw in nested :try {{{1
740"
741" When an exception is thrown from within nested :try blocks, the
742" :finally clauses of the non-catching try conditionals should be
743" executed before the matching :catch of the next surrounding :try
744" gets the control. If this also has a :finally clause, it is
745" executed afterwards.
746"-------------------------------------------------------------------------------
747
748func T46_F()
749 let sum = 0
750
751 try
752 Xpath 'a'
753 try
754 Xpath 'b'
755 try
756 Xpath 'c'
757 try
758 Xpath 'd'
759 throw "ABC"
760 Xpath 'e'
761 catch /xyz/
762 Xpath 'f'
763 finally
764 Xpath 'g'
765 if sum != 0
766 Xpath 'h'
767 endif
768 let sum = sum + 1
769 endtry
770 Xpath 'i'
771 catch /123/
772 Xpath 'j'
773 catch /321/
774 Xpath 'k'
775 finally
776 Xpath 'l'
777 if sum != 1
778 Xpath 'm'
779 endif
780 let sum = sum + 2
781 endtry
782 Xpath 'n'
783 finally
784 Xpath 'o'
785 if sum != 3
786 Xpath 'p'
787 endif
788 let sum = sum + 4
789 endtry
790 Xpath 'q'
791 catch /ABC/
792 Xpath 'r'
793 if sum != 7
794 Xpath 's'
795 endif
796 let sum = sum + 8
797 finally
798 Xpath 't'
799 if sum != 15
800 Xpath 'u'
801 endif
802 let sum = sum + 16
803 endtry
804 Xpath 'v'
805 if sum != 31
806 Xpath 'w'
807 endif
808endfunc
809
810func Test_finally_after_throw()
811 XpathINIT
812 call T46_F()
813 call assert_equal('abcdglortv', g:Xpath)
814endfunc
815
816
817"-------------------------------------------------------------------------------
818" Test 47: Throwing exceptions from a :catch clause {{{1
819"
820" When an exception is thrown from a :catch clause, it should not be
821" caught by a :catch of the same :try conditional. After executing
822" the :finally clause (if present), surrounding try conditionals
823" should be checked for a matching :catch.
824"-------------------------------------------------------------------------------
825
826func T47_F()
827 Xpath 'a'
828 try
829 Xpath 'b'
830 try
831 Xpath 'c'
832 try
833 Xpath 'd'
834 throw "x1"
835 Xpath 'e'
836 catch /x1/
837 Xpath 'f'
838 try
839 Xpath 'g'
840 throw "x2"
841 Xpath 'h'
842 catch /x1/
843 Xpath 'i'
844 catch /x2/
845 Xpath 'j'
846 try
847 Xpath 'k'
848 throw "x3"
849 Xpath 'l'
850 catch /x1/
851 Xpath 'm'
852 catch /x2/
853 Xpath 'n'
854 finally
855 Xpath 'o'
856 endtry
857 Xpath 'p'
858 catch /x3/
859 Xpath 'q'
860 endtry
861 Xpath 'r'
862 catch /x1/
863 Xpath 's'
864 catch /x2/
865 Xpath 't'
866 catch /x3/
867 Xpath 'u'
868 finally
869 Xpath 'v'
870 endtry
871 Xpath 'w'
872 catch /x1/
873 Xpath 'x'
874 catch /x2/
875 Xpath 'y'
876 catch /x3/
877 Xpath 'z'
878 endtry
879 Xpath 'A'
880 catch /.*/
881 Xpath 'B'
882 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
883 endtry
884 Xpath 'C'
885endfunc
886
887func Test_throw_from_catch()
888 XpathINIT
889 call T47_F()
890 call assert_equal('abcdfgjkovzAC', g:Xpath)
891endfunc
892
893
894"-------------------------------------------------------------------------------
895" Test 48: Throwing exceptions from a :finally clause {{{1
896"
897" When an exception is thrown from a :finally clause, it should not be
898" caught by a :catch of the same :try conditional. Surrounding try
899" conditionals should be checked for a matching :catch. A previously
900" thrown exception is discarded.
901"-------------------------------------------------------------------------------
902
903func T48_F()
904 try
905
906 try
907 try
908 Xpath 'a'
909 catch /x1/
910 Xpath 'b'
911 finally
912 Xpath 'c'
913 throw "x1"
914 Xpath 'd'
915 endtry
916 Xpath 'e'
917 catch /x1/
918 Xpath 'f'
919 endtry
920 Xpath 'g'
921
922 try
923 try
924 Xpath 'h'
925 throw "x2"
926 Xpath 'i'
927 catch /x2/
928 Xpath 'j'
929 catch /x3/
930 Xpath 'k'
931 finally
932 Xpath 'l'
933 throw "x3"
934 Xpath 'm'
935 endtry
936 Xpath 'n'
937 catch /x2/
938 Xpath 'o'
939 catch /x3/
940 Xpath 'p'
941 endtry
942 Xpath 'q'
943
944 try
945 try
946 try
947 Xpath 'r'
948 throw "x4"
949 Xpath 's'
950 catch /x5/
951 Xpath 't'
952 finally
953 Xpath 'u'
954 throw "x5" " discards 'x4'
955 Xpath 'v'
956 endtry
957 Xpath 'w'
958 catch /x4/
959 Xpath 'x'
960 finally
961 Xpath 'y'
962 endtry
963 Xpath 'z'
964 catch /x5/
965 Xpath 'A'
966 endtry
967 Xpath 'B'
968
969 catch /.*/
970 Xpath 'C'
971 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
972 endtry
973 Xpath 'D'
974endfunc
975
976func Test_throw_from_finally()
977 XpathINIT
978 call T48_F()
979 call assert_equal('acfghjlpqruyABD', g:Xpath)
980endfunc
981
982
983"-------------------------------------------------------------------------------
984" Test 51: Throwing exceptions across :execute and user commands {{{1
985"
986" A :throw command may be executed under an ":execute" or from
987" a user command.
988"-------------------------------------------------------------------------------
989
990func T51_F()
991 command! -nargs=? THROW1 throw <args> | throw 1
992 command! -nargs=? THROW2 try | throw <args> | endtry | throw 2
993 command! -nargs=? THROW3 try | throw 3 | catch /3/ | throw <args> | endtry
994 command! -nargs=? THROW4 try | throw 4 | finally | throw <args> | endtry
995
996 try
997
998 try
999 try
1000 Xpath 'a'
1001 THROW1 "A"
1002 catch /A/
1003 Xpath 'b'
1004 endtry
1005 catch /1/
1006 Xpath 'c'
1007 endtry
1008
1009 try
1010 try
1011 Xpath 'd'
1012 THROW2 "B"
1013 catch /B/
1014 Xpath 'e'
1015 endtry
1016 catch /2/
1017 Xpath 'f'
1018 endtry
1019
1020 try
1021 try
1022 Xpath 'g'
1023 THROW3 "C"
1024 catch /C/
1025 Xpath 'h'
1026 endtry
1027 catch /3/
1028 Xpath 'i'
1029 endtry
1030
1031 try
1032 try
1033 Xpath 'j'
1034 THROW4 "D"
1035 catch /D/
1036 Xpath 'k'
1037 endtry
1038 catch /4/
1039 Xpath 'l'
1040 endtry
1041
1042 try
1043 try
1044 Xpath 'm'
1045 execute 'throw "E" | throw 5'
1046 catch /E/
1047 Xpath 'n'
1048 endtry
1049 catch /5/
1050 Xpath 'o'
1051 endtry
1052
1053 try
1054 try
1055 Xpath 'p'
1056 execute 'try | throw "F" | endtry | throw 6'
1057 catch /F/
1058 Xpath 'q'
1059 endtry
1060 catch /6/
1061 Xpath 'r'
1062 endtry
1063
1064 try
1065 try
1066 Xpath 's'
1067 execute'try | throw 7 | catch /7/ | throw "G" | endtry'
1068 catch /G/
1069 Xpath 't'
1070 endtry
1071 catch /7/
1072 Xpath 'u'
1073 endtry
1074
1075 try
1076 try
1077 Xpath 'v'
1078 execute 'try | throw 8 | finally | throw "H" | endtry'
1079 catch /H/
1080 Xpath 'w'
1081 endtry
1082 catch /8/
1083 Xpath 'x'
1084 endtry
1085
1086 catch /.*/
1087 Xpath 'y'
1088 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
1089 endtry
1090
1091 Xpath 'z'
1092
1093 delcommand THROW1
1094 delcommand THROW2
1095 delcommand THROW3
1096 delcommand THROW4
1097endfunc
1098
1099func Test_throw_across_commands()
1100 XpathINIT
1101 call T51_F()
1102 call assert_equal('abdeghjkmnpqstvwz', g:Xpath)
1103endfunc
1104
1105
1106
1107"-------------------------------------------------------------------------------
1108" Test 69: :throw across :if, :elseif, :while {{{1
1109"
1110" On an :if, :elseif, or :while command, an exception might be thrown
1111" during evaluation of the expression to test. The exception can be
1112" caught by the script.
1113"-------------------------------------------------------------------------------
1114
1115func T69_throw(x)
1116 Xpath 'x'
1117 throw a:x
1118endfunc
1119
1120func Test_throw_ifelsewhile()
1121 XpathINIT
1122
1123 try
1124 try
1125 Xpath 'a'
1126 if 111 == T69_throw("if") + 111
1127 Xpath 'b'
1128 else
1129 Xpath 'c'
1130 endif
1131 Xpath 'd'
1132 catch /^if$/
1133 Xpath 'e'
1134 catch /.*/
1135 Xpath 'f'
1136 call assert_report("if: " . v:exception . " in " . v:throwpoint)
1137 endtry
1138
1139 try
1140 Xpath 'g'
1141 if v:false
1142 Xpath 'h'
1143 elseif 222 == T69_throw("elseif") + 222
1144 Xpath 'i'
1145 else
1146 Xpath 'j'
1147 endif
1148 Xpath 'k'
1149 catch /^elseif$/
1150 Xpath 'l'
1151 catch /.*/
1152 Xpath 'm'
1153 call assert_report("elseif: " . v:exception . " in " . v:throwpoint)
1154 endtry
1155
1156 try
1157 Xpath 'n'
1158 while 333 == T69_throw("while") + 333
1159 Xpath 'o'
1160 break
1161 endwhile
1162 Xpath 'p'
1163 catch /^while$/
1164 Xpath 'q'
1165 catch /.*/
1166 Xpath 'r'
1167 call assert_report("while: " .. v:exception .. " in " .. v:throwpoint)
1168 endtry
1169 catch /^0$/ " default return value
1170 Xpath 's'
1171 call assert_report(v:throwpoint)
1172 catch /.*/
1173 call assert_report(v:exception .. " in " .. v:throwpoint)
1174 Xpath 't'
1175 endtry
1176
1177 call assert_equal('axegxlnxq', g:Xpath)
1178endfunc
1179
1180
1181"-------------------------------------------------------------------------------
1182" Test 70: :throw across :return or :throw {{{1
1183"
1184" On a :return or :throw command, an exception might be thrown during
1185" evaluation of the expression to return or throw, respectively. The
1186" exception can be caught by the script.
1187"-------------------------------------------------------------------------------
1188
1189let T70_taken = ""
1190
1191func T70_throw(x, n)
1192 let g:T70_taken = g:T70_taken . "T" . a:n
1193 throw a:x
1194endfunc
1195
1196func T70_F(x, y, n)
1197 let g:T70_taken = g:T70_taken . "F" . a:n
1198 return a:x + T70_throw(a:y, a:n)
1199endfunc
1200
1201func T70_G(x, y, n)
1202 let g:T70_taken = g:T70_taken . "G" . a:n
1203 throw a:x . T70_throw(a:y, a:n)
1204 return a:x
1205endfunc
1206
1207func Test_throwreturn()
1208 XpathINIT
1209
1210 try
1211 try
1212 Xpath 'a'
1213 call T70_F(4711, "return", 1)
1214 Xpath 'b'
1215 catch /^return$/
1216 Xpath 'c'
1217 catch /.*/
1218 Xpath 'd'
1219 call assert_report("return: " .. v:exception .. " in " .. v:throwpoint)
1220 endtry
1221
1222 try
1223 Xpath 'e'
1224 let var = T70_F(4712, "return-var", 2)
1225 Xpath 'f'
1226 catch /^return-var$/
1227 Xpath 'g'
1228 catch /.*/
1229 Xpath 'h'
1230 call assert_report("return-var: " . v:exception . " in " . v:throwpoint)
1231 finally
1232 unlet! var
1233 endtry
1234
1235 try
1236 Xpath 'i'
1237 throw "except1" . T70_throw("throw1", 3)
1238 Xpath 'j'
1239 catch /^except1/
1240 Xpath 'k'
1241 catch /^throw1$/
1242 Xpath 'l'
1243 catch /.*/
1244 Xpath 'm'
1245 call assert_report("throw1: " .. v:exception .. " in " .. v:throwpoint)
1246 endtry
1247
1248 try
1249 Xpath 'n'
1250 call T70_G("except2", "throw2", 4)
1251 Xpath 'o'
1252 catch /^except2/
1253 Xpath 'p'
1254 catch /^throw2$/
1255 Xpath 'q'
1256 catch /.*/
1257 Xpath 'r'
1258 call assert_report("throw2: " .. v:exception .. " in " .. v:throwpoint)
1259 endtry
1260
1261 try
1262 Xpath 's'
1263 let var = T70_G("except3", "throw3", 5)
1264 Xpath 't'
1265 catch /^except3/
1266 Xpath 'u'
1267 catch /^throw3$/
1268 Xpath 'v'
1269 catch /.*/
1270 Xpath 'w'
1271 call assert_report("throw3: " .. v:exception .. " in " .. v:throwpoint)
1272 finally
1273 unlet! var
1274 endtry
1275
1276 call assert_equal('F1T1F2T2T3G4T4G5T5', g:T70_taken)
1277 Xpath 'x'
1278 catch /^0$/ " default return value
1279 Xpath 'y'
1280 call assert_report(v:throwpoint)
1281 catch /.*/
1282 Xpath 'z'
1283 call assert_report('Caught' .. v:exception .. ' in ' .. v:throwpoint)
1284 endtry
1285
1286 call assert_equal('acegilnqsvx', g:Xpath)
1287endfunc
1288
1289"-------------------------------------------------------------------------------
1290" Test 71: :throw across :echo variants and :execute {{{1
1291"
1292" On an :echo, :echon, :echomsg, :echoerr, or :execute command, an
1293" exception might be thrown during evaluation of the arguments to
1294" be displayed or executed as a command, respectively. Any following
1295" arguments are not evaluated, then. The exception can be caught by
1296" the script.
1297"-------------------------------------------------------------------------------
1298
1299let T71_taken = ""
1300
1301func T71_throw(x, n)
1302 let g:T71_taken = g:T71_taken . "T" . a:n
1303 throw a:x
1304endfunc
1305
1306func T71_F(n)
1307 let g:T71_taken = g:T71_taken . "F" . a:n
1308 return "F" . a:n
1309endfunc
1310
1311func Test_throw_echo()
1312 XpathINIT
1313
1314 try
1315 try
1316 Xpath 'a'
1317 echo 'echo ' . T71_throw("echo-except", 1) . T71_F(1)
1318 Xpath 'b'
1319 catch /^echo-except$/
1320 Xpath 'c'
1321 catch /.*/
1322 Xpath 'd'
1323 call assert_report("echo: " .. v:exception .. " in " .. v:throwpoint)
1324 endtry
1325
1326 try
1327 Xpath 'e'
1328 echon "echon " . T71_throw("echon-except", 2) . T71_F(2)
1329 Xpath 'f'
1330 catch /^echon-except$/
1331 Xpath 'g'
1332 catch /.*/
1333 Xpath 'h'
1334 call assert_report('echon: ' . v:exception . ' in ' . v:throwpoint)
1335 endtry
1336
1337 try
1338 Xpath 'i'
1339 echomsg "echomsg " . T71_throw("echomsg-except", 3) . T71_F(3)
1340 Xpath 'j'
1341 catch /^echomsg-except$/
1342 Xpath 'k'
1343 catch /.*/
1344 Xpath 'l'
1345 call assert_report('echomsg: ' . v:exception . ' in ' . v:throwpoint)
1346 endtry
1347
1348 try
1349 Xpath 'm'
1350 echoerr "echoerr " . T71_throw("echoerr-except", 4) . T71_F(4)
1351 Xpath 'n'
1352 catch /^echoerr-except$/
1353 Xpath 'o'
1354 catch /Vim/
1355 Xpath 'p'
1356 catch /echoerr/
1357 Xpath 'q'
1358 catch /.*/
1359 Xpath 'r'
1360 call assert_report('echoerr: ' . v:exception . ' in ' . v:throwpoint)
1361 endtry
1362
1363 try
1364 Xpath 's'
1365 execute "echo 'execute " . T71_throw("execute-except", 5) . T71_F(5) "'"
1366 Xpath 't'
1367 catch /^execute-except$/
1368 Xpath 'u'
1369 catch /.*/
1370 Xpath 'v'
1371 call assert_report('execute: ' . v:exception . ' in ' . v:throwpoint)
1372 endtry
1373
1374 call assert_equal('T1T2T3T4T5', g:T71_taken)
1375 Xpath 'w'
1376 catch /^0$/ " default return value
1377 Xpath 'x'
1378 call assert_report(v:throwpoint)
1379 catch /.*/
1380 Xpath 'y'
1381 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
1382 endtry
1383
1384 call assert_equal('acegikmosuw', g:Xpath)
1385endfunc
1386
1387
1388"-------------------------------------------------------------------------------
1389" Test 72: :throw across :let or :unlet {{{1
1390"
1391" On a :let command, an exception might be thrown during evaluation
1392" of the expression to assign. On an :let or :unlet command, the
1393" evaluation of the name of the variable to be assigned or list or
1394" deleted, respectively, may throw an exception. Any following
1395" arguments are not evaluated, then. The exception can be caught by
1396" the script.
1397"-------------------------------------------------------------------------------
1398
1399let throwcount = 0
1400
1401func T72_throw(x)
1402 let g:throwcount = g:throwcount + 1
1403 throw a:x
1404endfunc
1405
1406let T72_addpath = ''
1407
1408func T72_addpath(p)
1409 let g:T72_addpath = g:T72_addpath . a:p
1410endfunc
1411
1412func Test_throw_let()
1413 XpathINIT
1414
1415 try
1416 try
1417 let $VAR = 'old_value'
1418 Xpath 'a'
1419 let $VAR = 'let(' . T72_throw('var') . ')'
1420 Xpath 'b'
1421 catch /^var$/
1422 Xpath 'c'
1423 finally
1424 call assert_equal('old_value', $VAR)
1425 endtry
1426
1427 try
1428 let @a = 'old_value'
1429 Xpath 'd'
1430 let @a = 'let(' . T72_throw('reg') . ')'
1431 Xpath 'e'
1432 catch /^reg$/
1433 try
1434 Xpath 'f'
1435 let @A = 'let(' . T72_throw('REG') . ')'
1436 Xpath 'g'
1437 catch /^REG$/
1438 Xpath 'h'
1439 endtry
1440 finally
1441 call assert_equal('old_value', @a)
1442 call assert_equal('old_value', @A)
1443 endtry
1444
1445 try
1446 let saved_gpath = &g:path
1447 let saved_lpath = &l:path
1448 Xpath 'i'
1449 let &path = 'let(' . T72_throw('opt') . ')'
1450 Xpath 'j'
1451 catch /^opt$/
1452 try
1453 Xpath 'k'
1454 let &g:path = 'let(' . T72_throw('gopt') . ')'
1455 Xpath 'l'
1456 catch /^gopt$/
1457 try
1458 Xpath 'm'
1459 let &l:path = 'let(' . T72_throw('lopt') . ')'
1460 Xpath 'n'
1461 catch /^lopt$/
1462 Xpath 'o'
1463 endtry
1464 endtry
1465 finally
1466 call assert_equal(saved_gpath, &g:path)
1467 call assert_equal(saved_lpath, &l:path)
1468 let &g:path = saved_gpath
1469 let &l:path = saved_lpath
1470 endtry
1471
1472 unlet! var1 var2 var3
1473
1474 try
1475 Xpath 'p'
1476 let var1 = 'let(' . T72_throw('var1') . ')'
1477 Xpath 'q'
1478 catch /^var1$/
1479 Xpath 'r'
1480 finally
1481 call assert_true(!exists('var1'))
1482 endtry
1483
1484 try
1485 let var2 = 'old_value'
1486 Xpath 's'
1487 let var2 = 'let(' . T72_throw('var2'). ')'
1488 Xpath 't'
1489 catch /^var2$/
1490 Xpath 'u'
1491 finally
1492 call assert_equal('old_value', var2)
1493 endtry
1494
1495 try
1496 Xpath 'v'
1497 let var{T72_throw('var3')} = 4711
1498 Xpath 'w'
1499 catch /^var3$/
1500 Xpath 'x'
1501 endtry
1502
1503 try
1504 call T72_addpath('T1')
1505 let var{T72_throw('var4')} var{T72_addpath('T2')} | call T72_addpath('T3')
1506 call T72_addpath('T4')
1507 catch /^var4$/
1508 call T72_addpath('T5')
1509 endtry
1510
1511 try
1512 call T72_addpath('T6')
1513 unlet var{T72_throw('var5')} var{T72_addpath('T7')}
1514 \ | call T72_addpath('T8')
1515 call T72_addpath('T9')
1516 catch /^var5$/
1517 call T72_addpath('T10')
1518 endtry
1519
1520 call assert_equal('T1T5T6T10', g:T72_addpath)
1521 call assert_equal(11, g:throwcount)
1522 catch /.*/
1523 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
1524 endtry
1525
1526 call assert_equal('acdfhikmoprsuvx', g:Xpath)
1527endfunc
1528
1529
1530"-------------------------------------------------------------------------------
1531" Test 73: :throw across :function, :delfunction {{{1
1532"
1533" The :function and :delfunction commands may cause an expression
1534" specified in braces to be evaluated. During evaluation, an
1535" exception might be thrown. The exception can be caught by the
1536" script.
1537"-------------------------------------------------------------------------------
1538
1539let T73_taken = ''
1540
1541func T73_throw(x, n)
1542 let g:T73_taken = g:T73_taken . 'T' . a:n
1543 throw a:x
1544endfunc
1545
1546func T73_expr(x, n)
1547 let g:T73_taken = g:T73_taken . 'E' . a:n
1548 if a:n % 2 == 0
1549 call T73_throw(a:x, a:n)
1550 endif
1551 return 2 - a:n % 2
1552endfunc
1553
1554func Test_throw_func()
1555 XpathINIT
1556
1557 try
1558 try
1559 " Define function.
1560 Xpath 'a'
1561 function! F0()
1562 endfunction
1563 Xpath 'b'
1564 function! F{T73_expr('function-def-ok', 1)}()
1565 endfunction
1566 Xpath 'c'
1567 function! F{T73_expr('function-def', 2)}()
1568 endfunction
1569 Xpath 'd'
1570 catch /^function-def-ok$/
1571 Xpath 'e'
1572 catch /^function-def$/
1573 Xpath 'f'
1574 catch /.*/
1575 call assert_report('def: ' . v:exception . ' in ' . v:throwpoint)
1576 endtry
1577
1578 try
1579 " List function.
1580 Xpath 'g'
1581 function F0
1582 Xpath 'h'
1583 function F{T73_expr('function-lst-ok', 3)}
1584 Xpath 'i'
1585 function F{T73_expr('function-lst', 4)}
1586 Xpath 'j'
1587 catch /^function-lst-ok$/
1588 Xpath 'k'
1589 catch /^function-lst$/
1590 Xpath 'l'
1591 catch /.*/
1592 call assert_report('lst: ' . v:exception . ' in ' . v:throwpoint)
1593 endtry
1594
1595 try
1596 " Delete function
1597 Xpath 'm'
1598 delfunction F0
1599 Xpath 'n'
1600 delfunction F{T73_expr('function-del-ok', 5)}
1601 Xpath 'o'
1602 delfunction F{T73_expr('function-del', 6)}
1603 Xpath 'p'
1604 catch /^function-del-ok$/
1605 Xpath 'q'
1606 catch /^function-del$/
1607 Xpath 'r'
1608 catch /.*/
1609 call assert_report('del: ' . v:exception . ' in ' . v:throwpoint)
1610 endtry
1611 call assert_equal('E1E2T2E3E4T4E5E6T6', g:T73_taken)
1612 catch /.*/
1613 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
1614 endtry
1615
1616 call assert_equal('abcfghilmnor', g:Xpath)
1617endfunc
1618
1619
1620"-------------------------------------------------------------------------------
1621" Test 74: :throw across builtin functions and commands {{{1
1622"
1623" Some functions like exists(), searchpair() take expression
1624" arguments, other functions or commands like substitute() or
1625" :substitute cause an expression (specified in the regular
1626" expression) to be evaluated. During evaluation an exception
1627" might be thrown. The exception can be caught by the script.
1628"-------------------------------------------------------------------------------
1629
1630let T74_taken = ""
1631
1632func T74_throw(x, n)
1633 let g:T74_taken = g:T74_taken . "T" . a:n
1634 throw a:x
1635endfunc
1636
1637func T74_expr(x, n)
1638 let g:T74_taken = g:T74_taken . "E" . a:n
1639 call T74_throw(a:x . a:n, a:n)
1640 return "EXPR"
1641endfunc
1642
1643func T74_skip(x, n)
1644 let g:T74_taken = g:T74_taken . "S" . a:n . "(" . line(".")
1645 let theline = getline(".")
1646 if theline =~ "skip"
1647 let g:T74_taken = g:T74_taken . "s)"
1648 return 1
1649 elseif theline =~ "throw"
1650 let g:T74_taken = g:T74_taken . "t)"
1651 call T74_throw(a:x . a:n, a:n)
1652 else
1653 let g:T74_taken = g:T74_taken . ")"
1654 return 0
1655 endif
1656endfunc
1657
1658func T74_subst(x, n)
1659 let g:T74_taken = g:T74_taken . "U" . a:n . "(" . line(".")
1660 let theline = getline(".")
1661 if theline =~ "not" " T74_subst() should not be called for this line
1662 let g:T74_taken = g:T74_taken . "n)"
1663 call T74_throw(a:x . a:n, a:n)
1664 elseif theline =~ "throw"
1665 let g:T74_taken = g:T74_taken . "t)"
1666 call T74_throw(a:x . a:n, a:n)
1667 else
1668 let g:T74_taken = g:T74_taken . ")"
1669 return "replaced"
1670 endif
1671endfunc
1672
1673func Test_throw_builtin_func()
1674 XpathINIT
1675
1676 try
1677 try
1678 Xpath 'a'
1679 let result = exists('*{T74_expr("exists", 1)}')
1680 Xpath 'b'
1681 catch /^exists1$/
1682 Xpath 'c'
1683 try
1684 let result = exists('{T74_expr("exists", 2)}')
1685 Xpath 'd'
1686 catch /^exists2$/
1687 Xpath 'e'
1688 catch /.*/
1689 call assert_report('exists2: ' . v:exception . ' in ' . v:throwpoint)
1690 endtry
1691 catch /.*/
1692 call assert_report('exists1: ' . v:exception . ' in ' . v:throwpoint)
1693 endtry
1694
1695 try
1696 let file = tempname()
1697 exec "edit" file
1698 call append(0, [
1699 \ 'begin',
1700 \ 'xx',
1701 \ 'middle 3',
1702 \ 'xx',
1703 \ 'middle 5 skip',
1704 \ 'xx',
1705 \ 'middle 7 throw',
1706 \ 'xx',
1707 \ 'end'])
1708 normal! gg
1709 Xpath 'f'
1710 let result = searchpair("begin", "middle", "end", '',
1711 \ 'T74_skip("searchpair", 3)')
1712 Xpath 'g'
1713 let result = searchpair("begin", "middle", "end", '',
1714 \ 'T74_skip("searchpair", 4)')
1715 Xpath 'h'
1716 let result = searchpair("begin", "middle", "end", '',
1717 \ 'T74_skip("searchpair", 5)')
1718 Xpath 'i'
1719 catch /^searchpair[35]$/
1720 Xpath 'j'
1721 catch /^searchpair4$/
1722 Xpath 'k'
1723 catch /.*/
1724 call assert_report('searchpair: ' . v:exception . ' in ' . v:throwpoint)
1725 finally
1726 bwipeout!
1727 call delete(file)
1728 endtry
1729
1730 try
1731 let file = tempname()
1732 exec "edit" file
1733 call append(0, [
1734 \ 'subst 1',
1735 \ 'subst 2',
1736 \ 'not',
1737 \ 'subst 4',
1738 \ 'subst throw',
1739 \ 'subst 6'])
1740 normal! gg
1741 Xpath 'l'
1742 1,2substitute/subst/\=T74_subst("substitute", 6)/
1743 try
1744 Xpath 'm'
1745 try
1746 let v:errmsg = ""
1747 3substitute/subst/\=T74_subst("substitute", 7)/
1748 finally
1749 if v:errmsg != ""
1750 " If exceptions are not thrown on errors, fake the error
1751 " exception in order to get the same execution path.
1752 throw "faked Vim(substitute)"
1753 endif
1754 endtry
1755 catch /Vim(substitute)/ " Pattern not found ('e' flag missing)
1756 Xpath 'n'
1757 3substitute/subst/\=T74_subst("substitute", 8)/e
1758 Xpath 'o'
1759 endtry
1760 Xpath 'p'
1761 4,6substitute/subst/\=T74_subst("substitute", 9)/
1762 Xpath 'q'
1763 catch /^substitute[678]/
1764 Xpath 'r'
1765 catch /^substitute9/
1766 Xpath 's'
1767 finally
1768 bwipeout!
1769 call delete(file)
1770 endtry
1771
1772 try
1773 Xpath 't'
1774 let var = substitute("sub", "sub", '\=T74_throw("substitute()y", 10)', '')
1775 Xpath 'u'
1776 catch /substitute()y/
1777 Xpath 'v'
1778 catch /.*/
1779 call assert_report('substitute()y: ' . v:exception . ' in '
1780 \ . v:throwpoint)
1781 endtry
1782
1783 try
1784 Xpath 'w'
1785 let var = substitute("not", "sub", '\=T74_throw("substitute()n", 11)', '')
1786 Xpath 'x'
1787 catch /substitute()n/
1788 Xpath 'y'
1789 catch /.*/
1790 call assert_report('substitute()n: ' . v:exception . ' in '
1791 \ . v:throwpoint)
1792 endtry
1793
1794 call assert_equal('E1T1E2T2S3(3)S4(5s)S4(7t)T4U6(1)U6(2)U9(4)U9(5t)T9T10',
1795 \ g:T74_taken)
1796
1797 catch /.*/
1798 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
1799 endtry
1800
1801 call assert_equal('acefgklmnopstvwx', g:Xpath)
1802endfunc
1803
1804
1805"-------------------------------------------------------------------------------
1806" Test 75: Errors in builtin functions. {{{1
1807"
1808" On an error in a builtin function called inside a :try/:endtry
1809" region, the evaluation of the expression calling that function and
1810" the command containing that expression are abandoned. The error can
1811" be caught as an exception.
1812"
1813" A simple :call of the builtin function is a trivial case. If the
1814" builtin function is called in the argument list of another function,
1815" no further arguments are evaluated, and the other function is not
1816" executed. If the builtin function is called from the argument of
1817" a :return command, the :return command is not executed. If the
1818" builtin function is called from the argument of a :throw command,
1819" the :throw command is not executed. The evaluation of the
1820" expression calling the builtin function is abandoned.
1821"-------------------------------------------------------------------------------
1822
1823func T75_F1(arg1)
1824 Xpath 'a'
1825endfunc
1826
1827func T75_F2(arg1, arg2)
1828 Xpath 'b'
1829endfunc
1830
1831func T75_G()
1832 Xpath 'c'
1833endfunc
1834
1835func T75_H()
1836 Xpath 'd'
1837endfunc
1838
1839func T75_R()
1840 while 1
1841 try
1842 let caught = 0
1843 let v:errmsg = ""
1844 Xpath 'e'
1845 return append(1, "s")
1846 catch /E21/
1847 let caught = 1
1848 catch /.*/
1849 Xpath 'f'
1850 finally
1851 Xpath 'g'
1852 if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
1853 Xpath 'h'
1854 endif
1855 break " discard error for $VIMNOERRTHROW
1856 endtry
1857 endwhile
1858 Xpath 'i'
1859endfunc
1860
1861func Test_builtin_func_error()
1862 XpathINIT
1863
1864 try
1865 set noma " let append() fail with "E21"
1866
1867 while 1
1868 try
1869 let caught = 0
1870 let v:errmsg = ""
1871 Xpath 'j'
1872 call append(1, "s")
1873 catch /E21/
1874 let caught = 1
1875 catch /.*/
1876 Xpath 'k'
1877 finally
1878 Xpath 'l'
1879 if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
1880 Xpath 'm'
1881 endif
1882 break " discard error for $VIMNOERRTHROW
1883 endtry
1884 endwhile
1885
1886 while 1
1887 try
1888 let caught = 0
1889 let v:errmsg = ""
1890 Xpath 'n'
1891 call T75_F1('x' . append(1, "s"))
1892 catch /E21/
1893 let caught = 1
1894 catch /.*/
1895 Xpath 'o'
1896 finally
1897 Xpath 'p'
1898 if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
1899 Xpath 'q'
1900 endif
1901 break " discard error for $VIMNOERRTHROW
1902 endtry
1903 endwhile
1904
1905 while 1
1906 try
1907 let caught = 0
1908 let v:errmsg = ""
1909 Xpath 'r'
1910 call T75_F2('x' . append(1, "s"), T75_G())
1911 catch /E21/
1912 let caught = 1
1913 catch /.*/
1914 Xpath 's'
1915 finally
1916 Xpath 't'
1917 if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
1918 Xpath 'u'
1919 endif
1920 break " discard error for $VIMNOERRTHROW
1921 endtry
1922 endwhile
1923
1924 call T75_R()
1925
1926 while 1
1927 try
1928 let caught = 0
1929 let v:errmsg = ""
1930 Xpath 'v'
1931 throw "T" . append(1, "s")
1932 catch /E21/
1933 let caught = 1
1934 catch /^T.*/
1935 Xpath 'w'
1936 catch /.*/
1937 Xpath 'x'
1938 finally
1939 Xpath 'y'
1940 if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
1941 Xpath 'z'
1942 endif
1943 break " discard error for $VIMNOERRTHROW
1944 endtry
1945 endwhile
1946
1947 while 1
1948 try
1949 let caught = 0
1950 let v:errmsg = ""
1951 Xpath 'A'
1952 let x = "a"
1953 let x = x . "b" . append(1, "s") . T75_H()
1954 catch /E21/
1955 let caught = 1
1956 catch /.*/
1957 Xpath 'B'
1958 finally
1959 Xpath 'C'
1960 if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
1961 Xpath 'D'
1962 endif
1963 call assert_equal('a', x)
1964 break " discard error for $VIMNOERRTHROW
1965 endtry
1966 endwhile
1967 catch /.*/
1968 call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
1969 finally
1970 set ma&
1971 endtry
1972
1973 call assert_equal('jlmnpqrtueghivyzACD', g:Xpath)
1974endfunc
1975
Bram Moolenaara6e8f882019-12-14 16:18:15 +01001976func Test_reload_in_try_catch()
1977 call writefile(['x'], 'Xreload')
1978 set autoread
1979 edit Xreload
1980 tabnew
1981 call writefile(['xx'], 'Xreload')
1982 augroup ReLoad
1983 au FileReadPost Xreload let x = doesnotexist
1984 au BufReadPost Xreload let x = doesnotexist
1985 augroup END
1986 try
1987 edit Xreload
1988 catch
1989 endtry
1990 tabnew
1991
1992 tabclose
1993 tabclose
1994 autocmd! ReLoad
1995 set noautoread
1996 bwipe! Xreload
1997 call delete('Xreload')
1998endfunc
1999
Bram Moolenaar818fc9a2020-02-21 17:54:45 +01002000" Test for errors with :catch, :throw, :finally {{{1
2001func Test_try_catch_errors()
2002 call assert_fails('throw |', 'E471:')
2003 call assert_fails("throw \n ", 'E471:')
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02002004 call assert_fails('catch abc', 'E654:')
Bram Moolenaar818fc9a2020-02-21 17:54:45 +01002005 call assert_fails('try | let i = 1| finally | catch | endtry', 'E604:')
2006 call assert_fails('finally', 'E606:')
2007 call assert_fails('try | finally | finally | endtry', 'E607:')
2008 call assert_fails('try | for i in range(5) | endif | endtry', 'E580:')
2009 call assert_fails('try | while v:true | endtry', 'E170:')
2010 call assert_fails('try | if v:true | endtry', 'E171:')
2011endfunc
2012
2013" Test for verbose messages with :try :catch, and :finally {{{1
2014func Test_try_catch_verbose()
2015 " This test works only when the language is English
Bram Moolenaarcde0ff32020-04-04 14:00:39 +02002016 CheckEnglish
Bram Moolenaar818fc9a2020-02-21 17:54:45 +01002017
2018 set verbose=14
Bram Moolenaarb6541032020-02-22 21:21:27 +01002019
2020 " Test for verbose messages displayed when an exception is caught
Bram Moolenaar818fc9a2020-02-21 17:54:45 +01002021 redir => msg
2022 try
2023 echo i
2024 catch /E121:/
2025 finally
2026 endtry
2027 redir END
2028 let expected = [
Bram Moolenaarb6541032020-02-22 21:21:27 +01002029 \ 'Exception thrown: Vim(echo):E121: Undefined variable: i', '',
2030 \ 'Exception caught: Vim(echo):E121: Undefined variable: i', '',
2031 \ 'Exception finished: Vim(echo):E121: Undefined variable: i']
Bram Moolenaar818fc9a2020-02-21 17:54:45 +01002032 call assert_equal(expected, split(msg, "\n"))
Bram Moolenaarb6541032020-02-22 21:21:27 +01002033
2034 " Test for verbose messages displayed when an exception is discarded
2035 redir => msg
2036 try
2037 try
2038 throw 'abc'
2039 finally
2040 throw 'xyz'
2041 endtry
2042 catch
2043 endtry
2044 redir END
2045 let expected = [
2046 \ 'Exception thrown: abc', '',
2047 \ 'Exception made pending: abc', '',
2048 \ 'Exception thrown: xyz', '',
2049 \ 'Exception discarded: abc', '',
2050 \ 'Exception caught: xyz', '',
2051 \ 'Exception finished: xyz']
2052 call assert_equal(expected, split(msg, "\n"))
2053
2054 " Test for messages displayed when :throw is resumed after :finally
2055 redir => msg
2056 try
2057 try
2058 throw 'abc'
2059 finally
2060 endtry
2061 catch
2062 endtry
2063 redir END
2064 let expected = [
2065 \ 'Exception thrown: abc', '',
2066 \ 'Exception made pending: abc', '',
2067 \ 'Exception resumed: abc', '',
2068 \ 'Exception caught: abc', '',
2069 \ 'Exception finished: abc']
2070 call assert_equal(expected, split(msg, "\n"))
2071
2072 " Test for messages displayed when :break is resumed after :finally
2073 redir => msg
2074 for i in range(1)
2075 try
2076 break
2077 finally
2078 endtry
2079 endfor
2080 redir END
2081 let expected = [':break made pending', '', ':break resumed']
2082 call assert_equal(expected, split(msg, "\n"))
2083
2084 " Test for messages displayed when :continue is resumed after :finally
2085 redir => msg
2086 for i in range(1)
2087 try
2088 continue
2089 finally
2090 endtry
2091 endfor
2092 redir END
2093 let expected = [':continue made pending', '', ':continue resumed']
2094 call assert_equal(expected, split(msg, "\n"))
2095
2096 " Test for messages displayed when :return is resumed after :finally
2097 func Xtest()
2098 try
2099 return 'vim'
2100 finally
2101 endtry
2102 endfunc
2103 redir => msg
2104 call Xtest()
2105 redir END
2106 let expected = [
2107 \ 'calling Xtest()', '',
2108 \ ':return vim made pending', '',
2109 \ ':return vim resumed', '',
2110 \ 'Xtest returning ''vim''', '',
2111 \ 'continuing in Test_try_catch_verbose']
2112 call assert_equal(expected, split(msg, "\n"))
2113 delfunc Xtest
2114
2115 " Test for messages displayed when :finish is resumed after :finally
2116 call writefile(['try', 'finish', 'finally', 'endtry'], 'Xscript')
2117 redir => msg
2118 source Xscript
2119 redir END
2120 let expected = [
2121 \ ':finish made pending', '',
2122 \ ':finish resumed', '',
2123 \ 'finished sourcing Xscript',
2124 \ 'continuing in Test_try_catch_verbose']
2125 call assert_equal(expected, split(msg, "\n")[1:])
2126 call delete('Xscript')
2127
2128 " Test for messages displayed when a pending :continue is discarded by an
2129 " exception in a finally handler
2130 redir => msg
2131 try
2132 for i in range(1)
2133 try
2134 continue
2135 finally
2136 throw 'abc'
2137 endtry
2138 endfor
2139 catch
2140 endtry
2141 redir END
2142 let expected = [
2143 \ ':continue made pending', '',
2144 \ 'Exception thrown: abc', '',
2145 \ ':continue discarded', '',
2146 \ 'Exception caught: abc', '',
2147 \ 'Exception finished: abc']
2148 call assert_equal(expected, split(msg, "\n"))
2149
Bram Moolenaar818fc9a2020-02-21 17:54:45 +01002150 set verbose&
2151endfunc
2152
Bram Moolenaarb6541032020-02-22 21:21:27 +01002153" Test for throwing an exception from a BufEnter autocmd {{{1
2154func Test_BufEnter_exception()
2155 augroup bufenter_exception
2156 au!
2157 autocmd BufEnter Xfile1 throw 'abc'
2158 augroup END
2159
2160 let caught_abc = 0
2161 try
2162 sp Xfile1
2163 catch /^abc/
2164 let caught_abc = 1
2165 endtry
2166 call assert_equal(1, caught_abc)
2167 call assert_equal(1, winnr('$'))
2168
2169 augroup bufenter_exception
2170 au!
2171 augroup END
2172 augroup! bufenter_exception
2173 %bwipe!
2174
2175 " Test for recursively throwing exceptions in autocmds
2176 augroup bufenter_exception
2177 au!
2178 autocmd BufEnter Xfile1 throw 'bufenter'
2179 autocmd BufLeave Xfile1 throw 'bufleave'
2180 augroup END
2181
2182 let ex_count = 0
2183 try
2184 try
2185 sp Xfile1
2186 catch /^bufenter/
2187 let ex_count += 1
2188 endtry
2189 catch /^bufleave/
2190 let ex_count += 10
2191 endtry
2192 call assert_equal(10, ex_count)
2193 call assert_equal(2, winnr('$'))
2194
2195 augroup bufenter_exception
2196 au!
2197 augroup END
2198 augroup! bufenter_exception
2199 %bwipe!
2200endfunc
2201
Bram Moolenaar8143a532020-12-13 20:26:29 +01002202" Test for using try/catch in a user command with a failing expression {{{1
2203func Test_user_command_try_catch()
2204 let lines =<< trim END
2205 function s:throw() abort
2206 throw 'error'
2207 endfunction
2208
2209 command! Execute
2210 \ try
2211 \ | let s:x = s:throw()
2212 \ | catch
2213 \ | let g:caught = 'caught'
2214 \ | endtry
2215
2216 let g:caught = 'no'
2217 Execute
2218 call assert_equal('caught', g:caught)
2219 END
2220 call writefile(lines, 'XtestTryCatch')
2221 source XtestTryCatch
2222
2223 call delete('XtestTryCatch')
2224 unlet g:caught
2225endfunc
2226
Bram Moolenaara6e8f882019-12-14 16:18:15 +01002227" Modeline {{{1
Bram Moolenaar1f068232019-11-03 16:17:26 +01002228" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker