1321efdd7SBram Moolenaar" Functions shared by several tests. 2321efdd7SBram Moolenaar 3a5e6621aSBram Moolenaar" Only load this script once. 47a39dd7fSBram Moolenaarif exists('*PythonProg') 5a5e6621aSBram Moolenaar finish 6a5e6621aSBram Moolenaarendif 7a5e6621aSBram Moolenaar 87a39dd7fSBram Moolenaarsource view_util.vim 97a39dd7fSBram Moolenaar 10321efdd7SBram Moolenaar" Get the name of the Python executable. 11321efdd7SBram Moolenaar" Also keeps it in s:python. 12321efdd7SBram Moolenaarfunc PythonProg() 13321efdd7SBram Moolenaar " This test requires the Python command to run the test server. 14321efdd7SBram Moolenaar " This most likely only works on Unix and Windows. 15321efdd7SBram Moolenaar if has('unix') 16321efdd7SBram Moolenaar " We also need the job feature or the pkill command to make sure the server 17321efdd7SBram Moolenaar " can be stopped. 18321efdd7SBram Moolenaar if !(executable('python') && (has('job') || executable('pkill'))) 19321efdd7SBram Moolenaar return '' 20321efdd7SBram Moolenaar endif 21321efdd7SBram Moolenaar let s:python = 'python' 22321efdd7SBram Moolenaar elseif has('win32') 23321efdd7SBram Moolenaar " Use Python Launcher for Windows (py.exe) if available. 24*1bb0da25SBram Moolenaar " NOTE: if you get a "Python was not found" error, disable the Python 25*1bb0da25SBram Moolenaar " shortcuts in "Windows menu / Settings / Manage App Execution Aliases". 26321efdd7SBram Moolenaar if executable('py.exe') 27321efdd7SBram Moolenaar let s:python = 'py.exe' 28321efdd7SBram Moolenaar elseif executable('python.exe') 29321efdd7SBram Moolenaar let s:python = 'python.exe' 30321efdd7SBram Moolenaar else 31321efdd7SBram Moolenaar return '' 32321efdd7SBram Moolenaar endif 33321efdd7SBram Moolenaar else 34321efdd7SBram Moolenaar return '' 35321efdd7SBram Moolenaar endif 36321efdd7SBram Moolenaar return s:python 37321efdd7SBram Moolenaarendfunc 38321efdd7SBram Moolenaar 39321efdd7SBram Moolenaar" Run "cmd". Returns the job if using a job. 40321efdd7SBram Moolenaarfunc RunCommand(cmd) 414a070cc8SBram Moolenaar " Running an external command can occasionally be slow or fail. 424a070cc8SBram Moolenaar let g:test_is_flaky = 1 434a070cc8SBram Moolenaar 44321efdd7SBram Moolenaar let job = 0 45321efdd7SBram Moolenaar if has('job') 46321efdd7SBram Moolenaar let job = job_start(a:cmd, {"stoponexit": "hup"}) 47321efdd7SBram Moolenaar call job_setoptions(job, {"stoponexit": "kill"}) 48321efdd7SBram Moolenaar elseif has('win32') 49321efdd7SBram Moolenaar exe 'silent !start cmd /c start "test_channel" ' . a:cmd 50321efdd7SBram Moolenaar else 51321efdd7SBram Moolenaar exe 'silent !' . a:cmd . '&' 52321efdd7SBram Moolenaar endif 53321efdd7SBram Moolenaar return job 54321efdd7SBram Moolenaarendfunc 55321efdd7SBram Moolenaar 56321efdd7SBram Moolenaar" Read the port number from the Xportnr file. 57321efdd7SBram Moolenaarfunc GetPort() 58321efdd7SBram Moolenaar let l = [] 59453ce7c1SBram Moolenaar " with 200 it sometimes failed 60453ce7c1SBram Moolenaar for i in range(400) 61321efdd7SBram Moolenaar try 62321efdd7SBram Moolenaar let l = readfile("Xportnr") 63321efdd7SBram Moolenaar catch 64321efdd7SBram Moolenaar endtry 65321efdd7SBram Moolenaar if len(l) >= 1 66321efdd7SBram Moolenaar break 67321efdd7SBram Moolenaar endif 68321efdd7SBram Moolenaar sleep 10m 69321efdd7SBram Moolenaar endfor 70321efdd7SBram Moolenaar call delete("Xportnr") 71321efdd7SBram Moolenaar 72321efdd7SBram Moolenaar if len(l) == 0 73321efdd7SBram Moolenaar " Can't make the connection, give up. 74321efdd7SBram Moolenaar return 0 75321efdd7SBram Moolenaar endif 76321efdd7SBram Moolenaar return l[0] 77321efdd7SBram Moolenaarendfunc 78321efdd7SBram Moolenaar 79321efdd7SBram Moolenaar" Run a Python server for "cmd" and call "testfunc". 80321efdd7SBram Moolenaar" Always kills the server before returning. 81321efdd7SBram Moolenaarfunc RunServer(cmd, testfunc, args) 82321efdd7SBram Moolenaar " The Python program writes the port number in Xportnr. 83321efdd7SBram Moolenaar call delete("Xportnr") 84321efdd7SBram Moolenaar 85321efdd7SBram Moolenaar if len(a:args) == 1 86321efdd7SBram Moolenaar let arg = ' ' . a:args[0] 87321efdd7SBram Moolenaar else 88321efdd7SBram Moolenaar let arg = '' 89321efdd7SBram Moolenaar endif 90321efdd7SBram Moolenaar let pycmd = s:python . " " . a:cmd . arg 91321efdd7SBram Moolenaar 92321efdd7SBram Moolenaar try 93321efdd7SBram Moolenaar let g:currentJob = RunCommand(pycmd) 94321efdd7SBram Moolenaar 95321efdd7SBram Moolenaar " Wait for up to 2 seconds for the port number to be there. 96321efdd7SBram Moolenaar let port = GetPort() 97321efdd7SBram Moolenaar if port == 0 98321efdd7SBram Moolenaar call assert_false(1, "Can't start " . a:cmd) 99321efdd7SBram Moolenaar return 100321efdd7SBram Moolenaar endif 101321efdd7SBram Moolenaar 102321efdd7SBram Moolenaar call call(function(a:testfunc), [port]) 103321efdd7SBram Moolenaar catch 1044b785f69SBram Moolenaar call assert_false(1, 'Caught exception: "' . v:exception . '" in ' . v:throwpoint) 105321efdd7SBram Moolenaar finally 106321efdd7SBram Moolenaar call s:kill_server(a:cmd) 107321efdd7SBram Moolenaar endtry 108321efdd7SBram Moolenaarendfunc 109321efdd7SBram Moolenaar 110321efdd7SBram Moolenaarfunc s:kill_server(cmd) 111321efdd7SBram Moolenaar if has('job') 112321efdd7SBram Moolenaar if exists('g:currentJob') 113321efdd7SBram Moolenaar call job_stop(g:currentJob) 114321efdd7SBram Moolenaar unlet g:currentJob 115321efdd7SBram Moolenaar endif 116321efdd7SBram Moolenaar elseif has('win32') 117321efdd7SBram Moolenaar let cmd = substitute(a:cmd, ".py", '', '') 118321efdd7SBram Moolenaar call system('taskkill /IM ' . s:python . ' /T /F /FI "WINDOWTITLE eq ' . cmd . '"') 119321efdd7SBram Moolenaar else 120321efdd7SBram Moolenaar call system("pkill -f " . a:cmd) 121321efdd7SBram Moolenaar endif 122321efdd7SBram Moolenaarendfunc 123321efdd7SBram Moolenaar 124769e9d21SBram Moolenaar" Wait for up to five seconds for "expr" to become true. "expr" can be a 12513deab8dSBram Moolenaar" stringified expression to evaluate, or a funcref without arguments. 12650182fa8SBram Moolenaar" Using a lambda works best. Example: 12750182fa8SBram Moolenaar" call WaitFor({-> status == "ok"}) 12850182fa8SBram Moolenaar" 1295d7ead3bSBram Moolenaar" A second argument can be used to specify a different timeout in msec. 13013deab8dSBram Moolenaar" 13150182fa8SBram Moolenaar" When successful the time slept is returned. 13250182fa8SBram Moolenaar" When running into the timeout an exception is thrown, thus the function does 13350182fa8SBram Moolenaar" not return. 134cdb7e1b7SBram Moolenaarfunc WaitFor(expr, ...) 135769e9d21SBram Moolenaar let timeout = get(a:000, 0, 5000) 13650182fa8SBram Moolenaar let slept = s:WaitForCommon(a:expr, v:null, timeout) 13750182fa8SBram Moolenaar if slept < 0 13850182fa8SBram Moolenaar throw 'WaitFor() timed out after ' . timeout . ' msec' 139f267f8bdSBram Moolenaar endif 140b73598e2SBram Moolenaar return slept 14150182fa8SBram Moolenaarendfunc 14250182fa8SBram Moolenaar 14350182fa8SBram Moolenaar" Wait for up to five seconds for "assert" to return zero. "assert" must be a 14450182fa8SBram Moolenaar" (lambda) function containing one assert function. Example: 14550182fa8SBram Moolenaar" call WaitForAssert({-> assert_equal("dead", job_status(job)}) 14650182fa8SBram Moolenaar" 14750182fa8SBram Moolenaar" A second argument can be used to specify a different timeout in msec. 14850182fa8SBram Moolenaar" 14950182fa8SBram Moolenaar" Return zero for success, one for failure (like the assert function). 15050182fa8SBram Moolenaarfunc WaitForAssert(assert, ...) 15150182fa8SBram Moolenaar let timeout = get(a:000, 0, 5000) 15250182fa8SBram Moolenaar if s:WaitForCommon(v:null, a:assert, timeout) < 0 15350182fa8SBram Moolenaar return 1 154321efdd7SBram Moolenaar endif 15550182fa8SBram Moolenaar return 0 15650182fa8SBram Moolenaarendfunc 15750182fa8SBram Moolenaar 15850182fa8SBram Moolenaar" Common implementation of WaitFor() and WaitForAssert(). 15950182fa8SBram Moolenaar" Either "expr" or "assert" is not v:null 16050182fa8SBram Moolenaar" Return the waiting time for success, -1 for failure. 16150182fa8SBram Moolenaarfunc s:WaitForCommon(expr, assert, timeout) 16250182fa8SBram Moolenaar " using reltime() is more accurate, but not always available 16350182fa8SBram Moolenaar let slept = 0 1645feabe00SBram Moolenaar if exists('*reltimefloat') 16550182fa8SBram Moolenaar let start = reltime() 16650182fa8SBram Moolenaar endif 16750182fa8SBram Moolenaar 16850182fa8SBram Moolenaar while 1 16950182fa8SBram Moolenaar if type(a:expr) == v:t_func 17050182fa8SBram Moolenaar let success = a:expr() 17150182fa8SBram Moolenaar elseif type(a:assert) == v:t_func 17250182fa8SBram Moolenaar let success = a:assert() == 0 17350182fa8SBram Moolenaar else 17450182fa8SBram Moolenaar let success = eval(a:expr) 17550182fa8SBram Moolenaar endif 17650182fa8SBram Moolenaar if success 17750182fa8SBram Moolenaar return slept 17850182fa8SBram Moolenaar endif 17950182fa8SBram Moolenaar 18050182fa8SBram Moolenaar if slept >= a:timeout 18150182fa8SBram Moolenaar break 18250182fa8SBram Moolenaar endif 18350182fa8SBram Moolenaar if type(a:assert) == v:t_func 18450182fa8SBram Moolenaar " Remove the error added by the assert function. 18550182fa8SBram Moolenaar call remove(v:errors, -1) 18650182fa8SBram Moolenaar endif 18750182fa8SBram Moolenaar 18850182fa8SBram Moolenaar sleep 10m 1895feabe00SBram Moolenaar if exists('*reltimefloat') 19050182fa8SBram Moolenaar let slept = float2nr(reltimefloat(reltime(start)) * 1000) 19150182fa8SBram Moolenaar else 192b73598e2SBram Moolenaar let slept += 10 193f267f8bdSBram Moolenaar endif 19450182fa8SBram Moolenaar endwhile 19550182fa8SBram Moolenaar 19650182fa8SBram Moolenaar return -1 " timed out 197321efdd7SBram Moolenaarendfunc 19866459b7cSBram Moolenaar 19950182fa8SBram Moolenaar 20001688ad5SBram Moolenaar" Wait for up to a given milliseconds. 20101688ad5SBram Moolenaar" With the +timers feature this waits for key-input by getchar(), Resume() 20201688ad5SBram Moolenaar" feeds key-input and resumes process. Return time waited in milliseconds. 20301688ad5SBram Moolenaar" Without +timers it uses simply :sleep. 20401688ad5SBram Moolenaarfunc Standby(msec) 2055feabe00SBram Moolenaar if has('timers') && exists('*reltimefloat') 20601688ad5SBram Moolenaar let start = reltime() 20701688ad5SBram Moolenaar let g:_standby_timer = timer_start(a:msec, function('s:feedkeys')) 20801688ad5SBram Moolenaar call getchar() 20901688ad5SBram Moolenaar return float2nr(reltimefloat(reltime(start)) * 1000) 21001688ad5SBram Moolenaar else 21101688ad5SBram Moolenaar execute 'sleep ' a:msec . 'm' 21201688ad5SBram Moolenaar return a:msec 21301688ad5SBram Moolenaar endif 21401688ad5SBram Moolenaarendfunc 21501688ad5SBram Moolenaar 21601688ad5SBram Moolenaarfunc Resume() 21701688ad5SBram Moolenaar if exists('g:_standby_timer') 21801688ad5SBram Moolenaar call timer_stop(g:_standby_timer) 21901688ad5SBram Moolenaar call s:feedkeys(0) 22001688ad5SBram Moolenaar unlet g:_standby_timer 22101688ad5SBram Moolenaar endif 22201688ad5SBram Moolenaarendfunc 22301688ad5SBram Moolenaar 22401688ad5SBram Moolenaarfunc s:feedkeys(timer) 22501688ad5SBram Moolenaar call feedkeys('x', 'nt') 22601688ad5SBram Moolenaarendfunc 22701688ad5SBram Moolenaar 22822286895SBram Moolenaar" Get $VIMPROG to run the Vim executable. 22963182053SBram Moolenaar" The Makefile writes it as the first line in the "vimcmd" file. 23063182053SBram Moolenaarfunc GetVimProg() 23163182053SBram Moolenaar if !filereadable('vimcmd') 232da65058aSBram Moolenaar " Assume the script was sourced instead of running "make". 233da65058aSBram Moolenaar return '../vim' 23463182053SBram Moolenaar endif 23563182053SBram Moolenaar return readfile('vimcmd')[0] 23663182053SBram Moolenaarendfunc 23763182053SBram Moolenaar 238248be5c5SBram Moolenaarlet g:valgrind_cnt = 1 239248be5c5SBram Moolenaar 24015bf76d4SBram Moolenaar" Get the command to run Vim, with -u NONE and --not-a-term arguments. 2419d954207SBram Moolenaar" If there is an argument use it instead of "NONE". 2429d954207SBram Moolenaarfunc GetVimCommand(...) 24315bf76d4SBram Moolenaar if !filereadable('vimcmd') 244da65058aSBram Moolenaar echo 'Cannot read the "vimcmd" file, falling back to ../vim.' 245da65058aSBram Moolenaar let lines = ['../vim'] 246da65058aSBram Moolenaar else 247da65058aSBram Moolenaar let lines = readfile('vimcmd') 24815bf76d4SBram Moolenaar endif 2499d954207SBram Moolenaar if a:0 == 0 2509d954207SBram Moolenaar let name = 'NONE' 2519d954207SBram Moolenaar else 2529d954207SBram Moolenaar let name = a:1 2539d954207SBram Moolenaar endif 25463182053SBram Moolenaar " For Unix Makefile writes the command to use in the second line of the 25563182053SBram Moolenaar " "vimcmd" file, including environment options. 25663182053SBram Moolenaar " Other Makefiles just write the executable in the first line, so fall back 257248be5c5SBram Moolenaar " to that if there is no second line or it is empty. 258248be5c5SBram Moolenaar if len(lines) > 1 && lines[1] != '' 259248be5c5SBram Moolenaar let cmd = lines[1] 260248be5c5SBram Moolenaar else 261248be5c5SBram Moolenaar let cmd = lines[0] 262248be5c5SBram Moolenaar endif 263248be5c5SBram Moolenaar 2649d954207SBram Moolenaar let cmd = substitute(cmd, '-u \f\+', '-u ' . name, '') 2659d954207SBram Moolenaar if cmd !~ '-u '. name 2669d954207SBram Moolenaar let cmd = cmd . ' -u ' . name 26715bf76d4SBram Moolenaar endif 26815bf76d4SBram Moolenaar let cmd .= ' --not-a-term' 26941a82604SBram Moolenaar let cmd = substitute(cmd, 'VIMRUNTIME=\S\+', '', '') 270248be5c5SBram Moolenaar 271248be5c5SBram Moolenaar " If using valgrind, make sure every run uses a different log file. 272248be5c5SBram Moolenaar if cmd =~ 'valgrind.*--log-file=' 273657a826cSBram Moolenaar let cmd = substitute(cmd, '--log-file=\(\S*\)', '--log-file=\1.' . g:valgrind_cnt, '') 274248be5c5SBram Moolenaar let g:valgrind_cnt += 1 275248be5c5SBram Moolenaar endif 276248be5c5SBram Moolenaar 27715bf76d4SBram Moolenaar return cmd 27815bf76d4SBram Moolenaarendfunc 27915bf76d4SBram Moolenaar 280f1699968SBram Moolenaar" Get the command to run Vim, with --clean instead of "-u NONE". 281da65058aSBram Moolenaarfunc GetVimCommandClean() 282da65058aSBram Moolenaar let cmd = GetVimCommand() 283da65058aSBram Moolenaar let cmd = substitute(cmd, '-u NONE', '--clean', '') 284da65058aSBram Moolenaar let cmd = substitute(cmd, '--not-a-term', '', '') 285453ce7c1SBram Moolenaar 2860fdddeebSBram Moolenaar " Force using utf-8, Vim may pick up something else from the environment. 2870fdddeebSBram Moolenaar let cmd ..= ' --cmd "set enc=utf8" ' 2880fdddeebSBram Moolenaar 289453ce7c1SBram Moolenaar " Optionally run Vim under valgrind 290453ce7c1SBram Moolenaar " let cmd = 'valgrind --tool=memcheck --leak-check=yes --num-callers=25 --log-file=valgrind ' . cmd 291453ce7c1SBram Moolenaar 292da65058aSBram Moolenaar return cmd 293da65058aSBram Moolenaarendfunc 294da65058aSBram Moolenaar 2950d702028SBram Moolenaar" Get the command to run Vim, with --clean, and force to run in terminal so it 2960d702028SBram Moolenaar" won't start a new GUI. 2970d702028SBram Moolenaarfunc GetVimCommandCleanTerm() 2980d702028SBram Moolenaar " Add -v to have gvim run in the terminal (if possible) 2990d702028SBram Moolenaar return GetVimCommandClean() .. ' -v ' 3000d702028SBram Moolenaarendfunc 3010d702028SBram Moolenaar 30266459b7cSBram Moolenaar" Run Vim, using the "vimcmd" file and "-u NORC". 3033a938383SBram Moolenaar" "before" is a list of Vim commands to be executed before loading plugins. 3043a938383SBram Moolenaar" "after" is a list of Vim commands to be executed after loading plugins. 30566459b7cSBram Moolenaar" Plugins are not loaded, unless 'loadplugins' is set in "before". 30666459b7cSBram Moolenaar" Return 1 if Vim could be executed. 307472a0a88SBram Moolenaarfunc RunVim(before, after, arguments) 3087a9a5f40SBram Moolenaar return RunVimPiped(a:before, a:after, a:arguments, '') 3093a938383SBram Moolenaarendfunc 3103a938383SBram Moolenaar 3113a938383SBram Moolenaarfunc RunVimPiped(before, after, arguments, pipecmd) 31215bf76d4SBram Moolenaar let cmd = GetVimCommand() 313ba98bef1SBram Moolenaar let args = '' 314472a0a88SBram Moolenaar if len(a:before) > 0 31566459b7cSBram Moolenaar call writefile(a:before, 'Xbefore.vim') 316472a0a88SBram Moolenaar let args .= ' --cmd "so Xbefore.vim"' 317472a0a88SBram Moolenaar endif 318472a0a88SBram Moolenaar if len(a:after) > 0 31966459b7cSBram Moolenaar call writefile(a:after, 'Xafter.vim') 320472a0a88SBram Moolenaar let args .= ' -S Xafter.vim' 321472a0a88SBram Moolenaar endif 32266459b7cSBram Moolenaar 323f48ee3c2SBram Moolenaar " Optionally run Vim under valgrind 324f48ee3c2SBram Moolenaar " let cmd = 'valgrind --tool=memcheck --leak-check=yes --num-callers=25 --log-file=valgrind ' . cmd 325f48ee3c2SBram Moolenaar 3263a938383SBram Moolenaar exe "silent !" . a:pipecmd . cmd . args . ' ' . a:arguments 32766459b7cSBram Moolenaar 328472a0a88SBram Moolenaar if len(a:before) > 0 32966459b7cSBram Moolenaar call delete('Xbefore.vim') 330472a0a88SBram Moolenaar endif 331472a0a88SBram Moolenaar if len(a:after) > 0 33266459b7cSBram Moolenaar call delete('Xafter.vim') 333472a0a88SBram Moolenaar endif 33466459b7cSBram Moolenaar return 1 33566459b7cSBram Moolenaarendfunc 33607282f01SBram Moolenaar 33707282f01SBram Moolenaarfunc IsRoot() 33807282f01SBram Moolenaar if !has('unix') 33907282f01SBram Moolenaar return v:false 34007282f01SBram Moolenaar elseif $USER == 'root' || system('id -un') =~ '\<root\>' 34107282f01SBram Moolenaar return v:true 34207282f01SBram Moolenaar endif 34307282f01SBram Moolenaar return v:false 34407282f01SBram Moolenaarendfunc 345cde0ff39SBram Moolenaar 34688e6cc25SBram Moolenaar" Get all messages but drop the maintainer entry. 34788e6cc25SBram Moolenaarfunc GetMessages() 34888e6cc25SBram Moolenaar redir => result 34988e6cc25SBram Moolenaar redraw | messages 35088e6cc25SBram Moolenaar redir END 35188e6cc25SBram Moolenaar let msg_list = split(result, "\n") 35288e6cc25SBram Moolenaar if msg_list->len() > 0 && msg_list[0] =~ 'Messages maintainer:' 35388e6cc25SBram Moolenaar return msg_list[1:] 35488e6cc25SBram Moolenaar endif 35588e6cc25SBram Moolenaar return msg_list 35688e6cc25SBram Moolenaarendfunc 35788e6cc25SBram Moolenaar 358ab589463SBram Moolenaar" Run the list of commands in 'cmds' and look for 'errstr' in exception. 359ab589463SBram Moolenaar" Note that assert_fails() cannot be used in some places and this function 360ab589463SBram Moolenaar" can be used. 361ab589463SBram Moolenaarfunc AssertException(cmds, errstr) 362ab589463SBram Moolenaar let save_exception = '' 363ab589463SBram Moolenaar try 364ab589463SBram Moolenaar for cmd in a:cmds 365ab589463SBram Moolenaar exe cmd 366ab589463SBram Moolenaar endfor 367ab589463SBram Moolenaar catch 368ab589463SBram Moolenaar let save_exception = v:exception 369ab589463SBram Moolenaar endtry 370ab589463SBram Moolenaar call assert_match(a:errstr, save_exception) 371ab589463SBram Moolenaarendfunc 372ab589463SBram Moolenaar 373cde0ff39SBram Moolenaar" vim: shiftwidth=2 sts=2 expandtab 374