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" 16*dae453f3SBram Moolenaar" If the environment variable $TEST_SKIP_PAT is set then test functions 17*dae453f3SBram Moolenaar" matching this pattern will be skipped. It's the opposite of $TEST_FILTER. 18*dae453f3SBram Moolenaar" 196ca6ca48SBram Moolenaar" While working on a test you can make $TEST_NO_RETRY non-empty to not retry: 206ca6ca48SBram Moolenaar" export TEST_NO_RETRY=yes 216ca6ca48SBram Moolenaar" 22ce436de5SBram Moolenaar" To ignore failure for tests that are known to fail in a certain environment, 23ce436de5SBram Moolenaar" set $TEST_MAY_FAIL to a comma separated list of function names. E.g. for 24ce436de5SBram Moolenaar" sh/bash: 25ce436de5SBram Moolenaar" export TEST_MAY_FAIL=Test_channel_one,Test_channel_other 26ce436de5SBram Moolenaar" The failure report will then not be included in the test.log file and 27ce436de5SBram Moolenaar" "make test" will not fail. 28ce436de5SBram Moolenaar" 2943345546SBram Moolenaar" The test script may contain anything, only functions that start with 3043345546SBram Moolenaar" "Test_" are special. These will be invoked and should contain assert 3143345546SBram Moolenaar" functions. See test_assert.vim for an example. 3243345546SBram Moolenaar" 3343345546SBram Moolenaar" It is possible to source other files that contain "Test_" functions. This 3443345546SBram Moolenaar" can speed up testing, since Vim does not need to restart. But be careful 3543345546SBram Moolenaar" that the tests do not interfere with each other. 3643345546SBram Moolenaar" 3743345546SBram Moolenaar" If an error cannot be detected properly with an assert function add the 3843345546SBram Moolenaar" error to the v:errors list: 3943345546SBram Moolenaar" call add(v:errors, 'test foo failed: Cannot find xyz') 4043345546SBram Moolenaar" 4143345546SBram Moolenaar" If preparation for each Test_ function is needed, define a SetUp function. 4243345546SBram Moolenaar" It will be called before each Test_ function. 4343345546SBram Moolenaar" 4443345546SBram Moolenaar" If cleanup after each Test_ function is needed, define a TearDown function. 4543345546SBram Moolenaar" It will be called after each Test_ function. 4600af60bbSBram Moolenaar" 4700af60bbSBram Moolenaar" When debugging a test it can be useful to add messages to v:errors: 4800af60bbSBram Moolenaar" call add(v:errors, "this happened") 4900af60bbSBram Moolenaar 5043345546SBram Moolenaar 5143345546SBram Moolenaar" Without the +eval feature we can't run these tests, bail out. 52b96a32efSBram Moolenaarsilent! while 0 53b96a32efSBram Moolenaar qa! 54b96a32efSBram Moolenaarsilent! endwhile 5543345546SBram Moolenaar 5618aa13d1SBram Moolenaar" In the GUI we can always change the screen size. 5718aa13d1SBram Moolenaarif has('gui_running') 5818aa13d1SBram Moolenaar set columns=80 lines=25 5918aa13d1SBram Moolenaarendif 6018aa13d1SBram Moolenaar 6143345546SBram Moolenaar" Check that the screen size is at least 24 x 80 characters. 6243345546SBram Moolenaarif &lines < 24 || &columns < 80 630b5dc644SBram Moolenaar let error = 'Screen size too small! Tests require at least 24 lines with 80 characters, got ' .. &lines .. ' lines with ' .. &columns .. ' characters' 6443345546SBram Moolenaar echoerr error 6543345546SBram Moolenaar split test.log 6643345546SBram Moolenaar $put =error 6745aa07d3SBram Moolenaar write 6845aa07d3SBram Moolenaar split messages 690b5dc644SBram Moolenaar call append(line('$'), '') 700b5dc644SBram Moolenaar call append(line('$'), 'From ' . expand('%') . ':') 7145aa07d3SBram Moolenaar call append(line('$'), error) 7245aa07d3SBram Moolenaar write 7345aa07d3SBram Moolenaar qa! 7443345546SBram Moolenaarendif 7543345546SBram Moolenaar 7675ee544fSBram Moolenaarif has('reltime') 7775ee544fSBram Moolenaar let s:start_time = reltime() 7875ee544fSBram Moolenaarendif 7975ee544fSBram Moolenaar 8089b10421SBram Moolenaar" Common with all tests on all systems. 8189b10421SBram Moolenaarsource setup.vim 8289b10421SBram Moolenaar 83c0662466SBram Moolenaar" For consistency run all tests with 'nocompatible' set. 84c0662466SBram Moolenaar" This also enables use of line continuation. 85c0662466SBram Moolenaarset nocp viminfo+=nviminfo 86c0662466SBram Moolenaar 8730276f2bSBram Moolenaar" Use utf-8 by default, instead of whatever the system default happens to be. 88ed79d1e3SBram Moolenaar" Individual tests can overrule this at the top of the file and use 89ed79d1e3SBram Moolenaar" g:orig_encoding if needed. 90ed79d1e3SBram Moolenaarlet g:orig_encoding = &encoding 91ac105ed3SBram Moolenaarset encoding=utf-8 92ac105ed3SBram Moolenaar 93d8f27b30SBram Moolenaar" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for 94d8f27b30SBram Moolenaar" the test_name.vim file itself. Replace it here with a more restrictive one, 95d8f27b30SBram Moolenaar" so we still catch mistakes. 96d8f27b30SBram Moolenaarlet s:test_script_fname = expand('%') 97d8f27b30SBram Moolenaarau! SwapExists * call HandleSwapExists() 98d8f27b30SBram Moolenaarfunc HandleSwapExists() 998ce4b7edSBram Moolenaar if exists('g:ignoreSwapExists') 1008ce4b7edSBram Moolenaar return 1018ce4b7edSBram Moolenaar endif 102b073da89SBram Moolenaar " Ignore finding a swap file for the test script (the user might be 103d8f27b30SBram Moolenaar " editing it and do ":make test_name") and the output file. 104b073da89SBram Moolenaar " Report finding another swap file and chose 'q' to avoid getting stuck. 105d8f27b30SBram Moolenaar if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname 106d8f27b30SBram Moolenaar let v:swapchoice = 'e' 107b073da89SBram Moolenaar else 108b073da89SBram Moolenaar call assert_report('Unexpected swap file: ' .. v:swapname) 109b073da89SBram Moolenaar let v:swapchoice = 'q' 110d8f27b30SBram Moolenaar endif 111d8f27b30SBram Moolenaarendfunc 112d8f27b30SBram Moolenaar 1137a073549SBram Moolenaar" Avoid stopping at the "hit enter" prompt 1147a073549SBram Moolenaarset nomore 1157a073549SBram Moolenaar 116c0662466SBram Moolenaar" Output all messages in English. 117c0662466SBram Moolenaarlang mess C 118c0662466SBram Moolenaar 11910e1d01aSBram Moolenaar" suppress menu translation 12010e1d01aSBram Moolenaarif has('gui_running') && exists('did_install_default_menus') 12110e1d01aSBram Moolenaar source $VIMRUNTIME/delmenu.vim 12210e1d01aSBram Moolenaar set langmenu=none 12310e1d01aSBram Moolenaar source $VIMRUNTIME/menu.vim 12410e1d01aSBram Moolenaarendif 12510e1d01aSBram Moolenaar 126f60b796fSBram Moolenaar" Always use forward slashes. 127f60b796fSBram Moolenaarset shellslash 128f60b796fSBram Moolenaar 12928fb79dbSBram Moolenaarlet s:srcdir = expand('%:p:h:h') 13028fb79dbSBram Moolenaar 1312690b5aeSBram Moolenaarif has('win32') 1322690b5aeSBram Moolenaar " avoid prompt that is long or contains a line break 1332690b5aeSBram Moolenaar let $PROMPT = '$P$G' 13445df2a01SBram Moolenaar " On MS-Windows t_md and t_me are Vim specific escape sequences. 13545df2a01SBram Moolenaar let s:t_bold = "\x1b[1m" 13645df2a01SBram Moolenaar let s:t_normal = "\x1b[m" 13745df2a01SBram Moolenaarelse 13845df2a01SBram Moolenaar let s:t_bold = &t_md 13945df2a01SBram Moolenaar let s:t_normal = &t_me 1402690b5aeSBram Moolenaarendif 1412690b5aeSBram Moolenaar 1424b2ce129SBram Moolenaarif has('mac') 1434b2ce129SBram Moolenaar " In MacOS, when starting a shell in a terminal, a bash deprecation warning 1444b2ce129SBram Moolenaar " message is displayed. This breaks the terminal test. Disable the warning 1454b2ce129SBram Moolenaar " message. 1464b2ce129SBram Moolenaar let $BASH_SILENCE_DEPRECATION_WARNING = 1 1474b2ce129SBram Moolenaarendif 1484b2ce129SBram Moolenaar 1498e8df251SBram Moolenaar" Prepare for calling test_garbagecollect_now(). 150ebf7dfa6SBram Moolenaarlet v:testing = 1 151ebf7dfa6SBram Moolenaar 15228fb79dbSBram Moolenaar" Support function: get the alloc ID by name. 15328fb79dbSBram Moolenaarfunction GetAllocId(name) 15428fb79dbSBram Moolenaar exe 'split ' . s:srcdir . '/alloc.h' 155065ee9aeSBram Moolenaar let top = search('typedef enum') 156065ee9aeSBram Moolenaar if top == 0 157065ee9aeSBram Moolenaar call add(v:errors, 'typedef not found in alloc.h') 158065ee9aeSBram Moolenaar endif 15928fb79dbSBram Moolenaar let lnum = search('aid_' . a:name . ',') 16028fb79dbSBram Moolenaar if lnum == 0 16128fb79dbSBram Moolenaar call add(v:errors, 'Alloc ID ' . a:name . ' not defined') 16228fb79dbSBram Moolenaar endif 16328fb79dbSBram Moolenaar close 164065ee9aeSBram Moolenaar return lnum - top - 1 16528fb79dbSBram Moolenaarendfunc 16628fb79dbSBram Moolenaar 16742205551SBram Moolenaarfunc RunTheTest(test) 1684c86830fSBram Moolenaar echoconsole 'Executing ' . a:test 16975ee544fSBram Moolenaar if has('reltime') 17075ee544fSBram Moolenaar let func_start = reltime() 17175ee544fSBram Moolenaar endif 172e5f2a075SBram Moolenaar 173e5f2a075SBram Moolenaar " Avoid stopping at the "hit enter" prompt 174e5f2a075SBram Moolenaar set nomore 175e5f2a075SBram Moolenaar 176e5f2a075SBram Moolenaar " Avoid a three second wait when a message is about to be overwritten by the 177e5f2a075SBram Moolenaar " mode message. 178e5f2a075SBram Moolenaar set noshowmode 179e5f2a075SBram Moolenaar 180eb992cb9SBram Moolenaar " Clear any overrides. 181eb992cb9SBram Moolenaar call test_override('ALL', 0) 182eb992cb9SBram Moolenaar 183cf1ba35fSBram Moolenaar " Some tests wipe out buffers. To be consistent, always wipe out all 184cf1ba35fSBram Moolenaar " buffers. 185cf1ba35fSBram Moolenaar %bwipe! 186cf1ba35fSBram Moolenaar 187209d3874SBram Moolenaar " The test may change the current directory. Save and restore the 188209d3874SBram Moolenaar " directory after executing the test. 189209d3874SBram Moolenaar let save_cwd = getcwd() 190209d3874SBram Moolenaar 191b5760a1cSBram Moolenaar if exists("*SetUp") 192cc28e2d0SBram Moolenaar try 193b5760a1cSBram Moolenaar call SetUp() 194cc28e2d0SBram Moolenaar catch 195cc28e2d0SBram Moolenaar call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint) 196cc28e2d0SBram Moolenaar endtry 197b5760a1cSBram Moolenaar endif 198b5760a1cSBram Moolenaar 199f204e05aSBram Moolenaar if a:test =~ 'Test_nocatch_' 200f204e05aSBram Moolenaar " Function handles errors itself. This avoids skipping commands after the 201f204e05aSBram Moolenaar " error. 202776b9546SBram Moolenaar let g:skipped_reason = '' 203f204e05aSBram Moolenaar exe 'call ' . a:test 204776b9546SBram Moolenaar if g:skipped_reason != '' 205776b9546SBram Moolenaar call add(s:messages, ' Skipped') 206776b9546SBram Moolenaar call add(s:skipped, 'SKIPPED ' . a:test . ': ' . g:skipped_reason) 207776b9546SBram Moolenaar endif 208f204e05aSBram Moolenaar else 209b5760a1cSBram Moolenaar try 210bfe13cccSBram Moolenaar au VimLeavePre * call EarlyExit(g:testfunc) 211b5760a1cSBram Moolenaar exe 'call ' . a:test 2128903676dSBram Moolenaar au! VimLeavePre 213dac1947bSBram Moolenaar catch /^\cskipped/ 214dac1947bSBram Moolenaar call add(s:messages, ' Skipped') 215dac1947bSBram Moolenaar call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', '')) 216b5760a1cSBram Moolenaar catch 217b5760a1cSBram Moolenaar call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint) 218b5760a1cSBram Moolenaar endtry 219f204e05aSBram Moolenaar endif 2208ad16da7SBram Moolenaar 2218ad16da7SBram Moolenaar " In case 'insertmode' was set and something went wrong, make sure it is 2228ad16da7SBram Moolenaar " reset to avoid trouble with anything else. 2238ad16da7SBram Moolenaar set noinsertmode 224b5760a1cSBram Moolenaar 225b5760a1cSBram Moolenaar if exists("*TearDown") 226cc28e2d0SBram Moolenaar try 227b5760a1cSBram Moolenaar call TearDown() 228cc28e2d0SBram Moolenaar catch 229cc28e2d0SBram Moolenaar call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint) 230cc28e2d0SBram Moolenaar endtry 231b5760a1cSBram Moolenaar endif 2327cba71d7SBram Moolenaar 2330b5dc644SBram Moolenaar " Clear any autocommands and put back the catch-all for SwapExists. 234cf1ba35fSBram Moolenaar au! 235d8f27b30SBram Moolenaar au SwapExists * call HandleSwapExists() 236cf1ba35fSBram Moolenaar 237ef6b979bSBram Moolenaar " Check for and close any stray popup windows. 23805ad5ff0SBram Moolenaar if has('popupwin') 239ef6b979bSBram Moolenaar call assert_equal([], popup_list()) 24003a9f848SBram Moolenaar call popup_clear(1) 241ae943150SBram Moolenaar endif 242ae943150SBram Moolenaar 243ce11de87SBram Moolenaar " Close any extra tab pages and windows and make the current one not modified. 244ce11de87SBram Moolenaar while tabpagenr('$') > 1 245bdf931c2SBram Moolenaar let winid = win_getid() 246cf1ba35fSBram Moolenaar quit! 247bdf931c2SBram Moolenaar if winid == win_getid() 248bdf931c2SBram Moolenaar echoerr 'Could not quit window' 249bdf931c2SBram Moolenaar break 250bdf931c2SBram Moolenaar endif 251ce11de87SBram Moolenaar endwhile 252ce11de87SBram Moolenaar 253358308ddSBram Moolenaar while 1 254358308ddSBram Moolenaar let wincount = winnr('$') 255358308ddSBram Moolenaar if wincount == 1 256358308ddSBram Moolenaar break 257358308ddSBram Moolenaar endif 2587cba71d7SBram Moolenaar bwipe! 259358308ddSBram Moolenaar if wincount == winnr('$') 260358308ddSBram Moolenaar " Did not manage to close a window. 261358308ddSBram Moolenaar only! 262358308ddSBram Moolenaar break 263358308ddSBram Moolenaar endif 2647cba71d7SBram Moolenaar endwhile 265209d3874SBram Moolenaar 266209d3874SBram Moolenaar exe 'cd ' . save_cwd 267640d4f0cSBram Moolenaar 268640d4f0cSBram Moolenaar let message = 'Executed ' . a:test 269640d4f0cSBram Moolenaar if has('reltime') 2708d943796SBram Moolenaar let message ..= repeat(' ', 50 - len(message)) 2718d943796SBram Moolenaar let time = reltime(func_start) 2728d943796SBram Moolenaar if has('float') && reltimefloat(time) > 0.1 27345df2a01SBram Moolenaar let message = s:t_bold .. message 2748d943796SBram Moolenaar endif 2758d943796SBram Moolenaar let message ..= ' in ' .. reltimestr(time) .. ' seconds' 2768d943796SBram Moolenaar if has('float') && reltimefloat(time) > 0.1 27745df2a01SBram Moolenaar let message ..= s:t_normal 2788d943796SBram Moolenaar endif 279640d4f0cSBram Moolenaar endif 280640d4f0cSBram Moolenaar call add(s:messages, message) 281640d4f0cSBram Moolenaar let s:done += 1 282b5760a1cSBram Moolenaarendfunc 28328fb79dbSBram Moolenaar 284ce436de5SBram Moolenaarfunc AfterTheTest(func_name) 28543345546SBram Moolenaar if len(v:errors) > 0 286ce436de5SBram Moolenaar if match(s:may_fail_list, '^' .. a:func_name) >= 0 287ce436de5SBram Moolenaar let s:fail_expected += 1 288bfe13cccSBram Moolenaar call add(s:errors_expected, 'Found errors in ' . g:testfunc . ':') 289ce436de5SBram Moolenaar call extend(s:errors_expected, v:errors) 290ce436de5SBram Moolenaar else 29100af60bbSBram Moolenaar let s:fail += 1 292bfe13cccSBram Moolenaar call add(s:errors, 'Found errors in ' . g:testfunc . ':') 29300af60bbSBram Moolenaar call extend(s:errors, v:errors) 294ce436de5SBram Moolenaar endif 29543345546SBram Moolenaar let v:errors = [] 29643345546SBram Moolenaar endif 29742205551SBram Moolenaarendfunc 29842205551SBram Moolenaar 2998903676dSBram Moolenaarfunc EarlyExit(test) 3008903676dSBram Moolenaar " It's OK for the test we use to test the quit detection. 3018903676dSBram Moolenaar if a:test != 'Test_zz_quit_detected()' 3028903676dSBram Moolenaar call add(v:errors, 'Test caused Vim to exit: ' . a:test) 3038903676dSBram Moolenaar endif 3048903676dSBram Moolenaar 3058903676dSBram Moolenaar call FinishTesting() 3068903676dSBram Moolenaarendfunc 3078903676dSBram Moolenaar 30842205551SBram Moolenaar" This function can be called by a test if it wants to abort testing. 30942205551SBram Moolenaarfunc FinishTesting() 310ce436de5SBram Moolenaar call AfterTheTest('') 31143345546SBram Moolenaar 312fc4ad616SBram Moolenaar " Don't write viminfo on exit. 313fc4ad616SBram Moolenaar set viminfo= 314fc4ad616SBram Moolenaar 315d1ee0043SBram Moolenaar " Clean up files created by setup.vim 316d1ee0043SBram Moolenaar call delete('XfakeHOME', 'rf') 317d1ee0043SBram Moolenaar 318ce436de5SBram Moolenaar if s:fail == 0 && s:fail_expected == 0 31943345546SBram Moolenaar " Success, create the .res file so that make knows it's done. 32000af60bbSBram Moolenaar exe 'split ' . fnamemodify(g:testname, ':r') . '.res' 32143345546SBram Moolenaar write 32243345546SBram Moolenaar endif 32343345546SBram Moolenaar 32400af60bbSBram Moolenaar if len(s:errors) > 0 32543345546SBram Moolenaar " Append errors to test.log 32643345546SBram Moolenaar split test.log 32743345546SBram Moolenaar call append(line('$'), '') 32800af60bbSBram Moolenaar call append(line('$'), 'From ' . g:testname . ':') 32900af60bbSBram Moolenaar call append(line('$'), s:errors) 33043345546SBram Moolenaar write 33143345546SBram Moolenaar endif 33243345546SBram Moolenaar 33329f9ed20SBram Moolenaar if s:done == 0 3347b666c78SBram Moolenaar if s:filtered > 0 335*dae453f3SBram Moolenaar if $TEST_FILTER != '' 3367b666c78SBram Moolenaar let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'" 33729f9ed20SBram Moolenaar else 338*dae453f3SBram Moolenaar let message = "ALL tests match $TEST_SKIP_PAT: '" .. $TEST_SKIP_PAT .. "'" 339*dae453f3SBram Moolenaar endif 340*dae453f3SBram Moolenaar else 3417b666c78SBram Moolenaar let message = 'NO tests executed' 3427b666c78SBram Moolenaar endif 3437b666c78SBram Moolenaar else 3447b666c78SBram Moolenaar if s:filtered > 0 345*dae453f3SBram Moolenaar call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER and $TEST_SKIP_PAT") 3467b666c78SBram Moolenaar endif 34700af60bbSBram Moolenaar let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test') 34829f9ed20SBram Moolenaar endif 3497b666c78SBram Moolenaar if s:done > 0 && has('reltime') 35045df2a01SBram Moolenaar let message = s:t_bold .. message .. repeat(' ', 40 - len(message)) 35175ee544fSBram Moolenaar let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds' 35245df2a01SBram Moolenaar let message ..= s:t_normal 35375ee544fSBram Moolenaar endif 354096c8bb4SBram Moolenaar echo message 35500af60bbSBram Moolenaar call add(s:messages, message) 35600af60bbSBram Moolenaar if s:fail > 0 35700af60bbSBram Moolenaar let message = s:fail . ' FAILED:' 358096c8bb4SBram Moolenaar echo message 35900af60bbSBram Moolenaar call add(s:messages, message) 36000af60bbSBram Moolenaar call extend(s:messages, s:errors) 36143345546SBram Moolenaar endif 362ce436de5SBram Moolenaar if s:fail_expected > 0 363ce436de5SBram Moolenaar let message = s:fail_expected . ' FAILED (matching $TEST_MAY_FAIL):' 364ce436de5SBram Moolenaar echo message 365ce436de5SBram Moolenaar call add(s:messages, message) 366ce436de5SBram Moolenaar call extend(s:messages, s:errors_expected) 367ce436de5SBram Moolenaar endif 36843345546SBram Moolenaar 369dac1947bSBram Moolenaar " Add SKIPPED messages 370dac1947bSBram Moolenaar call extend(s:messages, s:skipped) 371dac1947bSBram Moolenaar 372dac1947bSBram Moolenaar " Append messages to the file "messages" 373096c8bb4SBram Moolenaar split messages 374096c8bb4SBram Moolenaar call append(line('$'), '') 37500af60bbSBram Moolenaar call append(line('$'), 'From ' . g:testname . ':') 37600af60bbSBram Moolenaar call append(line('$'), s:messages) 377096c8bb4SBram Moolenaar write 378096c8bb4SBram Moolenaar 37943345546SBram Moolenaar qall! 38042205551SBram Moolenaarendfunc 38142205551SBram Moolenaar 38242205551SBram Moolenaar" Source the test script. First grab the file name, in case the script 38342205551SBram Moolenaar" navigates away. g:testname can be used by the tests. 38442205551SBram Moolenaarlet g:testname = expand('%') 38542205551SBram Moolenaarlet s:done = 0 38642205551SBram Moolenaarlet s:fail = 0 387ce436de5SBram Moolenaarlet s:fail_expected = 0 38842205551SBram Moolenaarlet s:errors = [] 389ce436de5SBram Moolenaarlet s:errors_expected = [] 39042205551SBram Moolenaarlet s:messages = [] 39142205551SBram Moolenaarlet s:skipped = [] 39242205551SBram Moolenaarif expand('%') =~ 'test_vimscript.vim' 393ce436de5SBram Moolenaar " this test has intentional errors, don't use try/catch. 39442205551SBram Moolenaar source % 39542205551SBram Moolenaarelse 39642205551SBram Moolenaar try 39742205551SBram Moolenaar source % 3989c0cec65SBram Moolenaar catch /^\cskipped/ 3999c0cec65SBram Moolenaar call add(s:messages, ' Skipped') 4009c0cec65SBram Moolenaar call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '', '')) 40142205551SBram Moolenaar catch 40242205551SBram Moolenaar let s:fail += 1 40342205551SBram Moolenaar call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint) 40442205551SBram Moolenaar endtry 40542205551SBram Moolenaarendif 40642205551SBram Moolenaar 40742205551SBram Moolenaar" Names of flaky tests. 408dbc0d216SBram Moolenaarlet s:flaky_tests = [ 4097d697960SBram Moolenaar \ 'Test_BufWrite_lockmarks()', 4100d0c3ca0SBram Moolenaar \ 'Test_autocmd_SafeState()', 4117d697960SBram Moolenaar \ 'Test_bufunload_all()', 41242205551SBram Moolenaar \ 'Test_client_server()', 41342205551SBram Moolenaar \ 'Test_close_and_exit_cb()', 414d80232beSBram Moolenaar \ 'Test_close_output_buffer()', 41542205551SBram Moolenaar \ 'Test_collapse_buffers()', 41665873846SBram Moolenaar \ 'Test_cwd()', 417218959bcSBram Moolenaar \ 'Test_diff_screen()', 41842205551SBram Moolenaar \ 'Test_exit_callback_interval()', 419ea94c855SBram Moolenaar \ 'Test_map_timeout_with_timer_interrupt()', 4201eca6f13SBram Moolenaar \ 'Test_out_cb()', 42142205551SBram Moolenaar \ 'Test_pipe_through_sort_all()', 42242205551SBram Moolenaar \ 'Test_pipe_through_sort_some()', 42344f0bd87SBram Moolenaar \ 'Test_popup_and_window_resize()', 42442205551SBram Moolenaar \ 'Test_quoteplus()', 4257dd48506SBram Moolenaar \ 'Test_quotestar()', 42642205551SBram Moolenaar \ 'Test_reltime()', 4273c8cd4a1SBram Moolenaar \ 'Test_state()', 428f204e05aSBram Moolenaar \ 'Test_terminal_composing_unicode()', 4293876789bSBram Moolenaar \ 'Test_terminal_does_not_truncate_last_newlines()', 4303615abb6SBram Moolenaar \ 'Test_terminal_no_cmd()', 43175a60f74SBram Moolenaar \ 'Test_terminal_noblock()', 4327dd88c51SBram Moolenaar \ 'Test_terminal_redir_file()', 433e219f73eSBram Moolenaar \ 'Test_termwinscroll()', 4349a2fddcfSBram Moolenaar \ 'Test_timer_oneshot()', 4359a2fddcfSBram Moolenaar \ 'Test_timer_paused()', 4369a2fddcfSBram Moolenaar \ 'Test_timer_repeat_many()', 4379a2fddcfSBram Moolenaar \ 'Test_timer_repeat_three()', 4389a2fddcfSBram Moolenaar \ 'Test_timer_stop_all_in_callback()', 4399a2fddcfSBram Moolenaar \ 'Test_timer_stop_in_callback()', 4409a2fddcfSBram Moolenaar \ 'Test_timer_with_partial_callback()', 44142205551SBram Moolenaar \ ] 44242205551SBram Moolenaar 44342205551SBram Moolenaar" Locate Test_ functions and execute them. 44442205551SBram Moolenaarredir @q 44542205551SBram Moolenaarsilent function /^Test_ 44642205551SBram Moolenaarredir END 44761a6d4e4SBram Moolenaarlet s:tests = split(substitute(@q, '\(function\|def\) \(\k*()\)', '\2', 'g')) 44842205551SBram Moolenaar 44942205551SBram Moolenaar" If there is an extra argument filter the function names against it. 45042205551SBram Moolenaarif argc() > 1 45142205551SBram Moolenaar let s:tests = filter(s:tests, 'v:val =~ argv(1)') 45242205551SBram Moolenaarendif 45342205551SBram Moolenaar 454a7f6c3cfSBram Moolenaar" If the environment variable $TEST_FILTER is set then filter the function 455a7f6c3cfSBram Moolenaar" names against it. 4567b666c78SBram Moolenaarlet s:filtered = 0 457a7f6c3cfSBram Moolenaarif $TEST_FILTER != '' 4587b666c78SBram Moolenaar let s:filtered = len(s:tests) 459a7f6c3cfSBram Moolenaar let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER') 4607b666c78SBram Moolenaar let s:filtered -= len(s:tests) 461a7f6c3cfSBram Moolenaarendif 462a7f6c3cfSBram Moolenaar 463ce436de5SBram Moolenaarlet s:may_fail_list = [] 464ce436de5SBram Moolenaarif $TEST_MAY_FAIL != '' 465bfe13cccSBram Moolenaar " Split the list at commas and add () to make it match g:testfunc. 466ce436de5SBram Moolenaar let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'}) 467ce436de5SBram Moolenaarendif 468ce436de5SBram Moolenaar 46942205551SBram Moolenaar" Execute the tests in alphabetical order. 470bfe13cccSBram Moolenaarfor g:testfunc in sort(s:tests) 471*dae453f3SBram Moolenaar if $TEST_SKIP_PAT != '' && g:testfunc =~ $TEST_SKIP_PAT 472*dae453f3SBram Moolenaar call add(s:messages, g:testfunc .. ' matches $TEST_SKIP_PAT') 473*dae453f3SBram Moolenaar let s:filtered += 1 474*dae453f3SBram Moolenaar continue 475*dae453f3SBram Moolenaar endif 476*dae453f3SBram Moolenaar 4774a6fcf80SBram Moolenaar " Silence, please! 4784a6fcf80SBram Moolenaar set belloff=all 479f77af0e6SBram Moolenaar let prev_error = '' 480f77af0e6SBram Moolenaar let total_errors = [] 4813ed9efc2SBram Moolenaar let g:run_nr = 1 4824a6fcf80SBram Moolenaar 483bfe13cccSBram Moolenaar " A test can set g:test_is_flaky to retry running the test. 484bfe13cccSBram Moolenaar let g:test_is_flaky = 0 4853cdcb090SBram Moolenaar 486bfe13cccSBram Moolenaar call RunTheTest(g:testfunc) 48742205551SBram Moolenaar 488f77af0e6SBram Moolenaar " Repeat a flaky test. Give up when: 4896ca6ca48SBram Moolenaar " - $TEST_NO_RETRY is not empty 490f77af0e6SBram Moolenaar " - it fails again with the same message 4911bc353b6SBram Moolenaar " - it fails five times (with a different message) 492dbc0d216SBram Moolenaar if len(v:errors) > 0 493622b3568SBram Moolenaar \ && $TEST_NO_RETRY == '' 494bfe13cccSBram Moolenaar \ && (index(s:flaky_tests, g:testfunc) >= 0 495bfe13cccSBram Moolenaar \ || g:test_is_flaky) 496f77af0e6SBram Moolenaar while 1 497bfe13cccSBram Moolenaar call add(s:messages, 'Found errors in ' . g:testfunc . ':') 4986caf606bSBram Moolenaar call extend(s:messages, v:errors) 49915e737f7SBram Moolenaar 5003ed9efc2SBram Moolenaar call add(total_errors, 'Run ' . g:run_nr . ':') 501f77af0e6SBram Moolenaar call extend(total_errors, v:errors) 502f77af0e6SBram Moolenaar 5033ed9efc2SBram Moolenaar if g:run_nr == 5 || prev_error == v:errors[0] 504f77af0e6SBram Moolenaar call add(total_errors, 'Flaky test failed too often, giving up') 505f77af0e6SBram Moolenaar let v:errors = total_errors 506f77af0e6SBram Moolenaar break 507f77af0e6SBram Moolenaar endif 508f77af0e6SBram Moolenaar 509f77af0e6SBram Moolenaar call add(s:messages, 'Flaky test failed, running it again') 510f77af0e6SBram Moolenaar 511f77af0e6SBram Moolenaar " Flakiness is often caused by the system being very busy. Sleep a 512f77af0e6SBram Moolenaar " couple of seconds to have a higher chance of succeeding the second 513f77af0e6SBram Moolenaar " time. 51455058601SBram Moolenaar sleep 2 51555058601SBram Moolenaar 516f77af0e6SBram Moolenaar let prev_error = v:errors[0] 51742205551SBram Moolenaar let v:errors = [] 5183ed9efc2SBram Moolenaar let g:run_nr += 1 519f77af0e6SBram Moolenaar 520bfe13cccSBram Moolenaar call RunTheTest(g:testfunc) 521f77af0e6SBram Moolenaar 522f77af0e6SBram Moolenaar if len(v:errors) == 0 523f77af0e6SBram Moolenaar " Test passed on rerun. 524f77af0e6SBram Moolenaar break 52515e737f7SBram Moolenaar endif 526f77af0e6SBram Moolenaar endwhile 52742205551SBram Moolenaar endif 52842205551SBram Moolenaar 529bfe13cccSBram Moolenaar call AfterTheTest(g:testfunc) 53042205551SBram Moolenaarendfor 53142205551SBram Moolenaar 53242205551SBram Moolenaarcall FinishTesting() 533cc28e2d0SBram Moolenaar 534cc28e2d0SBram Moolenaar" vim: shiftwidth=2 sts=2 expandtab 535