xref: /vim-8.2.3635/src/testdir/runtest.vim (revision ce436de5)
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"
10*ce436de5SBram Moolenaar" If the environment variable $TEST_FILTER is set then only test functions
11*ce436de5SBram Moolenaar" matching this pattern are executed.  E.g. for sh/bash:
12*ce436de5SBram Moolenaar"     export TEST_FILTER=Test_channel
13*ce436de5SBram Moolenaar" For csh:
14*ce436de5SBram Moolenaar"     setenv TEST_FILTER Test_channel
15*ce436de5SBram Moolenaar"
16*ce436de5SBram Moolenaar" To ignore failure for tests that are known to fail in a certain environment,
17*ce436de5SBram Moolenaar" set $TEST_MAY_FAIL to a comma separated list of function names.  E.g. for
18*ce436de5SBram Moolenaar" sh/bash:
19*ce436de5SBram Moolenaar"     export TEST_MAY_FAIL=Test_channel_one,Test_channel_other
20*ce436de5SBram Moolenaar" The failure report will then not be included in the test.log file and
21*ce436de5SBram Moolenaar" "make test" will not fail.
22*ce436de5SBram Moolenaar"
2343345546SBram Moolenaar" The test script may contain anything, only functions that start with
2443345546SBram Moolenaar" "Test_" are special.  These will be invoked and should contain assert
2543345546SBram Moolenaar" functions.  See test_assert.vim for an example.
2643345546SBram Moolenaar"
2743345546SBram Moolenaar" It is possible to source other files that contain "Test_" functions.  This
2843345546SBram Moolenaar" can speed up testing, since Vim does not need to restart.  But be careful
2943345546SBram Moolenaar" that the tests do not interfere with each other.
3043345546SBram Moolenaar"
3143345546SBram Moolenaar" If an error cannot be detected properly with an assert function add the
3243345546SBram Moolenaar" error to the v:errors list:
3343345546SBram Moolenaar"   call add(v:errors, 'test foo failed: Cannot find xyz')
3443345546SBram Moolenaar"
3543345546SBram Moolenaar" If preparation for each Test_ function is needed, define a SetUp function.
3643345546SBram Moolenaar" It will be called before each Test_ function.
3743345546SBram Moolenaar"
3843345546SBram Moolenaar" If cleanup after each Test_ function is needed, define a TearDown function.
3943345546SBram Moolenaar" It will be called after each Test_ function.
4000af60bbSBram Moolenaar"
4100af60bbSBram Moolenaar" When debugging a test it can be useful to add messages to v:errors:
4200af60bbSBram Moolenaar"	call add(v:errors, "this happened")
4300af60bbSBram Moolenaar
4443345546SBram Moolenaar
4543345546SBram Moolenaar" Without the +eval feature we can't run these tests, bail out.
464686b323SBram Moolenaarso small.vim
4743345546SBram Moolenaar
4843345546SBram Moolenaar" Check that the screen size is at least 24 x 80 characters.
4943345546SBram Moolenaarif &lines < 24 || &columns < 80
500b5dc644SBram Moolenaar  let error = 'Screen size too small! Tests require at least 24 lines with 80 characters, got ' .. &lines .. ' lines with ' .. &columns .. ' characters'
5143345546SBram Moolenaar  echoerr error
5243345546SBram Moolenaar  split test.log
5343345546SBram Moolenaar  $put =error
5445aa07d3SBram Moolenaar  write
5545aa07d3SBram Moolenaar  split messages
560b5dc644SBram Moolenaar  call append(line('$'), '')
570b5dc644SBram Moolenaar  call append(line('$'), 'From ' . expand('%') . ':')
5845aa07d3SBram Moolenaar  call append(line('$'), error)
5945aa07d3SBram Moolenaar  write
6045aa07d3SBram Moolenaar  qa!
6143345546SBram Moolenaarendif
6243345546SBram Moolenaar
6375ee544fSBram Moolenaarif has('reltime')
6475ee544fSBram Moolenaar  let s:start_time = reltime()
6575ee544fSBram Moolenaarendif
6675ee544fSBram Moolenaar
6789b10421SBram Moolenaar" Common with all tests on all systems.
6889b10421SBram Moolenaarsource setup.vim
6989b10421SBram Moolenaar
70c0662466SBram Moolenaar" For consistency run all tests with 'nocompatible' set.
71c0662466SBram Moolenaar" This also enables use of line continuation.
72c0662466SBram Moolenaarset nocp viminfo+=nviminfo
73c0662466SBram Moolenaar
7430276f2bSBram Moolenaar" Use utf-8 by default, instead of whatever the system default happens to be.
75ed79d1e3SBram Moolenaar" Individual tests can overrule this at the top of the file and use
76ed79d1e3SBram Moolenaar" g:orig_encoding if needed.
77ed79d1e3SBram Moolenaarlet g:orig_encoding = &encoding
78ac105ed3SBram Moolenaarset encoding=utf-8
79ac105ed3SBram Moolenaar
80d8f27b30SBram Moolenaar" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for
81d8f27b30SBram Moolenaar" the test_name.vim file itself. Replace it here with a more restrictive one,
82d8f27b30SBram Moolenaar" so we still catch mistakes.
83d8f27b30SBram Moolenaarlet s:test_script_fname = expand('%')
84d8f27b30SBram Moolenaarau! SwapExists * call HandleSwapExists()
85d8f27b30SBram Moolenaarfunc HandleSwapExists()
86b073da89SBram Moolenaar  " Ignore finding a swap file for the test script (the user might be
87d8f27b30SBram Moolenaar  " editing it and do ":make test_name") and the output file.
88b073da89SBram Moolenaar  " Report finding another swap file and chose 'q' to avoid getting stuck.
89d8f27b30SBram Moolenaar  if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
90d8f27b30SBram Moolenaar    let v:swapchoice = 'e'
91b073da89SBram Moolenaar  else
92b073da89SBram Moolenaar    call assert_report('Unexpected swap file: ' .. v:swapname)
93b073da89SBram Moolenaar    let v:swapchoice = 'q'
94d8f27b30SBram Moolenaar  endif
95d8f27b30SBram Moolenaarendfunc
96d8f27b30SBram Moolenaar
977a073549SBram Moolenaar" Avoid stopping at the "hit enter" prompt
987a073549SBram Moolenaarset nomore
997a073549SBram Moolenaar
100c0662466SBram Moolenaar" Output all messages in English.
101c0662466SBram Moolenaarlang mess C
102c0662466SBram Moolenaar
103f60b796fSBram Moolenaar" Always use forward slashes.
104f60b796fSBram Moolenaarset shellslash
105f60b796fSBram Moolenaar
10628fb79dbSBram Moolenaarlet s:srcdir = expand('%:p:h:h')
10728fb79dbSBram Moolenaar
1088e8df251SBram Moolenaar" Prepare for calling test_garbagecollect_now().
109ebf7dfa6SBram Moolenaarlet v:testing = 1
110ebf7dfa6SBram Moolenaar
11128fb79dbSBram Moolenaar" Support function: get the alloc ID by name.
11228fb79dbSBram Moolenaarfunction GetAllocId(name)
11328fb79dbSBram Moolenaar  exe 'split ' . s:srcdir . '/alloc.h'
114065ee9aeSBram Moolenaar  let top = search('typedef enum')
115065ee9aeSBram Moolenaar  if top == 0
116065ee9aeSBram Moolenaar    call add(v:errors, 'typedef not found in alloc.h')
117065ee9aeSBram Moolenaar  endif
11828fb79dbSBram Moolenaar  let lnum = search('aid_' . a:name . ',')
11928fb79dbSBram Moolenaar  if lnum == 0
12028fb79dbSBram Moolenaar    call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
12128fb79dbSBram Moolenaar  endif
12228fb79dbSBram Moolenaar  close
123065ee9aeSBram Moolenaar  return lnum - top - 1
12428fb79dbSBram Moolenaarendfunc
12528fb79dbSBram Moolenaar
12642205551SBram Moolenaarfunc RunTheTest(test)
127b5760a1cSBram Moolenaar  echo 'Executing ' . a:test
12875ee544fSBram Moolenaar  if has('reltime')
12975ee544fSBram Moolenaar    let func_start = reltime()
13075ee544fSBram Moolenaar  endif
131e5f2a075SBram Moolenaar
132e5f2a075SBram Moolenaar  " Avoid stopping at the "hit enter" prompt
133e5f2a075SBram Moolenaar  set nomore
134e5f2a075SBram Moolenaar
135e5f2a075SBram Moolenaar  " Avoid a three second wait when a message is about to be overwritten by the
136e5f2a075SBram Moolenaar  " mode message.
137e5f2a075SBram Moolenaar  set noshowmode
138e5f2a075SBram Moolenaar
139eb992cb9SBram Moolenaar  " Clear any overrides.
140eb992cb9SBram Moolenaar  call test_override('ALL', 0)
141eb992cb9SBram Moolenaar
142cf1ba35fSBram Moolenaar  " Some tests wipe out buffers.  To be consistent, always wipe out all
143cf1ba35fSBram Moolenaar  " buffers.
144cf1ba35fSBram Moolenaar  %bwipe!
145cf1ba35fSBram Moolenaar
146209d3874SBram Moolenaar  " The test may change the current directory. Save and restore the
147209d3874SBram Moolenaar  " directory after executing the test.
148209d3874SBram Moolenaar  let save_cwd = getcwd()
149209d3874SBram Moolenaar
150b5760a1cSBram Moolenaar  if exists("*SetUp")
151cc28e2d0SBram Moolenaar    try
152b5760a1cSBram Moolenaar      call SetUp()
153cc28e2d0SBram Moolenaar    catch
154cc28e2d0SBram Moolenaar      call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
155cc28e2d0SBram Moolenaar    endtry
156b5760a1cSBram Moolenaar  endif
157b5760a1cSBram Moolenaar
158f204e05aSBram Moolenaar  if a:test =~ 'Test_nocatch_'
159f204e05aSBram Moolenaar    " Function handles errors itself.  This avoids skipping commands after the
160f204e05aSBram Moolenaar    " error.
161f204e05aSBram Moolenaar    exe 'call ' . a:test
162f204e05aSBram Moolenaar  else
163b5760a1cSBram Moolenaar    try
1648903676dSBram Moolenaar      let s:test = a:test
1658903676dSBram Moolenaar      au VimLeavePre * call EarlyExit(s:test)
166b5760a1cSBram Moolenaar      exe 'call ' . a:test
1678903676dSBram Moolenaar      au! VimLeavePre
168dac1947bSBram Moolenaar    catch /^\cskipped/
169dac1947bSBram Moolenaar      call add(s:messages, '    Skipped')
170dac1947bSBram Moolenaar      call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '',  ''))
171b5760a1cSBram Moolenaar    catch
172b5760a1cSBram Moolenaar      call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
173b5760a1cSBram Moolenaar    endtry
174f204e05aSBram Moolenaar  endif
1758ad16da7SBram Moolenaar
1768ad16da7SBram Moolenaar  " In case 'insertmode' was set and something went wrong, make sure it is
1778ad16da7SBram Moolenaar  " reset to avoid trouble with anything else.
1788ad16da7SBram Moolenaar  set noinsertmode
179b5760a1cSBram Moolenaar
180b5760a1cSBram Moolenaar  if exists("*TearDown")
181cc28e2d0SBram Moolenaar    try
182b5760a1cSBram Moolenaar      call TearDown()
183cc28e2d0SBram Moolenaar    catch
184cc28e2d0SBram Moolenaar      call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
185cc28e2d0SBram Moolenaar    endtry
186b5760a1cSBram Moolenaar  endif
1877cba71d7SBram Moolenaar
1880b5dc644SBram Moolenaar  " Clear any autocommands and put back the catch-all for SwapExists.
189cf1ba35fSBram Moolenaar  au!
190d8f27b30SBram Moolenaar  au SwapExists * call HandleSwapExists()
191cf1ba35fSBram Moolenaar
192ae943150SBram Moolenaar  " Close any stray popup windows
19305ad5ff0SBram Moolenaar  if has('popupwin')
194ae943150SBram Moolenaar    call popup_clear()
195ae943150SBram Moolenaar  endif
196ae943150SBram Moolenaar
197ce11de87SBram Moolenaar  " Close any extra tab pages and windows and make the current one not modified.
198ce11de87SBram Moolenaar  while tabpagenr('$') > 1
199cf1ba35fSBram Moolenaar    quit!
200ce11de87SBram Moolenaar  endwhile
201ce11de87SBram Moolenaar
202358308ddSBram Moolenaar  while 1
203358308ddSBram Moolenaar    let wincount = winnr('$')
204358308ddSBram Moolenaar    if wincount == 1
205358308ddSBram Moolenaar      break
206358308ddSBram Moolenaar    endif
2077cba71d7SBram Moolenaar    bwipe!
208358308ddSBram Moolenaar    if wincount == winnr('$')
209358308ddSBram Moolenaar      " Did not manage to close a window.
210358308ddSBram Moolenaar      only!
211358308ddSBram Moolenaar      break
212358308ddSBram Moolenaar    endif
2137cba71d7SBram Moolenaar  endwhile
214209d3874SBram Moolenaar
215209d3874SBram Moolenaar  exe 'cd ' . save_cwd
216640d4f0cSBram Moolenaar
217640d4f0cSBram Moolenaar  let message = 'Executed ' . a:test
218640d4f0cSBram Moolenaar  if has('reltime')
219640d4f0cSBram Moolenaar    let message ..= ' in ' .. reltimestr(reltime(func_start)) .. ' seconds'
220640d4f0cSBram Moolenaar  endif
221640d4f0cSBram Moolenaar  call add(s:messages, message)
222640d4f0cSBram Moolenaar  let s:done += 1
223b5760a1cSBram Moolenaarendfunc
22428fb79dbSBram Moolenaar
225*ce436de5SBram Moolenaarfunc AfterTheTest(func_name)
22643345546SBram Moolenaar  if len(v:errors) > 0
227*ce436de5SBram Moolenaar    if match(s:may_fail_list, '^' .. a:func_name) >= 0
228*ce436de5SBram Moolenaar      let s:fail_expected += 1
229*ce436de5SBram Moolenaar      call add(s:errors_expected, 'Found errors in ' . s:test . ':')
230*ce436de5SBram Moolenaar      call extend(s:errors_expected, v:errors)
231*ce436de5SBram Moolenaar    else
23200af60bbSBram Moolenaar      let s:fail += 1
23300af60bbSBram Moolenaar      call add(s:errors, 'Found errors in ' . s:test . ':')
23400af60bbSBram Moolenaar      call extend(s:errors, v:errors)
235*ce436de5SBram Moolenaar    endif
23643345546SBram Moolenaar    let v:errors = []
23743345546SBram Moolenaar  endif
23842205551SBram Moolenaarendfunc
23942205551SBram Moolenaar
2408903676dSBram Moolenaarfunc EarlyExit(test)
2418903676dSBram Moolenaar  " It's OK for the test we use to test the quit detection.
2428903676dSBram Moolenaar  if a:test != 'Test_zz_quit_detected()'
2438903676dSBram Moolenaar    call add(v:errors, 'Test caused Vim to exit: ' . a:test)
2448903676dSBram Moolenaar  endif
2458903676dSBram Moolenaar
2468903676dSBram Moolenaar  call FinishTesting()
2478903676dSBram Moolenaarendfunc
2488903676dSBram Moolenaar
24942205551SBram Moolenaar" This function can be called by a test if it wants to abort testing.
25042205551SBram Moolenaarfunc FinishTesting()
251*ce436de5SBram Moolenaar  call AfterTheTest('')
25243345546SBram Moolenaar
253fc4ad616SBram Moolenaar  " Don't write viminfo on exit.
254fc4ad616SBram Moolenaar  set viminfo=
255fc4ad616SBram Moolenaar
256d1ee0043SBram Moolenaar  " Clean up files created by setup.vim
257d1ee0043SBram Moolenaar  call delete('XfakeHOME', 'rf')
258d1ee0043SBram Moolenaar
259*ce436de5SBram Moolenaar  if s:fail == 0 && s:fail_expected == 0
26043345546SBram Moolenaar    " Success, create the .res file so that make knows it's done.
26100af60bbSBram Moolenaar    exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
26243345546SBram Moolenaar    write
26343345546SBram Moolenaar  endif
26443345546SBram Moolenaar
26500af60bbSBram Moolenaar  if len(s:errors) > 0
26643345546SBram Moolenaar    " Append errors to test.log
26743345546SBram Moolenaar    split test.log
26843345546SBram Moolenaar    call append(line('$'), '')
26900af60bbSBram Moolenaar    call append(line('$'), 'From ' . g:testname . ':')
27000af60bbSBram Moolenaar    call append(line('$'), s:errors)
27143345546SBram Moolenaar    write
27243345546SBram Moolenaar  endif
27343345546SBram Moolenaar
27429f9ed20SBram Moolenaar  if s:done == 0
2757b666c78SBram Moolenaar    if s:filtered > 0
2767b666c78SBram Moolenaar      let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'"
27729f9ed20SBram Moolenaar    else
2787b666c78SBram Moolenaar      let message = 'NO tests executed'
2797b666c78SBram Moolenaar    endif
2807b666c78SBram Moolenaar  else
2817b666c78SBram Moolenaar    if s:filtered > 0
2827b666c78SBram Moolenaar      call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER")
2837b666c78SBram Moolenaar    endif
28400af60bbSBram Moolenaar    let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
28529f9ed20SBram Moolenaar  endif
2867b666c78SBram Moolenaar  if s:done > 0 && has('reltime')
28775ee544fSBram Moolenaar    let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds'
28875ee544fSBram Moolenaar  endif
289096c8bb4SBram Moolenaar  echo message
29000af60bbSBram Moolenaar  call add(s:messages, message)
29100af60bbSBram Moolenaar  if s:fail > 0
29200af60bbSBram Moolenaar    let message = s:fail . ' FAILED:'
293096c8bb4SBram Moolenaar    echo message
29400af60bbSBram Moolenaar    call add(s:messages, message)
29500af60bbSBram Moolenaar    call extend(s:messages, s:errors)
29643345546SBram Moolenaar  endif
297*ce436de5SBram Moolenaar  if s:fail_expected > 0
298*ce436de5SBram Moolenaar    let message = s:fail_expected . ' FAILED (matching $TEST_MAY_FAIL):'
299*ce436de5SBram Moolenaar    echo message
300*ce436de5SBram Moolenaar    call add(s:messages, message)
301*ce436de5SBram Moolenaar    call extend(s:messages, s:errors_expected)
302*ce436de5SBram Moolenaar  endif
30343345546SBram Moolenaar
304dac1947bSBram Moolenaar  " Add SKIPPED messages
305dac1947bSBram Moolenaar  call extend(s:messages, s:skipped)
306dac1947bSBram Moolenaar
307dac1947bSBram Moolenaar  " Append messages to the file "messages"
308096c8bb4SBram Moolenaar  split messages
309096c8bb4SBram Moolenaar  call append(line('$'), '')
31000af60bbSBram Moolenaar  call append(line('$'), 'From ' . g:testname . ':')
31100af60bbSBram Moolenaar  call append(line('$'), s:messages)
312096c8bb4SBram Moolenaar  write
313096c8bb4SBram Moolenaar
31443345546SBram Moolenaar  qall!
31542205551SBram Moolenaarendfunc
31642205551SBram Moolenaar
31742205551SBram Moolenaar" Source the test script.  First grab the file name, in case the script
31842205551SBram Moolenaar" navigates away.  g:testname can be used by the tests.
31942205551SBram Moolenaarlet g:testname = expand('%')
32042205551SBram Moolenaarlet s:done = 0
32142205551SBram Moolenaarlet s:fail = 0
322*ce436de5SBram Moolenaarlet s:fail_expected = 0
32342205551SBram Moolenaarlet s:errors = []
324*ce436de5SBram Moolenaarlet s:errors_expected = []
32542205551SBram Moolenaarlet s:messages = []
32642205551SBram Moolenaarlet s:skipped = []
32742205551SBram Moolenaarif expand('%') =~ 'test_vimscript.vim'
328*ce436de5SBram Moolenaar  " this test has intentional errors, don't use try/catch.
32942205551SBram Moolenaar  source %
33042205551SBram Moolenaarelse
33142205551SBram Moolenaar  try
33242205551SBram Moolenaar    source %
3339c0cec65SBram Moolenaar  catch /^\cskipped/
3349c0cec65SBram Moolenaar    call add(s:messages, '    Skipped')
3359c0cec65SBram Moolenaar    call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '',  ''))
33642205551SBram Moolenaar  catch
33742205551SBram Moolenaar    let s:fail += 1
33842205551SBram Moolenaar    call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
33942205551SBram Moolenaar  endtry
34042205551SBram Moolenaarendif
34142205551SBram Moolenaar
34242205551SBram Moolenaar" Names of flaky tests.
343dbc0d216SBram Moolenaarlet s:flaky_tests = [
3440d0c3ca0SBram Moolenaar      \ 'Test_autocmd_SafeState()',
34542205551SBram Moolenaar      \ 'Test_client_server()',
34642205551SBram Moolenaar      \ 'Test_close_and_exit_cb()',
347d80232beSBram Moolenaar      \ 'Test_close_output_buffer()',
34842205551SBram Moolenaar      \ 'Test_collapse_buffers()',
34965873846SBram Moolenaar      \ 'Test_cwd()',
350218959bcSBram Moolenaar      \ 'Test_diff_screen()',
35142205551SBram Moolenaar      \ 'Test_exit_callback_interval()',
352ea94c855SBram Moolenaar      \ 'Test_map_timeout_with_timer_interrupt()',
35342205551SBram Moolenaar      \ 'Test_nb_basic()',
3541eca6f13SBram Moolenaar      \ 'Test_out_cb()',
35542205551SBram Moolenaar      \ 'Test_pipe_through_sort_all()',
35642205551SBram Moolenaar      \ 'Test_pipe_through_sort_some()',
35744f0bd87SBram Moolenaar      \ 'Test_popup_and_window_resize()',
35842205551SBram Moolenaar      \ 'Test_quoteplus()',
3597dd48506SBram Moolenaar      \ 'Test_quotestar()',
36042205551SBram Moolenaar      \ 'Test_reltime()',
3613c8cd4a1SBram Moolenaar      \ 'Test_state()',
362f204e05aSBram Moolenaar      \ 'Test_terminal_composing_unicode()',
3633876789bSBram Moolenaar      \ 'Test_terminal_does_not_truncate_last_newlines()',
3643615abb6SBram Moolenaar      \ 'Test_terminal_no_cmd()',
36575a60f74SBram Moolenaar      \ 'Test_terminal_noblock()',
3667dd88c51SBram Moolenaar      \ 'Test_terminal_redir_file()',
367e219f73eSBram Moolenaar      \ 'Test_termwinscroll()',
3689a2fddcfSBram Moolenaar      \ 'Test_timer_oneshot()',
3699a2fddcfSBram Moolenaar      \ 'Test_timer_paused()',
3709a2fddcfSBram Moolenaar      \ 'Test_timer_repeat_many()',
3719a2fddcfSBram Moolenaar      \ 'Test_timer_repeat_three()',
3729a2fddcfSBram Moolenaar      \ 'Test_timer_stop_all_in_callback()',
3739a2fddcfSBram Moolenaar      \ 'Test_timer_stop_in_callback()',
3749a2fddcfSBram Moolenaar      \ 'Test_timer_with_partial_callback()',
37542205551SBram Moolenaar      \ ]
37642205551SBram Moolenaar
37742205551SBram Moolenaar" Locate Test_ functions and execute them.
37842205551SBram Moolenaarredir @q
37942205551SBram Moolenaarsilent function /^Test_
38042205551SBram Moolenaarredir END
38161a6d4e4SBram Moolenaarlet s:tests = split(substitute(@q, '\(function\|def\) \(\k*()\)', '\2', 'g'))
38242205551SBram Moolenaar
38342205551SBram Moolenaar" If there is an extra argument filter the function names against it.
38442205551SBram Moolenaarif argc() > 1
38542205551SBram Moolenaar  let s:tests = filter(s:tests, 'v:val =~ argv(1)')
38642205551SBram Moolenaarendif
38742205551SBram Moolenaar
388a7f6c3cfSBram Moolenaar" If the environment variable $TEST_FILTER is set then filter the function
389a7f6c3cfSBram Moolenaar" names against it.
3907b666c78SBram Moolenaarlet s:filtered = 0
391a7f6c3cfSBram Moolenaarif $TEST_FILTER != ''
3927b666c78SBram Moolenaar  let s:filtered = len(s:tests)
393a7f6c3cfSBram Moolenaar  let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER')
3947b666c78SBram Moolenaar  let s:filtered -= len(s:tests)
395a7f6c3cfSBram Moolenaarendif
396a7f6c3cfSBram Moolenaar
397*ce436de5SBram Moolenaarlet s:may_fail_list = []
398*ce436de5SBram Moolenaarif $TEST_MAY_FAIL != ''
399*ce436de5SBram Moolenaar  " Split the list at commas and add () to make it match s:test.
400*ce436de5SBram Moolenaar  let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'})
401*ce436de5SBram Moolenaarendif
402*ce436de5SBram Moolenaar
40342205551SBram Moolenaar" Execute the tests in alphabetical order.
40442205551SBram Moolenaarfor s:test in sort(s:tests)
4054a6fcf80SBram Moolenaar  " Silence, please!
4064a6fcf80SBram Moolenaar  set belloff=all
407f77af0e6SBram Moolenaar  let prev_error = ''
408f77af0e6SBram Moolenaar  let total_errors = []
409f77af0e6SBram Moolenaar  let run_nr = 1
4104a6fcf80SBram Moolenaar
4113cdcb090SBram Moolenaar  " A test can set test_is_flaky to retry running the test.
4123cdcb090SBram Moolenaar  let test_is_flaky = 0
4133cdcb090SBram Moolenaar
41442205551SBram Moolenaar  call RunTheTest(s:test)
41542205551SBram Moolenaar
416f77af0e6SBram Moolenaar  " Repeat a flaky test.  Give up when:
417f77af0e6SBram Moolenaar  " - it fails again with the same message
4181bc353b6SBram Moolenaar  " - it fails five times (with a different message)
419dbc0d216SBram Moolenaar  if len(v:errors) > 0
420dbc0d216SBram Moolenaar        \ && (index(s:flaky_tests, s:test) >= 0
4213cdcb090SBram Moolenaar        \      || test_is_flaky)
422f77af0e6SBram Moolenaar    while 1
4236caf606bSBram Moolenaar      call add(s:messages, 'Found errors in ' . s:test . ':')
4246caf606bSBram Moolenaar      call extend(s:messages, v:errors)
42515e737f7SBram Moolenaar
426f77af0e6SBram Moolenaar      call add(total_errors, 'Run ' . run_nr . ':')
427f77af0e6SBram Moolenaar      call extend(total_errors, v:errors)
428f77af0e6SBram Moolenaar
429f77af0e6SBram Moolenaar      if run_nr == 5 || prev_error == v:errors[0]
430f77af0e6SBram Moolenaar        call add(total_errors, 'Flaky test failed too often, giving up')
431f77af0e6SBram Moolenaar        let v:errors = total_errors
432f77af0e6SBram Moolenaar        break
433f77af0e6SBram Moolenaar      endif
434f77af0e6SBram Moolenaar
435f77af0e6SBram Moolenaar      call add(s:messages, 'Flaky test failed, running it again')
436f77af0e6SBram Moolenaar
437f77af0e6SBram Moolenaar      " Flakiness is often caused by the system being very busy.  Sleep a
438f77af0e6SBram Moolenaar      " couple of seconds to have a higher chance of succeeding the second
439f77af0e6SBram Moolenaar      " time.
44055058601SBram Moolenaar      sleep 2
44155058601SBram Moolenaar
442f77af0e6SBram Moolenaar      let prev_error = v:errors[0]
44342205551SBram Moolenaar      let v:errors = []
444f77af0e6SBram Moolenaar      let run_nr += 1
445f77af0e6SBram Moolenaar
44642205551SBram Moolenaar      call RunTheTest(s:test)
447f77af0e6SBram Moolenaar
448f77af0e6SBram Moolenaar      if len(v:errors) == 0
449f77af0e6SBram Moolenaar        " Test passed on rerun.
450f77af0e6SBram Moolenaar        break
45115e737f7SBram Moolenaar      endif
452f77af0e6SBram Moolenaar    endwhile
45342205551SBram Moolenaar  endif
45442205551SBram Moolenaar
455*ce436de5SBram Moolenaar  call AfterTheTest(s:test)
45642205551SBram Moolenaarendfor
45742205551SBram Moolenaar
45842205551SBram Moolenaarcall FinishTesting()
459cc28e2d0SBram Moolenaar
460cc28e2d0SBram Moolenaar" vim: shiftwidth=2 sts=2 expandtab
461