xref: /vim-8.2.3635/src/testdir/shared.vim (revision 6199d43f)
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 $VIMPROG to run Vim executable.
174" The Makefile writes it as the first line in the "vimcmd" file.
175func GetVimProg()
176  if !filereadable('vimcmd')
177    return ''
178  endif
179  return readfile('vimcmd')[0]
180endfunc
181
182" Get the command to run Vim, with -u NONE and --not-a-term arguments.
183" If there is an argument use it instead of "NONE".
184" Returns an empty string on error.
185func GetVimCommand(...)
186  if !filereadable('vimcmd')
187    return ''
188  endif
189  if a:0 == 0
190    let name = 'NONE'
191  else
192    let name = a:1
193  endif
194  " For Unix Makefile writes the command to use in the second line of the
195  " "vimcmd" file, including environment options.
196  " Other Makefiles just write the executable in the first line, so fall back
197  " to that if there is no second line.
198  let lines = readfile('vimcmd')
199  let cmd = get(lines, 1, lines[0])
200  let cmd = substitute(cmd, '-u \f\+', '-u ' . name, '')
201  if cmd !~ '-u '. name
202    let cmd = cmd . ' -u ' . name
203  endif
204  let cmd .= ' --not-a-term'
205  let cmd = substitute(cmd, 'VIMRUNTIME=.*VIMRUNTIME;', '', '')
206  return cmd
207endfunc
208
209" Run Vim, using the "vimcmd" file and "-u NORC".
210" "before" is a list of Vim commands to be executed before loading plugins.
211" "after" is a list of Vim commands to be executed after loading plugins.
212" Plugins are not loaded, unless 'loadplugins' is set in "before".
213" Return 1 if Vim could be executed.
214func RunVim(before, after, arguments)
215  return RunVimPiped(a:before, a:after, a:arguments, '')
216endfunc
217
218func RunVimPiped(before, after, arguments, pipecmd)
219  let cmd = GetVimCommand()
220  if cmd == ''
221    return 0
222  endif
223  let args = ''
224  if len(a:before) > 0
225    call writefile(a:before, 'Xbefore.vim')
226    let args .= ' --cmd "so Xbefore.vim"'
227  endif
228  if len(a:after) > 0
229    call writefile(a:after, 'Xafter.vim')
230    let args .= ' -S Xafter.vim'
231  endif
232
233  exe "silent !" . a:pipecmd . cmd . args . ' ' . a:arguments
234
235  if len(a:before) > 0
236    call delete('Xbefore.vim')
237  endif
238  if len(a:after) > 0
239    call delete('Xafter.vim')
240  endif
241  return 1
242endfunc
243
244func CanRunGui()
245  return has('gui') && ($DISPLAY != "" || has('gui_running'))
246endfunc
247