1" Functions shared by several tests. 2 3" Get the name of the Python executable. 4" Also keeps it in s:python. 5func PythonProg() 6 " This test requires the Python command to run the test server. 7 " This most likely only works on Unix and Windows. 8 if has('unix') 9 " We also need the job feature or the pkill command to make sure the server 10 " can be stopped. 11 if !(executable('python') && (has('job') || executable('pkill'))) 12 return '' 13 endif 14 let s:python = 'python' 15 elseif has('win32') 16 " Use Python Launcher for Windows (py.exe) if available. 17 if executable('py.exe') 18 let s:python = 'py.exe' 19 elseif executable('python.exe') 20 let s:python = 'python.exe' 21 else 22 return '' 23 endif 24 else 25 return '' 26 endif 27 return s:python 28endfunc 29 30" Run "cmd". Returns the job if using a job. 31func RunCommand(cmd) 32 let job = 0 33 if has('job') 34 let job = job_start(a:cmd, {"stoponexit": "hup"}) 35 call job_setoptions(job, {"stoponexit": "kill"}) 36 elseif has('win32') 37 exe 'silent !start cmd /c start "test_channel" ' . a:cmd 38 else 39 exe 'silent !' . a:cmd . '&' 40 endif 41 return job 42endfunc 43 44" Read the port number from the Xportnr file. 45func GetPort() 46 let l = [] 47 for i in range(200) 48 try 49 let l = readfile("Xportnr") 50 catch 51 endtry 52 if len(l) >= 1 53 break 54 endif 55 sleep 10m 56 endfor 57 call delete("Xportnr") 58 59 if len(l) == 0 60 " Can't make the connection, give up. 61 return 0 62 endif 63 return l[0] 64endfunc 65 66" Run a Python server for "cmd" and call "testfunc". 67" Always kills the server before returning. 68func RunServer(cmd, testfunc, args) 69 " The Python program writes the port number in Xportnr. 70 call delete("Xportnr") 71 72 if len(a:args) == 1 73 let arg = ' ' . a:args[0] 74 else 75 let arg = '' 76 endif 77 let pycmd = s:python . " " . a:cmd . arg 78 79 try 80 let g:currentJob = RunCommand(pycmd) 81 82 " Wait for up to 2 seconds for the port number to be there. 83 let port = GetPort() 84 if port == 0 85 call assert_false(1, "Can't start " . a:cmd) 86 return 87 endif 88 89 call call(function(a:testfunc), [port]) 90 catch 91 call assert_false(1, 'Caught exception: "' . v:exception . '" in ' . v:throwpoint) 92 finally 93 call s:kill_server(a:cmd) 94 endtry 95endfunc 96 97func s:kill_server(cmd) 98 if has('job') 99 if exists('g:currentJob') 100 call job_stop(g:currentJob) 101 unlet g:currentJob 102 endif 103 elseif has('win32') 104 let cmd = substitute(a:cmd, ".py", '', '') 105 call system('taskkill /IM ' . s:python . ' /T /F /FI "WINDOWTITLE eq ' . cmd . '"') 106 else 107 call system("pkill -f " . a:cmd) 108 endif 109endfunc 110 111" Wait for up to a second for "expr" to become true. 112" Return time slept in milliseconds. With the +reltime feature this can be 113" more than the actual waiting time. Without +reltime it can also be less. 114func WaitFor(expr) 115 " using reltime() is more accurate, but not always available 116 if has('reltime') 117 let start = reltime() 118 else 119 let slept = 0 120 endif 121 for i in range(100) 122 try 123 if eval(a:expr) 124 if has('reltime') 125 return float2nr(reltimefloat(reltime(start)) * 1000) 126 endif 127 return slept 128 endif 129 catch 130 endtry 131 if !has('reltime') 132 let slept += 10 133 endif 134 sleep 10m 135 endfor 136 return 1000 137endfunc 138 139" Wait for up to a given milliseconds. 140" With the +timers feature this waits for key-input by getchar(), Resume() 141" feeds key-input and resumes process. Return time waited in milliseconds. 142" Without +timers it uses simply :sleep. 143func Standby(msec) 144 if has('timers') 145 let start = reltime() 146 let g:_standby_timer = timer_start(a:msec, function('s:feedkeys')) 147 call getchar() 148 return float2nr(reltimefloat(reltime(start)) * 1000) 149 else 150 execute 'sleep ' a:msec . 'm' 151 return a:msec 152 endif 153endfunc 154 155func Resume() 156 if exists('g:_standby_timer') 157 call timer_stop(g:_standby_timer) 158 call s:feedkeys(0) 159 unlet g:_standby_timer 160 endif 161endfunc 162 163func s:feedkeys(timer) 164 call feedkeys('x', 'nt') 165endfunc 166 167" Run Vim, using the "vimcmd" file and "-u NORC". 168" "before" is a list of Vim commands to be executed before loading plugins. 169" "after" is a list of Vim commands to be executed after loading plugins. 170" Plugins are not loaded, unless 'loadplugins' is set in "before". 171" Return 1 if Vim could be executed. 172func RunVim(before, after, arguments) 173 return RunVimPiped(a:before, a:after, a:arguments, '') 174endfunc 175 176func RunVimPiped(before, after, arguments, pipecmd) 177 if !filereadable('vimcmd') 178 return 0 179 endif 180 let args = '' 181 if len(a:before) > 0 182 call writefile(a:before, 'Xbefore.vim') 183 let args .= ' --cmd "so Xbefore.vim"' 184 endif 185 if len(a:after) > 0 186 call writefile(a:after, 'Xafter.vim') 187 let args .= ' -S Xafter.vim' 188 endif 189 190 let cmd = readfile('vimcmd')[0] 191 let cmd = substitute(cmd, '-u \f\+', '-u NONE', '') 192 if cmd !~ '-u NONE' 193 let cmd = cmd . ' -u NONE' 194 endif 195 196 " With pipecmd we can't set VIMRUNTIME. 197 if a:pipecmd != '' 198 let cmd = substitute(cmd, 'VIMRUNTIME=.*VIMRUNTIME;', '', '') 199 endif 200 201 exe "silent !" . a:pipecmd . cmd . args . ' ' . a:arguments 202 203 if len(a:before) > 0 204 call delete('Xbefore.vim') 205 endif 206 if len(a:after) > 0 207 call delete('Xafter.vim') 208 endif 209 return 1 210endfunc 211