xref: /vim-8.2.3635/src/testdir/runtest.vim (revision 776b9546)
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.
49b96a32efSBram Moolenaarsilent! while 0
50b96a32efSBram Moolenaar  qa!
51b96a32efSBram Moolenaarsilent! endwhile
5243345546SBram Moolenaar
5318aa13d1SBram Moolenaar" In the GUI we can always change the screen size.
5418aa13d1SBram Moolenaarif has('gui_running')
5518aa13d1SBram Moolenaar  set columns=80 lines=25
5618aa13d1SBram Moolenaarendif
5718aa13d1SBram Moolenaar
5843345546SBram Moolenaar" Check that the screen size is at least 24 x 80 characters.
5943345546SBram Moolenaarif &lines < 24 || &columns < 80
600b5dc644SBram Moolenaar  let error = 'Screen size too small! Tests require at least 24 lines with 80 characters, got ' .. &lines .. ' lines with ' .. &columns .. ' characters'
6143345546SBram Moolenaar  echoerr error
6243345546SBram Moolenaar  split test.log
6343345546SBram Moolenaar  $put =error
6445aa07d3SBram Moolenaar  write
6545aa07d3SBram Moolenaar  split messages
660b5dc644SBram Moolenaar  call append(line('$'), '')
670b5dc644SBram Moolenaar  call append(line('$'), 'From ' . expand('%') . ':')
6845aa07d3SBram Moolenaar  call append(line('$'), error)
6945aa07d3SBram Moolenaar  write
7045aa07d3SBram Moolenaar  qa!
7143345546SBram Moolenaarendif
7243345546SBram Moolenaar
7375ee544fSBram Moolenaarif has('reltime')
7475ee544fSBram Moolenaar  let s:start_time = reltime()
7575ee544fSBram Moolenaarendif
7675ee544fSBram Moolenaar
7789b10421SBram Moolenaar" Common with all tests on all systems.
7889b10421SBram Moolenaarsource setup.vim
7989b10421SBram Moolenaar
80c0662466SBram Moolenaar" For consistency run all tests with 'nocompatible' set.
81c0662466SBram Moolenaar" This also enables use of line continuation.
82c0662466SBram Moolenaarset nocp viminfo+=nviminfo
83c0662466SBram Moolenaar
8430276f2bSBram Moolenaar" Use utf-8 by default, instead of whatever the system default happens to be.
85ed79d1e3SBram Moolenaar" Individual tests can overrule this at the top of the file and use
86ed79d1e3SBram Moolenaar" g:orig_encoding if needed.
87ed79d1e3SBram Moolenaarlet g:orig_encoding = &encoding
88ac105ed3SBram Moolenaarset encoding=utf-8
89ac105ed3SBram Moolenaar
90d8f27b30SBram Moolenaar" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for
91d8f27b30SBram Moolenaar" the test_name.vim file itself. Replace it here with a more restrictive one,
92d8f27b30SBram Moolenaar" so we still catch mistakes.
93d8f27b30SBram Moolenaarlet s:test_script_fname = expand('%')
94d8f27b30SBram Moolenaarau! SwapExists * call HandleSwapExists()
95d8f27b30SBram Moolenaarfunc HandleSwapExists()
968ce4b7edSBram Moolenaar  if exists('g:ignoreSwapExists')
978ce4b7edSBram Moolenaar    return
988ce4b7edSBram Moolenaar  endif
99b073da89SBram Moolenaar  " Ignore finding a swap file for the test script (the user might be
100d8f27b30SBram Moolenaar  " editing it and do ":make test_name") and the output file.
101b073da89SBram Moolenaar  " Report finding another swap file and chose 'q' to avoid getting stuck.
102d8f27b30SBram Moolenaar  if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
103d8f27b30SBram Moolenaar    let v:swapchoice = 'e'
104b073da89SBram Moolenaar  else
105b073da89SBram Moolenaar    call assert_report('Unexpected swap file: ' .. v:swapname)
106b073da89SBram Moolenaar    let v:swapchoice = 'q'
107d8f27b30SBram Moolenaar  endif
108d8f27b30SBram Moolenaarendfunc
109d8f27b30SBram Moolenaar
1107a073549SBram Moolenaar" Avoid stopping at the "hit enter" prompt
1117a073549SBram Moolenaarset nomore
1127a073549SBram Moolenaar
113c0662466SBram Moolenaar" Output all messages in English.
114c0662466SBram Moolenaarlang mess C
115c0662466SBram Moolenaar
11610e1d01aSBram Moolenaar" suppress menu translation
11710e1d01aSBram Moolenaarif has('gui_running') && exists('did_install_default_menus')
11810e1d01aSBram Moolenaar  source $VIMRUNTIME/delmenu.vim
11910e1d01aSBram Moolenaar  set langmenu=none
12010e1d01aSBram Moolenaar  source $VIMRUNTIME/menu.vim
12110e1d01aSBram Moolenaarendif
12210e1d01aSBram Moolenaar
123f60b796fSBram Moolenaar" Always use forward slashes.
124f60b796fSBram Moolenaarset shellslash
125f60b796fSBram Moolenaar
12628fb79dbSBram Moolenaarlet s:srcdir = expand('%:p:h:h')
12728fb79dbSBram Moolenaar
1282690b5aeSBram Moolenaarif has('win32')
1292690b5aeSBram Moolenaar  " avoid prompt that is long or contains a line break
1302690b5aeSBram Moolenaar  let $PROMPT = '$P$G'
13145df2a01SBram Moolenaar  " On MS-Windows t_md and t_me are Vim specific escape sequences.
13245df2a01SBram Moolenaar  let s:t_bold = "\x1b[1m"
13345df2a01SBram Moolenaar  let s:t_normal = "\x1b[m"
13445df2a01SBram Moolenaarelse
13545df2a01SBram Moolenaar  let s:t_bold = &t_md
13645df2a01SBram Moolenaar  let s:t_normal = &t_me
1372690b5aeSBram Moolenaarendif
1382690b5aeSBram Moolenaar
1394b2ce129SBram Moolenaarif has('mac')
1404b2ce129SBram Moolenaar  " In MacOS, when starting a shell in a terminal, a bash deprecation warning
1414b2ce129SBram Moolenaar  " message is displayed. This breaks the terminal test. Disable the warning
1424b2ce129SBram Moolenaar  " message.
1434b2ce129SBram Moolenaar  let $BASH_SILENCE_DEPRECATION_WARNING = 1
1444b2ce129SBram Moolenaarendif
1454b2ce129SBram Moolenaar
1468e8df251SBram Moolenaar" Prepare for calling test_garbagecollect_now().
147ebf7dfa6SBram Moolenaarlet v:testing = 1
148ebf7dfa6SBram Moolenaar
14928fb79dbSBram Moolenaar" Support function: get the alloc ID by name.
15028fb79dbSBram Moolenaarfunction GetAllocId(name)
15128fb79dbSBram Moolenaar  exe 'split ' . s:srcdir . '/alloc.h'
152065ee9aeSBram Moolenaar  let top = search('typedef enum')
153065ee9aeSBram Moolenaar  if top == 0
154065ee9aeSBram Moolenaar    call add(v:errors, 'typedef not found in alloc.h')
155065ee9aeSBram Moolenaar  endif
15628fb79dbSBram Moolenaar  let lnum = search('aid_' . a:name . ',')
15728fb79dbSBram Moolenaar  if lnum == 0
15828fb79dbSBram Moolenaar    call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
15928fb79dbSBram Moolenaar  endif
16028fb79dbSBram Moolenaar  close
161065ee9aeSBram Moolenaar  return lnum - top - 1
16228fb79dbSBram Moolenaarendfunc
16328fb79dbSBram Moolenaar
16442205551SBram Moolenaarfunc RunTheTest(test)
165b5760a1cSBram Moolenaar  echo 'Executing ' . a:test
16675ee544fSBram Moolenaar  if has('reltime')
16775ee544fSBram Moolenaar    let func_start = reltime()
16875ee544fSBram Moolenaar  endif
169e5f2a075SBram Moolenaar
170e5f2a075SBram Moolenaar  " Avoid stopping at the "hit enter" prompt
171e5f2a075SBram Moolenaar  set nomore
172e5f2a075SBram Moolenaar
173e5f2a075SBram Moolenaar  " Avoid a three second wait when a message is about to be overwritten by the
174e5f2a075SBram Moolenaar  " mode message.
175e5f2a075SBram Moolenaar  set noshowmode
176e5f2a075SBram Moolenaar
177eb992cb9SBram Moolenaar  " Clear any overrides.
178eb992cb9SBram Moolenaar  call test_override('ALL', 0)
179eb992cb9SBram Moolenaar
180cf1ba35fSBram Moolenaar  " Some tests wipe out buffers.  To be consistent, always wipe out all
181cf1ba35fSBram Moolenaar  " buffers.
182cf1ba35fSBram Moolenaar  %bwipe!
183cf1ba35fSBram Moolenaar
184209d3874SBram Moolenaar  " The test may change the current directory. Save and restore the
185209d3874SBram Moolenaar  " directory after executing the test.
186209d3874SBram Moolenaar  let save_cwd = getcwd()
187209d3874SBram Moolenaar
188b5760a1cSBram Moolenaar  if exists("*SetUp")
189cc28e2d0SBram Moolenaar    try
190b5760a1cSBram Moolenaar      call SetUp()
191cc28e2d0SBram Moolenaar    catch
192cc28e2d0SBram Moolenaar      call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
193cc28e2d0SBram Moolenaar    endtry
194b5760a1cSBram Moolenaar  endif
195b5760a1cSBram Moolenaar
196f204e05aSBram Moolenaar  if a:test =~ 'Test_nocatch_'
197f204e05aSBram Moolenaar    " Function handles errors itself.  This avoids skipping commands after the
198f204e05aSBram Moolenaar    " error.
199*776b9546SBram Moolenaar    let g:skipped_reason = ''
200f204e05aSBram Moolenaar    exe 'call ' . a:test
201*776b9546SBram Moolenaar    if g:skipped_reason != ''
202*776b9546SBram Moolenaar      call add(s:messages, '    Skipped')
203*776b9546SBram Moolenaar      call add(s:skipped, 'SKIPPED ' . a:test . ': ' . g:skipped_reason)
204*776b9546SBram Moolenaar    endif
205f204e05aSBram Moolenaar  else
206b5760a1cSBram Moolenaar    try
207bfe13cccSBram Moolenaar      au VimLeavePre * call EarlyExit(g:testfunc)
208b5760a1cSBram Moolenaar      exe 'call ' . a:test
2098903676dSBram Moolenaar      au! VimLeavePre
210dac1947bSBram Moolenaar    catch /^\cskipped/
211dac1947bSBram Moolenaar      call add(s:messages, '    Skipped')
212dac1947bSBram Moolenaar      call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '',  ''))
213b5760a1cSBram Moolenaar    catch
214b5760a1cSBram Moolenaar      call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
215b5760a1cSBram Moolenaar    endtry
216f204e05aSBram Moolenaar  endif
2178ad16da7SBram Moolenaar
2188ad16da7SBram Moolenaar  " In case 'insertmode' was set and something went wrong, make sure it is
2198ad16da7SBram Moolenaar  " reset to avoid trouble with anything else.
2208ad16da7SBram Moolenaar  set noinsertmode
221b5760a1cSBram Moolenaar
222b5760a1cSBram Moolenaar  if exists("*TearDown")
223cc28e2d0SBram Moolenaar    try
224b5760a1cSBram Moolenaar      call TearDown()
225cc28e2d0SBram Moolenaar    catch
226cc28e2d0SBram Moolenaar      call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
227cc28e2d0SBram Moolenaar    endtry
228b5760a1cSBram Moolenaar  endif
2297cba71d7SBram Moolenaar
2300b5dc644SBram Moolenaar  " Clear any autocommands and put back the catch-all for SwapExists.
231cf1ba35fSBram Moolenaar  au!
232d8f27b30SBram Moolenaar  au SwapExists * call HandleSwapExists()
233cf1ba35fSBram Moolenaar
234ef6b979bSBram Moolenaar  " Check for and close any stray popup windows.
23505ad5ff0SBram Moolenaar  if has('popupwin')
236ef6b979bSBram Moolenaar    call assert_equal([], popup_list())
23703a9f848SBram Moolenaar    call popup_clear(1)
238ae943150SBram Moolenaar  endif
239ae943150SBram Moolenaar
240ce11de87SBram Moolenaar  " Close any extra tab pages and windows and make the current one not modified.
241ce11de87SBram Moolenaar  while tabpagenr('$') > 1
242bdf931c2SBram Moolenaar    let winid = win_getid()
243cf1ba35fSBram Moolenaar    quit!
244bdf931c2SBram Moolenaar    if winid == win_getid()
245bdf931c2SBram Moolenaar      echoerr 'Could not quit window'
246bdf931c2SBram Moolenaar      break
247bdf931c2SBram Moolenaar    endif
248ce11de87SBram Moolenaar  endwhile
249ce11de87SBram Moolenaar
250358308ddSBram Moolenaar  while 1
251358308ddSBram Moolenaar    let wincount = winnr('$')
252358308ddSBram Moolenaar    if wincount == 1
253358308ddSBram Moolenaar      break
254358308ddSBram Moolenaar    endif
2557cba71d7SBram Moolenaar    bwipe!
256358308ddSBram Moolenaar    if wincount == winnr('$')
257358308ddSBram Moolenaar      " Did not manage to close a window.
258358308ddSBram Moolenaar      only!
259358308ddSBram Moolenaar      break
260358308ddSBram Moolenaar    endif
2617cba71d7SBram Moolenaar  endwhile
262209d3874SBram Moolenaar
263209d3874SBram Moolenaar  exe 'cd ' . save_cwd
264640d4f0cSBram Moolenaar
265640d4f0cSBram Moolenaar  let message = 'Executed ' . a:test
266640d4f0cSBram Moolenaar  if has('reltime')
2678d943796SBram Moolenaar    let message ..= repeat(' ', 50 - len(message))
2688d943796SBram Moolenaar    let time = reltime(func_start)
2698d943796SBram Moolenaar    if has('float') && reltimefloat(time) > 0.1
27045df2a01SBram Moolenaar      let message = s:t_bold .. message
2718d943796SBram Moolenaar    endif
2728d943796SBram Moolenaar    let message ..= ' in ' .. reltimestr(time) .. ' seconds'
2738d943796SBram Moolenaar    if has('float') && reltimefloat(time) > 0.1
27445df2a01SBram Moolenaar      let message ..= s:t_normal
2758d943796SBram Moolenaar    endif
276640d4f0cSBram Moolenaar  endif
277640d4f0cSBram Moolenaar  call add(s:messages, message)
278640d4f0cSBram Moolenaar  let s:done += 1
279b5760a1cSBram Moolenaarendfunc
28028fb79dbSBram Moolenaar
281ce436de5SBram Moolenaarfunc AfterTheTest(func_name)
28243345546SBram Moolenaar  if len(v:errors) > 0
283ce436de5SBram Moolenaar    if match(s:may_fail_list, '^' .. a:func_name) >= 0
284ce436de5SBram Moolenaar      let s:fail_expected += 1
285bfe13cccSBram Moolenaar      call add(s:errors_expected, 'Found errors in ' . g:testfunc . ':')
286ce436de5SBram Moolenaar      call extend(s:errors_expected, v:errors)
287ce436de5SBram Moolenaar    else
28800af60bbSBram Moolenaar      let s:fail += 1
289bfe13cccSBram Moolenaar      call add(s:errors, 'Found errors in ' . g:testfunc . ':')
29000af60bbSBram Moolenaar      call extend(s:errors, v:errors)
291ce436de5SBram Moolenaar    endif
29243345546SBram Moolenaar    let v:errors = []
29343345546SBram Moolenaar  endif
29442205551SBram Moolenaarendfunc
29542205551SBram Moolenaar
2968903676dSBram Moolenaarfunc EarlyExit(test)
2978903676dSBram Moolenaar  " It's OK for the test we use to test the quit detection.
2988903676dSBram Moolenaar  if a:test != 'Test_zz_quit_detected()'
2998903676dSBram Moolenaar    call add(v:errors, 'Test caused Vim to exit: ' . a:test)
3008903676dSBram Moolenaar  endif
3018903676dSBram Moolenaar
3028903676dSBram Moolenaar  call FinishTesting()
3038903676dSBram Moolenaarendfunc
3048903676dSBram Moolenaar
30542205551SBram Moolenaar" This function can be called by a test if it wants to abort testing.
30642205551SBram Moolenaarfunc FinishTesting()
307ce436de5SBram Moolenaar  call AfterTheTest('')
30843345546SBram Moolenaar
309fc4ad616SBram Moolenaar  " Don't write viminfo on exit.
310fc4ad616SBram Moolenaar  set viminfo=
311fc4ad616SBram Moolenaar
312d1ee0043SBram Moolenaar  " Clean up files created by setup.vim
313d1ee0043SBram Moolenaar  call delete('XfakeHOME', 'rf')
314d1ee0043SBram Moolenaar
315ce436de5SBram Moolenaar  if s:fail == 0 && s:fail_expected == 0
31643345546SBram Moolenaar    " Success, create the .res file so that make knows it's done.
31700af60bbSBram Moolenaar    exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
31843345546SBram Moolenaar    write
31943345546SBram Moolenaar  endif
32043345546SBram Moolenaar
32100af60bbSBram Moolenaar  if len(s:errors) > 0
32243345546SBram Moolenaar    " Append errors to test.log
32343345546SBram Moolenaar    split test.log
32443345546SBram Moolenaar    call append(line('$'), '')
32500af60bbSBram Moolenaar    call append(line('$'), 'From ' . g:testname . ':')
32600af60bbSBram Moolenaar    call append(line('$'), s:errors)
32743345546SBram Moolenaar    write
32843345546SBram Moolenaar  endif
32943345546SBram Moolenaar
33029f9ed20SBram Moolenaar  if s:done == 0
3317b666c78SBram Moolenaar    if s:filtered > 0
3327b666c78SBram Moolenaar      let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'"
33329f9ed20SBram Moolenaar    else
3347b666c78SBram Moolenaar      let message = 'NO tests executed'
3357b666c78SBram Moolenaar    endif
3367b666c78SBram Moolenaar  else
3377b666c78SBram Moolenaar    if s:filtered > 0
3387b666c78SBram Moolenaar      call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER")
3397b666c78SBram Moolenaar    endif
34000af60bbSBram Moolenaar    let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
34129f9ed20SBram Moolenaar  endif
3427b666c78SBram Moolenaar  if s:done > 0 && has('reltime')
34345df2a01SBram Moolenaar    let message = s:t_bold .. message .. repeat(' ', 40 - len(message))
34475ee544fSBram Moolenaar    let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds'
34545df2a01SBram Moolenaar    let message ..= s:t_normal
34675ee544fSBram Moolenaar  endif
347096c8bb4SBram Moolenaar  echo message
34800af60bbSBram Moolenaar  call add(s:messages, message)
34900af60bbSBram Moolenaar  if s:fail > 0
35000af60bbSBram Moolenaar    let message = s:fail . ' FAILED:'
351096c8bb4SBram Moolenaar    echo message
35200af60bbSBram Moolenaar    call add(s:messages, message)
35300af60bbSBram Moolenaar    call extend(s:messages, s:errors)
35443345546SBram Moolenaar  endif
355ce436de5SBram Moolenaar  if s:fail_expected > 0
356ce436de5SBram Moolenaar    let message = s:fail_expected . ' FAILED (matching $TEST_MAY_FAIL):'
357ce436de5SBram Moolenaar    echo message
358ce436de5SBram Moolenaar    call add(s:messages, message)
359ce436de5SBram Moolenaar    call extend(s:messages, s:errors_expected)
360ce436de5SBram Moolenaar  endif
36143345546SBram Moolenaar
362dac1947bSBram Moolenaar  " Add SKIPPED messages
363dac1947bSBram Moolenaar  call extend(s:messages, s:skipped)
364dac1947bSBram Moolenaar
365dac1947bSBram Moolenaar  " Append messages to the file "messages"
366096c8bb4SBram Moolenaar  split messages
367096c8bb4SBram Moolenaar  call append(line('$'), '')
36800af60bbSBram Moolenaar  call append(line('$'), 'From ' . g:testname . ':')
36900af60bbSBram Moolenaar  call append(line('$'), s:messages)
370096c8bb4SBram Moolenaar  write
371096c8bb4SBram Moolenaar
37243345546SBram Moolenaar  qall!
37342205551SBram Moolenaarendfunc
37442205551SBram Moolenaar
37542205551SBram Moolenaar" Source the test script.  First grab the file name, in case the script
37642205551SBram Moolenaar" navigates away.  g:testname can be used by the tests.
37742205551SBram Moolenaarlet g:testname = expand('%')
37842205551SBram Moolenaarlet s:done = 0
37942205551SBram Moolenaarlet s:fail = 0
380ce436de5SBram Moolenaarlet s:fail_expected = 0
38142205551SBram Moolenaarlet s:errors = []
382ce436de5SBram Moolenaarlet s:errors_expected = []
38342205551SBram Moolenaarlet s:messages = []
38442205551SBram Moolenaarlet s:skipped = []
38542205551SBram Moolenaarif expand('%') =~ 'test_vimscript.vim'
386ce436de5SBram Moolenaar  " this test has intentional errors, don't use try/catch.
38742205551SBram Moolenaar  source %
38842205551SBram Moolenaarelse
38942205551SBram Moolenaar  try
39042205551SBram Moolenaar    source %
3919c0cec65SBram Moolenaar  catch /^\cskipped/
3929c0cec65SBram Moolenaar    call add(s:messages, '    Skipped')
3939c0cec65SBram Moolenaar    call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '',  ''))
39442205551SBram Moolenaar  catch
39542205551SBram Moolenaar    let s:fail += 1
39642205551SBram Moolenaar    call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
39742205551SBram Moolenaar  endtry
39842205551SBram Moolenaarendif
39942205551SBram Moolenaar
40042205551SBram Moolenaar" Names of flaky tests.
401dbc0d216SBram Moolenaarlet s:flaky_tests = [
4027d697960SBram Moolenaar      \ 'Test_BufWrite_lockmarks()',
4030d0c3ca0SBram Moolenaar      \ 'Test_autocmd_SafeState()',
4047d697960SBram Moolenaar      \ 'Test_bufunload_all()',
40542205551SBram Moolenaar      \ 'Test_client_server()',
40642205551SBram Moolenaar      \ 'Test_close_and_exit_cb()',
407d80232beSBram Moolenaar      \ 'Test_close_output_buffer()',
40842205551SBram Moolenaar      \ 'Test_collapse_buffers()',
40965873846SBram Moolenaar      \ 'Test_cwd()',
410218959bcSBram Moolenaar      \ 'Test_diff_screen()',
41142205551SBram Moolenaar      \ 'Test_exit_callback_interval()',
412ea94c855SBram Moolenaar      \ 'Test_map_timeout_with_timer_interrupt()',
4131eca6f13SBram Moolenaar      \ 'Test_out_cb()',
41442205551SBram Moolenaar      \ 'Test_pipe_through_sort_all()',
41542205551SBram Moolenaar      \ 'Test_pipe_through_sort_some()',
41644f0bd87SBram Moolenaar      \ 'Test_popup_and_window_resize()',
41742205551SBram Moolenaar      \ 'Test_quoteplus()',
4187dd48506SBram Moolenaar      \ 'Test_quotestar()',
41942205551SBram Moolenaar      \ 'Test_reltime()',
4203c8cd4a1SBram Moolenaar      \ 'Test_state()',
421f204e05aSBram Moolenaar      \ 'Test_terminal_composing_unicode()',
4223876789bSBram Moolenaar      \ 'Test_terminal_does_not_truncate_last_newlines()',
4233615abb6SBram Moolenaar      \ 'Test_terminal_no_cmd()',
42475a60f74SBram Moolenaar      \ 'Test_terminal_noblock()',
4257dd88c51SBram Moolenaar      \ 'Test_terminal_redir_file()',
426e219f73eSBram Moolenaar      \ 'Test_termwinscroll()',
4279a2fddcfSBram Moolenaar      \ 'Test_timer_oneshot()',
4289a2fddcfSBram Moolenaar      \ 'Test_timer_paused()',
4299a2fddcfSBram Moolenaar      \ 'Test_timer_repeat_many()',
4309a2fddcfSBram Moolenaar      \ 'Test_timer_repeat_three()',
4319a2fddcfSBram Moolenaar      \ 'Test_timer_stop_all_in_callback()',
4329a2fddcfSBram Moolenaar      \ 'Test_timer_stop_in_callback()',
4339a2fddcfSBram Moolenaar      \ 'Test_timer_with_partial_callback()',
43442205551SBram Moolenaar      \ ]
43542205551SBram Moolenaar
43642205551SBram Moolenaar" Locate Test_ functions and execute them.
43742205551SBram Moolenaarredir @q
43842205551SBram Moolenaarsilent function /^Test_
43942205551SBram Moolenaarredir END
44061a6d4e4SBram Moolenaarlet s:tests = split(substitute(@q, '\(function\|def\) \(\k*()\)', '\2', 'g'))
44142205551SBram Moolenaar
44242205551SBram Moolenaar" If there is an extra argument filter the function names against it.
44342205551SBram Moolenaarif argc() > 1
44442205551SBram Moolenaar  let s:tests = filter(s:tests, 'v:val =~ argv(1)')
44542205551SBram Moolenaarendif
44642205551SBram Moolenaar
447a7f6c3cfSBram Moolenaar" If the environment variable $TEST_FILTER is set then filter the function
448a7f6c3cfSBram Moolenaar" names against it.
4497b666c78SBram Moolenaarlet s:filtered = 0
450a7f6c3cfSBram Moolenaarif $TEST_FILTER != ''
4517b666c78SBram Moolenaar  let s:filtered = len(s:tests)
452a7f6c3cfSBram Moolenaar  let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER')
4537b666c78SBram Moolenaar  let s:filtered -= len(s:tests)
454a7f6c3cfSBram Moolenaarendif
455a7f6c3cfSBram Moolenaar
456ce436de5SBram Moolenaarlet s:may_fail_list = []
457ce436de5SBram Moolenaarif $TEST_MAY_FAIL != ''
458bfe13cccSBram Moolenaar  " Split the list at commas and add () to make it match g:testfunc.
459ce436de5SBram Moolenaar  let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'})
460ce436de5SBram Moolenaarendif
461ce436de5SBram Moolenaar
46242205551SBram Moolenaar" Execute the tests in alphabetical order.
463bfe13cccSBram Moolenaarfor g:testfunc in sort(s:tests)
4644a6fcf80SBram Moolenaar  " Silence, please!
4654a6fcf80SBram Moolenaar  set belloff=all
466f77af0e6SBram Moolenaar  let prev_error = ''
467f77af0e6SBram Moolenaar  let total_errors = []
4683ed9efc2SBram Moolenaar  let g:run_nr = 1
4694a6fcf80SBram Moolenaar
470bfe13cccSBram Moolenaar  " A test can set g:test_is_flaky to retry running the test.
471bfe13cccSBram Moolenaar  let g:test_is_flaky = 0
4723cdcb090SBram Moolenaar
473bfe13cccSBram Moolenaar  call RunTheTest(g:testfunc)
47442205551SBram Moolenaar
475f77af0e6SBram Moolenaar  " Repeat a flaky test.  Give up when:
4766ca6ca48SBram Moolenaar  " - $TEST_NO_RETRY is not empty
477f77af0e6SBram Moolenaar  " - it fails again with the same message
4781bc353b6SBram Moolenaar  " - it fails five times (with a different message)
479dbc0d216SBram Moolenaar  if len(v:errors) > 0
480622b3568SBram Moolenaar        \ && $TEST_NO_RETRY == ''
481bfe13cccSBram Moolenaar        \ && (index(s:flaky_tests, g:testfunc) >= 0
482bfe13cccSBram Moolenaar        \      || g:test_is_flaky)
483f77af0e6SBram Moolenaar    while 1
484bfe13cccSBram Moolenaar      call add(s:messages, 'Found errors in ' . g:testfunc . ':')
4856caf606bSBram Moolenaar      call extend(s:messages, v:errors)
48615e737f7SBram Moolenaar
4873ed9efc2SBram Moolenaar      call add(total_errors, 'Run ' . g:run_nr . ':')
488f77af0e6SBram Moolenaar      call extend(total_errors, v:errors)
489f77af0e6SBram Moolenaar
4903ed9efc2SBram Moolenaar      if g:run_nr == 5 || prev_error == v:errors[0]
491f77af0e6SBram Moolenaar        call add(total_errors, 'Flaky test failed too often, giving up')
492f77af0e6SBram Moolenaar        let v:errors = total_errors
493f77af0e6SBram Moolenaar        break
494f77af0e6SBram Moolenaar      endif
495f77af0e6SBram Moolenaar
496f77af0e6SBram Moolenaar      call add(s:messages, 'Flaky test failed, running it again')
497f77af0e6SBram Moolenaar
498f77af0e6SBram Moolenaar      " Flakiness is often caused by the system being very busy.  Sleep a
499f77af0e6SBram Moolenaar      " couple of seconds to have a higher chance of succeeding the second
500f77af0e6SBram Moolenaar      " time.
50155058601SBram Moolenaar      sleep 2
50255058601SBram Moolenaar
503f77af0e6SBram Moolenaar      let prev_error = v:errors[0]
50442205551SBram Moolenaar      let v:errors = []
5053ed9efc2SBram Moolenaar      let g:run_nr += 1
506f77af0e6SBram Moolenaar
507bfe13cccSBram Moolenaar      call RunTheTest(g:testfunc)
508f77af0e6SBram Moolenaar
509f77af0e6SBram Moolenaar      if len(v:errors) == 0
510f77af0e6SBram Moolenaar        " Test passed on rerun.
511f77af0e6SBram Moolenaar        break
51215e737f7SBram Moolenaar      endif
513f77af0e6SBram Moolenaar    endwhile
51442205551SBram Moolenaar  endif
51542205551SBram Moolenaar
516bfe13cccSBram Moolenaar  call AfterTheTest(g:testfunc)
51742205551SBram Moolenaarendfor
51842205551SBram Moolenaar
51942205551SBram Moolenaarcall FinishTesting()
520cc28e2d0SBram Moolenaar
521cc28e2d0SBram Moolenaar" vim: shiftwidth=2 sts=2 expandtab
522