xref: /vim-8.2.3635/src/testdir/runtest.vim (revision 622b3568)
143345546SBram Moolenaar" This script is sourced while editing the .vim file with the tests.
243345546SBram Moolenaar" When the script is successful the .res file will be created.
343345546SBram Moolenaar" Errors are appended to the test.log file.
443345546SBram Moolenaar"
5befb366aSBram Moolenaar" To execute only specific test functions, add a second argument.  It will be
6e219f73eSBram Moolenaar" matched against the names of the Test_ function.  E.g.:
7befb366aSBram Moolenaar"	../vim -u NONE -S runtest.vim test_channel.vim open_delay
8befb366aSBram Moolenaar" The output can be found in the "messages" file.
9befb366aSBram Moolenaar"
10ce436de5SBram Moolenaar" If the environment variable $TEST_FILTER is set then only test functions
11ce436de5SBram Moolenaar" matching this pattern are executed.  E.g. for sh/bash:
12ce436de5SBram Moolenaar"     export TEST_FILTER=Test_channel
13ce436de5SBram Moolenaar" For csh:
14ce436de5SBram Moolenaar"     setenv TEST_FILTER Test_channel
15ce436de5SBram Moolenaar"
166ca6ca48SBram Moolenaar" While working on a test you can make $TEST_NO_RETRY non-empty to not retry:
176ca6ca48SBram Moolenaar"     export TEST_NO_RETRY=yes
186ca6ca48SBram Moolenaar"
19ce436de5SBram Moolenaar" To ignore failure for tests that are known to fail in a certain environment,
20ce436de5SBram Moolenaar" set $TEST_MAY_FAIL to a comma separated list of function names.  E.g. for
21ce436de5SBram Moolenaar" sh/bash:
22ce436de5SBram Moolenaar"     export TEST_MAY_FAIL=Test_channel_one,Test_channel_other
23ce436de5SBram Moolenaar" The failure report will then not be included in the test.log file and
24ce436de5SBram Moolenaar" "make test" will not fail.
25ce436de5SBram Moolenaar"
2643345546SBram Moolenaar" The test script may contain anything, only functions that start with
2743345546SBram Moolenaar" "Test_" are special.  These will be invoked and should contain assert
2843345546SBram Moolenaar" functions.  See test_assert.vim for an example.
2943345546SBram Moolenaar"
3043345546SBram Moolenaar" It is possible to source other files that contain "Test_" functions.  This
3143345546SBram Moolenaar" can speed up testing, since Vim does not need to restart.  But be careful
3243345546SBram Moolenaar" that the tests do not interfere with each other.
3343345546SBram Moolenaar"
3443345546SBram Moolenaar" If an error cannot be detected properly with an assert function add the
3543345546SBram Moolenaar" error to the v:errors list:
3643345546SBram Moolenaar"   call add(v:errors, 'test foo failed: Cannot find xyz')
3743345546SBram Moolenaar"
3843345546SBram Moolenaar" If preparation for each Test_ function is needed, define a SetUp function.
3943345546SBram Moolenaar" It will be called before each Test_ function.
4043345546SBram Moolenaar"
4143345546SBram Moolenaar" If cleanup after each Test_ function is needed, define a TearDown function.
4243345546SBram Moolenaar" It will be called after each Test_ function.
4300af60bbSBram Moolenaar"
4400af60bbSBram Moolenaar" When debugging a test it can be useful to add messages to v:errors:
4500af60bbSBram Moolenaar"	call add(v:errors, "this happened")
4600af60bbSBram Moolenaar
4743345546SBram Moolenaar
4843345546SBram Moolenaar" Without the +eval feature we can't run these tests, bail out.
494686b323SBram Moolenaarso small.vim
5043345546SBram Moolenaar
5118aa13d1SBram Moolenaar" In the GUI we can always change the screen size.
5218aa13d1SBram Moolenaarif has('gui_running')
5318aa13d1SBram Moolenaar  set columns=80 lines=25
5418aa13d1SBram Moolenaarendif
5518aa13d1SBram Moolenaar
5643345546SBram Moolenaar" Check that the screen size is at least 24 x 80 characters.
5743345546SBram Moolenaarif &lines < 24 || &columns < 80
580b5dc644SBram Moolenaar  let error = 'Screen size too small! Tests require at least 24 lines with 80 characters, got ' .. &lines .. ' lines with ' .. &columns .. ' characters'
5943345546SBram Moolenaar  echoerr error
6043345546SBram Moolenaar  split test.log
6143345546SBram Moolenaar  $put =error
6245aa07d3SBram Moolenaar  write
6345aa07d3SBram Moolenaar  split messages
640b5dc644SBram Moolenaar  call append(line('$'), '')
650b5dc644SBram Moolenaar  call append(line('$'), 'From ' . expand('%') . ':')
6645aa07d3SBram Moolenaar  call append(line('$'), error)
6745aa07d3SBram Moolenaar  write
6845aa07d3SBram Moolenaar  qa!
6943345546SBram Moolenaarendif
7043345546SBram Moolenaar
7175ee544fSBram Moolenaarif has('reltime')
7275ee544fSBram Moolenaar  let s:start_time = reltime()
7375ee544fSBram Moolenaarendif
7475ee544fSBram Moolenaar
7589b10421SBram Moolenaar" Common with all tests on all systems.
7689b10421SBram Moolenaarsource setup.vim
7789b10421SBram Moolenaar
78c0662466SBram Moolenaar" For consistency run all tests with 'nocompatible' set.
79c0662466SBram Moolenaar" This also enables use of line continuation.
80c0662466SBram Moolenaarset nocp viminfo+=nviminfo
81c0662466SBram Moolenaar
8230276f2bSBram Moolenaar" Use utf-8 by default, instead of whatever the system default happens to be.
83ed79d1e3SBram Moolenaar" Individual tests can overrule this at the top of the file and use
84ed79d1e3SBram Moolenaar" g:orig_encoding if needed.
85ed79d1e3SBram Moolenaarlet g:orig_encoding = &encoding
86ac105ed3SBram Moolenaarset encoding=utf-8
87ac105ed3SBram Moolenaar
88d8f27b30SBram Moolenaar" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for
89d8f27b30SBram Moolenaar" the test_name.vim file itself. Replace it here with a more restrictive one,
90d8f27b30SBram Moolenaar" so we still catch mistakes.
91d8f27b30SBram Moolenaarlet s:test_script_fname = expand('%')
92d8f27b30SBram Moolenaarau! SwapExists * call HandleSwapExists()
93d8f27b30SBram Moolenaarfunc HandleSwapExists()
94b073da89SBram Moolenaar  " Ignore finding a swap file for the test script (the user might be
95d8f27b30SBram Moolenaar  " editing it and do ":make test_name") and the output file.
96b073da89SBram Moolenaar  " Report finding another swap file and chose 'q' to avoid getting stuck.
97d8f27b30SBram Moolenaar  if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
98d8f27b30SBram Moolenaar    let v:swapchoice = 'e'
99b073da89SBram Moolenaar  else
100b073da89SBram Moolenaar    call assert_report('Unexpected swap file: ' .. v:swapname)
101b073da89SBram Moolenaar    let v:swapchoice = 'q'
102d8f27b30SBram Moolenaar  endif
103d8f27b30SBram Moolenaarendfunc
104d8f27b30SBram Moolenaar
1057a073549SBram Moolenaar" Avoid stopping at the "hit enter" prompt
1067a073549SBram Moolenaarset nomore
1077a073549SBram Moolenaar
108c0662466SBram Moolenaar" Output all messages in English.
109c0662466SBram Moolenaarlang mess C
110c0662466SBram Moolenaar
11110e1d01aSBram Moolenaar" suppress menu translation
11210e1d01aSBram Moolenaarif has('gui_running') && exists('did_install_default_menus')
11310e1d01aSBram Moolenaar  source $VIMRUNTIME/delmenu.vim
11410e1d01aSBram Moolenaar  set langmenu=none
11510e1d01aSBram Moolenaar  source $VIMRUNTIME/menu.vim
11610e1d01aSBram Moolenaarendif
11710e1d01aSBram Moolenaar
118f60b796fSBram Moolenaar" Always use forward slashes.
119f60b796fSBram Moolenaarset shellslash
120f60b796fSBram Moolenaar
12128fb79dbSBram Moolenaarlet s:srcdir = expand('%:p:h:h')
12228fb79dbSBram Moolenaar
1232690b5aeSBram Moolenaarif has('win32')
1242690b5aeSBram Moolenaar  " avoid prompt that is long or contains a line break
1252690b5aeSBram Moolenaar  let $PROMPT = '$P$G'
1262690b5aeSBram Moolenaarendif
1272690b5aeSBram Moolenaar
1288e8df251SBram Moolenaar" Prepare for calling test_garbagecollect_now().
129ebf7dfa6SBram Moolenaarlet v:testing = 1
130ebf7dfa6SBram Moolenaar
13128fb79dbSBram Moolenaar" Support function: get the alloc ID by name.
13228fb79dbSBram Moolenaarfunction GetAllocId(name)
13328fb79dbSBram Moolenaar  exe 'split ' . s:srcdir . '/alloc.h'
134065ee9aeSBram Moolenaar  let top = search('typedef enum')
135065ee9aeSBram Moolenaar  if top == 0
136065ee9aeSBram Moolenaar    call add(v:errors, 'typedef not found in alloc.h')
137065ee9aeSBram Moolenaar  endif
13828fb79dbSBram Moolenaar  let lnum = search('aid_' . a:name . ',')
13928fb79dbSBram Moolenaar  if lnum == 0
14028fb79dbSBram Moolenaar    call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
14128fb79dbSBram Moolenaar  endif
14228fb79dbSBram Moolenaar  close
143065ee9aeSBram Moolenaar  return lnum - top - 1
14428fb79dbSBram Moolenaarendfunc
14528fb79dbSBram Moolenaar
14642205551SBram Moolenaarfunc RunTheTest(test)
147b5760a1cSBram Moolenaar  echo 'Executing ' . a:test
14875ee544fSBram Moolenaar  if has('reltime')
14975ee544fSBram Moolenaar    let func_start = reltime()
15075ee544fSBram Moolenaar  endif
151e5f2a075SBram Moolenaar
152e5f2a075SBram Moolenaar  " Avoid stopping at the "hit enter" prompt
153e5f2a075SBram Moolenaar  set nomore
154e5f2a075SBram Moolenaar
155e5f2a075SBram Moolenaar  " Avoid a three second wait when a message is about to be overwritten by the
156e5f2a075SBram Moolenaar  " mode message.
157e5f2a075SBram Moolenaar  set noshowmode
158e5f2a075SBram Moolenaar
159eb992cb9SBram Moolenaar  " Clear any overrides.
160eb992cb9SBram Moolenaar  call test_override('ALL', 0)
161eb992cb9SBram Moolenaar
162cf1ba35fSBram Moolenaar  " Some tests wipe out buffers.  To be consistent, always wipe out all
163cf1ba35fSBram Moolenaar  " buffers.
164cf1ba35fSBram Moolenaar  %bwipe!
165cf1ba35fSBram Moolenaar
166209d3874SBram Moolenaar  " The test may change the current directory. Save and restore the
167209d3874SBram Moolenaar  " directory after executing the test.
168209d3874SBram Moolenaar  let save_cwd = getcwd()
169209d3874SBram Moolenaar
170b5760a1cSBram Moolenaar  if exists("*SetUp")
171cc28e2d0SBram Moolenaar    try
172b5760a1cSBram Moolenaar      call SetUp()
173cc28e2d0SBram Moolenaar    catch
174cc28e2d0SBram Moolenaar      call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
175cc28e2d0SBram Moolenaar    endtry
176b5760a1cSBram Moolenaar  endif
177b5760a1cSBram Moolenaar
178f204e05aSBram Moolenaar  if a:test =~ 'Test_nocatch_'
179f204e05aSBram Moolenaar    " Function handles errors itself.  This avoids skipping commands after the
180f204e05aSBram Moolenaar    " error.
181f204e05aSBram Moolenaar    exe 'call ' . a:test
182f204e05aSBram Moolenaar  else
183b5760a1cSBram Moolenaar    try
184bfe13cccSBram Moolenaar      au VimLeavePre * call EarlyExit(g:testfunc)
185b5760a1cSBram Moolenaar      exe 'call ' . a:test
1868903676dSBram Moolenaar      au! VimLeavePre
187dac1947bSBram Moolenaar    catch /^\cskipped/
188dac1947bSBram Moolenaar      call add(s:messages, '    Skipped')
189dac1947bSBram Moolenaar      call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '',  ''))
190b5760a1cSBram Moolenaar    catch
191b5760a1cSBram Moolenaar      call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
192b5760a1cSBram Moolenaar    endtry
193f204e05aSBram Moolenaar  endif
1948ad16da7SBram Moolenaar
1958ad16da7SBram Moolenaar  " In case 'insertmode' was set and something went wrong, make sure it is
1968ad16da7SBram Moolenaar  " reset to avoid trouble with anything else.
1978ad16da7SBram Moolenaar  set noinsertmode
198b5760a1cSBram Moolenaar
199b5760a1cSBram Moolenaar  if exists("*TearDown")
200cc28e2d0SBram Moolenaar    try
201b5760a1cSBram Moolenaar      call TearDown()
202cc28e2d0SBram Moolenaar    catch
203cc28e2d0SBram Moolenaar      call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
204cc28e2d0SBram Moolenaar    endtry
205b5760a1cSBram Moolenaar  endif
2067cba71d7SBram Moolenaar
2070b5dc644SBram Moolenaar  " Clear any autocommands and put back the catch-all for SwapExists.
208cf1ba35fSBram Moolenaar  au!
209d8f27b30SBram Moolenaar  au SwapExists * call HandleSwapExists()
210cf1ba35fSBram Moolenaar
211ef6b979bSBram Moolenaar  " Check for and close any stray popup windows.
21205ad5ff0SBram Moolenaar  if has('popupwin')
213ef6b979bSBram Moolenaar    call assert_equal([], popup_list())
21403a9f848SBram Moolenaar    call popup_clear(1)
215ae943150SBram Moolenaar  endif
216ae943150SBram Moolenaar
217ce11de87SBram Moolenaar  " Close any extra tab pages and windows and make the current one not modified.
218ce11de87SBram Moolenaar  while tabpagenr('$') > 1
219cf1ba35fSBram Moolenaar    quit!
220ce11de87SBram Moolenaar  endwhile
221ce11de87SBram Moolenaar
222358308ddSBram Moolenaar  while 1
223358308ddSBram Moolenaar    let wincount = winnr('$')
224358308ddSBram Moolenaar    if wincount == 1
225358308ddSBram Moolenaar      break
226358308ddSBram Moolenaar    endif
2277cba71d7SBram Moolenaar    bwipe!
228358308ddSBram Moolenaar    if wincount == winnr('$')
229358308ddSBram Moolenaar      " Did not manage to close a window.
230358308ddSBram Moolenaar      only!
231358308ddSBram Moolenaar      break
232358308ddSBram Moolenaar    endif
2337cba71d7SBram Moolenaar  endwhile
234209d3874SBram Moolenaar
235209d3874SBram Moolenaar  exe 'cd ' . save_cwd
236640d4f0cSBram Moolenaar
237640d4f0cSBram Moolenaar  let message = 'Executed ' . a:test
238640d4f0cSBram Moolenaar  if has('reltime')
2398d943796SBram Moolenaar    let message ..= repeat(' ', 50 - len(message))
2408d943796SBram Moolenaar    let time = reltime(func_start)
2418d943796SBram Moolenaar    if has('float') && reltimefloat(time) > 0.1
2428d943796SBram Moolenaar      let message = &t_md .. message
2438d943796SBram Moolenaar    endif
2448d943796SBram Moolenaar    let message ..= ' in ' .. reltimestr(time) .. ' seconds'
2458d943796SBram Moolenaar    if has('float') && reltimefloat(time) > 0.1
2468d943796SBram Moolenaar      let message ..= &t_me
2478d943796SBram Moolenaar    endif
248640d4f0cSBram Moolenaar  endif
249640d4f0cSBram Moolenaar  call add(s:messages, message)
250640d4f0cSBram Moolenaar  let s:done += 1
251b5760a1cSBram Moolenaarendfunc
25228fb79dbSBram Moolenaar
253ce436de5SBram Moolenaarfunc AfterTheTest(func_name)
25443345546SBram Moolenaar  if len(v:errors) > 0
255ce436de5SBram Moolenaar    if match(s:may_fail_list, '^' .. a:func_name) >= 0
256ce436de5SBram Moolenaar      let s:fail_expected += 1
257bfe13cccSBram Moolenaar      call add(s:errors_expected, 'Found errors in ' . g:testfunc . ':')
258ce436de5SBram Moolenaar      call extend(s:errors_expected, v:errors)
259ce436de5SBram Moolenaar    else
26000af60bbSBram Moolenaar      let s:fail += 1
261bfe13cccSBram Moolenaar      call add(s:errors, 'Found errors in ' . g:testfunc . ':')
26200af60bbSBram Moolenaar      call extend(s:errors, v:errors)
263ce436de5SBram Moolenaar    endif
26443345546SBram Moolenaar    let v:errors = []
26543345546SBram Moolenaar  endif
26642205551SBram Moolenaarendfunc
26742205551SBram Moolenaar
2688903676dSBram Moolenaarfunc EarlyExit(test)
2698903676dSBram Moolenaar  " It's OK for the test we use to test the quit detection.
2708903676dSBram Moolenaar  if a:test != 'Test_zz_quit_detected()'
2718903676dSBram Moolenaar    call add(v:errors, 'Test caused Vim to exit: ' . a:test)
2728903676dSBram Moolenaar  endif
2738903676dSBram Moolenaar
2748903676dSBram Moolenaar  call FinishTesting()
2758903676dSBram Moolenaarendfunc
2768903676dSBram Moolenaar
27742205551SBram Moolenaar" This function can be called by a test if it wants to abort testing.
27842205551SBram Moolenaarfunc FinishTesting()
279ce436de5SBram Moolenaar  call AfterTheTest('')
28043345546SBram Moolenaar
281fc4ad616SBram Moolenaar  " Don't write viminfo on exit.
282fc4ad616SBram Moolenaar  set viminfo=
283fc4ad616SBram Moolenaar
284d1ee0043SBram Moolenaar  " Clean up files created by setup.vim
285d1ee0043SBram Moolenaar  call delete('XfakeHOME', 'rf')
286d1ee0043SBram Moolenaar
287ce436de5SBram Moolenaar  if s:fail == 0 && s:fail_expected == 0
28843345546SBram Moolenaar    " Success, create the .res file so that make knows it's done.
28900af60bbSBram Moolenaar    exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
29043345546SBram Moolenaar    write
29143345546SBram Moolenaar  endif
29243345546SBram Moolenaar
29300af60bbSBram Moolenaar  if len(s:errors) > 0
29443345546SBram Moolenaar    " Append errors to test.log
29543345546SBram Moolenaar    split test.log
29643345546SBram Moolenaar    call append(line('$'), '')
29700af60bbSBram Moolenaar    call append(line('$'), 'From ' . g:testname . ':')
29800af60bbSBram Moolenaar    call append(line('$'), s:errors)
29943345546SBram Moolenaar    write
30043345546SBram Moolenaar  endif
30143345546SBram Moolenaar
30229f9ed20SBram Moolenaar  if s:done == 0
3037b666c78SBram Moolenaar    if s:filtered > 0
3047b666c78SBram Moolenaar      let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'"
30529f9ed20SBram Moolenaar    else
3067b666c78SBram Moolenaar      let message = 'NO tests executed'
3077b666c78SBram Moolenaar    endif
3087b666c78SBram Moolenaar  else
3097b666c78SBram Moolenaar    if s:filtered > 0
3107b666c78SBram Moolenaar      call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER")
3117b666c78SBram Moolenaar    endif
31200af60bbSBram Moolenaar    let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
31329f9ed20SBram Moolenaar  endif
3147b666c78SBram Moolenaar  if s:done > 0 && has('reltime')
3158d943796SBram Moolenaar    let message = &t_md .. message .. repeat(' ', 40 - len(message))
31675ee544fSBram Moolenaar    let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds'
3178d943796SBram Moolenaar    let message ..= &t_me
31875ee544fSBram Moolenaar  endif
319096c8bb4SBram Moolenaar  echo message
32000af60bbSBram Moolenaar  call add(s:messages, message)
32100af60bbSBram Moolenaar  if s:fail > 0
32200af60bbSBram Moolenaar    let message = s:fail . ' FAILED:'
323096c8bb4SBram Moolenaar    echo message
32400af60bbSBram Moolenaar    call add(s:messages, message)
32500af60bbSBram Moolenaar    call extend(s:messages, s:errors)
32643345546SBram Moolenaar  endif
327ce436de5SBram Moolenaar  if s:fail_expected > 0
328ce436de5SBram Moolenaar    let message = s:fail_expected . ' FAILED (matching $TEST_MAY_FAIL):'
329ce436de5SBram Moolenaar    echo message
330ce436de5SBram Moolenaar    call add(s:messages, message)
331ce436de5SBram Moolenaar    call extend(s:messages, s:errors_expected)
332ce436de5SBram Moolenaar  endif
33343345546SBram Moolenaar
334dac1947bSBram Moolenaar  " Add SKIPPED messages
335dac1947bSBram Moolenaar  call extend(s:messages, s:skipped)
336dac1947bSBram Moolenaar
337dac1947bSBram Moolenaar  " Append messages to the file "messages"
338096c8bb4SBram Moolenaar  split messages
339096c8bb4SBram Moolenaar  call append(line('$'), '')
34000af60bbSBram Moolenaar  call append(line('$'), 'From ' . g:testname . ':')
34100af60bbSBram Moolenaar  call append(line('$'), s:messages)
342096c8bb4SBram Moolenaar  write
343096c8bb4SBram Moolenaar
34443345546SBram Moolenaar  qall!
34542205551SBram Moolenaarendfunc
34642205551SBram Moolenaar
34742205551SBram Moolenaar" Source the test script.  First grab the file name, in case the script
34842205551SBram Moolenaar" navigates away.  g:testname can be used by the tests.
34942205551SBram Moolenaarlet g:testname = expand('%')
35042205551SBram Moolenaarlet s:done = 0
35142205551SBram Moolenaarlet s:fail = 0
352ce436de5SBram Moolenaarlet s:fail_expected = 0
35342205551SBram Moolenaarlet s:errors = []
354ce436de5SBram Moolenaarlet s:errors_expected = []
35542205551SBram Moolenaarlet s:messages = []
35642205551SBram Moolenaarlet s:skipped = []
35742205551SBram Moolenaarif expand('%') =~ 'test_vimscript.vim'
358ce436de5SBram Moolenaar  " this test has intentional errors, don't use try/catch.
35942205551SBram Moolenaar  source %
36042205551SBram Moolenaarelse
36142205551SBram Moolenaar  try
36242205551SBram Moolenaar    source %
3639c0cec65SBram Moolenaar  catch /^\cskipped/
3649c0cec65SBram Moolenaar    call add(s:messages, '    Skipped')
3659c0cec65SBram Moolenaar    call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '',  ''))
36642205551SBram Moolenaar  catch
36742205551SBram Moolenaar    let s:fail += 1
36842205551SBram Moolenaar    call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
36942205551SBram Moolenaar  endtry
37042205551SBram Moolenaarendif
37142205551SBram Moolenaar
37242205551SBram Moolenaar" Names of flaky tests.
373dbc0d216SBram Moolenaarlet s:flaky_tests = [
3740d0c3ca0SBram Moolenaar      \ 'Test_autocmd_SafeState()',
37542205551SBram Moolenaar      \ 'Test_client_server()',
37642205551SBram Moolenaar      \ 'Test_close_and_exit_cb()',
377d80232beSBram Moolenaar      \ 'Test_close_output_buffer()',
37842205551SBram Moolenaar      \ 'Test_collapse_buffers()',
37965873846SBram Moolenaar      \ 'Test_cwd()',
380218959bcSBram Moolenaar      \ 'Test_diff_screen()',
38142205551SBram Moolenaar      \ 'Test_exit_callback_interval()',
382ea94c855SBram Moolenaar      \ 'Test_map_timeout_with_timer_interrupt()',
3831eca6f13SBram Moolenaar      \ 'Test_out_cb()',
38442205551SBram Moolenaar      \ 'Test_pipe_through_sort_all()',
38542205551SBram Moolenaar      \ 'Test_pipe_through_sort_some()',
38644f0bd87SBram Moolenaar      \ 'Test_popup_and_window_resize()',
38742205551SBram Moolenaar      \ 'Test_quoteplus()',
3887dd48506SBram Moolenaar      \ 'Test_quotestar()',
38942205551SBram Moolenaar      \ 'Test_reltime()',
3903c8cd4a1SBram Moolenaar      \ 'Test_state()',
391f204e05aSBram Moolenaar      \ 'Test_terminal_composing_unicode()',
3923876789bSBram Moolenaar      \ 'Test_terminal_does_not_truncate_last_newlines()',
3933615abb6SBram Moolenaar      \ 'Test_terminal_no_cmd()',
39475a60f74SBram Moolenaar      \ 'Test_terminal_noblock()',
3957dd88c51SBram Moolenaar      \ 'Test_terminal_redir_file()',
396e219f73eSBram Moolenaar      \ 'Test_termwinscroll()',
3979a2fddcfSBram Moolenaar      \ 'Test_timer_oneshot()',
3989a2fddcfSBram Moolenaar      \ 'Test_timer_paused()',
3999a2fddcfSBram Moolenaar      \ 'Test_timer_repeat_many()',
4009a2fddcfSBram Moolenaar      \ 'Test_timer_repeat_three()',
4019a2fddcfSBram Moolenaar      \ 'Test_timer_stop_all_in_callback()',
4029a2fddcfSBram Moolenaar      \ 'Test_timer_stop_in_callback()',
4039a2fddcfSBram Moolenaar      \ 'Test_timer_with_partial_callback()',
40442205551SBram Moolenaar      \ ]
40542205551SBram Moolenaar
40642205551SBram Moolenaar" Locate Test_ functions and execute them.
40742205551SBram Moolenaarredir @q
40842205551SBram Moolenaarsilent function /^Test_
40942205551SBram Moolenaarredir END
41061a6d4e4SBram Moolenaarlet s:tests = split(substitute(@q, '\(function\|def\) \(\k*()\)', '\2', 'g'))
41142205551SBram Moolenaar
41242205551SBram Moolenaar" If there is an extra argument filter the function names against it.
41342205551SBram Moolenaarif argc() > 1
41442205551SBram Moolenaar  let s:tests = filter(s:tests, 'v:val =~ argv(1)')
41542205551SBram Moolenaarendif
41642205551SBram Moolenaar
417a7f6c3cfSBram Moolenaar" If the environment variable $TEST_FILTER is set then filter the function
418a7f6c3cfSBram Moolenaar" names against it.
4197b666c78SBram Moolenaarlet s:filtered = 0
420a7f6c3cfSBram Moolenaarif $TEST_FILTER != ''
4217b666c78SBram Moolenaar  let s:filtered = len(s:tests)
422a7f6c3cfSBram Moolenaar  let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER')
4237b666c78SBram Moolenaar  let s:filtered -= len(s:tests)
424a7f6c3cfSBram Moolenaarendif
425a7f6c3cfSBram Moolenaar
426ce436de5SBram Moolenaarlet s:may_fail_list = []
427ce436de5SBram Moolenaarif $TEST_MAY_FAIL != ''
428bfe13cccSBram Moolenaar  " Split the list at commas and add () to make it match g:testfunc.
429ce436de5SBram Moolenaar  let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'})
430ce436de5SBram Moolenaarendif
431ce436de5SBram Moolenaar
43242205551SBram Moolenaar" Execute the tests in alphabetical order.
433bfe13cccSBram Moolenaarfor g:testfunc in sort(s:tests)
4344a6fcf80SBram Moolenaar  " Silence, please!
4354a6fcf80SBram Moolenaar  set belloff=all
436f77af0e6SBram Moolenaar  let prev_error = ''
437f77af0e6SBram Moolenaar  let total_errors = []
4383ed9efc2SBram Moolenaar  let g:run_nr = 1
4394a6fcf80SBram Moolenaar
440bfe13cccSBram Moolenaar  " A test can set g:test_is_flaky to retry running the test.
441bfe13cccSBram Moolenaar  let g:test_is_flaky = 0
4423cdcb090SBram Moolenaar
443bfe13cccSBram Moolenaar  call RunTheTest(g:testfunc)
44442205551SBram Moolenaar
445f77af0e6SBram Moolenaar  " Repeat a flaky test.  Give up when:
4466ca6ca48SBram Moolenaar  " - $TEST_NO_RETRY is not empty
447f77af0e6SBram Moolenaar  " - it fails again with the same message
4481bc353b6SBram Moolenaar  " - it fails five times (with a different message)
449dbc0d216SBram Moolenaar  if len(v:errors) > 0
450*622b3568SBram Moolenaar        \ && $TEST_NO_RETRY == ''
451bfe13cccSBram Moolenaar        \ && (index(s:flaky_tests, g:testfunc) >= 0
452bfe13cccSBram Moolenaar        \      || g:test_is_flaky)
453f77af0e6SBram Moolenaar    while 1
454bfe13cccSBram Moolenaar      call add(s:messages, 'Found errors in ' . g:testfunc . ':')
4556caf606bSBram Moolenaar      call extend(s:messages, v:errors)
45615e737f7SBram Moolenaar
4573ed9efc2SBram Moolenaar      call add(total_errors, 'Run ' . g:run_nr . ':')
458f77af0e6SBram Moolenaar      call extend(total_errors, v:errors)
459f77af0e6SBram Moolenaar
4603ed9efc2SBram Moolenaar      if g:run_nr == 5 || prev_error == v:errors[0]
461f77af0e6SBram Moolenaar        call add(total_errors, 'Flaky test failed too often, giving up')
462f77af0e6SBram Moolenaar        let v:errors = total_errors
463f77af0e6SBram Moolenaar        break
464f77af0e6SBram Moolenaar      endif
465f77af0e6SBram Moolenaar
466f77af0e6SBram Moolenaar      call add(s:messages, 'Flaky test failed, running it again')
467f77af0e6SBram Moolenaar
468f77af0e6SBram Moolenaar      " Flakiness is often caused by the system being very busy.  Sleep a
469f77af0e6SBram Moolenaar      " couple of seconds to have a higher chance of succeeding the second
470f77af0e6SBram Moolenaar      " time.
47155058601SBram Moolenaar      sleep 2
47255058601SBram Moolenaar
473f77af0e6SBram Moolenaar      let prev_error = v:errors[0]
47442205551SBram Moolenaar      let v:errors = []
4753ed9efc2SBram Moolenaar      let g:run_nr += 1
476f77af0e6SBram Moolenaar
477bfe13cccSBram Moolenaar      call RunTheTest(g:testfunc)
478f77af0e6SBram Moolenaar
479f77af0e6SBram Moolenaar      if len(v:errors) == 0
480f77af0e6SBram Moolenaar        " Test passed on rerun.
481f77af0e6SBram Moolenaar        break
48215e737f7SBram Moolenaar      endif
483f77af0e6SBram Moolenaar    endwhile
48442205551SBram Moolenaar  endif
48542205551SBram Moolenaar
486bfe13cccSBram Moolenaar  call AfterTheTest(g:testfunc)
48742205551SBram Moolenaarendfor
48842205551SBram Moolenaar
48942205551SBram Moolenaarcall FinishTesting()
490cc28e2d0SBram Moolenaar
491cc28e2d0SBram Moolenaar" vim: shiftwidth=2 sts=2 expandtab
492