9802 lines · 218.9 KB · Text
RawDownload
" Vim script language tests" Author:	Servatius Brandt <Servatius.Brandt@fujitsu-siemens.com>" Last Change:	2006 Apr 28 "-------------------------------------------------------------------------------" Test environment							    {{{1"-------------------------------------------------------------------------------  " Adding new tests easily.						    {{{2"" Writing new tests is eased considerably with the following functions and" abbreviations (see "Commands for recording the execution path", "Automatic" argument generation")."" To get the abbreviations, execute the command""    :let test49_set_env = 1 | source test49.vim"" To get them always (from src/testdir), put a line""    au! BufRead test49.vim let test49_set_env = 1 | source test49.vim"" into the local .vimrc file in the src/testdir directory."if exists("test49_set_env") && test49_set_env     " Automatic argument generation for the test environment commands.     function! Xsum()	let addend = substitute(getline("."), '^.*"\s*X:\s*\|^.*', '', "")	" Evaluate arithmetic expression.	if addend != ""	    exec "let g:Xsum = g:Xsum + " . addend	endif    endfunction     function! Xcheck()	let g:Xsum=0	?XpathINIT?,.call Xsum()	exec "norm A "	return g:Xsum    endfunction     iab Xcheck Xcheck<Space><C-R>=Xcheck()<CR><C-O>x     function! Xcomment(num)	let str = ""	let tabwidth = &sts ? &sts : &ts	let tabs = (48+tabwidth - a:num - virtcol(".")) / tabwidth	while tabs > 0	    let str = str . "\t"	    let tabs = tabs - 1	endwhile	let str = str . '" X:'	return str    endfunction     function! Xloop()	let back = line(".") . "|norm" . virtcol(".") . "|"	norm 0	let last = search('X\(loop\|path\)INIT\|Xloop\>', "bW")	exec back	let theline = getline(last)	if theline =~ 'X\(loop\|path\)INIT'	    let num = 1	else	    let num = 2 * substitute(theline, '.*Xloop\s*\(\d\+\).*', '\1', "")	endif	?X\(loop\|path\)INIT?	    \s/\(XloopINIT!\=\s*\d\+\s\+\)\@<=\(\d\+\)/\=2*submatch(2)/	exec back	exec "norm a "	return num . Xcomment(strlen(num))    endfunction     iab Xloop Xloop<Space><C-R>=Xloop()<CR><C-O>x     function! Xpath(loopinit)	let back = line(".") . "|norm" . virtcol(".") . "|"	norm 0	let last = search('XpathINIT\|Xpath\>\|XloopINIT', "bW")	exec back	let theline = getline(last)	if theline =~ 'XpathINIT'	    let num = 1	elseif theline =~ 'Xpath\>'	    let num = 2 * substitute(theline, '.*Xpath\s*\(\d\+\).*', '\1', "")	else	    let pattern = '.*XloopINIT!\=\s*\(\d\+\)\s*\(\d\+\).*'	    let num = substitute(theline, pattern, '\1', "")	    let factor = substitute(theline, pattern, '\2', "")	    " The "<C-O>x" from the "Xpath" iab and the character triggering its	    " expansion are in the input buffer.  Save and clear typeahead so	    " that it is not read away by the call to "input()" below.  Restore	    " afterwards.	    call inputsave()	    let loops = input("Number of iterations in previous loop? ")	    call inputrestore()	    while (loops > 0)		let num = num * factor		let loops = loops - 1	    endwhile	endif	exec "norm a "	if a:loopinit	    return num . " 1"	endif	return num . Xcomment(strlen(num))    endfunction     iab Xpath Xpath<Space><C-R>=Xpath(0)<CR><C-O>x    iab XloopINIT XloopINIT<Space><C-R>=Xpath(1)<CR><C-O>x     " Also useful (see ExtraVim below):    aug ExtraVim	au!	au  BufEnter <sfile> syn region ExtraVim		    \ start=+^if\s\+ExtraVim(.*)+ end=+^endif+		    \ transparent keepend	au  BufEnter <sfile> syn match ExtraComment /^"/		    \ contained containedin=ExtraVim	au  BufEnter <sfile> hi link ExtraComment vimComment    aug END     aug Xpath	au  BufEnter <sfile> syn keyword Xpath		    \ XpathINIT Xpath XloopINIT Xloop XloopNEXT Xcheck Xout	au  BufEnter <sfile> hi link Xpath Special    aug END     do BufEnter <sfile>     " Do not execute the tests when sourcing this file for getting the functions    " and abbreviations above, which are intended for easily adding new test    " cases; they are not needed for test execution.  Unlet the variable    " controlling this so that an explicit ":source" command for this file will    " execute the tests.    unlet test49_set_env    finish endif  " Commands for recording the execution path.				    {{{2"" The Xpath/Xloop commands can be used for computing the eXecution path by" adding (different) powers of 2 from those script lines, for which the" execution should be checked.  Xloop provides different addends for each" execution of a loop.  Permitted values are 2^0 to 2^30, so that 31 execution" points (multiply counted inside loops) can be tested."" Note that the arguments of the following commands can be generated" automatically, see below."" Usage:								    {{{3""   - Use XpathINIT at the beginning of the test.""   - Use Xpath to check if a line is executed."     Argument: power of 2 (decimal).""   - To check multiple execution of loops use Xloop for automatically"     computing Xpath values:""	- Use XloopINIT before the loop."	  Two arguments:"		- the first Xpath value (power of 2) to be used (Xnext),"		- factor for computing a new Xnext value when reexecuting a loop"		  (by a ":continue" or ":endwhile"); this should be 2^n where"		  n is the number of Xloop commands inside the loop."	  If XloopINIT! is used, the first execution of XloopNEXT is"	  a no-operation.""       - Use Xloop inside the loop:"	  One argument:"		The argument and the Xnext value are multiplied to build the"		next Xpath value.  No new Xnext value is prepared.  The argument"		should be 2^(n-1) for the nth Xloop command inside the loop."		If the loop has only one Xloop command, the argument can be"		ommitted (default: 1).""	- Use XloopNEXT before ":continue" and ":endwhile".  This computes a new"	  Xnext value for the next execution of the loop by multiplying the old"	  one with the factor specified in the XloopINIT command.  No Argument."	  Alternatively, when XloopINIT! is used, a single XloopNEXT at the"	  beginning of the loop can be used.""     Nested loops are not supported.""   - Use Xcheck at end of each test.  It prints the test number, the expected"     execution path value, the test result ("OK" or "FAIL"), and, if the tests"     fails, the actual execution path."     One argument:"	    Expected Xpath/Xloop sum for the correct execution path."	    In order that this value can be computed automatically, do the"	    following: For each line in the test with an Xpath and Xloop"	    command, add a comment starting with "X:" and specifying an"	    expression that evaluates to the value contributed by this line to"	    the correct execution path.  (For copying an Xpath argument of at"	    least two digits into the comment, press <C-P>.)  At the end of the"	    test, just type "Xcheck" and press <Esc>.""   - In order to add additional information to the test output file, use the"     Xout command.  Argument(s) like ":echo"."" Automatic argument generation:					    {{{3""   The arguments of the Xpath, XloopINIT, Xloop, and Xcheck commands can be"   generated automatically, so that new tests can easily be written without"   mental arithmetic.  The Xcheck argument is computed from the "X:" comments"   of the preceding Xpath and Xloop commands.  See the commands and"   abbreviations at the beginning of this file."" Implementation:							    {{{3"     XpathINIT, Xpath, XloopINIT, Xloop, XloopNEXT, Xcheck, Xout."" The variants for existing g:ExtraVimResult are needed when executing a script" in an extra Vim process, see ExtraVim below. " EXTRA_VIM_START - do not change or remove this line. com!		    XpathINIT	let g:Xpath = 0 if exists("g:ExtraVimResult")    com! -count -bar    Xpath	exec "!echo <count> >>" . g:ExtraVimResultelse    com! -count -bar    Xpath	let g:Xpath = g:Xpath + <count>endif com! -count -nargs=1 -bang		  \ XloopINIT	let g:Xnext = <count> |				    \ let g:Xfactor = <args> |				    \ let g:Xskip = strlen("<bang>") if exists("g:ExtraVimResult")    com! -count=1 -bar  Xloop	exec "!echo " . (g:Xnext * <count>) . " >>" .				    \ g:ExtraVimResultelse    com! -count=1 -bar  Xloop	let g:Xpath = g:Xpath + g:Xnext * <count>endif com!		    XloopNEXT	let g:Xnext = g:Xnext *				    \ (g:Xskip ? 1 : g:Xfactor) |				    \ let g:Xskip = 0 let @r = ""let Xtest = 1com! -count	    Xcheck	let Xresult = "*** Test " .				    \ (Xtest<10?"  ":Xtest<100?" ":"") .				    \ Xtest . ": " . (				    \ (Xpath==<count>) ? "OK (".Xpath.")" :					\ "FAIL (".Xpath." instead of <count>)"				    \ ) |				    \ let @R = Xresult . "\n" |				    \ echo Xresult |				    \ let Xtest = Xtest + 1 if exists("g:ExtraVimResult")    com! -nargs=+    Xoutq	exec "!echo @R:'" .				    \ substitute(substitute(<q-args>,				    \ "'", '&\\&&', "g"), "\n", "@NL@", "g")				    \ . "' >>" . g:ExtraVimResultelse    com! -nargs=+    Xoutq	let @R = "--- Test " .				    \ (g:Xtest<10?"  ":g:Xtest<100?" ":"") .				    \ g:Xtest . ": " . substitute(<q-args>,				    \ "\n", "&\t      ", "g") . "\n"endifcom! -nargs=+	    Xout	exec 'Xoutq' <args> " Switch off storing of lines for undoing changes.  Speeds things up a little.set undolevels=-1 " EXTRA_VIM_STOP - do not change or remove this line.  " ExtraVim() - Run a script file in an extra Vim process.		    {{{2"" This is useful for testing immediate abortion of the script processing due to" an error in a command dynamically enclosed by a :try/:tryend region or when an" exception is thrown but not caught or when an interrupt occurs.  It can also" be used for testing :finish."" An interrupt location can be specified by an "INTERRUPT" comment.  A number" telling how often this location is reached (in a loop or in several function" calls) should be specified as argument.  When missing, once per script" invocation or function call is assumed.  INTERRUPT locations are tested by" setting a breakpoint in that line and using the ">quit" debug command when" the breakpoint is reached.  A function for which an INTERRUPT location is" specified must be defined before calling it (or executing it as a script by" using ExecAsScript below)."" This function is only called in normal modus ("g:ExtraVimResult" undefined)."" Tests to be executed as an extra script should be written as follows:""	column 1			column 1"	|				|"	v				v""	XpathINIT			XpathINIT"	if ExtraVim()			if ExtraVim()"	    ...				"   ..."	    ...				"   ..."	endif				endif"	Xcheck <number>			Xcheck <number>"" Double quotes in column 1 are removed before the script is executed." They should be used if the test has unbalanced conditionals (:if/:endif," :while:/endwhile, :try/:endtry) or for a line with a syntax error.  The" extra script may use Xpath, XloopINIT, Xloop, XloopNEXT, and Xout as usual."" A file name may be specified as argument.  All messages of the extra Vim" process are then redirected to the file.  An existing file is overwritten."let ExtraVimCount = 0let ExtraVimBase = expand("<sfile>")let ExtraVimTestEnv = """function! ExtraVim(...)    " Count how often this function is called.    let g:ExtraVimCount = g:ExtraVimCount + 1     " Disable folds to prevent that the ranges in the ":write" commands below    " are extended up to the end of a closed fold.  This also speeds things up    " considerably.    set nofoldenable     " Open a buffer for this test script and copy the test environment to    " a temporary file.  Take account of parts relevant for the extra script    " execution only.    let current_buffnr = bufnr("%")    execute "view +1" g:ExtraVimBase    if g:ExtraVimCount == 1	let g:ExtraVimTestEnv = tempname()	execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w"		    \ g:ExtraVimTestEnv "|']+"	execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>"		    \ g:ExtraVimTestEnv "|']+"	execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>"		    \ g:ExtraVimTestEnv "|']+"	execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>"		    \ g:ExtraVimTestEnv "|']+"    endif     " Start the extra Vim script with a ":source" command for the test    " environment.  The source line number where the extra script will be    " appended, needs to be passed as variable "ExtraVimBegin" to the script.    let extra_script = tempname()    exec "!echo 'source " . g:ExtraVimTestEnv . "' >" . extra_script    let extra_begin = 1     " Starting behind the test environment, skip over the first g:ExtraVimCount    " occurrences of "if ExtraVim()" and copy the following lines up to the    " matching "endif" to the extra Vim script.    execute "/E" . "ND_OF_TEST_ENVIRONMENT/"    exec 'norm ' . g:ExtraVimCount . '/^\s*if\s\+ExtraVim(.*)/+' . "\n"    execute ".,/^endif/-write >>" . extra_script     " Open a buffer for the extra Vim script, delete all ^", and write the    " script if was actually modified.    execute "edit +" . (extra_begin + 1) extra_script    ,$s/^"//e    update     " Count the INTERRUPTs and build the breakpoint and quit commands.    let breakpoints = ""    let debug_quits = ""    let in_func = 0    exec extra_begin    while search(	    \ '"\s*INTERRUPT\h\@!\|^\s*fu\%[nction]\>!\=\s*\%(\u\|s:\)\w*\s*(\|'	    \ . '^\s*\\\|^\s*endf\%[unction]\>\|'	    \ . '\%(^\s*fu\%[nction]!\=\s*\)\@<!\%(\u\|s:\)\w*\s*(\|'	    \ . 'ExecAsScript\s\+\%(\u\|s:\)\w*',	    \ "W") > 0	let theline = getline(".")	if theline =~ '^\s*fu'	    " Function definition.	    let in_func = 1	    let func_start = line(".")	    let func_name = substitute(theline,		\ '^\s*fu\%[nction]!\=\s*\(\%(\u\|s:\)\w*\).*', '\1', "")	elseif theline =~ '^\s*endf'	    " End of function definition.	    let in_func = 0	else	    let finding = substitute(theline, '.*\(\%' . col(".") . 'c.*\)',		\ '\1', "")	    if finding =~ '^"\s*INTERRUPT\h\@!'		" Interrupt comment.  Compose as many quit commands as		" specified.		let cnt = substitute(finding,		    \ '^"\s*INTERRUPT\s*\(\d*\).*$', '\1', "")		let quits = ""		while cnt > 0		    " Use "\r" rather than "\n" to separate the quit commands.		    " "\r" is not interpreted as command separator by the ":!"		    " command below but works to separate commands in the		    " external vim.		    let quits = quits . "q\r"		    let cnt = cnt - 1		endwhile		if in_func		    " Add the function breakpoint and note the number of quits		    " to be used, if specified, or one for every call else.		    let breakpoints = breakpoints . " -c 'breakadd func " .			\ (line(".") - func_start) . " " .			\ func_name . "'"		    if quits != ""			let debug_quits = debug_quits . quits		    elseif !exists("quits{func_name}")			let quits{func_name} = "q\r"		    else			let quits{func_name} = quits{func_name} . "q\r"		    endif		else		    " Add the file breakpoint and the quits to be used for it.		    let breakpoints = breakpoints . " -c 'breakadd file " .			\ line(".") . " " . extra_script . "'"		    if quits == ""			let quits = "q\r"		    endif		    let debug_quits = debug_quits . quits		endif	    else		" Add the quits to be used for calling the function or executing		" it as script file.		if finding =~ '^ExecAsScript'		    " Sourcing function as script.		    let finding = substitute(finding,			\ '^ExecAsScript\s\+\(\%(\u\|s:\)\w*\).*', '\1', "")		else		    " Function call.		    let finding = substitute(finding,			\ '^\(\%(\u\|s:\)\w*\).*', '\1', "")		endif		if exists("quits{finding}")		    let debug_quits = debug_quits . quits{finding}		endif	    endif	endif    endwhile     " Close the buffer for the script and create an (empty) resultfile.    bwipeout    let resultfile = tempname()    exec "!>" . resultfile     " Run the script in an extra vim.  Switch to extra modus by passing the    " resultfile in ExtraVimResult.  Redirect messages to the file specified as    " argument if any.  Use ":debuggreedy" so that the commands provided on the    " pipe are consumed at the debug prompt.  Use "-N" to enable command-line    " continuation ("C" in 'cpo').  Add "nviminfo" to 'viminfo' to avoid    " messing up the user's viminfo file.    let redirect = a:0 ?	\ " -c 'au VimLeave * redir END' -c 'redir\\! >" . a:1 . "'" : ""    exec "!echo '" . debug_quits . "q' | ../vim -u NONE -N -Xes" . redirect .	\ " -c 'debuggreedy|set viminfo+=nviminfo'" .	\ " -c 'let ExtraVimBegin = " . extra_begin . "'" .	\ " -c 'let ExtraVimResult = \"" . resultfile . "\"'" . breakpoints .	\ " -S " . extra_script     " Build the resulting sum for resultfile and add it to g:Xpath.  Add Xout    " information provided by the extra Vim process to the test output.    let sum = 0    exec "edit" resultfile    let line = 1    while line <= line("$")	let theline = getline(line)	if theline =~ '^@R:'	    exec 'Xout "' . substitute(substitute(		\ escape(escape(theline, '"'), '\"'),		\ '^@R:', '', ""), '@NL@', "\n", "g") . '"'	else	    let sum = sum + getline(line)	endif	let line = line + 1    endwhile    bwipeout    let g:Xpath = g:Xpath + sum     " Delete the extra script and the resultfile.    call delete(extra_script)    call delete(resultfile)     " Switch back to the buffer that was active when this function was entered.    exec "buffer" current_buffnr     " Return 0.  This protects extra scripts from being run in the main Vim    " process.    return 0endfunction  " ExtraVimThrowpoint() - Relative throwpoint in ExtraVim script		    {{{2"" Evaluates v:throwpoint and returns the throwpoint relative to the beginning of" an ExtraVim script as passed by ExtraVim() in ExtraVimBegin.

Lines 1–500 of 9802.