xref: /vim-8.2.3635/src/testdir/shared.vim (revision 1bb0da25)
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