1" This script is sourced while editing the .vim file with the tests. 2" When the script is successful the .res file will be created. 3" Errors are appended to the test.log file. 4" 5" To execute only specific test functions, add a second argument. It will be 6" matched against the names of the Test_ funtion. E.g.: 7" ../vim -u NONE -S runtest.vim test_channel.vim open_delay 8" The output can be found in the "messages" file. 9" 10" The test script may contain anything, only functions that start with 11" "Test_" are special. These will be invoked and should contain assert 12" functions. See test_assert.vim for an example. 13" 14" It is possible to source other files that contain "Test_" functions. This 15" can speed up testing, since Vim does not need to restart. But be careful 16" that the tests do not interfere with each other. 17" 18" If an error cannot be detected properly with an assert function add the 19" error to the v:errors list: 20" call add(v:errors, 'test foo failed: Cannot find xyz') 21" 22" If preparation for each Test_ function is needed, define a SetUp function. 23" It will be called before each Test_ function. 24" 25" If cleanup after each Test_ function is needed, define a TearDown function. 26" It will be called after each Test_ function. 27" 28" When debugging a test it can be useful to add messages to v:errors: 29" call add(v:errors, "this happened") 30 31 32" Without the +eval feature we can't run these tests, bail out. 33so small.vim 34 35" Check that the screen size is at least 24 x 80 characters. 36if &lines < 24 || &columns < 80 37 let error = 'Screen size too small! Tests require at least 24 lines with 80 characters' 38 echoerr error 39 split test.log 40 $put =error 41 w 42 cquit 43endif 44 45" Common with all tests on all systems. 46source setup.vim 47 48" For consistency run all tests with 'nocompatible' set. 49" This also enables use of line continuation. 50set nocp viminfo+=nviminfo 51 52" Use utf-8 or latin1 be default, instead of whatever the system default 53" happens to be. Individual tests can overrule this at the top of the file. 54if has('multi_byte') 55 set encoding=utf-8 56else 57 set encoding=latin1 58endif 59 60" Avoid stopping at the "hit enter" prompt 61set nomore 62 63" Output all messages in English. 64lang mess C 65 66" Always use forward slashes. 67set shellslash 68 69let s:srcdir = expand('%:p:h:h') 70 71" Prepare for calling test_garbagecollect_now(). 72let v:testing = 1 73 74" Support function: get the alloc ID by name. 75function GetAllocId(name) 76 exe 'split ' . s:srcdir . '/alloc.h' 77 let top = search('typedef enum') 78 if top == 0 79 call add(v:errors, 'typedef not found in alloc.h') 80 endif 81 let lnum = search('aid_' . a:name . ',') 82 if lnum == 0 83 call add(v:errors, 'Alloc ID ' . a:name . ' not defined') 84 endif 85 close 86 return lnum - top - 1 87endfunc 88 89function RunTheTest(test) 90 echo 'Executing ' . a:test 91 if exists("*SetUp") 92 try 93 call SetUp() 94 catch 95 call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint) 96 endtry 97 endif 98 99 call add(s:messages, 'Executing ' . a:test) 100 let s:done += 1 101 try 102 exe 'call ' . a:test 103 catch /^\cskipped/ 104 call add(s:messages, ' Skipped') 105 call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', '')) 106 catch 107 call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint) 108 endtry 109 110 if exists("*TearDown") 111 try 112 call TearDown() 113 catch 114 call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint) 115 endtry 116 endif 117 118 " Close any extra windows and make the current one not modified. 119 while 1 120 let wincount = winnr('$') 121 if wincount == 1 122 break 123 endif 124 bwipe! 125 if wincount == winnr('$') 126 " Did not manage to close a window. 127 only! 128 break 129 endif 130 endwhile 131 set nomodified 132endfunc 133 134" Source the test script. First grab the file name, in case the script 135" navigates away. g:testname can be used by the tests. 136let g:testname = expand('%') 137let s:done = 0 138let s:fail = 0 139let s:errors = [] 140let s:messages = [] 141let s:skipped = [] 142if expand('%') =~ 'test_viml.vim' 143 " this test has intentional s:errors, don't use try/catch. 144 source % 145else 146 try 147 source % 148 catch 149 let s:fail += 1 150 call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint) 151 endtry 152endif 153 154" Names of flaky tests. 155let s:flaky = [ 156 \ 'Test_reltime()', 157 \ 'Test_nb_basic()', 158 \ 'Test_communicate()', 159 \ 'Test_pipe_through_sort_all()', 160 \ 'Test_pipe_through_sort_some()' 161 \ ] 162 163" Locate Test_ functions and execute them. 164set nomore 165redir @q 166silent function /^Test_ 167redir END 168let s:tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g')) 169 170" If there is an extra argument filter the function names against it. 171if argc() > 1 172 let s:tests = filter(s:tests, 'v:val =~ argv(1)') 173endif 174 175" Execute the tests in alphabetical order. 176for s:test in sort(s:tests) 177 call RunTheTest(s:test) 178 179 if len(v:errors) > 0 && index(s:flaky, s:test) >= 0 180 call add(s:messages, 'Flaky test failed, running it again') 181 let v:errors = [] 182 call RunTheTest(s:test) 183 endif 184 185 if len(v:errors) > 0 186 let s:fail += 1 187 call add(s:errors, 'Found errors in ' . s:test . ':') 188 call extend(s:errors, v:errors) 189 let v:errors = [] 190 endif 191endfor 192 193" Don't write viminfo on exit. 194set viminfo= 195 196if s:fail == 0 197 " Success, create the .res file so that make knows it's done. 198 exe 'split ' . fnamemodify(g:testname, ':r') . '.res' 199 write 200endif 201 202if len(s:errors) > 0 203 " Append errors to test.log 204 split test.log 205 call append(line('$'), '') 206 call append(line('$'), 'From ' . g:testname . ':') 207 call append(line('$'), s:errors) 208 write 209endif 210 211let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test') 212echo message 213call add(s:messages, message) 214if s:fail > 0 215 let message = s:fail . ' FAILED:' 216 echo message 217 call add(s:messages, message) 218 call extend(s:messages, s:errors) 219endif 220 221" Add SKIPPED messages 222call extend(s:messages, s:skipped) 223 224" Append messages to the file "messages" 225split messages 226call append(line('$'), '') 227call append(line('$'), 'From ' . g:testname . ':') 228call append(line('$'), s:messages) 229write 230 231qall! 232 233" vim: shiftwidth=2 sts=2 expandtab 234