mirror of
https://github.com/neovim/neovim.git
synced 2025-09-15 15:58:17 +00:00

Removes the `getoption_T` struct and also introduces the `OptVal` struct to unify the methods of getting/setting different option value types. This is the first of many PRs to reduce code duplication in the Vim option code as well as to make options easier to maintain. It also increases the flexibility and extensibility of options. Which opens the door for things like Array and Dictionary options.
7447 lines
188 KiB
VimL
7447 lines
188 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 functions 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 functions 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 functions checks 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_execption_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({}))
|
|
call assert_equal(5, type(0.0))
|
|
call assert_equal(6, type(v:false))
|
|
call assert_equal(6, type(v:true))
|
|
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_list, type([]))
|
|
call assert_equal(v:t_dict, type({}))
|
|
call assert_equal(v:t_float, type(0.0))
|
|
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.0, 1)", 'E805:')
|
|
call assert_fails("call and([], 1)", 'E745:')
|
|
call assert_fails("call and({}, 1)", 'E728:')
|
|
call assert_fails("call and(1, 1.0)", 'E805:')
|
|
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.0, 1)", 'E805:')
|
|
call assert_fails("call or([], 1)", 'E745:')
|
|
call assert_fails("call or({}, 1)", 'E728:')
|
|
call assert_fails("call or(1, 1.0)", 'E805:')
|
|
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))
|
|
call assert_fails("call xor(1.0, 1)", 'E805:')
|
|
call assert_fails("call xor([], 1)", 'E745:')
|
|
call assert_fails("call xor({}, 1)", 'E728:')
|
|
call assert_fails("call xor(1, 1.0)", 'E805:')
|
|
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))
|
|
call assert_fails("call invert(1.0)", 'E805:')
|
|
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)
|
|
" A different error is shown due to a change in implementation of option
|
|
" values.
|
|
" call assert_fails('let &scrolljump .= "j"', 'E734:')
|
|
call assert_fails('let &scrolljump .= "j"', 'E521:')
|
|
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 term_wait(buf)
|
|
call WaitForAssert({-> assert_match('^E579:', term_getline(buf, 5))})
|
|
|
|
" Deep nesting of for ... endfor
|
|
call term_sendkeys(buf, ":call Test2()\n")
|
|
call term_wait(buf)
|
|
call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
|
|
|
|
" Deep nesting of while ... endwhile
|
|
call term_sendkeys(buf, ":call Test3()\n")
|
|
call term_wait(buf)
|
|
call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
|
|
|
|
" Deep nesting of try ... endtry
|
|
call term_sendkeys(buf, ":call Test4()\n")
|
|
call term_wait(buf)
|
|
call WaitForAssert({-> assert_match('^E601:', term_getline(buf, 5))})
|
|
|
|
" Deep nesting of function ... endfunction
|
|
call term_sendkeys(buf, ":call Test5()\n")
|
|
call term_wait(buf)
|
|
call WaitForAssert({-> assert_match('^E1058:', term_getline(buf, 4))})
|
|
call term_sendkeys(buf, "\<C-C>\n")
|
|
call term_wait(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)
|
|
endfunc
|
|
|
|
"-------------------------------------------------------------------------------
|
|
" Modelines {{{1
|
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
|
"-------------------------------------------------------------------------------
|