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 139*4b2ce129SBram Moolenaarif has('mac') 140*4b2ce129SBram Moolenaar " In MacOS, when starting a shell in a terminal, a bash deprecation warning 141*4b2ce129SBram Moolenaar " message is displayed. This breaks the terminal test. Disable the warning 142*4b2ce129SBram Moolenaar " message. 143*4b2ce129SBram Moolenaar let $BASH_SILENCE_DEPRECATION_WARNING = 1 144*4b2ce129SBram Moolenaarendif 145*4b2ce129SBram 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. 199f204e05aSBram Moolenaar exe 'call ' . a:test 200f204e05aSBram Moolenaar else 201b5760a1cSBram Moolenaar try 202bfe13cccSBram Moolenaar au VimLeavePre * call EarlyExit(g:testfunc) 203b5760a1cSBram Moolenaar exe 'call ' . a:test 2048903676dSBram Moolenaar au! VimLeavePre 205dac1947bSBram Moolenaar catch /^\cskipped/ 206dac1947bSBram Moolenaar call add(s:messages, ' Skipped') 207dac1947bSBram Moolenaar call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', '')) 208b5760a1cSBram Moolenaar catch 209b5760a1cSBram Moolenaar call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint) 210b5760a1cSBram Moolenaar endtry 211f204e05aSBram Moolenaar endif 2128ad16da7SBram Moolenaar 2138ad16da7SBram Moolenaar " In case 'insertmode' was set and something went wrong, make sure it is 2148ad16da7SBram Moolenaar " reset to avoid trouble with anything else. 2158ad16da7SBram Moolenaar set noinsertmode 216b5760a1cSBram Moolenaar 217b5760a1cSBram Moolenaar if exists("*TearDown") 218cc28e2d0SBram Moolenaar try 219b5760a1cSBram Moolenaar call TearDown() 220cc28e2d0SBram Moolenaar catch 221cc28e2d0SBram Moolenaar call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint) 222cc28e2d0SBram Moolenaar endtry 223b5760a1cSBram Moolenaar endif 2247cba71d7SBram Moolenaar 2250b5dc644SBram Moolenaar " Clear any autocommands and put back the catch-all for SwapExists. 226cf1ba35fSBram Moolenaar au! 227d8f27b30SBram Moolenaar au SwapExists * call HandleSwapExists() 228cf1ba35fSBram Moolenaar 229ef6b979bSBram Moolenaar " Check for and close any stray popup windows. 23005ad5ff0SBram Moolenaar if has('popupwin') 231ef6b979bSBram Moolenaar call assert_equal([], popup_list()) 23203a9f848SBram Moolenaar call popup_clear(1) 233ae943150SBram Moolenaar endif 234ae943150SBram Moolenaar 235ce11de87SBram Moolenaar " Close any extra tab pages and windows and make the current one not modified. 236ce11de87SBram Moolenaar while tabpagenr('$') > 1 237bdf931c2SBram Moolenaar let winid = win_getid() 238cf1ba35fSBram Moolenaar quit! 239bdf931c2SBram Moolenaar if winid == win_getid() 240bdf931c2SBram Moolenaar echoerr 'Could not quit window' 241bdf931c2SBram Moolenaar break 242bdf931c2SBram Moolenaar endif 243ce11de87SBram Moolenaar endwhile 244ce11de87SBram Moolenaar 245358308ddSBram Moolenaar while 1 246358308ddSBram Moolenaar let wincount = winnr('$') 247358308ddSBram Moolenaar if wincount == 1 248358308ddSBram Moolenaar break 249358308ddSBram Moolenaar endif 2507cba71d7SBram Moolenaar bwipe! 251358308ddSBram Moolenaar if wincount == winnr('$') 252358308ddSBram Moolenaar " Did not manage to close a window. 253358308ddSBram Moolenaar only! 254358308ddSBram Moolenaar break 255358308ddSBram Moolenaar endif 2567cba71d7SBram Moolenaar endwhile 257209d3874SBram Moolenaar 258209d3874SBram Moolenaar exe 'cd ' . save_cwd 259640d4f0cSBram Moolenaar 260640d4f0cSBram Moolenaar let message = 'Executed ' . a:test 261640d4f0cSBram Moolenaar if has('reltime') 2628d943796SBram Moolenaar let message ..= repeat(' ', 50 - len(message)) 2638d943796SBram Moolenaar let time = reltime(func_start) 2648d943796SBram Moolenaar if has('float') && reltimefloat(time) > 0.1 26545df2a01SBram Moolenaar let message = s:t_bold .. message 2668d943796SBram Moolenaar endif 2678d943796SBram Moolenaar let message ..= ' in ' .. reltimestr(time) .. ' seconds' 2688d943796SBram Moolenaar if has('float') && reltimefloat(time) > 0.1 26945df2a01SBram Moolenaar let message ..= s:t_normal 2708d943796SBram Moolenaar endif 271640d4f0cSBram Moolenaar endif 272640d4f0cSBram Moolenaar call add(s:messages, message) 273640d4f0cSBram Moolenaar let s:done += 1 274b5760a1cSBram Moolenaarendfunc 27528fb79dbSBram Moolenaar 276ce436de5SBram Moolenaarfunc AfterTheTest(func_name) 27743345546SBram Moolenaar if len(v:errors) > 0 278ce436de5SBram Moolenaar if match(s:may_fail_list, '^' .. a:func_name) >= 0 279ce436de5SBram Moolenaar let s:fail_expected += 1 280bfe13cccSBram Moolenaar call add(s:errors_expected, 'Found errors in ' . g:testfunc . ':') 281ce436de5SBram Moolenaar call extend(s:errors_expected, v:errors) 282ce436de5SBram Moolenaar else 28300af60bbSBram Moolenaar let s:fail += 1 284bfe13cccSBram Moolenaar call add(s:errors, 'Found errors in ' . g:testfunc . ':') 28500af60bbSBram Moolenaar call extend(s:errors, v:errors) 286ce436de5SBram Moolenaar endif 28743345546SBram Moolenaar let v:errors = [] 28843345546SBram Moolenaar endif 28942205551SBram Moolenaarendfunc 29042205551SBram Moolenaar 2918903676dSBram Moolenaarfunc EarlyExit(test) 2928903676dSBram Moolenaar " It's OK for the test we use to test the quit detection. 2938903676dSBram Moolenaar if a:test != 'Test_zz_quit_detected()' 2948903676dSBram Moolenaar call add(v:errors, 'Test caused Vim to exit: ' . a:test) 2958903676dSBram Moolenaar endif 2968903676dSBram Moolenaar 2978903676dSBram Moolenaar call FinishTesting() 2988903676dSBram Moolenaarendfunc 2998903676dSBram Moolenaar 30042205551SBram Moolenaar" This function can be called by a test if it wants to abort testing. 30142205551SBram Moolenaarfunc FinishTesting() 302ce436de5SBram Moolenaar call AfterTheTest('') 30343345546SBram Moolenaar 304fc4ad616SBram Moolenaar " Don't write viminfo on exit. 305fc4ad616SBram Moolenaar set viminfo= 306fc4ad616SBram Moolenaar 307d1ee0043SBram Moolenaar " Clean up files created by setup.vim 308d1ee0043SBram Moolenaar call delete('XfakeHOME', 'rf') 309d1ee0043SBram Moolenaar 310ce436de5SBram Moolenaar if s:fail == 0 && s:fail_expected == 0 31143345546SBram Moolenaar " Success, create the .res file so that make knows it's done. 31200af60bbSBram Moolenaar exe 'split ' . fnamemodify(g:testname, ':r') . '.res' 31343345546SBram Moolenaar write 31443345546SBram Moolenaar endif 31543345546SBram Moolenaar 31600af60bbSBram Moolenaar if len(s:errors) > 0 31743345546SBram Moolenaar " Append errors to test.log 31843345546SBram Moolenaar split test.log 31943345546SBram Moolenaar call append(line('$'), '') 32000af60bbSBram Moolenaar call append(line('$'), 'From ' . g:testname . ':') 32100af60bbSBram Moolenaar call append(line('$'), s:errors) 32243345546SBram Moolenaar write 32343345546SBram Moolenaar endif 32443345546SBram Moolenaar 32529f9ed20SBram Moolenaar if s:done == 0 3267b666c78SBram Moolenaar if s:filtered > 0 3277b666c78SBram Moolenaar let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'" 32829f9ed20SBram Moolenaar else 3297b666c78SBram Moolenaar let message = 'NO tests executed' 3307b666c78SBram Moolenaar endif 3317b666c78SBram Moolenaar else 3327b666c78SBram Moolenaar if s:filtered > 0 3337b666c78SBram Moolenaar call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER") 3347b666c78SBram Moolenaar endif 33500af60bbSBram Moolenaar let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test') 33629f9ed20SBram Moolenaar endif 3377b666c78SBram Moolenaar if s:done > 0 && has('reltime') 33845df2a01SBram Moolenaar let message = s:t_bold .. message .. repeat(' ', 40 - len(message)) 33975ee544fSBram Moolenaar let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds' 34045df2a01SBram Moolenaar let message ..= s:t_normal 34175ee544fSBram Moolenaar endif 342096c8bb4SBram Moolenaar echo message 34300af60bbSBram Moolenaar call add(s:messages, message) 34400af60bbSBram Moolenaar if s:fail > 0 34500af60bbSBram Moolenaar let message = s:fail . ' FAILED:' 346096c8bb4SBram Moolenaar echo message 34700af60bbSBram Moolenaar call add(s:messages, message) 34800af60bbSBram Moolenaar call extend(s:messages, s:errors) 34943345546SBram Moolenaar endif 350ce436de5SBram Moolenaar if s:fail_expected > 0 351ce436de5SBram Moolenaar let message = s:fail_expected . ' FAILED (matching $TEST_MAY_FAIL):' 352ce436de5SBram Moolenaar echo message 353ce436de5SBram Moolenaar call add(s:messages, message) 354ce436de5SBram Moolenaar call extend(s:messages, s:errors_expected) 355ce436de5SBram Moolenaar endif 35643345546SBram Moolenaar 357dac1947bSBram Moolenaar " Add SKIPPED messages 358dac1947bSBram Moolenaar call extend(s:messages, s:skipped) 359dac1947bSBram Moolenaar 360dac1947bSBram Moolenaar " Append messages to the file "messages" 361096c8bb4SBram Moolenaar split messages 362096c8bb4SBram Moolenaar call append(line('$'), '') 36300af60bbSBram Moolenaar call append(line('$'), 'From ' . g:testname . ':') 36400af60bbSBram Moolenaar call append(line('$'), s:messages) 365096c8bb4SBram Moolenaar write 366096c8bb4SBram Moolenaar 36743345546SBram Moolenaar qall! 36842205551SBram Moolenaarendfunc 36942205551SBram Moolenaar 37042205551SBram Moolenaar" Source the test script. First grab the file name, in case the script 37142205551SBram Moolenaar" navigates away. g:testname can be used by the tests. 37242205551SBram Moolenaarlet g:testname = expand('%') 37342205551SBram Moolenaarlet s:done = 0 37442205551SBram Moolenaarlet s:fail = 0 375ce436de5SBram Moolenaarlet s:fail_expected = 0 37642205551SBram Moolenaarlet s:errors = [] 377ce436de5SBram Moolenaarlet s:errors_expected = [] 37842205551SBram Moolenaarlet s:messages = [] 37942205551SBram Moolenaarlet s:skipped = [] 38042205551SBram Moolenaarif expand('%') =~ 'test_vimscript.vim' 381ce436de5SBram Moolenaar " this test has intentional errors, don't use try/catch. 38242205551SBram Moolenaar source % 38342205551SBram Moolenaarelse 38442205551SBram Moolenaar try 38542205551SBram Moolenaar source % 3869c0cec65SBram Moolenaar catch /^\cskipped/ 3879c0cec65SBram Moolenaar call add(s:messages, ' Skipped') 3889c0cec65SBram Moolenaar call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '', '')) 38942205551SBram Moolenaar catch 39042205551SBram Moolenaar let s:fail += 1 39142205551SBram Moolenaar call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint) 39242205551SBram Moolenaar endtry 39342205551SBram Moolenaarendif 39442205551SBram Moolenaar 39542205551SBram Moolenaar" Names of flaky tests. 396dbc0d216SBram Moolenaarlet s:flaky_tests = [ 3977d697960SBram Moolenaar \ 'Test_BufWrite_lockmarks()', 3980d0c3ca0SBram Moolenaar \ 'Test_autocmd_SafeState()', 3997d697960SBram Moolenaar \ 'Test_bufunload_all()', 40042205551SBram Moolenaar \ 'Test_client_server()', 40142205551SBram Moolenaar \ 'Test_close_and_exit_cb()', 402d80232beSBram Moolenaar \ 'Test_close_output_buffer()', 40342205551SBram Moolenaar \ 'Test_collapse_buffers()', 40465873846SBram Moolenaar \ 'Test_cwd()', 405218959bcSBram Moolenaar \ 'Test_diff_screen()', 40642205551SBram Moolenaar \ 'Test_exit_callback_interval()', 407ea94c855SBram Moolenaar \ 'Test_map_timeout_with_timer_interrupt()', 4081eca6f13SBram Moolenaar \ 'Test_out_cb()', 40942205551SBram Moolenaar \ 'Test_pipe_through_sort_all()', 41042205551SBram Moolenaar \ 'Test_pipe_through_sort_some()', 41144f0bd87SBram Moolenaar \ 'Test_popup_and_window_resize()', 41242205551SBram Moolenaar \ 'Test_quoteplus()', 4137dd48506SBram Moolenaar \ 'Test_quotestar()', 41442205551SBram Moolenaar \ 'Test_reltime()', 4153c8cd4a1SBram Moolenaar \ 'Test_state()', 416f204e05aSBram Moolenaar \ 'Test_terminal_composing_unicode()', 4173876789bSBram Moolenaar \ 'Test_terminal_does_not_truncate_last_newlines()', 4183615abb6SBram Moolenaar \ 'Test_terminal_no_cmd()', 41975a60f74SBram Moolenaar \ 'Test_terminal_noblock()', 4207dd88c51SBram Moolenaar \ 'Test_terminal_redir_file()', 421e219f73eSBram Moolenaar \ 'Test_termwinscroll()', 4229a2fddcfSBram Moolenaar \ 'Test_timer_oneshot()', 4239a2fddcfSBram Moolenaar \ 'Test_timer_paused()', 4249a2fddcfSBram Moolenaar \ 'Test_timer_repeat_many()', 4259a2fddcfSBram Moolenaar \ 'Test_timer_repeat_three()', 4269a2fddcfSBram Moolenaar \ 'Test_timer_stop_all_in_callback()', 4279a2fddcfSBram Moolenaar \ 'Test_timer_stop_in_callback()', 4289a2fddcfSBram Moolenaar \ 'Test_timer_with_partial_callback()', 42942205551SBram Moolenaar \ ] 43042205551SBram Moolenaar 43142205551SBram Moolenaar" Locate Test_ functions and execute them. 43242205551SBram Moolenaarredir @q 43342205551SBram Moolenaarsilent function /^Test_ 43442205551SBram Moolenaarredir END 43561a6d4e4SBram Moolenaarlet s:tests = split(substitute(@q, '\(function\|def\) \(\k*()\)', '\2', 'g')) 43642205551SBram Moolenaar 43742205551SBram Moolenaar" If there is an extra argument filter the function names against it. 43842205551SBram Moolenaarif argc() > 1 43942205551SBram Moolenaar let s:tests = filter(s:tests, 'v:val =~ argv(1)') 44042205551SBram Moolenaarendif 44142205551SBram Moolenaar 442a7f6c3cfSBram Moolenaar" If the environment variable $TEST_FILTER is set then filter the function 443a7f6c3cfSBram Moolenaar" names against it. 4447b666c78SBram Moolenaarlet s:filtered = 0 445a7f6c3cfSBram Moolenaarif $TEST_FILTER != '' 4467b666c78SBram Moolenaar let s:filtered = len(s:tests) 447a7f6c3cfSBram Moolenaar let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER') 4487b666c78SBram Moolenaar let s:filtered -= len(s:tests) 449a7f6c3cfSBram Moolenaarendif 450a7f6c3cfSBram Moolenaar 451ce436de5SBram Moolenaarlet s:may_fail_list = [] 452ce436de5SBram Moolenaarif $TEST_MAY_FAIL != '' 453bfe13cccSBram Moolenaar " Split the list at commas and add () to make it match g:testfunc. 454ce436de5SBram Moolenaar let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'}) 455ce436de5SBram Moolenaarendif 456ce436de5SBram Moolenaar 45742205551SBram Moolenaar" Execute the tests in alphabetical order. 458bfe13cccSBram Moolenaarfor g:testfunc in sort(s:tests) 4594a6fcf80SBram Moolenaar " Silence, please! 4604a6fcf80SBram Moolenaar set belloff=all 461f77af0e6SBram Moolenaar let prev_error = '' 462f77af0e6SBram Moolenaar let total_errors = [] 4633ed9efc2SBram Moolenaar let g:run_nr = 1 4644a6fcf80SBram Moolenaar 465bfe13cccSBram Moolenaar " A test can set g:test_is_flaky to retry running the test. 466bfe13cccSBram Moolenaar let g:test_is_flaky = 0 4673cdcb090SBram Moolenaar 468bfe13cccSBram Moolenaar call RunTheTest(g:testfunc) 46942205551SBram Moolenaar 470f77af0e6SBram Moolenaar " Repeat a flaky test. Give up when: 4716ca6ca48SBram Moolenaar " - $TEST_NO_RETRY is not empty 472f77af0e6SBram Moolenaar " - it fails again with the same message 4731bc353b6SBram Moolenaar " - it fails five times (with a different message) 474dbc0d216SBram Moolenaar if len(v:errors) > 0 475622b3568SBram Moolenaar \ && $TEST_NO_RETRY == '' 476bfe13cccSBram Moolenaar \ && (index(s:flaky_tests, g:testfunc) >= 0 477bfe13cccSBram Moolenaar \ || g:test_is_flaky) 478f77af0e6SBram Moolenaar while 1 479bfe13cccSBram Moolenaar call add(s:messages, 'Found errors in ' . g:testfunc . ':') 4806caf606bSBram Moolenaar call extend(s:messages, v:errors) 48115e737f7SBram Moolenaar 4823ed9efc2SBram Moolenaar call add(total_errors, 'Run ' . g:run_nr . ':') 483f77af0e6SBram Moolenaar call extend(total_errors, v:errors) 484f77af0e6SBram Moolenaar 4853ed9efc2SBram Moolenaar if g:run_nr == 5 || prev_error == v:errors[0] 486f77af0e6SBram Moolenaar call add(total_errors, 'Flaky test failed too often, giving up') 487f77af0e6SBram Moolenaar let v:errors = total_errors 488f77af0e6SBram Moolenaar break 489f77af0e6SBram Moolenaar endif 490f77af0e6SBram Moolenaar 491f77af0e6SBram Moolenaar call add(s:messages, 'Flaky test failed, running it again') 492f77af0e6SBram Moolenaar 493f77af0e6SBram Moolenaar " Flakiness is often caused by the system being very busy. Sleep a 494f77af0e6SBram Moolenaar " couple of seconds to have a higher chance of succeeding the second 495f77af0e6SBram Moolenaar " time. 49655058601SBram Moolenaar sleep 2 49755058601SBram Moolenaar 498f77af0e6SBram Moolenaar let prev_error = v:errors[0] 49942205551SBram Moolenaar let v:errors = [] 5003ed9efc2SBram Moolenaar let g:run_nr += 1 501f77af0e6SBram Moolenaar 502bfe13cccSBram Moolenaar call RunTheTest(g:testfunc) 503f77af0e6SBram Moolenaar 504f77af0e6SBram Moolenaar if len(v:errors) == 0 505f77af0e6SBram Moolenaar " Test passed on rerun. 506f77af0e6SBram Moolenaar break 50715e737f7SBram Moolenaar endif 508f77af0e6SBram Moolenaar endwhile 50942205551SBram Moolenaar endif 51042205551SBram Moolenaar 511bfe13cccSBram Moolenaar call AfterTheTest(g:testfunc) 51242205551SBram Moolenaarendfor 51342205551SBram Moolenaar 51442205551SBram Moolenaarcall FinishTesting() 515cc28e2d0SBram Moolenaar 516cc28e2d0SBram Moolenaar" vim: shiftwidth=2 sts=2 expandtab 517