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