neovim/test/old/testdir/test_vimscript.vim
zeertzjq 30f85fcb7f vim-patch:9.1.0419: eval.c not sufficiently tested
Problem:  eval.c not sufficiently tested
Solution: Add a few more additional tests for eval.c,
          (Yegappan Lakshmanan)

closes: vim/vim#14799

4776e64e72

Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
2024-07-31 10:49:57 +08:00

7509 lines
189 KiB
VimL

" Test various aspects of the Vim script language.
" Most of this was formerly in test49.vim (developed by Servatius Brandt
" <Servatius.Brandt@fujitsu-siemens.com>)
source check.vim
source shared.vim
source script_util.vim
"-------------------------------------------------------------------------------
" Test environment {{{1
"-------------------------------------------------------------------------------
" Append a message to the "messages" file
func Xout(text)
split messages
$put =a:text
wq
endfunc
com! -nargs=1 Xout call Xout(<args>)
" Create a new instance of Vim and run the commands in 'test' and then 'verify'
" The commands in 'test' are expected to store the test results in the Xtest.out
" file. If the test passes successfully, then Xtest.out should be empty.
func RunInNewVim(test, verify)
let init =<< trim END
set cpo-=C " support line-continuation in sourced script
source script_util.vim
XpathINIT
XloopINIT
END
let cleanup =<< trim END
call writefile(v:errors, 'Xtest.out')
qall
END
call writefile(init, 'Xtest.vim')
call writefile(a:test, 'Xtest.vim', 'a')
call writefile(a:verify, 'Xverify.vim')
call writefile(cleanup, 'Xverify.vim', 'a')
call RunVim([], [], "-S Xtest.vim -S Xverify.vim")
call assert_equal([], readfile('Xtest.out'))
call delete('Xtest.out')
call delete('Xtest.vim')
call delete('Xverify.vim')
endfunc
"-------------------------------------------------------------------------------
" Test 1: :endwhile in function {{{1
"
" Detect if a broken loop is (incorrectly) reactivated by the
" :endwhile. Use a :return to prevent an endless loop, and make
" this test first to get a meaningful result on an error before other
" tests will hang.
"-------------------------------------------------------------------------------
func T1_F()
Xpath 'a'
let first = 1
while 1
Xpath 'b'
if first
Xpath 'c'
let first = 0
break
else
Xpath 'd'
return
endif
endwhile
endfunc
func T1_G()
Xpath 'h'
let first = 1
while 1
Xpath 'i'
if first
Xpath 'j'
let first = 0
break
else
Xpath 'k'
return
endif
if 1 " unmatched :if
endwhile
endfunc
func Test_endwhile_function()
XpathINIT
call T1_F()
Xpath 'F'
try
call T1_G()
catch
" Catch missing :endif
call assert_true(v:exception =~ 'E171')
Xpath 'x'
endtry
Xpath 'G'
call assert_equal('abcFhijxG', g:Xpath)
endfunc
"-------------------------------------------------------------------------------
" Test 2: :endwhile in script {{{1
"
" Detect if a broken loop is (incorrectly) reactivated by the
" :endwhile. Use a :finish to prevent an endless loop, and place
" this test before others that might hang to get a meaningful result
" on an error.
"
" This test executes the bodies of the functions T1_F and T1_G from
" the previous test as script files (:return replaced by :finish).
"-------------------------------------------------------------------------------
func Test_endwhile_script()
XpathINIT
ExecAsScript T1_F
Xpath 'F'
call DeleteTheScript()
try
ExecAsScript T1_G
catch
" Catch missing :endif
call assert_true(v:exception =~ 'E171')
Xpath 'x'
endtry
Xpath 'G'
call DeleteTheScript()
call assert_equal('abcFhijxG', g:Xpath)
endfunc
"-------------------------------------------------------------------------------
" Test 3: :if, :elseif, :while, :continue, :break {{{1
"-------------------------------------------------------------------------------
func Test_if_while()
XpathINIT
if 1
Xpath 'a'
let loops = 3
while loops > -1 " main loop: loops == 3, 2, 1 (which breaks)
if loops <= 0
let break_err = 1
let loops = -1
else
Xpath 'b' . loops
endif
if (loops == 2)
while loops == 2 " dummy loop
Xpath 'c' . loops
let loops = loops - 1
continue " stop dummy loop
Xpath 'd' . loops
endwhile
continue " continue main loop
Xpath 'e' . loops
elseif (loops == 1)
let p = 1
while p " dummy loop
Xpath 'f' . loops
let p = 0
break " break dummy loop
Xpath 'g' . loops
endwhile
Xpath 'h' . loops
unlet p
break " break main loop
Xpath 'i' . loops
endif
if (loops > 0)
Xpath 'j' . loops
endif
while loops == 3 " dummy loop
let loops = loops - 1
endwhile " end dummy loop
endwhile " end main loop
Xpath 'k'
else
Xpath 'l'
endif
Xpath 'm'
if exists("break_err")
Xpath 'm'
unlet break_err
endif
unlet loops
call assert_equal('ab3j3b2c2b1f1h1km', g:Xpath)
endfunc
" Check double quote after skipped "elseif" does not give error E15
func Test_skipped_elseif()
if "foo" ==? "foo"
let result = "first"
elseif "foo" ==? "foo"
let result = "second"
endif
call assert_equal('first', result)
endfunc
"-------------------------------------------------------------------------------
" Test 4: :return {{{1
"-------------------------------------------------------------------------------
func T4_F()
if 1
Xpath 'a'
let loops = 3
while loops > 0 " 3: 2: 1:
Xpath 'b' . loops
if (loops == 2)
Xpath 'c' . loops
return
Xpath 'd' . loops
endif
Xpath 'e' . loops
let loops = loops - 1
endwhile
Xpath 'f'
else
Xpath 'g'
endif
endfunc
func Test_return()
XpathINIT
call T4_F()
Xpath '4'
call assert_equal('ab3e3b2c24', g:Xpath)
endfunc
"-------------------------------------------------------------------------------
" Test 5: :finish {{{1
"
" This test executes the body of the function T4_F from the previous
" test as a script file (:return replaced by :finish).
"-------------------------------------------------------------------------------
func Test_finish()
XpathINIT
ExecAsScript T4_F
Xpath '5'
call DeleteTheScript()
call assert_equal('ab3e3b2c25', g:Xpath)
endfunc
"-------------------------------------------------------------------------------
" Test 6: Defining functions in :while loops {{{1
"
" Functions can be defined inside other functions. An inner function
" gets defined when the outer function is executed. Functions may
" also be defined inside while loops. Expressions in braces for
" defining the function name are allowed.
"
" The functions are defined when sourcing the script, only the
" resulting path is checked in the test function.
"-------------------------------------------------------------------------------
XpathINIT
" The command CALL collects the argument of all its invocations in "calls"
" when used from a function (that is, when the global variable "calls" needs
" the "g:" prefix). This is to check that the function code is skipped when
" the function is defined. For inner functions, do so only if the outer
" function is not being executed.
"
let calls = ""
com! -nargs=1 CALL
\ if !exists("calls") && !exists("outer") |
\ let g:calls = g:calls . <args> |
\ endif
let i = 0
while i < 3
let i = i + 1
if i == 1
Xpath 'a'
function! F1(arg)
CALL a:arg
let outer = 1
let j = 0
while j < 1
Xpath 'b'
let j = j + 1
function! G1(arg)
CALL a:arg
endfunction
Xpath 'c'
endwhile
endfunction
Xpath 'd'
continue
endif
Xpath 'e' . i
function! F{i}(i, arg)
CALL a:arg
let outer = 1
if a:i == 3
Xpath 'f'
endif
let k = 0
while k < 3
Xpath 'g' . k
let k = k + 1
function! G{a:i}{k}(arg)
CALL a:arg
endfunction
Xpath 'h' . k
endwhile
endfunction
Xpath 'i'
endwhile
if exists("*G1")
Xpath 'j'
endif
if exists("*F1")
call F1("F1")
if exists("*G1")
call G1("G1")
endif
endif
if exists("G21") || exists("G22") || exists("G23")
Xpath 'k'
endif
if exists("*F2")
call F2(2, "F2")
if exists("*G21")
call G21("G21")
endif
if exists("*G22")
call G22("G22")
endif
if exists("*G23")
call G23("G23")
endif
endif
if exists("G31") || exists("G32") || exists("G33")
Xpath 'l'
endif
if exists("*F3")
call F3(3, "F3")
if exists("*G31")
call G31("G31")
endif
if exists("*G32")
call G32("G32")
endif
if exists("*G33")
call G33("G33")
endif
endif
Xpath 'm'
let g:test6_result = g:Xpath
let g:test6_calls = calls
unlet calls
delfunction F1
delfunction G1
delfunction F2
delfunction G21
delfunction G22
delfunction G23
delfunction G31
delfunction G32
delfunction G33
func Test_defining_functions()
call assert_equal('ade2ie3ibcg0h1g1h2g2h3fg0h1g1h2g2h3m', g:test6_result)
call assert_equal('F1G1F2G21G22G23F3G31G32G33', g:test6_calls)
endfunc
"-------------------------------------------------------------------------------
" Test 7: Continuing on errors outside functions {{{1
"
" On an error outside a function, the script processing continues
" at the line following the outermost :endif or :endwhile. When not
" inside an :if or :while, the script processing continues at the next
" line.
"-------------------------------------------------------------------------------
XpathINIT
if 1
Xpath 'a'
while 1
Xpath 'b'
asdf
Xpath 'c'
break
endwhile | Xpath 'd'
Xpath 'e'
endif | Xpath 'f'
Xpath 'g'
while 1
Xpath 'h'
if 1
Xpath 'i'
asdf
Xpath 'j'
endif | Xpath 'k'
Xpath 'l'
break
endwhile | Xpath 'm'
Xpath 'n'
asdf
Xpath 'o'
asdf | Xpath 'p'
Xpath 'q'
let g:test7_result = g:Xpath
func Test_error_in_script()
call assert_equal('abghinoq', g:test7_result)
endfunc
"-------------------------------------------------------------------------------
" Test 8: Aborting and continuing on errors inside functions {{{1
"
" On an error inside a function without the "abort" attribute, the
" script processing continues at the next line (unless the error was
" in a :return command). On an error inside a function with the
" "abort" attribute, the function is aborted and the script processing
" continues after the function call; the value -1 is returned then.
"-------------------------------------------------------------------------------
XpathINIT
func T8_F()
if 1
Xpath 'a'
while 1
Xpath 'b'
asdf
Xpath 'c'
asdf | Xpath 'd'
Xpath 'e'
break
endwhile
Xpath 'f'
endif | Xpath 'g'
Xpath 'h'
while 1
Xpath 'i'
if 1
Xpath 'j'
asdf
Xpath 'k'
asdf | Xpath 'l'
Xpath 'm'
endif
Xpath 'n'
break
endwhile | Xpath 'o'
Xpath 'p'
return novar " returns (default return value 0)
Xpath 'q'
return 1 " not reached
endfunc
func T8_G() abort
if 1
Xpath 'r'
while 1
Xpath 's'
asdf " returns -1
Xpath 't'
break
endwhile
Xpath 'v'
endif | Xpath 'w'
Xpath 'x'
return -4 " not reached
endfunc
func T8_H() abort
while 1
Xpath 'A'
if 1
Xpath 'B'
asdf " returns -1
Xpath 'C'
endif
Xpath 'D'
break
endwhile | Xpath 'E'
Xpath 'F'
return -4 " not reached
endfunc
" Aborted functions (T8_G and T8_H) return -1.
let g:test8_sum = (T8_F() + 1) - 4 * T8_G() - 8 * T8_H()
Xpath 'X'
let g:test8_result = g:Xpath
func Test_error_in_function()
call assert_equal(13, g:test8_sum)
call assert_equal('abcefghijkmnoprsABX', g:test8_result)
delfunction T8_F
delfunction T8_G
delfunction T8_H
endfunc
"-------------------------------------------------------------------------------
" Test 9: Continuing after aborted functions {{{1
"
" When a function with the "abort" attribute is aborted due to an
" error, the next function back in the call hierarchy without an
" "abort" attribute continues; the value -1 is returned then.
"-------------------------------------------------------------------------------
XpathINIT
func F() abort
Xpath 'a'
let result = G() " not aborted
Xpath 'b'
if result != 2
Xpath 'c'
endif
return 1
endfunc
func G() " no abort attribute
Xpath 'd'
if H() != -1 " aborted
Xpath 'e'
endif
Xpath 'f'
return 2
endfunc
func H() abort
Xpath 'g'
call I() " aborted
Xpath 'h'
return 4
endfunc
func I() abort
Xpath 'i'
asdf " error
Xpath 'j'
return 8
endfunc
if F() != 1
Xpath 'k'
endif
let g:test9_result = g:Xpath
delfunction F
delfunction G
delfunction H
delfunction I
func Test_func_abort()
call assert_equal('adgifb', g:test9_result)
endfunc
"-------------------------------------------------------------------------------
" Test 10: :if, :elseif, :while argument parsing {{{1
"
" A '"' or '|' in an argument expression must not be mixed up with
" a comment or a next command after a bar. Parsing errors should
" be recognized.
"-------------------------------------------------------------------------------
XpathINIT
func MSG(enr, emsg)
let english = v:lang == "C" || v:lang =~ '^[Ee]n'
if a:enr == ""
Xout "TODO: Add message number for:" a:emsg
let v:errmsg = ":" . v:errmsg
endif
let match = 1
if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
let match = 0
if v:errmsg == ""
Xout "Message missing."
else
let v:errmsg = v:errmsg->escape('"')
Xout "Unexpected message:" v:errmsg
endif
endif
return match
endfunc
if 1 || strlen("\"") | Xpath 'a'
Xpath 'b'
endif
Xpath 'c'
if 0
elseif 1 || strlen("\"") | Xpath 'd'
Xpath 'e'
endif
Xpath 'f'
while 1 || strlen("\"") | Xpath 'g'
Xpath 'h'
break
endwhile
Xpath 'i'
let v:errmsg = ""
if 1 ||| strlen("\"") | Xpath 'j'
Xpath 'k'
endif
Xpath 'l'
if !MSG('E15', "Invalid expression")
Xpath 'm'
endif
let v:errmsg = ""
if 0
elseif 1 ||| strlen("\"") | Xpath 'n'
Xpath 'o'
endif
Xpath 'p'
if !MSG('E15', "Invalid expression")
Xpath 'q'
endif
let v:errmsg = ""
while 1 ||| strlen("\"") | Xpath 'r'
Xpath 's'
break
endwhile
Xpath 't'
if !MSG('E15', "Invalid expression")
Xpath 'u'
endif
let g:test10_result = g:Xpath
delfunction MSG
func Test_expr_parsing()
call assert_equal('abcdefghilpt', g:test10_result)
endfunc
"-------------------------------------------------------------------------------
" Test 11: :if, :elseif, :while argument evaluation after abort {{{1
"
" When code is skipped over due to an error, the boolean argument to
" an :if, :elseif, or :while must not be evaluated.
"-------------------------------------------------------------------------------
XpathINIT
let calls = 0
func P(num)
let g:calls = g:calls + a:num " side effect on call
return 0
endfunc
if 1
Xpath 'a'
asdf " error
Xpath 'b'
if P(1) " should not be called
Xpath 'c'
elseif !P(2) " should not be called
Xpath 'd'
else
Xpath 'e'
endif
Xpath 'f'
while P(4) " should not be called
Xpath 'g'
endwhile
Xpath 'h'
endif
Xpath 'x'
let g:test11_calls = calls
let g:test11_result = g:Xpath
unlet calls
delfunction P
func Test_arg_abort()
call assert_equal(0, g:test11_calls)
call assert_equal('ax', g:test11_result)
endfunc
"-------------------------------------------------------------------------------
" Test 12: Expressions in braces in skipped code {{{1
"
" In code skipped over due to an error or inactive conditional,
" an expression in braces as part of a variable or function name
" should not be evaluated.
"-------------------------------------------------------------------------------
XpathINIT
func NULL()
Xpath 'a'
return 0
endfunc
func ZERO()
Xpath 'b'
return 0
endfunc
func! F0()
Xpath 'c'
endfunc
func! F1(arg)
Xpath 'e'
endfunc
let V0 = 1
Xpath 'f'
echo 0 ? F{NULL() + V{ZERO()}}() : 1
Xpath 'g'
if 0
Xpath 'h'
call F{NULL() + V{ZERO()}}()
endif
Xpath 'i'
if 1
asdf " error
Xpath 'j'
call F1(F{NULL() + V{ZERO()}}())
endif
Xpath 'k'
if 1
asdf " error
Xpath 'l'
call F{NULL() + V{ZERO()}}()
endif
let g:test12_result = g:Xpath
func Test_braces_skipped()
call assert_equal('fgik', g:test12_result)
endfunc
"-------------------------------------------------------------------------------
" Test 13: Failure in argument evaluation for :while {{{1
"
" A failure in the expression evaluation for the condition of a :while
" causes the whole :while loop until the matching :endwhile being
" ignored. Continuation is at the next following line.
"-------------------------------------------------------------------------------
XpathINIT
Xpath 'a'
while asdf
Xpath 'b'
while 1
Xpath 'c'
break
endwhile
Xpath 'd'
break
endwhile
Xpath 'e'
while asdf | Xpath 'f' | endwhile | Xpath 'g'
Xpath 'h'
let g:test13_result = g:Xpath
func Test_while_fail()
call assert_equal('aeh', g:test13_result)
endfunc
"-------------------------------------------------------------------------------
" Test 14: Failure in argument evaluation for :if {{{1
"
" A failure in the expression evaluation for the condition of an :if
" does not cause the corresponding :else or :endif being matched to
" a previous :if/:elseif. Neither of both branches of the failed :if
" are executed.
"-------------------------------------------------------------------------------
XpathINIT
function! F()
Xpath 'a'
let x = 0
if x " false
Xpath 'b'
elseif !x " always true
Xpath 'c'
let x = 1
if g:boolvar " possibly undefined
Xpath 'd'
else
Xpath 'e'
endif
Xpath 'f'
elseif x " never executed
Xpath 'g'
endif
Xpath 'h'
endfunction
let boolvar = 1
call F()
Xpath '-'
unlet boolvar
call F()
let g:test14_result = g:Xpath
delfunction F
func Test_if_fail()
call assert_equal('acdfh-acfh', g:test14_result)
endfunc
"-------------------------------------------------------------------------------
" Test 15: Failure in argument evaluation for :if (bar) {{{1
"
" Like previous test, except that the failing :if ... | ... | :endif
" is in a single line.
"-------------------------------------------------------------------------------
XpathINIT
function! F()
Xpath 'a'
let x = 0
if x " false
Xpath 'b'
elseif !x " always true
Xpath 'c'
let x = 1
if g:boolvar | Xpath 'd' | else | Xpath 'e' | endif
Xpath 'f'
elseif x " never executed
Xpath 'g'
endif
Xpath 'h'
endfunction
let boolvar = 1
call F()
Xpath '-'
unlet boolvar
call F()
let g:test15_result = g:Xpath
delfunction F
func Test_if_bar_fail()
call assert_equal('acdfh-acfh', g:test15_result)
endfunc
"-------------------------------------------------------------------------------
" Test 16: Double :else or :elseif after :else {{{1
"
" Multiple :elses or an :elseif after an :else are forbidden.
"-------------------------------------------------------------------------------
func T16_F() abort
if 0
Xpath 'a'
else
Xpath 'b'
else " aborts function
Xpath 'c'
endif
Xpath 'd'
endfunc
func T16_G() abort
if 0
Xpath 'a'
else
Xpath 'b'
elseif 1 " aborts function
Xpath 'c'
else
Xpath 'd'
endif
Xpath 'e'
endfunc
func T16_H() abort
if 0
Xpath 'a'
elseif 0
Xpath 'b'
else
Xpath 'c'
else " aborts function
Xpath 'd'
endif
Xpath 'e'
endfunc
func T16_I() abort
if 0
Xpath 'a'
elseif 0
Xpath 'b'
else
Xpath 'c'
elseif 1 " aborts function
Xpath 'd'
else
Xpath 'e'
endif
Xpath 'f'
endfunc
func Test_Multi_Else()
XpathINIT
try
call T16_F()
catch /E583:/
Xpath 'e'
endtry
call assert_equal('be', g:Xpath)
XpathINIT
try
call T16_G()
catch /E584:/
Xpath 'f'
endtry
call assert_equal('bf', g:Xpath)
XpathINIT
try
call T16_H()
catch /E583:/
Xpath 'f'
endtry
call assert_equal('cf', g:Xpath)
XpathINIT
try
call T16_I()
catch /E584:/
Xpath 'g'
endtry
call assert_equal('cg', g:Xpath)
endfunc
"-------------------------------------------------------------------------------
" Test 17: Nesting of unmatched :if or :endif inside a :while {{{1
"
" The :while/:endwhile takes precedence in nesting over an unclosed
" :if or an unopened :endif.
"-------------------------------------------------------------------------------
" While loops inside a function are continued on error.
func T17_F()
let loops = 3
while loops > 0
let loops -= 1
Xpath 'a' . loops
if (loops == 1)
Xpath 'b' . loops
continue
elseif (loops == 0)
Xpath 'c' . loops
break
elseif 1
Xpath 'd' . loops
" endif missing!
endwhile " :endwhile after :if 1
Xpath 'e'
endfunc
func T17_G()
let loops = 2
while loops > 0
let loops -= 1
Xpath 'a' . loops
if 0
Xpath 'b' . loops
" endif missing
endwhile " :endwhile after :if 0
endfunc
func T17_H()
let loops = 2
while loops > 0
let loops -= 1
Xpath 'a' . loops
" if missing!
endif " :endif without :if in while
Xpath 'b' . loops
endwhile
endfunc
" Error continuation outside a function is at the outermost :endwhile or :endif.
XpathINIT
let v:errmsg = ''
let loops = 2
while loops > 0
let loops -= 1
Xpath 'a' . loops
if 0
Xpath 'b' . loops
" endif missing! Following :endwhile fails.
endwhile | Xpath 'c'
Xpath 'd'
call assert_match('E171:', v:errmsg)
call assert_equal('a1d', g:Xpath)
func Test_unmatched_if_in_while()
XpathINIT
call assert_fails('call T17_F()', 'E171:')
call assert_equal('a2d2a1b1a0c0e', g:Xpath)
XpathINIT
call assert_fails('call T17_G()', 'E171:')
call assert_equal('a1a0', g:Xpath)
XpathINIT
call assert_fails('call T17_H()', 'E580:')
call assert_equal('a1b1a0b0', g:Xpath)
endfunc
"-------------------------------------------------------------------------------
" Test 18: Interrupt (Ctrl-C pressed) {{{1
"
" On an interrupt, the script processing is terminated immediately.
"-------------------------------------------------------------------------------
func Test_interrupt_while_if()
let test =<< trim [CODE]
try
if 1
Xpath 'a'
while 1
Xpath 'b'
if 1
Xpath 'c'
call interrupt()
call assert_report('should not get here')
break
finish
endif | call assert_report('should not get here')
call assert_report('should not get here')
endwhile | call assert_report('should not get here')
call assert_report('should not get here')
endif | call assert_report('should not get here')
call assert_report('should not get here')
catch /^Vim:Interrupt$/
Xpath 'd'
endtry | Xpath 'e'
Xpath 'f'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdef', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_interrupt_try()
let test =<< trim [CODE]
try
try
Xpath 'a'
call interrupt()
call assert_report('should not get here')
endtry | call assert_report('should not get here')
call assert_report('should not get here')
catch /^Vim:Interrupt$/
Xpath 'b'
endtry | Xpath 'c'
Xpath 'd'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcd', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_interrupt_func_while_if()
let test =<< trim [CODE]
func F()
if 1
Xpath 'a'
while 1
Xpath 'b'
if 1
Xpath 'c'
call interrupt()
call assert_report('should not get here')
break
return
endif | call assert_report('should not get here')
call assert_report('should not get here')
endwhile | call assert_report('should not get here')
call assert_report('should not get here')
endif | call assert_report('should not get here')
call assert_report('should not get here')
endfunc
Xpath 'd'
try
call F() | call assert_report('should not get here')
catch /^Vim:Interrupt$/
Xpath 'e'
endtry | Xpath 'f'
Xpath 'g'
[CODE]
let verify =<< trim [CODE]
call assert_equal('dabcefg', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_interrupt_func_try()
let test =<< trim [CODE]
func G()
try
Xpath 'a'
call interrupt()
call assert_report('should not get here')
endtry | call assert_report('should not get here')
call assert_report('should not get here')
endfunc
Xpath 'b'
try
call G() | call assert_report('should not get here')
catch /^Vim:Interrupt$/
Xpath 'c'
endtry | Xpath 'd'
Xpath 'e'
[CODE]
let verify =<< trim [CODE]
call assert_equal('bacde', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 19: Aborting on errors inside :try/:endtry {{{1
"
" An error in a command dynamically enclosed in a :try/:endtry region
" aborts script processing immediately. It does not matter whether
" the failing command is outside or inside a function and whether a
" function has an "abort" attribute.
"-------------------------------------------------------------------------------
func Test_try_error_abort_1()
let test =<< trim [CODE]
func F() abort
Xpath 'a'
asdf
call assert_report('should not get here')
endfunc
try
Xpath 'b'
call F()
call assert_report('should not get here')
endtry | call assert_report('should not get here')
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('ba', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_try_error_abort_2()
let test =<< trim [CODE]
func G()
Xpath 'a'
asdf
call assert_report('should not get here')
endfunc
try
Xpath 'b'
call G()
call assert_report('should not get here')
endtry | call assert_report('should not get here')
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('ba', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_try_error_abort_3()
let test =<< trim [CODE]
try
Xpath 'a'
asdf
call assert_report('should not get here')
endtry | call assert_report('should not get here')
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('a', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_try_error_abort_4()
let test =<< trim [CODE]
if 1
try
Xpath 'a'
asdf
call assert_report('should not get here')
endtry | call assert_report('should not get here')
endif | call assert_report('should not get here')
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('a', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_try_error_abort_5()
let test =<< trim [CODE]
let p = 1
while p
let p = 0
try
Xpath 'a'
asdf
call assert_report('should not get here')
endtry | call assert_report('should not get here')
endwhile | call assert_report('should not get here')
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('a', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_try_error_abort_6()
let test =<< trim [CODE]
let p = 1
Xpath 'a'
while p
Xpath 'b'
let p = 0
try
Xpath 'c'
endwhile | call assert_report('should not get here')
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('abc', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 20: Aborting on errors after :try/:endtry {{{1
"
" When an error occurs after the last active :try/:endtry region has
" been left, termination behavior is as if no :try/:endtry has been
" seen.
"-------------------------------------------------------------------------------
func Test_error_after_try_1()
let test =<< trim [CODE]
let p = 1
while p
let p = 0
Xpath 'a'
try
Xpath 'b'
endtry
asdf
call assert_report('should not get here')
endwhile | call assert_report('should not get here')
Xpath 'c'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abc', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_error_after_try_2()
let test =<< trim [CODE]
while 1
try
Xpath 'a'
break
call assert_report('should not get here')
endtry
endwhile
Xpath 'b'
asdf
Xpath 'c'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abc', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_error_after_try_3()
let test =<< trim [CODE]
while 1
try
Xpath 'a'
break
call assert_report('should not get here')
finally
Xpath 'b'
endtry
endwhile
Xpath 'c'
asdf
Xpath 'd'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcd', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_error_after_try_4()
let test =<< trim [CODE]
while 1
try
Xpath 'a'
finally
Xpath 'b'
break
call assert_report('should not get here')
endtry
endwhile
Xpath 'c'
asdf
Xpath 'd'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcd', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_error_after_try_5()
let test =<< trim [CODE]
let p = 1
while p
let p = 0
try
Xpath 'a'
continue
call assert_report('should not get here')
endtry
endwhile
Xpath 'b'
asdf
Xpath 'c'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abc', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_error_after_try_6()
let test =<< trim [CODE]
let p = 1
while p
let p = 0
try
Xpath 'a'
continue
call assert_report('should not get here')
finally
Xpath 'b'
endtry
endwhile
Xpath 'c'
asdf
Xpath 'd'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcd', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_error_after_try_7()
let test =<< trim [CODE]
let p = 1
while p
let p = 0
try
Xpath 'a'
finally
Xpath 'b'
continue
call assert_report('should not get here')
endtry
endwhile
Xpath 'c'
asdf
Xpath 'd'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcd', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 21: :finally for :try after :continue/:break/:return/:finish {{{1
"
" If a :try conditional stays inactive due to a preceding :continue,
" :break, :return, or :finish, its :finally clause should not be
" executed.
"-------------------------------------------------------------------------------
func Test_finally_after_loop_ctrl_statement()
let test =<< trim [CODE]
func F()
let loops = 2
while loops > 0
XloopNEXT
let loops = loops - 1
try
if loops == 1
Xloop 'a'
continue
call assert_report('should not get here')
elseif loops == 0
Xloop 'b'
break
call assert_report('should not get here')
endif
try " inactive
call assert_report('should not get here')
finally
call assert_report('should not get here')
endtry
finally
Xloop 'c'
endtry
call assert_report('should not get here')
endwhile
try
Xpath 'd'
return
call assert_report('should not get here')
try " inactive
call assert_report('should not get here')
finally
call assert_report('should not get here')
endtry
finally
Xpath 'e'
endtry
call assert_report('should not get here')
endfunc
try
Xpath 'f'
call F()
Xpath 'g'
finish
call assert_report('should not get here')
try " inactive
call assert_report('should not get here')
finally
call assert_report('should not get here')
endtry
finally
Xpath 'h'
endtry
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('fa2c2b3c3degh', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 22: :finally for a :try after an error/interrupt/:throw {{{1
"
" If a :try conditional stays inactive due to a preceding error or
" interrupt or :throw, its :finally clause should not be executed.
"-------------------------------------------------------------------------------
func Test_finally_after_error_in_func()
let test =<< trim [CODE]
func Error()
try
Xpath 'b'
asdf " aborting error, triggering error exception
call assert_report('should not get here')
endtry
call assert_report('should not get here')
endfunc
Xpath 'a'
call Error()
call assert_report('should not get here')
if 1 " not active due to error
try " not active since :if inactive
call assert_report('should not get here')
finally
call assert_report('should not get here')
endtry
endif
try " not active due to error
call assert_report('should not get here')
finally
call assert_report('should not get here')
endtry
[CODE]
let verify =<< trim [CODE]
call assert_equal('ab', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_finally_after_interrupt()
let test =<< trim [CODE]
func Interrupt()
try
Xpath 'a'
call interrupt() " triggering interrupt exception
call assert_report('should not get here')
endtry
endfunc
Xpath 'b'
try
call Interrupt()
catch /^Vim:Interrupt$/
Xpath 'c'
finish
endtry
call assert_report('should not get here')
if 1 " not active due to interrupt
try " not active since :if inactive
call assert_report('should not get here')
finally
call assert_report('should not get here')
endtry
endif
try " not active due to interrupt
call assert_report('should not get here')
finally
call assert_report('should not get here')
endtry
[CODE]
let verify =<< trim [CODE]
call assert_equal('bac', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_finally_after_throw()
let test =<< trim [CODE]
func Throw()
Xpath 'a'
throw 'xyz'
endfunc
Xpath 'b'
call Throw()
call assert_report('should not get here')
if 1 " not active due to :throw
try " not active since :if inactive
call assert_report('should not get here')
finally
call assert_report('should not get here')
endtry
endif
try " not active due to :throw
call assert_report('should not get here')
finally
call assert_report('should not get here')
endtry
[CODE]
let verify =<< trim [CODE]
call assert_equal('ba', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 23: :catch clauses for a :try after a :throw {{{1
"
" If a :try conditional stays inactive due to a preceding :throw,
" none of its :catch clauses should be executed.
"-------------------------------------------------------------------------------
func Test_catch_after_throw()
let test =<< trim [CODE]
try
Xpath 'a'
throw "xyz"
call assert_report('should not get here')
if 1 " not active due to :throw
try " not active since :if inactive
call assert_report('should not get here')
catch /xyz/
call assert_report('should not get here')
endtry
endif
catch /xyz/
Xpath 'b'
endtry
Xpath 'c'
throw "abc"
call assert_report('should not get here')
try " not active due to :throw
call assert_report('should not get here')
catch /abc/
call assert_report('should not get here')
endtry
[CODE]
let verify =<< trim [CODE]
call assert_equal('abc', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 24: :endtry for a :try after a :throw {{{1
"
" If a :try conditional stays inactive due to a preceding :throw,
" its :endtry should not rethrow the exception to the next surrounding
" active :try conditional.
"-------------------------------------------------------------------------------
func Test_endtry_after_throw()
let test =<< trim [CODE]
try " try 1
try " try 2
Xpath 'a'
throw "xyz" " makes try 2 inactive
call assert_report('should not get here')
try " try 3
call assert_report('should not get here')
endtry " no rethrow to try 1
catch /xyz/ " should catch although try 2 inactive
Xpath 'b'
endtry
catch /xyz/ " try 1 active, but exception already caught
call assert_report('should not get here')
endtry
Xpath 'c'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abc', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 27: Executing :finally clauses after :return {{{1
"
" For a :return command dynamically enclosed in a :try/:endtry region,
" :finally clauses are executed and the called function is ended.
"-------------------------------------------------------------------------------
func T27_F()
try
Xpath 'a'
try
Xpath 'b'
return
call assert_report('should not get here')
finally
Xpath 'c'
endtry
Xpath 'd'
finally
Xpath 'e'
endtry
call assert_report('should not get here')
endfunc
func T27_G()
try
Xpath 'f'
return
call assert_report('should not get here')
finally
Xpath 'g'
call T27_F()
Xpath 'h'
endtry
call assert_report('should not get here')
endfunc
func T27_H()
try
Xpath 'i'
call T27_G()
Xpath 'j'
finally
Xpath 'k'
return
call assert_report('should not get here')
endtry
call assert_report('should not get here')
endfunction
func Test_finally_after_return()
XpathINIT
try
Xpath 'l'
call T27_H()
Xpath 'm'
finally
Xpath 'n'
endtry
call assert_equal('lifgabcehjkmn', g:Xpath)
endfunc
"-------------------------------------------------------------------------------
" Test 28: Executing :finally clauses after :finish {{{1
"
" For a :finish command dynamically enclosed in a :try/:endtry region,
" :finally clauses are executed and the sourced file is finished.
"
" This test executes the bodies of the functions F, G, and H from the
" previous test as script files (:return replaced by :finish).
"-------------------------------------------------------------------------------
func Test_finally_after_finish()
XpathINIT
let scriptF = MakeScript("T27_F")
let scriptG = MakeScript("T27_G", scriptF)
let scriptH = MakeScript("T27_H", scriptG)
try
Xpath 'A'
exec "source" scriptH
Xpath 'B'
finally
Xpath 'C'
endtry
Xpath 'D'
call assert_equal('AifgabcehjkBCD', g:Xpath)
call delete(scriptF)
call delete(scriptG)
call delete(scriptH)
endfunc
"-------------------------------------------------------------------------------
" Test 29: Executing :finally clauses on errors {{{1
"
" After an error in a command dynamically enclosed in a :try/:endtry
" region, :finally clauses are executed and the script processing is
" terminated.
"-------------------------------------------------------------------------------
func Test_finally_after_error_1()
let test =<< trim [CODE]
func F()
while 1
try
Xpath 'a'
while 1
try
Xpath 'b'
asdf " error
call assert_report('should not get here')
finally
Xpath 'c'
endtry | call assert_report('should not get here')
call assert_report('should not get here')
break
endwhile
call assert_report('should not get here')
finally
Xpath 'd'
endtry | call assert_report('should not get here')
call assert_report('should not get here')
break
endwhile
call assert_report('should not get here')
endfunc
while 1
try
Xpath 'e'
while 1
call F()
call assert_report('should not get here')
break
endwhile | call assert_report('should not get here')
call assert_report('should not get here')
finally
Xpath 'f'
endtry | call assert_report('should not get here')
endwhile | call assert_report('should not get here')
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('eabcdf', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_finally_after_error_2()
let test =<< trim [CODE]
func G() abort
if 1
try
Xpath 'a'
asdf " error
call assert_report('should not get here')
finally
Xpath 'b'
endtry | Xpath 'c'
endif | Xpath 'd'
call assert_report('should not get here')
endfunc
if 1
try
Xpath 'e'
call G()
call assert_report('should not get here')
finally
Xpath 'f'
endtry | call assert_report('should not get here')
endif | call assert_report('should not get here')
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('eabf', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 30: Executing :finally clauses on interrupt {{{1
"
" After an interrupt in a command dynamically enclosed in
" a :try/:endtry region, :finally clauses are executed and the
" script processing is terminated.
"-------------------------------------------------------------------------------
func Test_finally_on_interrupt()
let test =<< trim [CODE]
func F()
try
Xloop 'a'
call interrupt()
call assert_report('should not get here')
finally
Xloop 'b'
endtry
call assert_report('should not get here')
endfunc
try
try
Xpath 'c'
try
Xpath 'd'
call interrupt()
call assert_report('should not get here')
finally
Xpath 'e'
try
Xpath 'f'
try
Xpath 'g'
finally
Xpath 'h'
try
Xpath 'i'
call interrupt()
call assert_report('should not get here')
endtry
call assert_report('should not get here')
endtry
call assert_report('should not get here')
endtry
call assert_report('should not get here')
endtry
call assert_report('should not get here')
finally
Xpath 'j'
try
Xpath 'k'
call F()
call assert_report('should not get here')
finally
Xpath 'l'
try
Xpath 'm'
XloopNEXT
ExecAsScript F
call assert_report('should not get here')
finally
Xpath 'n'
endtry
call assert_report('should not get here')
endtry
call assert_report('should not get here')
endtry
call assert_report('should not get here')
catch /^Vim:Interrupt$/
Xpath 'o'
endtry
[CODE]
let verify =<< trim [CODE]
call assert_equal('cdefghijka1b1lma2b2no', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 31: Executing :finally clauses after :throw {{{1
"
" After a :throw dynamically enclosed in a :try/:endtry region,
" :finally clauses are executed and the script processing is
" terminated.
"-------------------------------------------------------------------------------
func Test_finally_after_throw_2()
let test =<< trim [CODE]
func F()
try
Xloop 'a'
throw "exception"
call assert_report('should not get here')
finally
Xloop 'b'
endtry
call assert_report('should not get here')
endfunc
try
Xpath 'c'
try
Xpath 'd'
throw "exception"
call assert_report('should not get here')
finally
Xpath 'e'
try
Xpath 'f'
try
Xpath 'g'
finally
Xpath 'h'
try
Xpath 'i'
throw "exception"
call assert_report('should not get here')
endtry
call assert_report('should not get here')
endtry
call assert_report('should not get here')
endtry
call assert_report('should not get here')
endtry
call assert_report('should not get here')
finally
Xpath 'j'
try
Xpath 'k'
call F()
call assert_report('should not get here')
finally
Xpath 'l'
try
Xpath 'm'
XloopNEXT
ExecAsScript F
call assert_report('should not get here')
finally
Xpath 'n'
endtry
call assert_report('should not get here')
endtry
call assert_report('should not get here')
endtry
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('cdefghijka1b1lma2b2n', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 34: :finally reason discarded by :continue {{{1
"
" When a :finally clause is executed due to a :continue, :break,
" :return, :finish, error, interrupt or :throw, the jump reason is
" discarded by a :continue in the finally clause.
"-------------------------------------------------------------------------------
func Test_finally_after_continue()
let test =<< trim [CODE]
func C(jump)
XloopNEXT
let loop = 0
while loop < 2
let loop = loop + 1
if loop == 1
try
if a:jump == "continue"
continue
elseif a:jump == "break"
break
elseif a:jump == "return" || a:jump == "finish"
return
elseif a:jump == "error"
asdf
elseif a:jump == "interrupt"
call interrupt()
let dummy = 0
elseif a:jump == "throw"
throw "abc"
endif
finally
continue " discards jump that caused the :finally
call assert_report('should not get here')
endtry
call assert_report('should not get here')
elseif loop == 2
Xloop 'a'
endif
endwhile
endfunc
call C("continue")
Xpath 'b'
call C("break")
Xpath 'c'
call C("return")
Xpath 'd'
let g:jump = "finish"
ExecAsScript C
unlet g:jump
Xpath 'e'
try
call C("error")
Xpath 'f'
finally
Xpath 'g'
try
call C("interrupt")
Xpath 'h'
finally
Xpath 'i'
call C("throw")
Xpath 'j'
endtry
endtry
Xpath 'k'
[CODE]
let verify =<< trim [CODE]
call assert_equal('a2ba3ca4da5ea6fga7hia8jk', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 35: :finally reason discarded by :break {{{1
"
" When a :finally clause is executed due to a :continue, :break,
" :return, :finish, error, interrupt or :throw, the jump reason is
" discarded by a :break in the finally clause.
"-------------------------------------------------------------------------------
func Test_finally_discard_by_break()
let test =<< trim [CODE]
func B(jump)
XloopNEXT
let loop = 0
while loop < 2
let loop = loop + 1
if loop == 1
try
if a:jump == "continue"
continue
elseif a:jump == "break"
break
elseif a:jump == "return" || a:jump == "finish"
return
elseif a:jump == "error"
asdf
elseif a:jump == "interrupt"
call interrupt()
let dummy = 0
elseif a:jump == "throw"
throw "abc"
endif
finally
break " discards jump that caused the :finally
call assert_report('should not get here')
endtry
elseif loop == 2
call assert_report('should not get here')
endif
endwhile
Xloop 'a'
endfunc
call B("continue")
Xpath 'b'
call B("break")
Xpath 'c'
call B("return")
Xpath 'd'
let g:jump = "finish"
ExecAsScript B
unlet g:jump
Xpath 'e'
try
call B("error")
Xpath 'f'
finally
Xpath 'g'
try
call B("interrupt")
Xpath 'h'
finally
Xpath 'i'
call B("throw")
Xpath 'j'
endtry
endtry
Xpath 'k'
[CODE]
let verify =<< trim [CODE]
call assert_equal('a2ba3ca4da5ea6fga7hia8jk', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 36: :finally reason discarded by :return {{{1
"
" When a :finally clause is executed due to a :continue, :break,
" :return, :finish, error, interrupt or :throw, the jump reason is
" discarded by a :return in the finally clause.
"-------------------------------------------------------------------------------
func Test_finally_discard_by_return()
let test =<< trim [CODE]
func R(jump, retval) abort
let loop = 0
while loop < 2
let loop = loop + 1
if loop == 1
try
if a:jump == "continue"
continue
elseif a:jump == "break"
break
elseif a:jump == "return"
return
elseif a:jump == "error"
asdf
elseif a:jump == "interrupt"
call interrupt()
let dummy = 0
elseif a:jump == "throw"
throw "abc"
endif
finally
return a:retval " discards jump that caused the :finally
call assert_report('should not get here')
endtry
elseif loop == 2
call assert_report('should not get here')
endif
endwhile
call assert_report('should not get here')
endfunc
let sum = -R("continue", -8)
Xpath 'a'
let sum = sum - R("break", -16)
Xpath 'b'
let sum = sum - R("return", -32)
Xpath 'c'
try
let sum = sum - R("error", -64)
Xpath 'd'
finally
Xpath 'e'
try
let sum = sum - R("interrupt", -128)
Xpath 'f'
finally
Xpath 'g'
let sum = sum - R("throw", -256)
Xpath 'h'
endtry
endtry
Xpath 'i'
let expected = 8 + 16 + 32 + 64 + 128 + 256
call assert_equal(sum, expected)
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdefghi', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 37: :finally reason discarded by :finish {{{1
"
" When a :finally clause is executed due to a :continue, :break,
" :return, :finish, error, interrupt or :throw, the jump reason is
" discarded by a :finish in the finally clause.
"-------------------------------------------------------------------------------
func Test_finally_discard_by_finish()
let test =<< trim [CODE]
func F(jump) " not executed as function, transformed to a script
let loop = 0
while loop < 2
let loop = loop + 1
if loop == 1
try
if a:jump == "continue"
continue
elseif a:jump == "break"
break
elseif a:jump == "finish"
finish
elseif a:jump == "error"
asdf
elseif a:jump == "interrupt"
call interrupt()
let dummy = 0
elseif a:jump == "throw"
throw "abc"
endif
finally
finish " discards jump that caused the :finally
call assert_report('should not get here')
endtry
elseif loop == 2
call assert_report('should not get here')
endif
endwhile
call assert_report('should not get here')
endfunc
let scriptF = MakeScript("F")
delfunction F
let g:jump = "continue"
exec "source" scriptF
Xpath 'a'
let g:jump = "break"
exec "source" scriptF
Xpath 'b'
let g:jump = "finish"
exec "source" scriptF
Xpath 'c'
try
let g:jump = "error"
exec "source" scriptF
Xpath 'd'
finally
Xpath 'e'
try
let g:jump = "interrupt"
exec "source" scriptF
Xpath 'f'
finally
Xpath 'g'
try
let g:jump = "throw"
exec "source" scriptF
Xpath 'h'
finally
Xpath 'i'
endtry
endtry
endtry
unlet g:jump
call delete(scriptF)
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdefghi', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 38: :finally reason discarded by an error {{{1
"
" When a :finally clause is executed due to a :continue, :break,
" :return, :finish, error, interrupt or :throw, the jump reason is
" discarded by an error in the finally clause.
"-------------------------------------------------------------------------------
func Test_finally_discard_by_error()
let test =<< trim [CODE]
func E(jump)
let loop = 0
while loop < 2
let loop = loop + 1
if loop == 1
try
if a:jump == "continue"
continue
elseif a:jump == "break"
break
elseif a:jump == "return" || a:jump == "finish"
return
elseif a:jump == "error"
asdf
elseif a:jump == "interrupt"
call interrupt()
let dummy = 0
elseif a:jump == "throw"
throw "abc"
endif
finally
asdf " error; discards jump that caused the :finally
endtry
elseif loop == 2
call assert_report('should not get here')
endif
endwhile
call assert_report('should not get here')
endfunc
try
Xpath 'a'
call E("continue")
call assert_report('should not get here')
finally
try
Xpath 'b'
call E("break")
call assert_report('should not get here')
finally
try
Xpath 'c'
call E("return")
call assert_report('should not get here')
finally
try
Xpath 'd'
let g:jump = "finish"
ExecAsScript E
call assert_report('should not get here')
finally
unlet g:jump
try
Xpath 'e'
call E("error")
call assert_report('should not get here')
finally
try
Xpath 'f'
call E("interrupt")
call assert_report('should not get here')
finally
try
Xpath 'g'
call E("throw")
call assert_report('should not get here')
finally
Xpath 'h'
delfunction E
endtry
endtry
endtry
endtry
endtry
endtry
endtry
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdefgh', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 39: :finally reason discarded by an interrupt {{{1
"
" When a :finally clause is executed due to a :continue, :break,
" :return, :finish, error, interrupt or :throw, the jump reason is
" discarded by an interrupt in the finally clause.
"-------------------------------------------------------------------------------
func Test_finally_discarded_by_interrupt()
let test =<< trim [CODE]
func I(jump)
let loop = 0
while loop < 2
let loop = loop + 1
if loop == 1
try
if a:jump == "continue"
continue
elseif a:jump == "break"
break
elseif a:jump == "return" || a:jump == "finish"
return
elseif a:jump == "error"
asdf
elseif a:jump == "interrupt"
call interrupt()
let dummy = 0
elseif a:jump == "throw"
throw "abc"
endif
finally
call interrupt()
let dummy = 0
endtry
elseif loop == 2
call assert_report('should not get here')
endif
endwhile
call assert_report('should not get here')
endfunc
try
try
Xpath 'a'
call I("continue")
call assert_report('should not get here')
finally
try
Xpath 'b'
call I("break")
call assert_report('should not get here')
finally
try
Xpath 'c'
call I("return")
call assert_report('should not get here')
finally
try
Xpath 'd'
let g:jump = "finish"
ExecAsScript I
call assert_report('should not get here')
finally
unlet g:jump
try
Xpath 'e'
call I("error")
call assert_report('should not get here')
finally
try
Xpath 'f'
call I("interrupt")
call assert_report('should not get here')
finally
try
Xpath 'g'
call I("throw")
call assert_report('should not get here')
finally
Xpath 'h'
delfunction I
endtry
endtry
endtry
endtry
endtry
endtry
endtry
call assert_report('should not get here')
catch /^Vim:Interrupt$/
Xpath 'A'
endtry
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdefghA', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 40: :finally reason discarded by :throw {{{1
"
" When a :finally clause is executed due to a :continue, :break,
" :return, :finish, error, interrupt or :throw, the jump reason is
" discarded by a :throw in the finally clause.
"-------------------------------------------------------------------------------
func Test_finally_discard_by_throw()
let test =<< trim [CODE]
func T(jump)
let loop = 0
while loop < 2
let loop = loop + 1
if loop == 1
try
if a:jump == "continue"
continue
elseif a:jump == "break"
break
elseif a:jump == "return" || a:jump == "finish"
return
elseif a:jump == "error"
asdf
elseif a:jump == "interrupt"
call interrupt()
let dummy = 0
elseif a:jump == "throw"
throw "abc"
endif
finally
throw "xyz" " discards jump that caused the :finally
endtry
elseif loop == 2
call assert_report('should not get here')
endif
endwhile
call assert_report('should not get here')
endfunc
try
Xpath 'a'
call T("continue")
call assert_report('should not get here')
finally
try
Xpath 'b'
call T("break")
call assert_report('should not get here')
finally
try
Xpath 'c'
call T("return")
call assert_report('should not get here')
finally
try
Xpath 'd'
let g:jump = "finish"
ExecAsScript T
call assert_report('should not get here')
finally
unlet g:jump
try
Xpath 'e'
call T("error")
call assert_report('should not get here')
finally
try
Xpath 'f'
call T("interrupt")
call assert_report('should not get here')
finally
try
Xpath 'g'
call T("throw")
call assert_report('should not get here')
finally
Xpath 'h'
delfunction T
endtry
endtry
endtry
endtry
endtry
endtry
endtry
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdefgh', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 49: Throwing exceptions across functions {{{1
"
" When an exception is thrown but not caught inside a function, the
" caller is checked for a matching :catch clause.
"-------------------------------------------------------------------------------
func T49_C()
try
Xpath 'a'
throw "arrgh"
call assert_report('should not get here')
catch /arrgh/
Xpath 'b'
endtry
Xpath 'c'
endfunc
func T49_T1()
XloopNEXT
try
Xloop 'd'
throw "arrgh"
call assert_report('should not get here')
finally
Xloop 'e'
endtry
Xloop 'f'
endfunc
func T49_T2()
try
Xpath 'g'
call T49_T1()
call assert_report('should not get here')
finally
Xpath 'h'
endtry
call assert_report('should not get here')
endfunc
func Test_throw_exception_across_funcs()
XpathINIT
XloopINIT
try
Xpath 'i'
call T49_C() " throw and catch
Xpath 'j'
catch /.*/
call assert_report('should not get here')
endtry
try
Xpath 'k'
call T49_T1() " throw, one level
call assert_report('should not get here')
catch /arrgh/
Xpath 'l'
catch /.*/
call assert_report('should not get here')
endtry
try
Xpath 'm'
call T49_T2() " throw, two levels
call assert_report('should not get here')
catch /arrgh/
Xpath 'n'
catch /.*/
call assert_report('should not get here')
endtry
Xpath 'o'
call assert_equal('iabcjkd2e2lmgd3e3hno', g:Xpath)
endfunc
"-------------------------------------------------------------------------------
" Test 50: Throwing exceptions across script files {{{1
"
" When an exception is thrown but not caught inside a script file,
" the sourcing script or function is checked for a matching :catch
" clause.
"
" This test executes the bodies of the functions C, T1, and T2 from
" the previous test as script files (:return replaced by :finish).
"-------------------------------------------------------------------------------
func T50_F()
try
Xpath 'A'
exec "source" g:scriptC
Xpath 'B'
catch /.*/
call assert_report('should not get here')
endtry
try
Xpath 'C'
exec "source" g:scriptT1
call assert_report('should not get here')
catch /arrgh/
Xpath 'D'
catch /.*/
call assert_report('should not get here')
endtry
endfunc
func Test_throw_across_script()
XpathINIT
XloopINIT
let g:scriptC = MakeScript("T49_C")
let g:scriptT1 = MakeScript("T49_T1")
let scriptT2 = MakeScript("T49_T2", g:scriptT1)
try
Xpath 'E'
call T50_F()
Xpath 'F'
exec "source" scriptT2
call assert_report('should not get here')
catch /arrgh/
Xpath 'G'
catch /.*/
call assert_report('should not get here')
endtry
Xpath 'H'
call assert_equal('EAabcBCd2e2DFgd3e3hGH', g:Xpath)
call delete(g:scriptC)
call delete(g:scriptT1)
call delete(scriptT2)
unlet g:scriptC g:scriptT1 scriptT2
endfunc
"-------------------------------------------------------------------------------
" Test 52: Uncaught exceptions {{{1
"
" When an exception is thrown but not caught, an error message is
" displayed when the script is terminated. In case of an interrupt
" or error exception, the normal interrupt or error message(s) are
" displayed.
"-------------------------------------------------------------------------------
func Test_uncaught_exception_1()
CheckEnglish
let test =<< trim [CODE]
Xpath 'a'
throw "arrgh"
call assert_report('should not get here')`
[CODE]
let verify =<< trim [CODE]
call assert_equal('E605: Exception not caught: arrgh', v:errmsg)
call assert_equal('a', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_uncaught_exception_2()
CheckEnglish
let test =<< trim [CODE]
try
Xpath 'a'
throw "oops"
call assert_report('should not get here')`
catch /arrgh/
call assert_report('should not get here')`
endtry
call assert_report('should not get here')`
[CODE]
let verify =<< trim [CODE]
call assert_equal('E605: Exception not caught: oops', v:errmsg)
call assert_equal('a', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_uncaught_exception_3()
CheckEnglish
let test =<< trim [CODE]
func T()
Xpath 'c'
throw "brrr"
call assert_report('should not get here')`
endfunc
try
Xpath 'a'
throw "arrgh"
call assert_report('should not get here')`
catch /.*/
Xpath 'b'
call T()
call assert_report('should not get here')`
endtry
call assert_report('should not get here')`
[CODE]
let verify =<< trim [CODE]
call assert_equal('E605: Exception not caught: brrr', v:errmsg)
call assert_equal('abc', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_uncaught_exception_4()
CheckEnglish
let test =<< trim [CODE]
try
Xpath 'a'
throw "arrgh"
call assert_report('should not get here')`
finally
Xpath 'b'
throw "brrr"
call assert_report('should not get here')`
endtry
call assert_report('should not get here')`
[CODE]
let verify =<< trim [CODE]
call assert_equal('E605: Exception not caught: brrr', v:errmsg)
call assert_equal('ab', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_uncaught_exception_5()
CheckEnglish
" Need to catch and handle interrupt, otherwise the test will wait for the
" user to press <Enter> to continue
let test =<< trim [CODE]
try
try
Xpath 'a'
call interrupt()
call assert_report('should not get here')
endtry
call assert_report('should not get here')
catch /^Vim:Interrupt$/
Xpath 'b'
endtry
[CODE]
let verify =<< trim [CODE]
call assert_equal('ab', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_uncaught_exception_6()
CheckEnglish
let test =<< trim [CODE]
try
Xpath 'a'
let x = novar " error E121; exception: E121
catch /E15:/ " should not catch
call assert_report('should not get here')
endtry
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('a', g:Xpath)
call assert_equal('E121: Undefined variable: novar', v:errmsg)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_uncaught_exception_7()
CheckEnglish
let test =<< trim [CODE]
try
Xpath 'a'
" error E108/E488; exception: E488
unlet novar #
catch /E108:/ " should not catch
call assert_report('should not get here')
endtry
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('a', g:Xpath)
call assert_equal('E488: Trailing characters: #', v:errmsg)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 53: Nesting errors: :endif/:else/:elseif {{{1
"
" For nesting errors of :if conditionals the correct error messages
" should be given.
"-------------------------------------------------------------------------------
func Test_nested_if_else_errors()
CheckEnglish
" :endif without :if
let code =<< trim END
endif
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
" :endif without :if
let code =<< trim END
while 1
endif
endwhile
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
" :endif without :if
let code =<< trim END
try
finally
endif
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
" :endif without :if
let code =<< trim END
try
endif
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
" :endif without :if
let code =<< trim END
try
throw "a"
catch /a/
endif
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
" :else without :if
let code =<< trim END
else
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
" :else without :if
let code =<< trim END
while 1
else
endwhile
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
" :else without :if
let code =<< trim END
try
finally
else
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
" :else without :if
let code =<< trim END
try
else
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
" :else without :if
let code =<< trim END
try
throw "a"
catch /a/
else
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
" :elseif without :if
let code =<< trim END
elseif 1
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
" :elseif without :if
let code =<< trim END
while 1
elseif 1
endwhile
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
" :elseif without :if
let code =<< trim END
try
finally
elseif 1
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
" :elseif without :if
let code =<< trim END
try
elseif 1
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
" :elseif without :if
let code =<< trim END
try
throw "a"
catch /a/
elseif 1
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
" multiple :else
let code =<< trim END
if 1
else
else
endif
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(else):E583: Multiple :else')
" :elseif after :else
let code =<< trim END
if 1
else
elseif 1
endif
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(elseif):E584: :elseif after :else')
call delete('Xtest')
endfunc
"-------------------------------------------------------------------------------
" Test 54: Nesting errors: :while/:endwhile {{{1
"
" For nesting errors of :while conditionals the correct error messages
" should be given.
"
" This test reuses the function MESSAGES() from the previous test.
" This function checks the messages in g:msgfile.
"-------------------------------------------------------------------------------
func Test_nested_while_error()
CheckEnglish
" :endwhile without :while
let code =<< trim END
endwhile
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
" :endwhile without :while
let code =<< trim END
if 1
endwhile
endif
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
" Missing :endif
let code =<< trim END
while 1
if 1
endwhile
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endwhile):E171: Missing :endif')
" :endwhile without :while
let code =<< trim END
try
finally
endwhile
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
" Missing :endtry
let code =<< trim END
while 1
try
finally
endwhile
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endwhile):E600: Missing :endtry')
" Missing :endtry
let code =<< trim END
while 1
if 1
try
finally
endwhile
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endwhile):E600: Missing :endtry')
" Missing :endif
let code =<< trim END
while 1
try
finally
if 1
endwhile
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endwhile):E171: Missing :endif')
" :endwhile without :while
let code =<< trim END
try
endwhile
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
" :endwhile without :while
let code =<< trim END
while 1
try
endwhile
endtry
endwhile
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
" :endwhile without :while
let code =<< trim END
try
throw "a"
catch /a/
endwhile
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
" :endwhile without :while
let code =<< trim END
while 1
try
throw "a"
catch /a/
endwhile
endtry
endwhile
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
call delete('Xtest')
endfunc
"-------------------------------------------------------------------------------
" Test 55: Nesting errors: :continue/:break {{{1
"
" For nesting errors of :continue and :break commands the correct
" error messages should be given.
"
" This test reuses the function MESSAGES() from the previous test.
" This function checks the messages in g:msgfile.
"-------------------------------------------------------------------------------
func Test_nested_cont_break_error()
CheckEnglish
" :continue without :while
let code =<< trim END
continue
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
" :continue without :while
let code =<< trim END
if 1
continue
endif
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
" :continue without :while
let code =<< trim END
try
finally
continue
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
" :continue without :while
let code =<< trim END
try
continue
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
" :continue without :while
let code =<< trim END
try
throw "a"
catch /a/
continue
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
" :break without :while
let code =<< trim END
break
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
" :break without :while
let code =<< trim END
if 1
break
endif
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
" :break without :while
let code =<< trim END
try
finally
break
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
" :break without :while
let code =<< trim END
try
break
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
" :break without :while
let code =<< trim END
try
throw "a"
catch /a/
break
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
call delete('Xtest')
endfunc
"-------------------------------------------------------------------------------
" Test 56: Nesting errors: :endtry {{{1
"
" For nesting errors of :try conditionals the correct error messages
" should be given.
"
" This test reuses the function MESSAGES() from the previous test.
" This function check the messages in g:msgfile.
"-------------------------------------------------------------------------------
func Test_nested_endtry_error()
CheckEnglish
" :endtry without :try
let code =<< trim END
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endtry):E602: :endtry without :try')
" :endtry without :try
let code =<< trim END
if 1
endtry
endif
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endtry):E602: :endtry without :try')
" :endtry without :try
let code =<< trim END
while 1
endtry
endwhile
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endtry):E602: :endtry without :try')
" Missing :endif
let code =<< trim END
try
if 1
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endtry):E171: Missing :endif')
" Missing :endwhile
let code =<< trim END
try
while 1
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endtry):E170: Missing :endwhile')
" Missing :endif
let code =<< trim END
try
finally
if 1
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endtry):E171: Missing :endif')
" Missing :endwhile
let code =<< trim END
try
finally
while 1
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endtry):E170: Missing :endwhile')
" Missing :endif
let code =<< trim END
try
throw "a"
catch /a/
if 1
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endtry):E171: Missing :endif')
" Missing :endwhile
let code =<< trim END
try
throw "a"
catch /a/
while 1
endtry
END
call writefile(code, 'Xtest')
call AssertException(['source Xtest'], 'Vim(endtry):E170: Missing :endwhile')
call delete('Xtest')
endfunc
"-------------------------------------------------------------------------------
" Test 57: v:exception and v:throwpoint for user exceptions {{{1
"
" v:exception evaluates to the value of the exception that was caught
" most recently and is not finished. (A caught exception is finished
" when the next ":catch", ":finally", or ":endtry" is reached.)
" v:throwpoint evaluates to the script/function name and line number
" where that exception has been thrown.
"-------------------------------------------------------------------------------
func Test_user_exception_info()
CheckEnglish
XpathINIT
XloopINIT
func FuncException()
let g:exception = v:exception
endfunc
func FuncThrowpoint()
let g:throwpoint = v:throwpoint
endfunc
let scriptException = MakeScript("FuncException")
let scriptThrowPoint = MakeScript("FuncThrowpoint")
command! CmdException let g:exception = v:exception
command! CmdThrowpoint let g:throwpoint = v:throwpoint
func T(arg, line)
if a:line == 2
throw a:arg " in line 2
elseif a:line == 4
throw a:arg " in line 4
elseif a:line == 6
throw a:arg " in line 6
elseif a:line == 8
throw a:arg " in line 8
endif
endfunc
func G(arg, line)
call T(a:arg, a:line)
endfunc
func F(arg, line)
call G(a:arg, a:line)
endfunc
let scriptT = MakeScript("T")
let scriptG = MakeScript("G", scriptT)
let scriptF = MakeScript("F", scriptG)
try
Xpath 'a'
call F("oops", 2)
catch /.*/
Xpath 'b'
let exception = v:exception
let throwpoint = v:throwpoint
call assert_equal("oops", v:exception)
call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<2\>', v:throwpoint)
exec "let exception = v:exception"
exec "let throwpoint = v:throwpoint"
call assert_equal("oops", v:exception)
call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<2\>', v:throwpoint)
CmdException
CmdThrowpoint
call assert_equal("oops", v:exception)
call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<2\>', v:throwpoint)
call FuncException()
call FuncThrowpoint()
call assert_equal("oops", v:exception)
call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<2\>', v:throwpoint)
exec "source" scriptException
exec "source" scriptThrowPoint
call assert_equal("oops", v:exception)
call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<2\>', v:throwpoint)
try
Xpath 'c'
call G("arrgh", 4)
catch /.*/
Xpath 'd'
let exception = v:exception
let throwpoint = v:throwpoint
call assert_equal("arrgh", v:exception)
call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<4\>', v:throwpoint)
try
Xpath 'e'
let g:arg = "autsch"
let g:line = 6
exec "source" scriptF
catch /.*/
Xpath 'f'
let exception = v:exception
let throwpoint = v:throwpoint
call assert_equal("autsch", v:exception)
call assert_match(fnamemodify(scriptT, ':t'), v:throwpoint)
call assert_match('\<6\>', v:throwpoint)
finally
Xpath 'g'
let exception = v:exception
let throwpoint = v:throwpoint
call assert_equal("arrgh", v:exception)
call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<4\>', v:throwpoint)
try
Xpath 'h'
let g:arg = "brrrr"
let g:line = 8
exec "source" scriptG
catch /.*/
Xpath 'i'
let exception = v:exception
let throwpoint = v:throwpoint
" Resolve scriptT for matching it against v:throwpoint.
call assert_equal("brrrr", v:exception)
call assert_match(fnamemodify(scriptT, ':t'), v:throwpoint)
call assert_match('\<8\>', v:throwpoint)
finally
Xpath 'j'
let exception = v:exception
let throwpoint = v:throwpoint
call assert_equal("arrgh", v:exception)
call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<4\>', v:throwpoint)
endtry
Xpath 'k'
let exception = v:exception
let throwpoint = v:throwpoint
call assert_equal("arrgh", v:exception)
call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<4\>', v:throwpoint)
endtry
Xpath 'l'
let exception = v:exception
let throwpoint = v:throwpoint
call assert_equal("arrgh", v:exception)
call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<4\>', v:throwpoint)
finally
Xpath 'm'
let exception = v:exception
let throwpoint = v:throwpoint
call assert_equal("oops", v:exception)
call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<2\>', v:throwpoint)
endtry
Xpath 'n'
let exception = v:exception
let throwpoint = v:throwpoint
call assert_equal("oops", v:exception)
call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
call assert_match('\<2\>', v:throwpoint)
finally
Xpath 'o'
let exception = v:exception
let throwpoint = v:throwpoint
call assert_equal("", v:exception)
call assert_match('^$', v:throwpoint)
call assert_match('^$', v:throwpoint)
endtry
call assert_equal('abcdefghijklmno', g:Xpath)
unlet exception throwpoint
delfunction FuncException
delfunction FuncThrowpoint
call delete(scriptException)
call delete(scriptThrowPoint)
unlet scriptException scriptThrowPoint
delcommand CmdException
delcommand CmdThrowpoint
delfunction T
delfunction G
delfunction F
call delete(scriptT)
call delete(scriptG)
call delete(scriptF)
unlet scriptT scriptG scriptF
endfunc
"-------------------------------------------------------------------------------
"
" Test 58: v:exception and v:throwpoint for error/interrupt exceptions {{{1
"
" v:exception and v:throwpoint work also for error and interrupt
" exceptions.
"-------------------------------------------------------------------------------
func Test_exception_info_for_error()
CheckEnglish
let test =<< trim [CODE]
func T(line)
if a:line == 2
delfunction T " error (function in use) in line 2
elseif a:line == 4
call interrupt()
endif
endfunc
while 1
try
Xpath 'a'
call T(2)
call assert_report('should not get here')
catch /.*/
Xpath 'b'
if v:exception !~ 'Vim(delfunction):'
call assert_report('should not get here')
endif
if v:throwpoint !~ '\<T\>'
call assert_report('should not get here')
endif
if v:throwpoint !~ '\<2\>'
call assert_report('should not get here')
endif
finally
Xpath 'c'
if v:exception != ""
call assert_report('should not get here')
endif
if v:throwpoint != ""
call assert_report('should not get here')
endif
break
endtry
endwhile
Xpath 'd'
if v:exception != ""
call assert_report('should not get here')
endif
if v:throwpoint != ""
call assert_report('should not get here')
endif
while 1
try
Xpath 'e'
call T(4)
call assert_report('should not get here')
catch /.*/
Xpath 'f'
if v:exception != 'Vim:Interrupt'
call assert_report('should not get here')
endif
if v:throwpoint !~ 'function T'
call assert_report('should not get here')
endif
if v:throwpoint !~ '\<4\>'
call assert_report('should not get here')
endif
finally
Xpath 'g'
if v:exception != ""
call assert_report('should not get here')
endif
if v:throwpoint != ""
call assert_report('should not get here')
endif
break
endtry
endwhile
Xpath 'h'
if v:exception != ""
call assert_report('should not get here')
endif
if v:throwpoint != ""
call assert_report('should not get here')
endif
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdefgh', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
"
" Test 59: v:exception and v:throwpoint when discarding exceptions {{{1
"
" When a :catch clause is left by a ":break" etc or an error or
" interrupt exception, v:exception and v:throwpoint are reset. They
" are not affected by an exception that is discarded before being
" caught.
"-------------------------------------------------------------------------------
func Test_exception_info_on_discard()
CheckEnglish
let test =<< trim [CODE]
let sfile = expand("<sfile>")
while 1
try
throw "x1"
catch /.*/
break
endtry
endwhile
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
while 1
try
throw "x2"
catch /.*/
break
finally
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
endtry
break
endwhile
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
while 1
try
let errcaught = 0
try
try
throw "x3"
catch /.*/
let lnum = expand("<sflnum>")
asdf
endtry
catch /.*/
let errcaught = 1
call assert_match('Vim:E492: Not an editor command:', v:exception)
call assert_match('line ' .. (lnum + 1), v:throwpoint)
endtry
finally
call assert_equal(1, errcaught)
break
endtry
endwhile
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
Xpath 'a'
while 1
try
let intcaught = 0
try
try
throw "x4"
catch /.*/
let lnum = expand("<sflnum>")
call interrupt()
endtry
catch /.*/
let intcaught = 1
call assert_match('Vim:Interrupt', v:exception)
call assert_match('line ' .. (lnum + 1), v:throwpoint)
endtry
finally
call assert_equal(1, intcaught)
break
endtry
endwhile
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
Xpath 'b'
while 1
try
let errcaught = 0
try
try
if 1
let lnum = expand("<sflnum>")
throw "x5"
" missing endif
catch /.*/
call assert_report('should not get here')
endtry
catch /.*/
let errcaught = 1
call assert_match('Vim(catch):E171: Missing :endif:', v:exception)
call assert_match('line ' .. (lnum + 3), v:throwpoint)
endtry
finally
call assert_equal(1, errcaught)
break
endtry
endwhile
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
Xpath 'c'
try
while 1
try
throw "x6"
finally
break
endtry
break
endwhile
catch /.*/
call assert_report('should not get here')
endtry
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
try
while 1
try
throw "x7"
finally
break
endtry
break
endwhile
catch /.*/
call assert_report('should not get here')
finally
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
endtry
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
while 1
try
let errcaught = 0
try
try
throw "x8"
finally
let lnum = expand("<sflnum>")
asdf
endtry
catch /.*/
let errcaught = 1
call assert_match('Vim:E492: Not an editor command:', v:exception)
call assert_match('line ' .. (lnum + 1), v:throwpoint)
endtry
finally
call assert_equal(1, errcaught)
break
endtry
endwhile
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
Xpath 'd'
while 1
try
let intcaught = 0
try
try
throw "x9"
finally
let lnum = expand("<sflnum>")
call interrupt()
endtry
catch /.*/
let intcaught = 1
call assert_match('Vim:Interrupt', v:exception)
call assert_match('line ' .. (lnum + 1), v:throwpoint)
endtry
finally
call assert_equal(1, intcaught)
break
endtry
endwhile
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
Xpath 'e'
while 1
try
let errcaught = 0
try
try
if 1
let lnum = expand("<sflnum>")
throw "x10"
" missing endif
finally
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
endtry
catch /.*/
let errcaught = 1
call assert_match('Vim(finally):E171: Missing :endif:', v:exception)
call assert_match('line ' .. (lnum + 3), v:throwpoint)
endtry
finally
call assert_equal(1, errcaught)
break
endtry
endwhile
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
Xpath 'f'
while 1
try
let errcaught = 0
try
try
if 1
let lnum = expand("<sflnum>")
throw "x11"
" missing endif
endtry
catch /.*/
let errcaught = 1
call assert_match('Vim(endtry):E171: Missing :endif:', v:exception)
call assert_match('line ' .. (lnum + 3), v:throwpoint)
endtry
finally
call assert_equal(1, errcaught)
break
endtry
endwhile
call assert_equal('', v:exception)
call assert_equal('', v:throwpoint)
Xpath 'g'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdefg', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
"
" Test 60: (Re)throwing v:exception; :echoerr. {{{1
"
" A user exception can be rethrown after catching by throwing
" v:exception. An error or interrupt exception cannot be rethrown
" because Vim exceptions cannot be faked. A Vim exception using the
" value of v:exception can, however, be triggered by the :echoerr
" command.
"-------------------------------------------------------------------------------
func Test_rethrow_exception_1()
XpathINIT
try
try
Xpath 'a'
throw "oops"
catch /oops/
Xpath 'b'
throw v:exception " rethrow user exception
catch /.*/
call assert_report('should not get here')
endtry
catch /^oops$/ " catches rethrown user exception
Xpath 'c'
catch /.*/
call assert_report('should not get here')
endtry
call assert_equal('abc', g:Xpath)
endfunc
func Test_rethrow_exception_2()
XpathINIT
try
let caught = 0
try
Xpath 'a'
write /n/o/n/w/r/i/t/a/b/l/e/_/f/i/l/e
call assert_report('should not get here')
catch /^Vim(write):/
let caught = 1
throw v:exception " throw error: cannot fake Vim exception
catch /.*/
call assert_report('should not get here')
finally
Xpath 'b'
call assert_equal(1, caught)
endtry
catch /^Vim(throw):/ " catches throw error
let caught = caught + 1
catch /.*/
call assert_report('should not get here')
finally
Xpath 'c'
call assert_equal(2, caught)
endtry
call assert_equal('abc', g:Xpath)
endfunc
func Test_rethrow_exception_3()
XpathINIT
try
let caught = 0
try
Xpath 'a'
asdf
catch /^Vim/ " catch error exception
let caught = 1
" Trigger Vim error exception with value specified after :echoerr
let value = substitute(v:exception, '^Vim\((.*)\)\=:', '', "")
echoerr value
catch /.*/
call assert_report('should not get here')
finally
Xpath 'b'
call assert_equal(1, caught)
endtry
catch /^Vim(echoerr):/
let caught = caught + 1
call assert_match(value, v:exception)
catch /.*/
call assert_report('should not get here')
finally
Xpath 'c'
call assert_equal(2, caught)
endtry
call assert_equal('abc', g:Xpath)
endfunc
func Test_rethrow_exception_3()
XpathINIT
try
let errcaught = 0
try
Xpath 'a'
let intcaught = 0
call interrupt()
catch /^Vim:/ " catch interrupt exception
let intcaught = 1
" Trigger Vim error exception with value specified after :echoerr
echoerr substitute(v:exception, '^Vim\((.*)\)\=:', '', "")
catch /.*/
call assert_report('should not get here')
finally
Xpath 'b'
call assert_equal(1, intcaught)
endtry
catch /^Vim(echoerr):/
let errcaught = 1
call assert_match('Interrupt', v:exception)
finally
Xpath 'c'
call assert_equal(1, errcaught)
endtry
call assert_equal('abc', g:Xpath)
endfunc
"-------------------------------------------------------------------------------
" Test 61: Catching interrupt exceptions {{{1
"
" When an interrupt occurs inside a :try/:endtry region, an
" interrupt exception is thrown and can be caught. Its value is
" "Vim:Interrupt". If the interrupt occurs after an error or a :throw
" but before a matching :catch is reached, all following :catches of
" that try block are ignored, but the interrupt exception can be
" caught by the next surrounding try conditional. An interrupt is
" ignored when there is a previous interrupt that has not been caught
" or causes a :finally clause to be executed.
"-------------------------------------------------------------------------------
func Test_catch_intr_exception()
let test =<< trim [CODE]
while 1
try
try
Xpath 'a'
call interrupt()
call assert_report('should not get here')
catch /^Vim:Interrupt$/
Xpath 'b'
finally
Xpath 'c'
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'd'
break
endtry
endwhile
while 1
try
try
try
Xpath 'e'
asdf
call assert_report('should not get here')
catch /do_not_catch/
call assert_report('should not get here')
catch /.*/
Xpath 'f'
call interrupt()
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
finally
Xpath 'g'
call interrupt()
call assert_report('should not get here')
endtry
catch /^Vim:Interrupt$/
Xpath 'h'
finally
Xpath 'i'
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'j'
break
endtry
endwhile
while 1
try
try
try
Xpath 'k'
throw "x"
call assert_report('should not get here')
catch /do_not_catch/
call assert_report('should not get here')
catch /x/
Xpath 'l'
call interrupt()
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
endtry
catch /^Vim:Interrupt$/
Xpath 'm'
finally
Xpath 'n'
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'o'
break
endtry
endwhile
while 1
try
try
Xpath 'p'
call interrupt()
call assert_report('should not get here')
catch /do_not_catch/
call interrupt()
call assert_report('should not get here')
catch /^Vim:Interrupt$/
Xpath 'q'
finally
Xpath 'r'
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 's'
break
endtry
endwhile
Xpath 't'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdefghijklmnopqrst', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 62: Catching error exceptions {{{1
"
" An error inside a :try/:endtry region is converted to an exception
" and can be caught. The error exception has a "Vim(cmdname):" prefix
" where cmdname is the name of the failing command, or a "Vim:" prefix
" if no command name is known. The "Vim" prefixes cannot be faked.
"-------------------------------------------------------------------------------
func Test_catch_err_exception_1()
XpathINIT
while 1
try
try
let caught = 0
unlet novar
catch /^Vim(unlet):/
Xpath 'a'
let caught = 1
let v:errmsg = substitute(v:exception, '^Vim(unlet):', '', "")
finally
Xpath 'b'
call assert_equal(1, caught)
call assert_match('E108: No such variable: "novar"', v:errmsg)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'c'
break
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abc', g:Xpath)
endfunc
func Test_catch_err_exception_2()
XpathINIT
while 1
try
try
let caught = 0
throw novar " error in :throw
catch /^Vim(throw):/
Xpath 'a'
let caught = 1
let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "")
finally
Xpath 'b'
call assert_equal(1, caught)
call assert_match('E121: Undefined variable: novar', v:errmsg)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'c'
break
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abc', g:Xpath)
endfunc
func Test_catch_err_exception_3()
XpathINIT
while 1
try
try
let caught = 0
throw "Vim:faked" " error: cannot fake Vim exception
catch /^Vim(throw):/
Xpath 'a'
let caught = 1
let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "")
finally
Xpath 'b'
call assert_equal(1, caught)
call assert_match("E608: Cannot :throw exceptions with 'Vim' prefix",
\ v:errmsg)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'c'
break
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abc', g:Xpath)
endfunc
func Test_catch_err_exception_4()
XpathINIT
func F()
while 1
" Missing :endwhile
endfunc
while 1
try
try
let caught = 0
call F()
catch /^Vim(endfunction):/
Xpath 'a'
let caught = 1
let v:errmsg = substitute(v:exception, '^Vim(endfunction):', '', "")
finally
Xpath 'b'
call assert_equal(1, caught)
call assert_match("E170: Missing :endwhile", v:errmsg)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'c'
break
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abc', g:Xpath)
delfunc F
endfunc
func Test_catch_err_exception_5()
XpathINIT
func F()
while 1
" Missing :endwhile
endfunc
while 1
try
try
let caught = 0
ExecAsScript F
catch /^Vim:/
Xpath 'a'
let caught = 1
let v:errmsg = substitute(v:exception, '^Vim:', '', "")
finally
Xpath 'b'
call assert_equal(1, caught)
call assert_match("E170: Missing :endwhile", v:errmsg)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'c'
break
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abc', g:Xpath)
delfunc F
endfunc
func Test_catch_err_exception_6()
XpathINIT
func G()
call G()
endfunc
while 1
try
let mfd_save = &mfd
set mfd=3
try
let caught = 0
call G()
catch /^Vim(call):/
Xpath 'a'
let caught = 1
let v:errmsg = substitute(v:exception, '^Vim(call):', '', "")
finally
Xpath 'b'
call assert_equal(1, caught)
call assert_match("E132: Function call depth is higher than 'maxfuncdepth'", v:errmsg)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'c'
let &mfd = mfd_save
break
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abc', g:Xpath)
delfunc G
endfunc
func Test_catch_err_exception_7()
XpathINIT
func H()
return H()
endfunc
while 1
try
let mfd_save = &mfd
set mfd=3
try
let caught = 0
call H()
catch /^Vim(return):/
Xpath 'a'
let caught = 1
let v:errmsg = substitute(v:exception, '^Vim(return):', '', "")
finally
Xpath 'b'
call assert_equal(1, caught)
call assert_match("E132: Function call depth is higher than 'maxfuncdepth'", v:errmsg)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'c'
let &mfd = mfd_save
break " discard error for $VIMNOERRTHROW
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abc', g:Xpath)
delfunc H
endfunc
"-------------------------------------------------------------------------------
" Test 63: Suppressing error exceptions by :silent!. {{{1
"
" A :silent! command inside a :try/:endtry region suppresses the
" conversion of errors to an exception and the immediate abortion on
" error. When the commands executed by the :silent! themselves open
" a new :try/:endtry region, conversion of errors to exception and
" immediate abortion is switched on again - until the next :silent!
" etc. The :silent! has the effect of setting v:errmsg to the error
" message text (without displaying it) and continuing with the next
" script line.
"
" When a command triggering autocommands is executed by :silent!
" inside a :try/:endtry, the autocommand execution is not suppressed
" on error.
"
" This test reuses the function MSG() from the previous test.
"-------------------------------------------------------------------------------
func Test_silent_exception()
XpathINIT
XloopINIT
let g:taken = ""
func S(n) abort
XloopNEXT
let g:taken = g:taken . "E" . a:n
let v:errmsg = ""
exec "asdf" . a:n
" Check that ":silent!" continues:
Xloop 'a'
" Check that ":silent!" sets "v:errmsg":
call assert_match("E492: Not an editor command", v:errmsg)
endfunc
func Foo()
while 1
try
try
let caught = 0
" This is not silent:
call S(3)
catch /^Vim:/
Xpath 'b'
let caught = 1
let errmsg3 = substitute(v:exception, '^Vim:', '', "")
silent! call S(4)
finally
call assert_equal(1, caught)
Xpath 'c'
call assert_match("E492: Not an editor command", errmsg3)
silent! call S(5)
" Break out of try conditionals that cover ":silent!". This also
" discards the aborting error when $VIMNOERRTHROW is non-zero.
break
endtry
catch /.*/
call assert_report('should not get here')
endtry
endwhile
" This is a double ":silent!" (see caller).
silent! call S(6)
endfunc
func Bar()
try
silent! call S(2)
silent! execute "call Foo() | call S(7)"
silent! call S(8)
endtry " normal end of try cond that covers ":silent!"
" This has a ":silent!" from the caller:
call S(9)
endfunc
silent! call S(1)
silent! call Bar()
silent! call S(10)
call assert_equal("E1E2E3E4E5E6E7E8E9E10", g:taken)
augroup TMP
au!
autocmd BufWritePost * Xpath 'd'
augroup END
Xpath 'e'
silent! write /i/m/p/o/s/s/i/b/l/e
Xpath 'f'
call assert_equal('a2a3ba5ca6a7a8a9a10a11edf', g:Xpath)
augroup TMP
au!
augroup END
augroup! TMP
delfunction S
delfunction Foo
delfunction Bar
endfunc
"-------------------------------------------------------------------------------
" Test 64: Error exceptions after error, interrupt or :throw {{{1
"
" When an error occurs after an interrupt or a :throw but before
" a matching :catch is reached, all following :catches of that try
" block are ignored, but the error exception can be caught by the next
" surrounding try conditional. Any previous error exception is
" discarded. An error is ignored when there is a previous error that
" has not been caught.
"-------------------------------------------------------------------------------
func Test_exception_after_error_1()
XpathINIT
while 1
try
try
Xpath 'a'
let caught = 0
while 1
if 1
" Missing :endif
endwhile " throw error exception
catch /^Vim(/
Xpath 'b'
let caught = 1
finally
Xpath 'c'
call assert_equal(1, caught)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'd'
break
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abcd', g:Xpath)
endfunc
func Test_exception_after_error_2()
XpathINIT
while 1
try
try
Xpath 'a'
let caught = 0
try
if 1
" Missing :endif
catch /.*/ " throw error exception
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
endtry
catch /^Vim(/
Xpath 'b'
let caught = 1
finally
Xpath 'c'
call assert_equal(1, caught)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'd'
break
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abcd', g:Xpath)
endfunc
func Test_exception_after_error_3()
XpathINIT
while 1
try
try
let caught = 0
try
Xpath 'a'
call interrupt()
catch /do_not_catch/
call assert_report('should not get here')
if 1
" Missing :endif
catch /.*/ " throw error exception
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
endtry
catch /^Vim(/
Xpath 'b'
let caught = 1
finally
Xpath 'c'
call assert_equal(1, caught)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'd'
break
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abcd', g:Xpath)
endfunc
func Test_exception_after_error_4()
XpathINIT
while 1
try
try
let caught = 0
try
Xpath 'a'
throw "x"
catch /do_not_catch/
call assert_report('should not get here')
if 1
" Missing :endif
catch /x/ " throw error exception
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
endtry
catch /^Vim(/
Xpath 'b'
let caught = 1
finally
Xpath 'c'
call assert_equal(1, caught)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'd'
break
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abcd', g:Xpath)
endfunc
func Test_exception_after_error_5()
XpathINIT
while 1
try
try
let caught = 0
Xpath 'a'
endif " :endif without :if; throw error exception
if 1
" Missing :endif
catch /do_not_catch/ " ignore new error
call assert_report('should not get here')
catch /^Vim(endif):/
Xpath 'b'
let caught = 1
catch /^Vim(/
call assert_report('should not get here')
finally
Xpath 'c'
call assert_equal(1, caught)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'd'
break
endtry
call assert_report('should not get here')
endwhile
call assert_equal('abcd', g:Xpath)
endfunc
"-------------------------------------------------------------------------------
" Test 65: Errors in the /pattern/ argument of a :catch {{{1
"
" On an error in the /pattern/ argument of a :catch, the :catch does
" not match. Any following :catches of the same :try/:endtry don't
" match either. Finally clauses are executed.
"-------------------------------------------------------------------------------
func Test_catch_pattern_error()
CheckEnglish
XpathINIT
try
try
Xpath 'a'
throw "oops"
catch /^oops$/
Xpath 'b'
catch /\)/ " not checked; exception has already been caught
call assert_report('should not get here')
endtry
Xpath 'c'
catch /.*/
call assert_report('should not get here')
endtry
call assert_equal('abc', g:Xpath)
XpathINIT
func F()
try
try
try
Xpath 'a'
throw "ab"
catch /abc/ " does not catch
call assert_report('should not get here')
catch /\)/ " error; discards exception
call assert_report('should not get here')
catch /.*/ " not checked
call assert_report('should not get here')
finally
Xpath 'b'
endtry
call assert_report('should not get here')
catch /^ab$/ " checked, but original exception is discarded
call assert_report('should not get here')
catch /^Vim(catch):/
Xpath 'c'
call assert_match('Vim(catch):E475: Invalid argument:', v:exception)
finally
Xpath 'd'
endtry
Xpath 'e'
catch /.*/
call assert_report('should not get here')
endtry
Xpath 'f'
endfunc
call F()
call assert_equal('abcdef', g:Xpath)
delfunc F
endfunc
"-------------------------------------------------------------------------------
" Test 66: Stop range :call on error, interrupt, or :throw {{{1
"
" When a function which is multiply called for a range since it
" doesn't handle the range itself has an error in a command
" dynamically enclosed by :try/:endtry or gets an interrupt or
" executes a :throw, no more calls for the remaining lines in the
" range are made. On an error in a command not dynamically enclosed
" by :try/:endtry, the function is executed again for the remaining
" lines in the range.
"-------------------------------------------------------------------------------
func Test_stop_range_on_error()
let test =<< trim [CODE]
let file = tempname()
exec "edit" file
call setline(1, ['line 1', 'line 2', 'line 3'])
let taken = ""
let expected = "G1EF1E(1)F1E(2)F1E(3)G2EF2E(1)G3IF3I(1)G4TF4T(1)G5AF5A(1)"
func F(reason, n) abort
let g:taken = g:taken .. "F" .. a:n ..
\ substitute(a:reason, '\(\l\).*', '\u\1', "") ..
\ "(" .. line(".") .. ")"
if a:reason == "error"
asdf
elseif a:reason == "interrupt"
call interrupt()
elseif a:reason == "throw"
throw "xyz"
elseif a:reason == "aborting error"
XloopNEXT
call assert_equal(g:taken, g:expected)
try
bwipeout!
call delete(g:file)
asdf
endtry
endif
endfunc
func G(reason, n)
let g:taken = g:taken .. "G" .. a:n ..
\ substitute(a:reason, '\(\l\).*', '\u\1', "")
1,3call F(a:reason, a:n)
endfunc
Xpath 'a'
call G("error", 1)
try
Xpath 'b'
try
call G("error", 2)
call assert_report('should not get here')
finally
Xpath 'c'
try
call G("interrupt", 3)
call assert_report('should not get here')
finally
Xpath 'd'
try
call G("throw", 4)
call assert_report('should not get here')
endtry
endtry
endtry
catch /xyz/
Xpath 'e'
catch /.*/
call assert_report('should not get here')
endtry
Xpath 'f'
call G("aborting error", 5)
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdef', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 67: :throw across :call command {{{1
"
" On a call command, an exception might be thrown when evaluating the
" function name, during evaluation of the arguments, or when the
" function is being executed. The exception can be caught by the
" caller.
"-------------------------------------------------------------------------------
func THROW(x, n)
if a:n == 1
Xpath 'A'
elseif a:n == 2
Xpath 'B'
elseif a:n == 3
Xpath 'C'
endif
throw a:x
endfunc
func NAME(x, n)
if a:n == 1
call assert_report('should not get here')
elseif a:n == 2
Xpath 'D'
elseif a:n == 3
Xpath 'E'
elseif a:n == 4
Xpath 'F'
endif
return a:x
endfunc
func ARG(x, n)
if a:n == 1
call assert_report('should not get here')
elseif a:n == 2
call assert_report('should not get here')
elseif a:n == 3
Xpath 'G'
elseif a:n == 4
Xpath 'I'
endif
return a:x
endfunc
func Test_throw_across_call_cmd()
XpathINIT
func F(x, n)
if a:n == 2
call assert_report('should not get here')
elseif a:n == 4
Xpath 'a'
endif
endfunc
while 1
try
let v:errmsg = ""
while 1
try
Xpath 'b'
call {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1)
call assert_report('should not get here')
catch /^name$/
Xpath 'c'
catch /.*/
call assert_report('should not get here')
finally
call assert_equal("", v:errmsg)
let v:errmsg = ""
break
endtry
endwhile
while 1
try
Xpath 'd'
call {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2)
call assert_report('should not get here')
catch /^arg$/
Xpath 'e'
catch /.*/
call assert_report('should not get here')
finally
call assert_equal("", v:errmsg)
let v:errmsg = ""
break
endtry
endwhile
while 1
try
Xpath 'f'
call {NAME("THROW", 3)}(ARG("call", 3), 3)
call assert_report('should not get here')
catch /^call$/
Xpath 'g'
catch /^0$/ " default return value
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
finally
call assert_equal("", v:errmsg)
let v:errmsg = ""
break
endtry
endwhile
while 1
try
Xpath 'h'
call {NAME("F", 4)}(ARG(4711, 4), 4)
Xpath 'i'
catch /.*/
call assert_report('should not get here')
finally
call assert_equal("", v:errmsg)
let v:errmsg = ""
break
endtry
endwhile
catch /^0$/ " default return value
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
finally
call assert_equal("", v:errmsg)
let v:errmsg = ""
break
endtry
endwhile
call assert_equal('bAcdDBefEGCghFIai', g:Xpath)
delfunction F
endfunc
"-------------------------------------------------------------------------------
" Test 68: :throw across function calls in expressions {{{1
"
" On a function call within an expression, an exception might be
" thrown when evaluating the function name, during evaluation of the
" arguments, or when the function is being executed. The exception
" can be caught by the caller.
"
" This test reuses the functions THROW(), NAME(), and ARG() from the
" previous test.
"-------------------------------------------------------------------------------
func Test_throw_across_call_expr()
XpathINIT
func F(x, n)
if a:n == 2
call assert_report('should not get here')
elseif a:n == 4
Xpath 'a'
endif
return a:x
endfunction
while 1
try
let error = 0
let v:errmsg = ""
while 1
try
Xpath 'b'
let var1 = {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1)
call assert_report('should not get here')
catch /^name$/
Xpath 'c'
catch /.*/
call assert_report('should not get here')
finally
call assert_equal("", v:errmsg)
let v:errmsg = ""
break
endtry
endwhile
call assert_true(!exists('var1'))
while 1
try
Xpath 'd'
let var2 = {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2)
call assert_report('should not get here')
catch /^arg$/
Xpath 'e'
catch /.*/
call assert_report('should not get here')
finally
call assert_equal("", v:errmsg)
let v:errmsg = ""
break
endtry
endwhile
call assert_true(!exists('var2'))
while 1
try
Xpath 'f'
let var3 = {NAME("THROW", 3)}(ARG("call", 3), 3)
call assert_report('should not get here')
catch /^call$/
Xpath 'g'
catch /^0$/ " default return value
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
finally
call assert_equal("", v:errmsg)
let v:errmsg = ""
break
endtry
endwhile
call assert_true(!exists('var3'))
while 1
try
Xpath 'h'
let var4 = {NAME("F", 4)}(ARG(4711, 4), 4)
Xpath 'i'
catch /.*/
call assert_report('should not get here')
finally
call assert_equal("", v:errmsg)
let v:errmsg = ""
break
endtry
endwhile
call assert_true(exists('var4') && var4 == 4711)
catch /^0$/ " default return value
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
finally
call assert_equal("", v:errmsg)
break
endtry
endwhile
call assert_equal('bAcdDBefEGCghFIai', g:Xpath)
delfunc F
endfunc
"-------------------------------------------------------------------------------
" Test 76: Errors, interrupts, :throw during expression evaluation {{{1
"
" When a function call made during expression evaluation is aborted
" due to an error inside a :try/:endtry region or due to an interrupt
" or a :throw, the expression evaluation is aborted as well. No
" message is displayed for the cancelled expression evaluation. On an
" error not inside :try/:endtry, the expression evaluation continues.
"-------------------------------------------------------------------------------
func Test_expr_eval_error()
let test =<< trim [CODE]
let taken = ""
func ERR(n)
let g:taken = g:taken .. "E" .. a:n
asdf
endfunc
func ERRabort(n) abort
let g:taken = g:taken .. "A" .. a:n
asdf
endfunc " returns -1; may cause follow-up msg for illegal var/func name
func WRAP(n, arg)
let g:taken = g:taken .. "W" .. a:n
let g:saved_errmsg = v:errmsg
return arg
endfunc
func INT(n)
let g:taken = g:taken .. "I" .. a:n
call interrupt()
endfunc
func THR(n)
let g:taken = g:taken .. "T" .. a:n
throw "should not be caught"
endfunc
func CONT(n)
let g:taken = g:taken .. "C" .. a:n
endfunc
func MSG(n)
let g:taken = g:taken .. "M" .. a:n
let errmsg = (a:n >= 37 && a:n <= 44) ? g:saved_errmsg : v:errmsg
let msgptn = (a:n >= 10 && a:n <= 27) ? "^$" : "asdf"
call assert_match(msgptn, errmsg)
let v:errmsg = ""
let g:saved_errmsg = ""
endfunc
let v:errmsg = ""
try
let t = 1
while t <= 9
Xloop 'a'
try
if t == 1
let v{ERR(t) + CONT(t)} = 0
elseif t == 2
let v{ERR(t) + CONT(t)}
elseif t == 3
let var = exists('v{ERR(t) + CONT(t)}')
elseif t == 4
unlet v{ERR(t) + CONT(t)}
elseif t == 5
function F{ERR(t) + CONT(t)}()
endfunction
elseif t == 6
function F{ERR(t) + CONT(t)}
elseif t == 7
let var = exists('*F{ERR(t) + CONT(t)}')
elseif t == 8
delfunction F{ERR(t) + CONT(t)}
elseif t == 9
let var = ERR(t) + CONT(t)
endif
catch /asdf/
" v:errmsg is not set when the error message is converted to an
" exception. Set it to the original error message.
let v:errmsg = substitute(v:exception, '^Vim:', '', "")
catch /^Vim\((\a\+)\)\=:/
" An error exception has been thrown after the original error.
let v:errmsg = ""
finally
call MSG(t)
let t = t + 1
XloopNEXT
continue " discard an aborting error
endtry
endwhile
catch /.*/
call assert_report('should not get here')
endtry
try
let t = 10
while t <= 18
Xloop 'b'
try
if t == 10
let v{INT(t) + CONT(t)} = 0
elseif t == 11
let v{INT(t) + CONT(t)}
elseif t == 12
let var = exists('v{INT(t) + CONT(t)}')
elseif t == 13
unlet v{INT(t) + CONT(t)}
elseif t == 14
function F{INT(t) + CONT(t)}()
endfunction
elseif t == 15
function F{INT(t) + CONT(t)}
elseif t == 16
let var = exists('*F{INT(t) + CONT(t)}')
elseif t == 17
delfunction F{INT(t) + CONT(t)}
elseif t == 18
let var = INT(t) + CONT(t)
endif
catch /^Vim\((\a\+)\)\=:\(Interrupt\)\@!/
" An error exception has been triggered after the interrupt.
let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
finally
call MSG(t)
let t = t + 1
XloopNEXT
continue " discard interrupt
endtry
endwhile
catch /.*/
call assert_report('should not get here')
endtry
try
let t = 19
while t <= 27
Xloop 'c'
try
if t == 19
let v{THR(t) + CONT(t)} = 0
elseif t == 20
let v{THR(t) + CONT(t)}
elseif t == 21
let var = exists('v{THR(t) + CONT(t)}')
elseif t == 22
unlet v{THR(t) + CONT(t)}
elseif t == 23
function F{THR(t) + CONT(t)}()
endfunction
elseif t == 24
function F{THR(t) + CONT(t)}
elseif t == 25
let var = exists('*F{THR(t) + CONT(t)}')
elseif t == 26
delfunction F{THR(t) + CONT(t)}
elseif t == 27
let var = THR(t) + CONT(t)
endif
catch /^Vim\((\a\+)\)\=:/
" An error exception has been triggered after the :throw.
let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
finally
call MSG(t)
let t = t + 1
XloopNEXT
continue " discard exception
endtry
endwhile
catch /.*/
call assert_report('should not get here')
endtry
let v{ERR(28) + CONT(28)} = 0
call MSG(28)
let v{ERR(29) + CONT(29)}
call MSG(29)
let var = exists('v{ERR(30) + CONT(30)}')
call MSG(30)
unlet v{ERR(31) + CONT(31)}
call MSG(31)
function F{ERR(32) + CONT(32)}()
endfunction
call MSG(32)
function F{ERR(33) + CONT(33)}
call MSG(33)
let var = exists('*F{ERR(34) + CONT(34)}')
call MSG(34)
delfunction F{ERR(35) + CONT(35)}
call MSG(35)
let var = ERR(36) + CONT(36)
call MSG(36)
let saved_errmsg = ""
let v{WRAP(37, ERRabort(37)) + CONT(37)} = 0
call MSG(37)
let v{WRAP(38, ERRabort(38)) + CONT(38)}
call MSG(38)
let var = exists('v{WRAP(39, ERRabort(39)) + CONT(39)}')
call MSG(39)
unlet v{WRAP(40, ERRabort(40)) + CONT(40)}
call MSG(40)
function F{WRAP(41, ERRabort(41)) + CONT(41)}()
endfunction
call MSG(41)
function F{WRAP(42, ERRabort(42)) + CONT(42)}
call MSG(42)
let var = exists('*F{WRAP(43, ERRabort(43)) + CONT(43)}')
call MSG(43)
delfunction F{WRAP(44, ERRabort(44)) + CONT(44)}
call MSG(44)
let var = ERRabort(45) + CONT(45)
call MSG(45)
Xpath 'd'
let expected = ""
\ .. "E1M1E2M2E3M3E4M4E5M5E6M6E7M7E8M8E9M9"
\ .. "I10M10I11M11I12M12I13M13I14M14I15M15I16M16I17M17I18M18"
\ .. "T19M19T20M20T21M21T22M22T23M23T24M24T25M25T26M26T27M27"
\ .. "E28C28M28E29C29M29E30C30M30E31C31M31E32C32M32E33C33M33"
\ .. "E34C34M34E35C35M35E36C36M36"
\ .. "A37W37C37M37A38W38C38M38A39W39C39M39A40W40C40M40A41W41C41M41"
\ .. "A42W42C42M42A43W43C43M43A44W44C44M44A45C45M45"
call assert_equal(expected, taken)
[CODE]
let verify =<< trim [CODE]
let expected = "a1a2a3a4a5a6a7a8a9"
\ .. "b10b11b12b13b14b15b16b17b18"
\ .. "c19c20c21c22c23c24c25c26c27d"
call assert_equal(expected, g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 77: Errors, interrupts, :throw in name{brace-expression} {{{1
"
" When a function call made during evaluation of an expression in
" braces as part of a function name after ":function" is aborted due
" to an error inside a :try/:endtry region or due to an interrupt or
" a :throw, the expression evaluation is aborted as well, and the
" function definition is ignored, skipping all commands to the
" ":endfunction". On an error not inside :try/:endtry, the expression
" evaluation continues and the function gets defined, and can be
" called and deleted.
"-------------------------------------------------------------------------------
func Test_brace_expr_error()
let test =<< trim [CODE]
func ERR() abort
Xloop 'a'
asdf
endfunc " returns -1
func OK()
Xloop 'b'
let v:errmsg = ""
return 0
endfunc
let v:errmsg = ""
Xpath 'c'
func F{1 + ERR() + OK()}(arg)
" F0 should be defined.
if exists("a:arg") && a:arg == "calling"
Xpath 'd'
else
call assert_report('should not get here')
endif
endfunction
call assert_equal("", v:errmsg)
XloopNEXT
Xpath 'e'
call F{1 + ERR() + OK()}("calling")
call assert_equal("", v:errmsg)
XloopNEXT
Xpath 'f'
delfunction F{1 + ERR() + OK()}
call assert_equal("", v:errmsg)
XloopNEXT
try
while 1
try
Xpath 'g'
func G{1 + ERR() + OK()}(arg)
" G0 should not be defined, and the function body should be
" skipped.
call assert_report('should not get here')
" Use an unmatched ":finally" to check whether the body is
" skipped when an error occurs in ERR(). This works whether or
" not the exception is converted to an exception.
finally
call assert_report('should not get here')
endtry
try
call assert_report('should not get here')
endfunction
call assert_report('should not get here')
catch /asdf/
" Jumped to when the function is not defined and the body is
" skipped.
Xpath 'h'
catch /.*/
call assert_report('should not get here')
finally
Xpath 'i'
break
endtry " jumped to when the body is not skipped
endwhile
catch /.*/
call assert_report('should not get here')
endtry
[CODE]
let verify =<< trim [CODE]
call assert_equal('ca1b1ea2b2dfa3b3ga4hi', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 78: Messages on parsing errors in expression evaluation {{{1
"
" When an expression evaluation detects a parsing error, an error
" message is given and converted to an exception, and the expression
" evaluation is aborted.
"-------------------------------------------------------------------------------
func Test_expr_eval_error_msg()
CheckEnglish
let test =<< trim [CODE]
let taken = ""
func F(n)
let g:taken = g:taken . "F" . a:n
endfunc
func MSG(n, enr, emsg)
let g:taken = g:taken . "M" . a:n
call assert_match('^' .. a:enr .. ':', v:errmsg)
call assert_match(a:emsg, v:errmsg)
endfunc
func CONT(n)
let g:taken = g:taken . "C" . a:n
endfunc
let v:errmsg = ""
try
let t = 1
while t <= 14
let g:taken = g:taken . "T" . t
let v:errmsg = ""
try
if t == 1
let v{novar + CONT(t)} = 0
elseif t == 2
let v{novar + CONT(t)}
elseif t == 3
let var = exists('v{novar + CONT(t)}')
elseif t == 4
unlet v{novar + CONT(t)}
elseif t == 5
function F{novar + CONT(t)}()
endfunction
elseif t == 6
function F{novar + CONT(t)}
elseif t == 7
let var = exists('*F{novar + CONT(t)}')
elseif t == 8
delfunction F{novar + CONT(t)}
elseif t == 9
echo novar + CONT(t)
elseif t == 10
echo v{novar + CONT(t)}
elseif t == 11
echo F{novar + CONT(t)}
elseif t == 12
let var = novar + CONT(t)
elseif t == 13
let var = v{novar + CONT(t)}
elseif t == 14
let var = F{novar + CONT(t)}()
endif
catch /^Vim\((\a\+)\)\=:/
Xloop 'a'
" v:errmsg is not set when the error message is converted to an
" exception. Set it to the original error message.
let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
finally
Xloop 'b'
if t <= 8 && t != 3 && t != 7
call MSG(t, 'E475', 'Invalid argument\>')
else
call MSG(t, 'E121', "Undefined variable")
endif
let t = t + 1
XloopNEXT
continue " discard an aborting error
endtry
endwhile
catch /.*/
call assert_report('should not get here')
endtry
func T(n, expr, enr, emsg)
try
let g:taken = g:taken . "T" . a:n
let v:errmsg = ""
try
execute "let var = " . a:expr
catch /^Vim\((\a\+)\)\=:/
Xloop 'c'
" v:errmsg is not set when the error message is converted to an
" exception. Set it to the original error message.
let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
finally
Xloop 'd'
call MSG(a:n, a:enr, a:emsg)
XloopNEXT
" Discard an aborting error:
return
endtry
catch /.*/
call assert_report('should not get here')
endtry
endfunc
call T(15, 'Nofunc() + CONT(15)', 'E117', "Unknown function")
call T(16, 'F(1 2 + CONT(16))', 'E116', "Invalid arguments")
call T(17, 'F(1, 2) + CONT(17)', 'E118', "Too many arguments")
call T(18, 'F() + CONT(18)', 'E119', "Not enough arguments")
call T(19, '{(1} + CONT(19)', 'E110', "Missing ')'")
call T(20, '("abc"[1) + CONT(20)', 'E111', "Missing ']'")
call T(21, '(1 +) + CONT(21)', 'E15', "Invalid expression")
call T(22, '1 2 + CONT(22)', 'E488', "Trailing characters: 2 +")
call T(23, '(1 ? 2) + CONT(23)', 'E109', "Missing ':' after '?'")
call T(24, '("abc) + CONT(24)', 'E114', "Missing quote")
call T(25, "('abc) + CONT(25)", 'E115', "Missing quote")
call T(26, '& + CONT(26)', 'E112', "Option name missing")
call T(27, '&asdf + CONT(27)', 'E113', "Unknown option")
let expected = ""
\ .. "T1M1T2M2T3M3T4M4T5M5T6M6T7M7T8M8T9M9T10M10T11M11T12M12T13M13T14M14"
\ .. "T15M15T16M16T17M17T18M18T19M19T20M20T21M21T22M22T23M23T24M24T25M25"
\ .. "T26M26T27M27"
call assert_equal(expected, taken)
[CODE]
let verify =<< trim [CODE]
let expected = "a1b1a2b2a3b3a4b4a5b5a6b6a7b7a8b8a9b9a10b10a11b11a12b12"
\ .. "a13b13a14b14c15d15c16d16c17d17c18d18c19d19c20d20"
\ .. "c21d21c22d22c23d23c24d24c25d25c26d26c27d27"
call assert_equal(expected, g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 79: Throwing one of several errors for the same command {{{1
"
" When several errors appear in a row (for instance during expression
" evaluation), the first as the most specific one is used when
" throwing an error exception. If, however, a syntax error is
" detected afterwards, this one is used for the error exception.
" On a syntax error, the next command is not executed, on a normal
" error, however, it is (relevant only in a function without the
" "abort" flag). v:errmsg is not set.
"
" If throwing error exceptions is configured off, v:errmsg is always
" set to the latest error message, that is, to the more general
" message or the syntax error, respectively.
"-------------------------------------------------------------------------------
func Test_throw_multi_error()
CheckEnglish
let test =<< trim [CODE]
func NEXT(cmd)
exec a:cmd . " | Xloop 'a'"
endfun
call NEXT('echo novar') " (checks nextcmd)
XloopNEXT
call NEXT('let novar #') " (skips nextcmd)
XloopNEXT
call NEXT('unlet novar #') " (skips nextcmd)
XloopNEXT
call NEXT('let {novar}') " (skips nextcmd)
XloopNEXT
call NEXT('unlet{ novar}') " (skips nextcmd)
call assert_equal('a1', g:Xpath)
XpathINIT
XloopINIT
func EXEC(cmd)
exec a:cmd
endfunc
try
while 1 " dummy loop
try
let v:errmsg = ""
call EXEC('echo novar') " normal error
catch /^Vim\((\a\+)\)\=:/
Xpath 'b'
call assert_match('E121: Undefined variable: novar', v:exception)
finally
Xpath 'c'
call assert_equal("", v:errmsg)
break
endtry
endwhile
Xpath 'd'
let cmd = "let"
while cmd != ""
try
let v:errmsg = ""
call EXEC(cmd . ' novar #') " normal plus syntax error
catch /^Vim\((\a\+)\)\=:/
Xloop 'e'
call assert_match('E488: Trailing characters', v:exception)
finally
Xloop 'f'
call assert_equal("", v:errmsg)
if cmd == "let"
let cmd = "unlet"
else
let cmd = ""
endif
XloopNEXT
continue
endtry
endwhile
Xpath 'g'
let cmd = "let"
while cmd != ""
try
let v:errmsg = ""
call EXEC(cmd . ' {novar}') " normal plus syntax error
catch /^Vim\((\a\+)\)\=:/
Xloop 'h'
call assert_match('E475: Invalid argument: {novar}', v:exception)
finally
Xloop 'i'
call assert_equal("", v:errmsg)
if cmd == "let"
let cmd = "unlet"
else
let cmd = ""
endif
XloopNEXT
continue
endtry
endwhile
catch /.*/
call assert_report('should not get here')
endtry
Xpath 'j'
[CODE]
let verify =<< trim [CODE]
call assert_equal('bcde1f1e2f2gh3i3h4i4j', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 80: Syntax error in expression for illegal :elseif {{{1
"
" If there is a syntax error in the expression after an illegal
" :elseif, an error message is given (or an error exception thrown)
" for the illegal :elseif rather than the expression error.
"-------------------------------------------------------------------------------
func Test_if_syntax_error()
CheckEnglish
let test =<< trim [CODE]
let v:errmsg = ""
if 0
else
elseif 1 ||| 2
endif
Xpath 'a'
call assert_match('E584: :elseif after :else', v:errmsg)
let v:errmsg = ""
if 1
else
elseif 1 ||| 2
endif
Xpath 'b'
call assert_match('E584: :elseif after :else', v:errmsg)
let v:errmsg = ""
elseif 1 ||| 2
Xpath 'c'
call assert_match('E582: :elseif without :if', v:errmsg)
let v:errmsg = ""
while 1
elseif 1 ||| 2
endwhile
Xpath 'd'
call assert_match('E582: :elseif without :if', v:errmsg)
while 1
try
try
let v:errmsg = ""
if 0
else
elseif 1 ||| 2
endif
catch /^Vim\((\a\+)\)\=:/
Xpath 'e'
call assert_match('E584: :elseif after :else', v:exception)
finally
Xpath 'f'
call assert_equal("", v:errmsg)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'g'
break
endtry
endwhile
while 1
try
try
let v:errmsg = ""
if 1
else
elseif 1 ||| 2
endif
catch /^Vim\((\a\+)\)\=:/
Xpath 'h'
call assert_match('E584: :elseif after :else', v:exception)
finally
Xpath 'i'
call assert_equal("", v:errmsg)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'j'
break
endtry
endwhile
while 1
try
try
let v:errmsg = ""
elseif 1 ||| 2
catch /^Vim\((\a\+)\)\=:/
Xpath 'k'
call assert_match('E582: :elseif without :if', v:exception)
finally
Xpath 'l'
call assert_equal("", v:errmsg)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'm'
break
endtry
endwhile
while 1
try
try
let v:errmsg = ""
while 1
elseif 1 ||| 2
endwhile
catch /^Vim\((\a\+)\)\=:/
Xpath 'n'
call assert_match('E582: :elseif without :if', v:exception)
finally
Xpath 'o'
call assert_equal("", v:errmsg)
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'p'
break
endtry
endwhile
Xpath 'q'
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdefghijklmnopq', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 81: Discarding exceptions after an error or interrupt {{{1
"
" When an exception is thrown from inside a :try conditional without
" :catch and :finally clauses and an error or interrupt occurs before
" the :endtry is reached, the exception is discarded.
"-------------------------------------------------------------------------------
func Test_discard_exception_after_error_1()
let test =<< trim [CODE]
try
Xpath 'a'
try
Xpath 'b'
throw "arrgh"
call assert_report('should not get here')
if 1
call assert_report('should not get here')
" error after :throw: missing :endif
endtry
call assert_report('should not get here')
catch /arrgh/
call assert_report('should not get here')
endtry
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('ab', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
" interrupt the code before the endtry is invoked
func Test_discard_exception_after_error_2()
XpathINIT
let lines =<< trim [CODE]
try
Xpath 'a'
try
Xpath 'b'
throw "arrgh"
call assert_report('should not get here')
endtry " interrupt here
call assert_report('should not get here')
catch /arrgh/
call assert_report('should not get here')
endtry
call assert_report('should not get here')
[CODE]
call writefile(lines, 'Xscript')
breakadd file 7 Xscript
try
let caught_intr = 0
debuggreedy
call feedkeys(":source Xscript\<CR>quit\<CR>", "xt")
catch /^Vim:Interrupt$/
call assert_match('Xscript, line 7', v:throwpoint)
let caught_intr = 1
endtry
0debuggreedy
call assert_equal(1, caught_intr)
call assert_equal('ab', g:Xpath)
breakdel *
call delete('Xscript')
endfunc
"-------------------------------------------------------------------------------
" Test 82: Ignoring :catch clauses after an error or interrupt {{{1
"
" When an exception is thrown and an error or interrupt occurs before
" the matching :catch clause is reached, the exception is discarded
" and the :catch clause is ignored (also for the error or interrupt
" exception being thrown then).
"-------------------------------------------------------------------------------
func Test_ignore_catch_after_error_1()
let test =<< trim [CODE]
try
try
Xpath 'a'
throw "arrgh"
call assert_report('should not get here')
if 1
call assert_report('should not get here')
" error after :throw: missing :endif
catch /.*/
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
endtry
call assert_report('should not get here')
catch /arrgh/
call assert_report('should not get here')
endtry
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('a', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
func Test_ignore_catch_after_error_2()
let test =<< trim [CODE]
func E()
try
try
Xpath 'a'
throw "arrgh"
call assert_report('should not get here')
if 1
call assert_report('should not get here')
" error after :throw: missing :endif
catch /.*/
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
endtry
call assert_report('should not get here')
catch /arrgh/
call assert_report('should not get here')
endtry
endfunc
call E()
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('a', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
" interrupt right before a catch is invoked in a script
func Test_ignore_catch_after_intr_1()
" for unknown reasons this test sometimes fails on MS-Windows.
let g:test_is_flaky = 1
XpathINIT
let lines =<< trim [CODE]
try
try
Xpath 'a'
throw "arrgh"
call assert_report('should not get here')
catch /.*/ " interrupt here
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
endtry
call assert_report('should not get here')
catch /arrgh/
call assert_report('should not get here')
endtry
call assert_report('should not get here')
[CODE]
call writefile(lines, 'Xscript')
breakadd file 6 Xscript
try
let caught_intr = 0
debuggreedy
call feedkeys(":source Xscript\<CR>quit\<CR>", "xt")
catch /^Vim:Interrupt$/
call assert_match('Xscript, line 6', v:throwpoint)
let caught_intr = 1
endtry
0debuggreedy
call assert_equal(1, caught_intr)
call assert_equal('a', g:Xpath)
breakdel *
call delete('Xscript')
endfunc
" interrupt right before a catch is invoked inside a function.
func Test_ignore_catch_after_intr_2()
" for unknown reasons this test sometimes fails on MS-Windows.
let g:test_is_flaky = 1
XpathINIT
func F()
try
try
Xpath 'a'
throw "arrgh"
call assert_report('should not get here')
catch /.*/ " interrupt here
call assert_report('should not get here')
catch /.*/
call assert_report('should not get here')
endtry
call assert_report('should not get here')
catch /arrgh/
call assert_report('should not get here')
endtry
call assert_report('should not get here')
endfunc
breakadd func 6 F
try
let caught_intr = 0
debuggreedy
call feedkeys(":call F()\<CR>quit\<CR>", "xt")
catch /^Vim:Interrupt$/
call assert_match('\.F, line 6', v:throwpoint)
let caught_intr = 1
endtry
0debuggreedy
call assert_equal(1, caught_intr)
call assert_equal('a', g:Xpath)
breakdel *
delfunc F
endfunc
"-------------------------------------------------------------------------------
" Test 83: Executing :finally clauses after an error or interrupt {{{1
"
" When an exception is thrown and an error or interrupt occurs before
" the :finally of the innermost :try is reached, the exception is
" discarded and the :finally clause is executed.
"-------------------------------------------------------------------------------
func Test_finally_after_error()
let test =<< trim [CODE]
try
Xpath 'a'
try
Xpath 'b'
throw "arrgh"
call assert_report('should not get here')
if 1
call assert_report('should not get here')
" error after :throw: missing :endif
finally
Xpath 'c'
endtry
call assert_report('should not get here')
catch /arrgh/
call assert_report('should not get here')
endtry
call assert_report('should not get here')
[CODE]
let verify =<< trim [CODE]
call assert_equal('abc', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
" interrupt the code right before the finally is invoked
func Test_finally_after_intr()
XpathINIT
let lines =<< trim [CODE]
try
Xpath 'a'
try
Xpath 'b'
throw "arrgh"
call assert_report('should not get here')
finally " interrupt here
Xpath 'c'
endtry
call assert_report('should not get here')
catch /arrgh/
call assert_report('should not get here')
endtry
call assert_report('should not get here')
[CODE]
call writefile(lines, 'Xscript')
breakadd file 7 Xscript
try
let caught_intr = 0
debuggreedy
call feedkeys(":source Xscript\<CR>quit\<CR>", "xt")
catch /^Vim:Interrupt$/
call assert_match('Xscript, line 7', v:throwpoint)
let caught_intr = 1
endtry
0debuggreedy
call assert_equal(1, caught_intr)
call assert_equal('abc', g:Xpath)
breakdel *
call delete('Xscript')
endfunc
"-------------------------------------------------------------------------------
" Test 84: Exceptions in autocommand sequences. {{{1
"
" When an exception occurs in a sequence of autocommands for
" a specific event, the rest of the sequence is not executed. The
" command that triggered the autocommand execution aborts, and the
" exception is propagated to the caller.
"
" For the FuncUndefined event under a function call expression or
" :call command, the function is not executed, even when it has
" been defined by the autocommands before the exception occurred.
"-------------------------------------------------------------------------------
func Test_autocmd_exception()
let test =<< trim [CODE]
func INT()
call interrupt()
endfunc
aug TMP
autocmd!
autocmd User x1 Xpath 'a'
autocmd User x1 throw "x1"
autocmd User x1 call assert_report('should not get here')
autocmd User x2 Xpath 'b'
autocmd User x2 asdf
autocmd User x2 call assert_report('should not get here')
autocmd User x3 Xpath 'c'
autocmd User x3 call INT()
autocmd User x3 call assert_report('should not get here')
autocmd FuncUndefined U1 func U1()
autocmd FuncUndefined U1 call assert_report('should not get here')
autocmd FuncUndefined U1 endfunc
autocmd FuncUndefined U1 Xpath 'd'
autocmd FuncUndefined U1 throw "U1"
autocmd FuncUndefined U1 call assert_report('should not get here')
autocmd FuncUndefined U2 func U2()
autocmd FuncUndefined U2 call assert_report('should not get here')
autocmd FuncUndefined U2 endfunc
autocmd FuncUndefined U2 Xpath 'e'
autocmd FuncUndefined U2 ASDF
autocmd FuncUndefined U2 call assert_report('should not get here')
autocmd FuncUndefined U3 func U3()
autocmd FuncUndefined U3 call assert_report('should not get here')
autocmd FuncUndefined U3 endfunc
autocmd FuncUndefined U3 Xpath 'f'
autocmd FuncUndefined U3 call INT()
autocmd FuncUndefined U3 call assert_report('should not get here')
aug END
try
try
Xpath 'g'
doautocmd User x1
catch /x1/
Xpath 'h'
endtry
while 1
try
Xpath 'i'
doautocmd User x2
catch /asdf/
Xpath 'j'
finally
Xpath 'k'
break
endtry
endwhile
while 1
try
Xpath 'l'
doautocmd User x3
catch /Vim:Interrupt/
Xpath 'm'
finally
Xpath 'n'
" ... but break loop for caught interrupt exception,
" or discard interrupt and break loop if $VIMNOINTTHROW
break
endtry
endwhile
if exists("*U1") | delfunction U1 | endif
if exists("*U2") | delfunction U2 | endif
if exists("*U3") | delfunction U3 | endif
try
Xpath 'o'
call U1()
catch /U1/
Xpath 'p'
endtry
while 1
try
Xpath 'q'
call U2()
catch /ASDF/
Xpath 'r'
finally
Xpath 's'
" ... but break loop for caught error exception,
" or discard error and break loop if $VIMNOERRTHROW
break
endtry
endwhile
while 1
try
Xpath 't'
call U3()
catch /Vim:Interrupt/
Xpath 'u'
finally
Xpath 'v'
" ... but break loop for caught interrupt exception,
" or discard interrupt and break loop if $VIMNOINTTHROW
break
endtry
endwhile
catch /.*/
call assert_report('should not get here')
endtry
Xpath 'w'
[CODE]
let verify =<< trim [CODE]
call assert_equal('gahibjklcmnodpqerstfuvw', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 85: Error exceptions in autocommands for I/O command events {{{1
"
" When an I/O command is inside :try/:endtry, autocommands to be
" executed after it should be skipped on an error (exception) in the
" command itself or in autocommands to be executed before the command.
" In the latter case, the I/O command should not be executed either.
" Example 1: BufWritePre, :write, BufWritePost
" Example 2: FileReadPre, :read, FileReadPost.
"-------------------------------------------------------------------------------
func Test_autocmd_error_io_exception()
let test =<< trim [CODE]
" Remove the autocommands for the events specified as arguments in all used
" autogroups.
func Delete_autocommands(...)
let augfile = tempname()
while 1
try
exec "redir >" . augfile
aug
redir END
exec "edit" augfile
g/^$/d
norm G$
let wrap = "w"
while search('\%( \|^\)\@<=.\{-}\%( \)\@=', wrap) > 0
let wrap = "W"
exec "norm y/ \n"
let argno = 1
while argno <= a:0
exec "au!" escape(@", " ") a:{argno}
let argno = argno + 1
endwhile
endwhile
catch /.*/
finally
bwipeout!
call delete(augfile)
break
endtry
endwhile
endfunc
call Delete_autocommands("BufWritePre", "BufWritePost")
while 1
try
try
let post = 0
aug TMP
au! BufWritePost * let post = 1
aug END
write /n/o/n/e/x/i/s/t/e/n/t
catch /^Vim(write):/
Xpath 'a'
call assert_match("E212: Can't open file for writing", v:exception)
finally
Xpath 'b'
call assert_equal(0, post)
au! TMP
aug! TMP
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'c'
break
endtry
endwhile
while 1
try
try
let post = 0
aug TMP
au! BufWritePre * asdf
au! BufWritePost * let post = 1
aug END
let tmpfile = tempname()
exec "write" tmpfile
catch /^Vim\((write)\)\=:/
Xpath 'd'
call assert_match('E492: Not an editor command', v:exception)
finally
Xpath 'e'
if filereadable(tmpfile)
call assert_report('should not get here')
endif
call assert_equal(0, post)
au! TMP
aug! TMP
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'f'
break
endtry
endwhile
call delete(tmpfile)
call Delete_autocommands("BufWritePre", "BufWritePost",
\ "BufReadPre", "BufReadPost", "FileReadPre", "FileReadPost")
while 1
try
try
let post = 0
aug TMP
au! FileReadPost * let post = 1
aug END
let caught = 0
read /n/o/n/e/x/i/s/t/e/n/t
catch /^Vim(read):/
Xpath 'g'
call assert_match("E484: Can't open file", v:exception)
finally
Xpath 'h'
call assert_equal(0, post)
au! TMP
aug! TMP
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'i'
break
endtry
endwhile
while 1
try
let infile = tempname()
let tmpfile = tempname()
call writefile(["XYZ"], infile)
exec "edit" tmpfile
try
Xpath 'j'
try
let post = 0
aug TMP
au! FileReadPre * asdf
au! FileReadPost * let post = 1
aug END
exec "0read" infile
catch /^Vim\((read)\)\=:/
Xpath 'k'
call assert_match('E492: Not an editor command', v:exception)
finally
Xpath 'l'
if getline("1") == "XYZ"
call assert_report('should not get here')
endif
call assert_equal(0, post)
au! TMP
aug! TMP
endtry
finally
Xpath 'm'
bwipeout!
endtry
catch /.*/
call assert_report('should not get here')
finally
Xpath 'n'
break
endtry
endwhile
call delete(infile)
call delete(tmpfile)
[CODE]
let verify =<< trim [CODE]
call assert_equal('abcdefghijklmn', g:Xpath)
[CODE]
call RunInNewVim(test, verify)
endfunc
"-------------------------------------------------------------------------------
" Test 87 using (expr) ? funcref : funcref {{{1
"
" Vim needs to correctly parse the funcref and even when it does
" not execute the funcref, it needs to consume the trailing ()
"-------------------------------------------------------------------------------
func Add2(x1, x2)
return a:x1 + a:x2
endfu
func GetStr()
return "abcdefghijklmnopqrstuvwxyp"
endfu
func Test_funcref_with_condexpr()
call assert_equal(5, function('Add2')(2,3))
call assert_equal(3, 1 ? function('Add2')(1,2) : function('Add2')(2,3))
call assert_equal(5, 0 ? function('Add2')(1,2) : function('Add2')(2,3))
" Make sure, GetStr() still works.
call assert_equal('abcdefghijk', GetStr()[0:10])
endfunc
"-------------------------------------------------------------------------------
" Test 90: Recognizing {} in variable name. {{{1
"-------------------------------------------------------------------------------
func Test_curlies()
let s:var = 66
let ns = 's'
call assert_equal(66, {ns}:var)
let g:a = {}
let g:b = 't'
let g:a[g:b] = 77
call assert_equal(77, g:a['t'])
endfunc
"-------------------------------------------------------------------------------
" Test 91: using type(). {{{1
"-------------------------------------------------------------------------------
func Test_type()
call assert_equal(0, type(0))
call assert_equal(1, type(""))
call assert_equal(2, type(function("tr")))
call assert_equal(2, type(function("tr", [8])))
call assert_equal(3, type([]))
call assert_equal(4, type({}))
if has('float')
call assert_equal(5, type(0.0))
endif
call assert_equal(6, type(v:false))
call assert_equal(6, type(v:true))
" call assert_equal(7, type(v:none))
call assert_equal(7, type(v:null))
call assert_equal(v:t_number, type(0))
call assert_equal(v:t_string, type(""))
call assert_equal(v:t_func, type(function("tr")))
call assert_equal(v:t_func, type(function("tr", [8])))
call assert_equal(v:t_list, type([]))
call assert_equal(v:t_dict, type({}))
if has('float')
call assert_equal(v:t_float, type(0.0))
endif
call assert_equal(v:t_bool, type(v:false))
call assert_equal(v:t_bool, type(v:true))
" call assert_equal(v:t_none, type(v:none))
" call assert_equal(v:t_none, type(v:null))
call assert_equal(v:t_string, type(v:_null_string))
call assert_equal(v:t_list, type(v:_null_list))
call assert_equal(v:t_dict, type(v:_null_dict))
if has('job')
call assert_equal(v:t_job, type(test_null_job()))
endif
if has('channel')
call assert_equal(v:t_channel, type(test_null_channel()))
endif
call assert_equal(v:t_blob, type(v:_null_blob))
call assert_equal(0, 0 + v:false)
call assert_equal(1, 0 + v:true)
" call assert_equal(0, 0 + v:none)
call assert_equal(0, 0 + v:null)
call assert_equal('v:false', '' . v:false)
call assert_equal('v:true', '' . v:true)
" call assert_equal('v:none', '' . v:none)
call assert_equal('v:null', '' . v:null)
call assert_true(v:false == 0)
call assert_false(v:false != 0)
call assert_true(v:true == 1)
call assert_false(v:true != 1)
call assert_false(v:true == v:false)
call assert_true(v:true != v:false)
call assert_true(v:null == 0)
call assert_false(v:null != 0)
" call assert_true(v:none == 0)
" call assert_false(v:none != 0)
call assert_true(v:false is v:false)
call assert_true(v:true is v:true)
" call assert_true(v:none is v:none)
call assert_true(v:null is v:null)
call assert_false(v:false isnot v:false)
call assert_false(v:true isnot v:true)
" call assert_false(v:none isnot v:none)
call assert_false(v:null isnot v:null)
call assert_false(v:false is 0)
call assert_false(v:true is 1)
call assert_false(v:true is v:false)
" call assert_false(v:none is 0)
call assert_false(v:null is 0)
" call assert_false(v:null is v:none)
call assert_true(v:false isnot 0)
call assert_true(v:true isnot 1)
call assert_true(v:true isnot v:false)
" call assert_true(v:none isnot 0)
call assert_true(v:null isnot 0)
" call assert_true(v:null isnot v:none)
call assert_equal(v:false, eval(string(v:false)))
call assert_equal(v:true, eval(string(v:true)))
" call assert_equal(v:none, eval(string(v:none)))
call assert_equal(v:null, eval(string(v:null)))
call assert_equal(v:false, copy(v:false))
call assert_equal(v:true, copy(v:true))
" call assert_equal(v:none, copy(v:none))
call assert_equal(v:null, copy(v:null))
call assert_equal([v:false], deepcopy([v:false]))
call assert_equal([v:true], deepcopy([v:true]))
" call assert_equal([v:none], deepcopy([v:none]))
call assert_equal([v:null], deepcopy([v:null]))
call assert_true(empty(v:false))
call assert_false(empty(v:true))
call assert_true(empty(v:null))
" call assert_true(empty(v:none))
func ChangeYourMind()
try
return v:true
finally
return 'something else'
endtry
endfunc
call ChangeYourMind()
endfunc
"-------------------------------------------------------------------------------
" Test 92: skipping code {{{1
"-------------------------------------------------------------------------------
func Test_skip()
let Fn = function('Test_type')
call assert_false(0 && Fn[1])
call assert_false(0 && string(Fn))
call assert_false(0 && len(Fn))
let l = []
call assert_false(0 && l[1])
call assert_false(0 && string(l))
call assert_false(0 && len(l))
let f = 1.0
call assert_false(0 && f[1])
call assert_false(0 && string(f))
call assert_false(0 && len(f))
let sp = v:null
call assert_false(0 && sp[1])
call assert_false(0 && string(sp))
call assert_false(0 && len(sp))
endfunc
"-------------------------------------------------------------------------------
" Test 93: :echo and string() {{{1
"-------------------------------------------------------------------------------
func Test_echo_and_string()
" String
let a = 'foo bar'
redir => result
echo a
echo string(a)
redir END
let l = split(result, "\n")
call assert_equal(["foo bar",
\ "'foo bar'"], l)
" Float
if has('float')
let a = -1.2e0
redir => result
echo a
echo string(a)
redir END
let l = split(result, "\n")
call assert_equal(["-1.2",
\ "-1.2"], l)
endif
" Funcref
redir => result
echo function('string')
echo string(function('string'))
redir END
let l = split(result, "\n")
call assert_equal(["string",
\ "function('string')"], l)
" Empty dictionaries in a list
let a = {}
redir => result
echo [a, a, a]
echo string([a, a, a])
redir END
let l = split(result, "\n")
call assert_equal(["[{}, {}, {}]",
\ "[{}, {}, {}]"], l)
" Empty dictionaries in a dictionary
let a = {}
let b = {"a": a, "b": a}
redir => result
echo b
echo string(b)
redir END
let l = split(result, "\n")
call assert_equal(["{'a': {}, 'b': {}}",
\ "{'a': {}, 'b': {}}"], l)
" Empty lists in a list
let a = []
redir => result
echo [a, a, a]
echo string([a, a, a])
redir END
let l = split(result, "\n")
call assert_equal(["[[], [], []]",
\ "[[], [], []]"], l)
" Empty lists in a dictionary
let a = []
let b = {"a": a, "b": a}
redir => result
echo b
echo string(b)
redir END
let l = split(result, "\n")
call assert_equal(["{'a': [], 'b': []}",
\ "{'a': [], 'b': []}"], l)
call assert_fails('echo &:', 'E112:')
call assert_fails('echo &g:', 'E112:')
call assert_fails('echo &l:', 'E112:')
endfunc
"-------------------------------------------------------------------------------
" Test 94: 64-bit Numbers {{{1
"-------------------------------------------------------------------------------
func Test_num64()
call assert_notequal( 4294967296, 0)
call assert_notequal(-4294967296, 0)
call assert_equal( 4294967296, 0xFFFFffff + 1)
call assert_equal(-4294967296, -0xFFFFffff - 1)
call assert_equal( 9223372036854775807, 1 / 0)
call assert_equal(-9223372036854775807, -1 / 0)
call assert_equal(-9223372036854775807 - 1, 0 / 0)
if has('float')
call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150))
call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150))
endif
let rng = range(0xFFFFffff, 0x100000001)
call assert_equal([0xFFFFffff, 0x100000000, 0x100000001], rng)
call assert_equal(0x100000001, max(rng))
call assert_equal(0xFFFFffff, min(rng))
call assert_equal(rng, sort(range(0x100000001, 0xFFFFffff, -1), 'N'))
endfunc
"-------------------------------------------------------------------------------
" Test 95: lines of :append, :change, :insert {{{1
"-------------------------------------------------------------------------------
func DefineFunction(name, body)
let func = join(['function! ' . a:name . '()'] + a:body + ['endfunction'], "\n")
exec func
endfunc
func Test_script_lines()
" :append
try
call DefineFunction('T_Append', [
\ 'append',
\ 'py <<EOS',
\ '.',
\ ])
catch
call assert_report("Can't define function")
endtry
try
call DefineFunction('T_Append', [
\ 'append',
\ 'abc',
\ ])
call assert_report("Shouldn't be able to define function")
catch
call assert_exception('Vim(function):E1145: Missing heredoc end marker: .')
endtry
" :change
try
call DefineFunction('T_Change', [
\ 'change',
\ 'py <<EOS',
\ '.',
\ ])
catch
call assert_report("Can't define function")
endtry
try
call DefineFunction('T_Change', [
\ 'change',
\ 'abc',
\ ])
call assert_report("Shouldn't be able to define function")
catch
call assert_exception('Vim(function):E1145: Missing heredoc end marker: .')
endtry
" :insert
try
call DefineFunction('T_Insert', [
\ 'insert',
\ 'py <<EOS',
\ '.',
\ ])
catch
call assert_report("Can't define function")
endtry
try
call DefineFunction('T_Insert', [
\ 'insert',
\ 'abc',
\ ])
call assert_report("Shouldn't be able to define function")
catch
call assert_exception('Vim(function):E1145: Missing heredoc end marker: .')
endtry
endfunc
"-------------------------------------------------------------------------------
" Test 96: line continuation {{{1
"
" Undefined behavior was detected by ubsan with line continuation
" after an empty line.
"-------------------------------------------------------------------------------
func Test_script_empty_line_continuation()
\
endfunc
"-------------------------------------------------------------------------------
" Test 97: bitwise functions {{{1
"-------------------------------------------------------------------------------
func Test_bitwise_functions()
" and
call assert_equal(127, and(127, 127))
call assert_equal(16, and(127, 16))
eval 127->and(16)->assert_equal(16)
call assert_equal(0, and(127, 128))
call assert_fails("call and([], 1)", 'E745:')
call assert_fails("call and({}, 1)", 'E728:')
if has('float')
call assert_fails("call and(1.0, 1)", 'E805:')
call assert_fails("call and(1, 1.0)", 'E805:')
endif
call assert_fails("call and(1, [])", 'E745:')
call assert_fails("call and(1, {})", 'E728:')
" or
call assert_equal(23, or(16, 7))
call assert_equal(15, or(8, 7))
eval 8->or(7)->assert_equal(15)
call assert_equal(123, or(0, 123))
call assert_fails("call or([], 1)", 'E745:')
call assert_fails("call or({}, 1)", 'E728:')
if has('float')
call assert_fails("call or(1.0, 1)", 'E805:')
call assert_fails("call or(1, 1.0)", 'E805:')
endif
call assert_fails("call or(1, [])", 'E745:')
call assert_fails("call or(1, {})", 'E728:')
" xor
call assert_equal(0, xor(127, 127))
call assert_equal(111, xor(127, 16))
eval 127->xor(16)->assert_equal(111)
call assert_equal(255, xor(127, 128))
if has('float')
call assert_fails("call xor(1.0, 1)", 'E805:')
call assert_fails("call xor(1, 1.0)", 'E805:')
endif
call assert_fails("call xor([], 1)", 'E745:')
call assert_fails("call xor({}, 1)", 'E728:')
call assert_fails("call xor(1, [])", 'E745:')
call assert_fails("call xor(1, {})", 'E728:')
" invert
call assert_equal(65408, and(invert(127), 65535))
eval 127->invert()->and(65535)->assert_equal(65408)
call assert_equal(65519, and(invert(16), 65535))
call assert_equal(65407, and(invert(128), 65535))
if has('float')
call assert_fails("call invert(1.0)", 'E805:')
endif
call assert_fails("call invert([])", 'E745:')
call assert_fails("call invert({})", 'E728:')
endfunc
" Test using bang after user command {{{1
func Test_user_command_with_bang()
command -bang Nieuw let nieuw = 1
Ni!
call assert_equal(1, nieuw)
unlet nieuw
delcommand Nieuw
endfunc
func Test_script_expand_sfile()
let lines =<< trim END
func s:snr()
return expand('<sfile>')
endfunc
let g:result = s:snr()
END
call writefile(lines, 'Xexpand')
source Xexpand
call assert_match('<SNR>\d\+_snr', g:result)
source Xexpand
call assert_match('<SNR>\d\+_snr', g:result)
call delete('Xexpand')
unlet g:result
endfunc
func Test_compound_assignment_operators()
" Test for number
let x = 1
let x += 10
call assert_equal(11, x)
let x -= 5
call assert_equal(6, x)
let x *= 4
call assert_equal(24, x)
let x /= 3
call assert_equal(8, x)
let x %= 3
call assert_equal(2, x)
let x .= 'n'
call assert_equal('2n', x)
" Test special cases: division or modulus with 0.
let x = 1
let x /= 0
call assert_equal(0x7FFFFFFFFFFFFFFF, x)
let x = -1
let x /= 0
call assert_equal(-0x7FFFFFFFFFFFFFFF, x)
let x = 0
let x /= 0
call assert_equal(-0x7FFFFFFFFFFFFFFF - 1, x)
let x = 1
let x %= 0
call assert_equal(0, x)
let x = -1
let x %= 0
call assert_equal(0, x)
let x = 0
let x %= 0
call assert_equal(0, x)
" Test for string
let x = 'str'
let x .= 'ing'
call assert_equal('string', x)
let x += 1
call assert_equal(1, x)
if has('float')
" Test for float
let x -= 1.5
call assert_equal(-0.5, x)
let x = 0.5
let x += 4.5
call assert_equal(5.0, x)
let x -= 1.5
call assert_equal(3.5, x)
let x *= 3.0
call assert_equal(10.5, x)
let x /= 2.5
call assert_equal(4.2, x)
call assert_fails('let x %= 0.5', 'E734')
call assert_fails('let x .= "f"', 'E734')
let x = !3.14
call assert_equal(0.0, x)
" integer and float operations
let x = 1
let x *= 2.1
call assert_equal(2.1, x)
let x = 1
let x /= 0.25
call assert_equal(4.0, x)
let x = 1
call assert_fails('let x %= 0.25', 'E734:')
let x = 1
call assert_fails('let x .= 0.25', 'E734:')
let x = 1.0
call assert_fails('let x += [1.1]', 'E734:')
endif
" Test for environment variable
let $FOO = 1
call assert_fails('let $FOO += 1', 'E734')
call assert_fails('let $FOO -= 1', 'E734')
call assert_fails('let $FOO *= 1', 'E734')
call assert_fails('let $FOO /= 1', 'E734')
call assert_fails('let $FOO %= 1', 'E734')
let $FOO .= 's'
call assert_equal('1s', $FOO)
unlet $FOO
" Test for option variable (type: number)
let &scrolljump = 1
let &scrolljump += 5
call assert_equal(6, &scrolljump)
let &scrolljump -= 2
call assert_equal(4, &scrolljump)
let &scrolljump *= 3
call assert_equal(12, &scrolljump)
let &scrolljump /= 2
call assert_equal(6, &scrolljump)
let &scrolljump %= 5
call assert_equal(1, &scrolljump)
call assert_fails('let &scrolljump .= "j"', ['E734:', 'E734:'])
set scrolljump&vim
let &foldlevelstart = 2
let &foldlevelstart -= 1
call assert_equal(1, &foldlevelstart)
let &foldlevelstart -= 1
call assert_equal(0, &foldlevelstart)
let &foldlevelstart = 2
let &foldlevelstart -= 2
call assert_equal(0, &foldlevelstart)
" Test for register
let @/ = 1
call assert_fails('let @/ += 1', 'E734:')
call assert_fails('let @/ -= 1', 'E734:')
call assert_fails('let @/ *= 1', 'E734:')
call assert_fails('let @/ /= 1', 'E734:')
call assert_fails('let @/ %= 1', 'E734:')
let @/ .= 's'
call assert_equal('1s', @/)
let @/ = ''
endfunc
func Test_unlet_env()
let $TESTVAR = 'yes'
call assert_equal('yes', $TESTVAR)
call assert_fails('lockvar $TESTVAR', 'E940')
call assert_fails('unlockvar $TESTVAR', 'E940')
call assert_equal('yes', $TESTVAR)
if 0
unlet $TESTVAR
endif
call assert_equal('yes', $TESTVAR)
unlet $TESTVAR
call assert_equal('', $TESTVAR)
endfunc
func Test_refcount()
throw 'Skipped: Nvim does not support test_refcount()'
" Immediate values
call assert_equal(-1, test_refcount(1))
call assert_equal(-1, test_refcount('s'))
call assert_equal(-1, test_refcount(v:true))
call assert_equal(0, test_refcount([]))
call assert_equal(0, test_refcount({}))
call assert_equal(0, test_refcount(0zff))
call assert_equal(0, test_refcount({-> line('.')}))
call assert_equal(-1, test_refcount(0.1))
if has('job')
call assert_equal(0, test_refcount(job_start([&shell, &shellcmdflag, 'echo .'])))
endif
" No refcount types
let x = 1
call assert_equal(-1, test_refcount(x))
let x = 's'
call assert_equal(-1, test_refcount(x))
let x = v:true
call assert_equal(-1, test_refcount(x))
let x = 0.1
call assert_equal(-1, test_refcount(x))
" Check refcount
let x = []
call assert_equal(1, test_refcount(x))
let x = {}
call assert_equal(1, x->test_refcount())
let x = 0zff
call assert_equal(1, test_refcount(x))
let X = {-> line('.')}
call assert_equal(1, test_refcount(X))
let Y = X
call assert_equal(2, test_refcount(X))
if has('job')
let job = job_start([&shell, &shellcmdflag, 'echo .'])
call assert_equal(1, test_refcount(job))
call assert_equal(1, test_refcount(job_getchannel(job)))
call assert_equal(1, test_refcount(job))
endif
" Function arguments, copying and unassigning
func ExprCheck(x, i)
let i = a:i + 1
call assert_equal(i, test_refcount(a:x))
let Y = a:x
call assert_equal(i + 1, test_refcount(a:x))
call assert_equal(test_refcount(a:x), test_refcount(Y))
let Y = 0
call assert_equal(i, test_refcount(a:x))
endfunc
call ExprCheck([], 0)
call ExprCheck({}, 0)
call ExprCheck(0zff, 0)
call ExprCheck({-> line('.')}, 0)
if has('job')
call ExprCheck(job, 1)
call ExprCheck(job_getchannel(job), 1)
call job_stop(job)
endif
delfunc ExprCheck
" Regarding function
func Func(x) abort
call assert_equal(2, test_refcount(function('Func')))
call assert_equal(0, test_refcount(funcref('Func')))
endfunc
call assert_equal(1, test_refcount(function('Func')))
call assert_equal(0, test_refcount(function('Func', [1])))
call assert_equal(0, test_refcount(funcref('Func')))
call assert_equal(0, test_refcount(funcref('Func', [1])))
let X = function('Func')
let Y = X
call assert_equal(1, test_refcount(X))
let X = function('Func', [1])
let Y = X
call assert_equal(2, test_refcount(X))
let X = funcref('Func')
let Y = X
call assert_equal(2, test_refcount(X))
let X = funcref('Func', [1])
let Y = X
call assert_equal(2, test_refcount(X))
unlet X
unlet Y
call Func(1)
delfunc Func
" Function with dict
func DictFunc() dict
call assert_equal(3, test_refcount(self))
endfunc
let d = {'Func': function('DictFunc')}
call assert_equal(1, test_refcount(d))
call assert_equal(0, test_refcount(d.Func))
call d.Func()
unlet d
delfunc DictFunc
if has('channel')
call assert_equal(-1, test_refcount(test_null_job()))
call assert_equal(-1, test_refcount(test_null_channel()))
endif
call assert_equal(-1, test_refcount(test_null_function()))
call assert_equal(-1, test_refcount(test_null_partial()))
call assert_equal(-1, test_refcount(test_null_blob()))
call assert_equal(-1, test_refcount(test_null_list()))
call assert_equal(-1, test_refcount(test_null_dict()))
endfunc
" Test for missing :endif, :endfor, :endwhile and :endtry {{{1
func Test_missing_end()
call writefile(['if 2 > 1', 'echo ">"'], 'Xscript')
call assert_fails('source Xscript', 'E171:')
call writefile(['for i in range(5)', 'echo i'], 'Xscript')
call assert_fails('source Xscript', 'E170:')
call writefile(['while v:true', 'echo "."'], 'Xscript')
call assert_fails('source Xscript', 'E170:')
call writefile(['try', 'echo "."'], 'Xscript')
call assert_fails('source Xscript', 'E600:')
call delete('Xscript')
" Using endfor with :while
let caught_e732 = 0
try
while v:true
endfor
catch /E732:/
let caught_e732 = 1
endtry
call assert_equal(1, caught_e732)
" Using endwhile with :for
let caught_e733 = 0
try
for i in range(1)
endwhile
catch /E733:/
let caught_e733 = 1
endtry
call assert_equal(1, caught_e733)
" Using endfunc with :if
call assert_fails('exe "if 1 | endfunc | endif"', 'E193:')
" Missing 'in' in a :for statement
call assert_fails('for i range(1) | endfor', 'E690:')
" Incorrect number of variables in for
call assert_fails('for [i,] in range(3) | endfor', 'E475:')
endfunc
" Test for deep nesting of if/for/while/try statements {{{1
func Test_deep_nest()
CheckRunVimInTerminal
let lines =<< trim [SCRIPT]
" Deep nesting of if ... endif
func Test1()
let @a = join(repeat(['if v:true'], 51), "\n")
let @a ..= "\n"
let @a ..= join(repeat(['endif'], 51), "\n")
@a
let @a = ''
endfunc
" Deep nesting of for ... endfor
func Test2()
let @a = join(repeat(['for i in [1]'], 51), "\n")
let @a ..= "\n"
let @a ..= join(repeat(['endfor'], 51), "\n")
@a
let @a = ''
endfunc
" Deep nesting of while ... endwhile
func Test3()
let @a = join(repeat(['while v:true'], 51), "\n")
let @a ..= "\n"
let @a ..= join(repeat(['endwhile'], 51), "\n")
@a
let @a = ''
endfunc
" Deep nesting of try ... endtry
func Test4()
let @a = join(repeat(['try'], 51), "\n")
let @a ..= "\necho v:true\n"
let @a ..= join(repeat(['endtry'], 51), "\n")
@a
let @a = ''
endfunc
" Deep nesting of function ... endfunction
func Test5()
let @a = join(repeat(['function X()'], 51), "\n")
let @a ..= "\necho v:true\n"
let @a ..= join(repeat(['endfunction'], 51), "\n")
@a
let @a = ''
endfunc
[SCRIPT]
call writefile(lines, 'Xscript')
let buf = RunVimInTerminal('-S Xscript', {'rows': 6})
" Deep nesting of if ... endif
call term_sendkeys(buf, ":call Test1()\n")
call TermWait(buf)
call WaitForAssert({-> assert_match('^E579:', term_getline(buf, 5))})
" Deep nesting of for ... endfor
call term_sendkeys(buf, ":call Test2()\n")
call TermWait(buf)
call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
" Deep nesting of while ... endwhile
call term_sendkeys(buf, ":call Test3()\n")
call TermWait(buf)
call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
" Deep nesting of try ... endtry
call term_sendkeys(buf, ":call Test4()\n")
call TermWait(buf)
call WaitForAssert({-> assert_match('^E601:', term_getline(buf, 5))})
" Deep nesting of function ... endfunction
call term_sendkeys(buf, ":call Test5()\n")
call TermWait(buf)
call WaitForAssert({-> assert_match('^E1058:', term_getline(buf, 4))})
call term_sendkeys(buf, "\<C-C>\n")
call TermWait(buf)
"let l = ''
"for i in range(1, 6)
" let l ..= term_getline(buf, i) . "\n"
"endfor
"call assert_report(l)
call StopVimInTerminal(buf)
call delete('Xscript')
endfunc
" Test for errors in converting to float from various types {{{1
func Test_float_conversion_errors()
if has('float')
call assert_fails('let x = 4.0 % 2.0', 'E804')
call assert_fails('echo 1.1[0]', 'E806')
call assert_fails('echo sort([function("min"), 1], "f")', 'E891:')
call assert_fails('echo 3.2 == "vim"', 'E892:')
call assert_fails('echo sort([[], 1], "f")', 'E893:')
call assert_fails('echo sort([{}, 1], "f")', 'E894:')
call assert_fails('echo 3.2 == v:true', 'E362:')
" call assert_fails('echo 3.2 == v:none', 'E907:')
endif
endfunc
" invalid function names {{{1
func Test_invalid_function_names()
" function name not starting with capital
let caught_e128 = 0
try
func! g:test()
echo "test"
endfunc
catch /E128:/
let caught_e128 = 1
endtry
call assert_equal(1, caught_e128)
" function name includes a colon
let caught_e884 = 0
try
func! b:test()
echo "test"
endfunc
catch /E884:/
let caught_e884 = 1
endtry
call assert_equal(1, caught_e884)
" function name followed by #
let caught_e128 = 0
try
func! test2() "#
echo "test2"
endfunc
catch /E128:/
let caught_e128 = 1
endtry
call assert_equal(1, caught_e128)
" function name starting with/without "g:", buffer-local funcref.
function! g:Foo(n)
return 'called Foo(' . a:n . ')'
endfunction
let b:my_func = function('Foo')
call assert_equal('called Foo(1)', b:my_func(1))
call assert_equal('called Foo(2)', g:Foo(2))
call assert_equal('called Foo(3)', Foo(3))
delfunc g:Foo
" script-local function used in Funcref must exist.
let lines =<< trim END
func s:Testje()
return "foo"
endfunc
let Bar = function('s:Testje')
call assert_equal(0, exists('s:Testje'))
call assert_equal(1, exists('*s:Testje'))
call assert_equal(1, exists('Bar'))
call assert_equal(1, exists('*Bar'))
END
call writefile(lines, 'Xscript')
source Xscript
call delete('Xscript')
endfunc
" substring and variable name {{{1
func Test_substring_var()
let str = 'abcdef'
let n = 3
call assert_equal('def', str[n:])
call assert_equal('abcd', str[:n])
call assert_equal('d', str[n:n])
unlet n
let nn = 3
call assert_equal('def', str[nn:])
call assert_equal('abcd', str[:nn])
call assert_equal('d', str[nn:nn])
unlet nn
let b:nn = 4
call assert_equal('ef', str[b:nn:])
call assert_equal('abcde', str[:b:nn])
call assert_equal('e', str[b:nn:b:nn])
unlet b:nn
endfunc
" Test using s: with a typed command {{{1
func Test_typed_script_var()
CheckRunVimInTerminal
let buf = RunVimInTerminal('', {'rows': 6})
" Deep nesting of if ... endif
call term_sendkeys(buf, ":echo get(s:, 'foo', 'x')\n")
call TermWait(buf)
call WaitForAssert({-> assert_match('^E116:', term_getline(buf, 5))})
call StopVimInTerminal(buf)
endfunc
" Test for issue6776 {{{1
func Test_ternary_expression()
try
call eval('0 ? 0')
catch
endtry
" previous failure should not cause next expression to fail
call assert_equal(v:false, eval(string(v:false)))
try
call eval('0 ? "burp')
catch
endtry
" previous failure should not cause next expression to fail
call assert_equal(v:false, eval(string(v:false)))
try
call eval('1 ? 0 : "burp')
catch
endtry
" previous failure should not cause next expression to fail
call assert_equal(v:false, eval(string(v:false)))
endfunction
func Test_for_over_string()
let res = ''
for c in 'aéc̀d'
let res ..= c .. '-'
endfor
call assert_equal('a-é-c̀-d-', res)
let res = ''
for c in ''
let res ..= c .. '-'
endfor
call assert_equal('', res)
let res = ''
for c in v:_null_string
let res ..= c .. '-'
endfor
call assert_equal('', res)
" Test for using "_" as the loop variable
let i = 0
let s = 'abc'
for _ in s
call assert_equal(s[i], _)
let i += 1
endfor
endfunc
" Test for deeply nested :source command {{{1
func Test_deeply_nested_source()
throw 'Skipped: Vim9 script is N/A'
let lines =<< trim END
so
sil 0scr
delete
so
0
END
call writefile(["vim9 silent! @0 \n/"] + lines, 'Xnested.vim', 'D')
" this must not crash
let cmd = GetVimCommand() .. " -e -s -S Xnested.vim -c qa!"
call system(cmd)
endfunc
func Test_exception_silent()
XpathINIT
let lines =<< trim END
func Throw()
Xpath 'a'
throw "Uncaught"
" This line is not executed.
Xpath 'b'
endfunc
" The exception is suppressed due to the presence of silent!.
silent! call Throw()
try
call DoesNotExist()
catch /E117:/
Xpath 'c'
endtry
Xpath 'd'
END
let verify =<< trim END
call assert_equal('acd', g:Xpath)
END
call RunInNewVim(lines, verify)
endfunc
"-------------------------------------------------------------------------------
" Modelines {{{1
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
"-------------------------------------------------------------------------------