xref: /vim-8.2.3635/src/testdir/runtest.vim (revision 18aa13d1)
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"
16ce436de5SBram Moolenaar" To ignore failure for tests that are known to fail in a certain environment,
17ce436de5SBram Moolenaar" set $TEST_MAY_FAIL to a comma separated list of function names.  E.g. for
18ce436de5SBram Moolenaar" sh/bash:
19ce436de5SBram Moolenaar"     export TEST_MAY_FAIL=Test_channel_one,Test_channel_other
20ce436de5SBram Moolenaar" The failure report will then not be included in the test.log file and
21ce436de5SBram Moolenaar" "make test" will not fail.
22ce436de5SBram 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
48*18aa13d1SBram Moolenaar" In the GUI we can always change the screen size.
49*18aa13d1SBram Moolenaarif has('gui_running')
50*18aa13d1SBram Moolenaar  set columns=80 lines=25
51*18aa13d1SBram Moolenaarendif
52*18aa13d1SBram Moolenaar
5343345546SBram Moolenaar" Check that the screen size is at least 24 x 80 characters.
5443345546SBram Moolenaarif &lines < 24 || &columns < 80
550b5dc644SBram Moolenaar  let error = 'Screen size too small! Tests require at least 24 lines with 80 characters, got ' .. &lines .. ' lines with ' .. &columns .. ' characters'
5643345546SBram Moolenaar  echoerr error
5743345546SBram Moolenaar  split test.log
5843345546SBram Moolenaar  $put =error
5945aa07d3SBram Moolenaar  write
6045aa07d3SBram Moolenaar  split messages
610b5dc644SBram Moolenaar  call append(line('$'), '')
620b5dc644SBram Moolenaar  call append(line('$'), 'From ' . expand('%') . ':')
6345aa07d3SBram Moolenaar  call append(line('$'), error)
6445aa07d3SBram Moolenaar  write
6545aa07d3SBram Moolenaar  qa!
6643345546SBram Moolenaarendif
6743345546SBram Moolenaar
6875ee544fSBram Moolenaarif has('reltime')
6975ee544fSBram Moolenaar  let s:start_time = reltime()
7075ee544fSBram Moolenaarendif
7175ee544fSBram Moolenaar
7289b10421SBram Moolenaar" Common with all tests on all systems.
7389b10421SBram Moolenaarsource setup.vim
7489b10421SBram Moolenaar
75c0662466SBram Moolenaar" For consistency run all tests with 'nocompatible' set.
76c0662466SBram Moolenaar" This also enables use of line continuation.
77c0662466SBram Moolenaarset nocp viminfo+=nviminfo
78c0662466SBram Moolenaar
7930276f2bSBram Moolenaar" Use utf-8 by default, instead of whatever the system default happens to be.
80ed79d1e3SBram Moolenaar" Individual tests can overrule this at the top of the file and use
81ed79d1e3SBram Moolenaar" g:orig_encoding if needed.
82ed79d1e3SBram Moolenaarlet g:orig_encoding = &encoding
83ac105ed3SBram Moolenaarset encoding=utf-8
84ac105ed3SBram Moolenaar
85d8f27b30SBram Moolenaar" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for
86d8f27b30SBram Moolenaar" the test_name.vim file itself. Replace it here with a more restrictive one,
87d8f27b30SBram Moolenaar" so we still catch mistakes.
88d8f27b30SBram Moolenaarlet s:test_script_fname = expand('%')
89d8f27b30SBram Moolenaarau! SwapExists * call HandleSwapExists()
90d8f27b30SBram Moolenaarfunc HandleSwapExists()
91b073da89SBram Moolenaar  " Ignore finding a swap file for the test script (the user might be
92d8f27b30SBram Moolenaar  " editing it and do ":make test_name") and the output file.
93b073da89SBram Moolenaar  " Report finding another swap file and chose 'q' to avoid getting stuck.
94d8f27b30SBram Moolenaar  if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
95d8f27b30SBram Moolenaar    let v:swapchoice = 'e'
96b073da89SBram Moolenaar  else
97b073da89SBram Moolenaar    call assert_report('Unexpected swap file: ' .. v:swapname)
98b073da89SBram Moolenaar    let v:swapchoice = 'q'
99d8f27b30SBram Moolenaar  endif
100d8f27b30SBram Moolenaarendfunc
101d8f27b30SBram Moolenaar
1027a073549SBram Moolenaar" Avoid stopping at the "hit enter" prompt
1037a073549SBram Moolenaarset nomore
1047a073549SBram Moolenaar
105c0662466SBram Moolenaar" Output all messages in English.
106c0662466SBram Moolenaarlang mess C
107c0662466SBram Moolenaar
108f60b796fSBram Moolenaar" Always use forward slashes.
109f60b796fSBram Moolenaarset shellslash
110f60b796fSBram Moolenaar
11128fb79dbSBram Moolenaarlet s:srcdir = expand('%:p:h:h')
11228fb79dbSBram Moolenaar
1138e8df251SBram Moolenaar" Prepare for calling test_garbagecollect_now().
114ebf7dfa6SBram Moolenaarlet v:testing = 1
115ebf7dfa6SBram Moolenaar
11628fb79dbSBram Moolenaar" Support function: get the alloc ID by name.
11728fb79dbSBram Moolenaarfunction GetAllocId(name)
11828fb79dbSBram Moolenaar  exe 'split ' . s:srcdir . '/alloc.h'
119065ee9aeSBram Moolenaar  let top = search('typedef enum')
120065ee9aeSBram Moolenaar  if top == 0
121065ee9aeSBram Moolenaar    call add(v:errors, 'typedef not found in alloc.h')
122065ee9aeSBram Moolenaar  endif
12328fb79dbSBram Moolenaar  let lnum = search('aid_' . a:name . ',')
12428fb79dbSBram Moolenaar  if lnum == 0
12528fb79dbSBram Moolenaar    call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
12628fb79dbSBram Moolenaar  endif
12728fb79dbSBram Moolenaar  close
128065ee9aeSBram Moolenaar  return lnum - top - 1
12928fb79dbSBram Moolenaarendfunc
13028fb79dbSBram Moolenaar
13142205551SBram Moolenaarfunc RunTheTest(test)
132b5760a1cSBram Moolenaar  echo 'Executing ' . a:test
13375ee544fSBram Moolenaar  if has('reltime')
13475ee544fSBram Moolenaar    let func_start = reltime()
13575ee544fSBram Moolenaar  endif
136e5f2a075SBram Moolenaar
137e5f2a075SBram Moolenaar  " Avoid stopping at the "hit enter" prompt
138e5f2a075SBram Moolenaar  set nomore
139e5f2a075SBram Moolenaar
140e5f2a075SBram Moolenaar  " Avoid a three second wait when a message is about to be overwritten by the
141e5f2a075SBram Moolenaar  " mode message.
142e5f2a075SBram Moolenaar  set noshowmode
143e5f2a075SBram Moolenaar
144eb992cb9SBram Moolenaar  " Clear any overrides.
145eb992cb9SBram Moolenaar  call test_override('ALL', 0)
146eb992cb9SBram Moolenaar
147cf1ba35fSBram Moolenaar  " Some tests wipe out buffers.  To be consistent, always wipe out all
148cf1ba35fSBram Moolenaar  " buffers.
149cf1ba35fSBram Moolenaar  %bwipe!
150cf1ba35fSBram Moolenaar
151209d3874SBram Moolenaar  " The test may change the current directory. Save and restore the
152209d3874SBram Moolenaar  " directory after executing the test.
153209d3874SBram Moolenaar  let save_cwd = getcwd()
154209d3874SBram Moolenaar
155b5760a1cSBram Moolenaar  if exists("*SetUp")
156cc28e2d0SBram Moolenaar    try
157b5760a1cSBram Moolenaar      call SetUp()
158cc28e2d0SBram Moolenaar    catch
159cc28e2d0SBram Moolenaar      call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
160cc28e2d0SBram Moolenaar    endtry
161b5760a1cSBram Moolenaar  endif
162b5760a1cSBram Moolenaar
163f204e05aSBram Moolenaar  if a:test =~ 'Test_nocatch_'
164f204e05aSBram Moolenaar    " Function handles errors itself.  This avoids skipping commands after the
165f204e05aSBram Moolenaar    " error.
166f204e05aSBram Moolenaar    exe 'call ' . a:test
167f204e05aSBram Moolenaar  else
168b5760a1cSBram Moolenaar    try
169bfe13cccSBram Moolenaar      au VimLeavePre * call EarlyExit(g:testfunc)
170b5760a1cSBram Moolenaar      exe 'call ' . a:test
1718903676dSBram Moolenaar      au! VimLeavePre
172dac1947bSBram Moolenaar    catch /^\cskipped/
173dac1947bSBram Moolenaar      call add(s:messages, '    Skipped')
174dac1947bSBram Moolenaar      call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '',  ''))
175b5760a1cSBram Moolenaar    catch
176b5760a1cSBram Moolenaar      call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
177b5760a1cSBram Moolenaar    endtry
178f204e05aSBram Moolenaar  endif
1798ad16da7SBram Moolenaar
1808ad16da7SBram Moolenaar  " In case 'insertmode' was set and something went wrong, make sure it is
1818ad16da7SBram Moolenaar  " reset to avoid trouble with anything else.
1828ad16da7SBram Moolenaar  set noinsertmode
183b5760a1cSBram Moolenaar
184b5760a1cSBram Moolenaar  if exists("*TearDown")
185cc28e2d0SBram Moolenaar    try
186b5760a1cSBram Moolenaar      call TearDown()
187cc28e2d0SBram Moolenaar    catch
188cc28e2d0SBram Moolenaar      call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
189cc28e2d0SBram Moolenaar    endtry
190b5760a1cSBram Moolenaar  endif
1917cba71d7SBram Moolenaar
1920b5dc644SBram Moolenaar  " Clear any autocommands and put back the catch-all for SwapExists.
193cf1ba35fSBram Moolenaar  au!
194d8f27b30SBram Moolenaar  au SwapExists * call HandleSwapExists()
195cf1ba35fSBram Moolenaar
196ef6b979bSBram Moolenaar  " Check for and close any stray popup windows.
19705ad5ff0SBram Moolenaar  if has('popupwin')
198ef6b979bSBram Moolenaar    call assert_equal([], popup_list())
19903a9f848SBram Moolenaar    call popup_clear(1)
200ae943150SBram Moolenaar  endif
201ae943150SBram Moolenaar
202ce11de87SBram Moolenaar  " Close any extra tab pages and windows and make the current one not modified.
203ce11de87SBram Moolenaar  while tabpagenr('$') > 1
204cf1ba35fSBram Moolenaar    quit!
205ce11de87SBram Moolenaar  endwhile
206ce11de87SBram Moolenaar
207358308ddSBram Moolenaar  while 1
208358308ddSBram Moolenaar    let wincount = winnr('$')
209358308ddSBram Moolenaar    if wincount == 1
210358308ddSBram Moolenaar      break
211358308ddSBram Moolenaar    endif
2127cba71d7SBram Moolenaar    bwipe!
213358308ddSBram Moolenaar    if wincount == winnr('$')
214358308ddSBram Moolenaar      " Did not manage to close a window.
215358308ddSBram Moolenaar      only!
216358308ddSBram Moolenaar      break
217358308ddSBram Moolenaar    endif
2187cba71d7SBram Moolenaar  endwhile
219209d3874SBram Moolenaar
220209d3874SBram Moolenaar  exe 'cd ' . save_cwd
221640d4f0cSBram Moolenaar
222640d4f0cSBram Moolenaar  let message = 'Executed ' . a:test
223640d4f0cSBram Moolenaar  if has('reltime')
2248d943796SBram Moolenaar    let message ..= repeat(' ', 50 - len(message))
2258d943796SBram Moolenaar    let time = reltime(func_start)
2268d943796SBram Moolenaar    if has('float') && reltimefloat(time) > 0.1
2278d943796SBram Moolenaar      let message = &t_md .. message
2288d943796SBram Moolenaar    endif
2298d943796SBram Moolenaar    let message ..= ' in ' .. reltimestr(time) .. ' seconds'
2308d943796SBram Moolenaar    if has('float') && reltimefloat(time) > 0.1
2318d943796SBram Moolenaar      let message ..= &t_me
2328d943796SBram Moolenaar    endif
233640d4f0cSBram Moolenaar  endif
234640d4f0cSBram Moolenaar  call add(s:messages, message)
235640d4f0cSBram Moolenaar  let s:done += 1
236b5760a1cSBram Moolenaarendfunc
23728fb79dbSBram Moolenaar
238ce436de5SBram Moolenaarfunc AfterTheTest(func_name)
23943345546SBram Moolenaar  if len(v:errors) > 0
240ce436de5SBram Moolenaar    if match(s:may_fail_list, '^' .. a:func_name) >= 0
241ce436de5SBram Moolenaar      let s:fail_expected += 1
242bfe13cccSBram Moolenaar      call add(s:errors_expected, 'Found errors in ' . g:testfunc . ':')
243ce436de5SBram Moolenaar      call extend(s:errors_expected, v:errors)
244ce436de5SBram Moolenaar    else
24500af60bbSBram Moolenaar      let s:fail += 1
246bfe13cccSBram Moolenaar      call add(s:errors, 'Found errors in ' . g:testfunc . ':')
24700af60bbSBram Moolenaar      call extend(s:errors, v:errors)
248ce436de5SBram Moolenaar    endif
24943345546SBram Moolenaar    let v:errors = []
25043345546SBram Moolenaar  endif
25142205551SBram Moolenaarendfunc
25242205551SBram Moolenaar
2538903676dSBram Moolenaarfunc EarlyExit(test)
2548903676dSBram Moolenaar  " It's OK for the test we use to test the quit detection.
2558903676dSBram Moolenaar  if a:test != 'Test_zz_quit_detected()'
2568903676dSBram Moolenaar    call add(v:errors, 'Test caused Vim to exit: ' . a:test)
2578903676dSBram Moolenaar  endif
2588903676dSBram Moolenaar
2598903676dSBram Moolenaar  call FinishTesting()
2608903676dSBram Moolenaarendfunc
2618903676dSBram Moolenaar
26242205551SBram Moolenaar" This function can be called by a test if it wants to abort testing.
26342205551SBram Moolenaarfunc FinishTesting()
264ce436de5SBram Moolenaar  call AfterTheTest('')
26543345546SBram Moolenaar
266fc4ad616SBram Moolenaar  " Don't write viminfo on exit.
267fc4ad616SBram Moolenaar  set viminfo=
268fc4ad616SBram Moolenaar
269d1ee0043SBram Moolenaar  " Clean up files created by setup.vim
270d1ee0043SBram Moolenaar  call delete('XfakeHOME', 'rf')
271d1ee0043SBram Moolenaar
272ce436de5SBram Moolenaar  if s:fail == 0 && s:fail_expected == 0
27343345546SBram Moolenaar    " Success, create the .res file so that make knows it's done.
27400af60bbSBram Moolenaar    exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
27543345546SBram Moolenaar    write
27643345546SBram Moolenaar  endif
27743345546SBram Moolenaar
27800af60bbSBram Moolenaar  if len(s:errors) > 0
27943345546SBram Moolenaar    " Append errors to test.log
28043345546SBram Moolenaar    split test.log
28143345546SBram Moolenaar    call append(line('$'), '')
28200af60bbSBram Moolenaar    call append(line('$'), 'From ' . g:testname . ':')
28300af60bbSBram Moolenaar    call append(line('$'), s:errors)
28443345546SBram Moolenaar    write
28543345546SBram Moolenaar  endif
28643345546SBram Moolenaar
28729f9ed20SBram Moolenaar  if s:done == 0
2887b666c78SBram Moolenaar    if s:filtered > 0
2897b666c78SBram Moolenaar      let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'"
29029f9ed20SBram Moolenaar    else
2917b666c78SBram Moolenaar      let message = 'NO tests executed'
2927b666c78SBram Moolenaar    endif
2937b666c78SBram Moolenaar  else
2947b666c78SBram Moolenaar    if s:filtered > 0
2957b666c78SBram Moolenaar      call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER")
2967b666c78SBram Moolenaar    endif
29700af60bbSBram Moolenaar    let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
29829f9ed20SBram Moolenaar  endif
2997b666c78SBram Moolenaar  if s:done > 0 && has('reltime')
3008d943796SBram Moolenaar    let message = &t_md .. message .. repeat(' ', 40 - len(message))
30175ee544fSBram Moolenaar    let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds'
3028d943796SBram Moolenaar    let message ..= &t_me
30375ee544fSBram Moolenaar  endif
304096c8bb4SBram Moolenaar  echo message
30500af60bbSBram Moolenaar  call add(s:messages, message)
30600af60bbSBram Moolenaar  if s:fail > 0
30700af60bbSBram Moolenaar    let message = s:fail . ' FAILED:'
308096c8bb4SBram Moolenaar    echo message
30900af60bbSBram Moolenaar    call add(s:messages, message)
31000af60bbSBram Moolenaar    call extend(s:messages, s:errors)
31143345546SBram Moolenaar  endif
312ce436de5SBram Moolenaar  if s:fail_expected > 0
313ce436de5SBram Moolenaar    let message = s:fail_expected . ' FAILED (matching $TEST_MAY_FAIL):'
314ce436de5SBram Moolenaar    echo message
315ce436de5SBram Moolenaar    call add(s:messages, message)
316ce436de5SBram Moolenaar    call extend(s:messages, s:errors_expected)
317ce436de5SBram Moolenaar  endif
31843345546SBram Moolenaar
319dac1947bSBram Moolenaar  " Add SKIPPED messages
320dac1947bSBram Moolenaar  call extend(s:messages, s:skipped)
321dac1947bSBram Moolenaar
322dac1947bSBram Moolenaar  " Append messages to the file "messages"
323096c8bb4SBram Moolenaar  split messages
324096c8bb4SBram Moolenaar  call append(line('$'), '')
32500af60bbSBram Moolenaar  call append(line('$'), 'From ' . g:testname . ':')
32600af60bbSBram Moolenaar  call append(line('$'), s:messages)
327096c8bb4SBram Moolenaar  write
328096c8bb4SBram Moolenaar
32943345546SBram Moolenaar  qall!
33042205551SBram Moolenaarendfunc
33142205551SBram Moolenaar
33242205551SBram Moolenaar" Source the test script.  First grab the file name, in case the script
33342205551SBram Moolenaar" navigates away.  g:testname can be used by the tests.
33442205551SBram Moolenaarlet g:testname = expand('%')
33542205551SBram Moolenaarlet s:done = 0
33642205551SBram Moolenaarlet s:fail = 0
337ce436de5SBram Moolenaarlet s:fail_expected = 0
33842205551SBram Moolenaarlet s:errors = []
339ce436de5SBram Moolenaarlet s:errors_expected = []
34042205551SBram Moolenaarlet s:messages = []
34142205551SBram Moolenaarlet s:skipped = []
34242205551SBram Moolenaarif expand('%') =~ 'test_vimscript.vim'
343ce436de5SBram Moolenaar  " this test has intentional errors, don't use try/catch.
34442205551SBram Moolenaar  source %
34542205551SBram Moolenaarelse
34642205551SBram Moolenaar  try
34742205551SBram Moolenaar    source %
3489c0cec65SBram Moolenaar  catch /^\cskipped/
3499c0cec65SBram Moolenaar    call add(s:messages, '    Skipped')
3509c0cec65SBram Moolenaar    call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '',  ''))
35142205551SBram Moolenaar  catch
35242205551SBram Moolenaar    let s:fail += 1
35342205551SBram Moolenaar    call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
35442205551SBram Moolenaar  endtry
35542205551SBram Moolenaarendif
35642205551SBram Moolenaar
35742205551SBram Moolenaar" Names of flaky tests.
358dbc0d216SBram Moolenaarlet s:flaky_tests = [
3590d0c3ca0SBram Moolenaar      \ 'Test_autocmd_SafeState()',
36042205551SBram Moolenaar      \ 'Test_client_server()',
36142205551SBram Moolenaar      \ 'Test_close_and_exit_cb()',
362d80232beSBram Moolenaar      \ 'Test_close_output_buffer()',
36342205551SBram Moolenaar      \ 'Test_collapse_buffers()',
36465873846SBram Moolenaar      \ 'Test_cwd()',
365218959bcSBram Moolenaar      \ 'Test_diff_screen()',
36642205551SBram Moolenaar      \ 'Test_exit_callback_interval()',
367ea94c855SBram Moolenaar      \ 'Test_map_timeout_with_timer_interrupt()',
3681eca6f13SBram Moolenaar      \ 'Test_out_cb()',
36942205551SBram Moolenaar      \ 'Test_pipe_through_sort_all()',
37042205551SBram Moolenaar      \ 'Test_pipe_through_sort_some()',
37144f0bd87SBram Moolenaar      \ 'Test_popup_and_window_resize()',
37242205551SBram Moolenaar      \ 'Test_quoteplus()',
3737dd48506SBram Moolenaar      \ 'Test_quotestar()',
37442205551SBram Moolenaar      \ 'Test_reltime()',
3753c8cd4a1SBram Moolenaar      \ 'Test_state()',
376f204e05aSBram Moolenaar      \ 'Test_terminal_composing_unicode()',
3773876789bSBram Moolenaar      \ 'Test_terminal_does_not_truncate_last_newlines()',
3783615abb6SBram Moolenaar      \ 'Test_terminal_no_cmd()',
37975a60f74SBram Moolenaar      \ 'Test_terminal_noblock()',
3807dd88c51SBram Moolenaar      \ 'Test_terminal_redir_file()',
381e219f73eSBram Moolenaar      \ 'Test_termwinscroll()',
3829a2fddcfSBram Moolenaar      \ 'Test_timer_oneshot()',
3839a2fddcfSBram Moolenaar      \ 'Test_timer_paused()',
3849a2fddcfSBram Moolenaar      \ 'Test_timer_repeat_many()',
3859a2fddcfSBram Moolenaar      \ 'Test_timer_repeat_three()',
3869a2fddcfSBram Moolenaar      \ 'Test_timer_stop_all_in_callback()',
3879a2fddcfSBram Moolenaar      \ 'Test_timer_stop_in_callback()',
3889a2fddcfSBram Moolenaar      \ 'Test_timer_with_partial_callback()',
38942205551SBram Moolenaar      \ ]
39042205551SBram Moolenaar
39142205551SBram Moolenaar" Locate Test_ functions and execute them.
39242205551SBram Moolenaarredir @q
39342205551SBram Moolenaarsilent function /^Test_
39442205551SBram Moolenaarredir END
39561a6d4e4SBram Moolenaarlet s:tests = split(substitute(@q, '\(function\|def\) \(\k*()\)', '\2', 'g'))
39642205551SBram Moolenaar
39742205551SBram Moolenaar" If there is an extra argument filter the function names against it.
39842205551SBram Moolenaarif argc() > 1
39942205551SBram Moolenaar  let s:tests = filter(s:tests, 'v:val =~ argv(1)')
40042205551SBram Moolenaarendif
40142205551SBram Moolenaar
402a7f6c3cfSBram Moolenaar" If the environment variable $TEST_FILTER is set then filter the function
403a7f6c3cfSBram Moolenaar" names against it.
4047b666c78SBram Moolenaarlet s:filtered = 0
405a7f6c3cfSBram Moolenaarif $TEST_FILTER != ''
4067b666c78SBram Moolenaar  let s:filtered = len(s:tests)
407a7f6c3cfSBram Moolenaar  let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER')
4087b666c78SBram Moolenaar  let s:filtered -= len(s:tests)
409a7f6c3cfSBram Moolenaarendif
410a7f6c3cfSBram Moolenaar
411ce436de5SBram Moolenaarlet s:may_fail_list = []
412ce436de5SBram Moolenaarif $TEST_MAY_FAIL != ''
413bfe13cccSBram Moolenaar  " Split the list at commas and add () to make it match g:testfunc.
414ce436de5SBram Moolenaar  let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'})
415ce436de5SBram Moolenaarendif
416ce436de5SBram Moolenaar
41742205551SBram Moolenaar" Execute the tests in alphabetical order.
418bfe13cccSBram Moolenaarfor g:testfunc in sort(s:tests)
4194a6fcf80SBram Moolenaar  " Silence, please!
4204a6fcf80SBram Moolenaar  set belloff=all
421f77af0e6SBram Moolenaar  let prev_error = ''
422f77af0e6SBram Moolenaar  let total_errors = []
4233ed9efc2SBram Moolenaar  let g:run_nr = 1
4244a6fcf80SBram Moolenaar
425bfe13cccSBram Moolenaar  " A test can set g:test_is_flaky to retry running the test.
426bfe13cccSBram Moolenaar  let g:test_is_flaky = 0
4273cdcb090SBram Moolenaar
428bfe13cccSBram Moolenaar  call RunTheTest(g:testfunc)
42942205551SBram Moolenaar
430f77af0e6SBram Moolenaar  " Repeat a flaky test.  Give up when:
431f77af0e6SBram Moolenaar  " - it fails again with the same message
4321bc353b6SBram Moolenaar  " - it fails five times (with a different message)
433dbc0d216SBram Moolenaar  if len(v:errors) > 0
434bfe13cccSBram Moolenaar        \ && (index(s:flaky_tests, g:testfunc) >= 0
435bfe13cccSBram Moolenaar        \      || g:test_is_flaky)
436f77af0e6SBram Moolenaar    while 1
437bfe13cccSBram Moolenaar      call add(s:messages, 'Found errors in ' . g:testfunc . ':')
4386caf606bSBram Moolenaar      call extend(s:messages, v:errors)
43915e737f7SBram Moolenaar
4403ed9efc2SBram Moolenaar      call add(total_errors, 'Run ' . g:run_nr . ':')
441f77af0e6SBram Moolenaar      call extend(total_errors, v:errors)
442f77af0e6SBram Moolenaar
4433ed9efc2SBram Moolenaar      if g:run_nr == 5 || prev_error == v:errors[0]
444f77af0e6SBram Moolenaar        call add(total_errors, 'Flaky test failed too often, giving up')
445f77af0e6SBram Moolenaar        let v:errors = total_errors
446f77af0e6SBram Moolenaar        break
447f77af0e6SBram Moolenaar      endif
448f77af0e6SBram Moolenaar
449f77af0e6SBram Moolenaar      call add(s:messages, 'Flaky test failed, running it again')
450f77af0e6SBram Moolenaar
451f77af0e6SBram Moolenaar      " Flakiness is often caused by the system being very busy.  Sleep a
452f77af0e6SBram Moolenaar      " couple of seconds to have a higher chance of succeeding the second
453f77af0e6SBram Moolenaar      " time.
45455058601SBram Moolenaar      sleep 2
45555058601SBram Moolenaar
456f77af0e6SBram Moolenaar      let prev_error = v:errors[0]
45742205551SBram Moolenaar      let v:errors = []
4583ed9efc2SBram Moolenaar      let g:run_nr += 1
459f77af0e6SBram Moolenaar
460bfe13cccSBram Moolenaar      call RunTheTest(g:testfunc)
461f77af0e6SBram Moolenaar
462f77af0e6SBram Moolenaar      if len(v:errors) == 0
463f77af0e6SBram Moolenaar        " Test passed on rerun.
464f77af0e6SBram Moolenaar        break
46515e737f7SBram Moolenaar      endif
466f77af0e6SBram Moolenaar    endwhile
46742205551SBram Moolenaar  endif
46842205551SBram Moolenaar
469bfe13cccSBram Moolenaar  call AfterTheTest(g:testfunc)
47042205551SBram Moolenaarendfor
47142205551SBram Moolenaar
47242205551SBram Moolenaarcall FinishTesting()
473cc28e2d0SBram Moolenaar
474cc28e2d0SBram Moolenaar" vim: shiftwidth=2 sts=2 expandtab
475