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 by 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 89func RunTheTest(test) 90 echo 'Executing ' . a:test 91 92 " Avoid stopping at the "hit enter" prompt 93 set nomore 94 95 " Avoid a three second wait when a message is about to be overwritten by the 96 " mode message. 97 set noshowmode 98 99 " Clear any overrides. 100 call test_override('ALL', 0) 101 102 " Some tests wipe out buffers. To be consistent, always wipe out all 103 " buffers. 104 %bwipe! 105 106 if exists("*SetUp") 107 try 108 call SetUp() 109 catch 110 call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint) 111 endtry 112 endif 113 114 call add(s:messages, 'Executing ' . a:test) 115 let s:done += 1 116 117 if a:test =~ 'Test_nocatch_' 118 " Function handles errors itself. This avoids skipping commands after the 119 " error. 120 exe 'call ' . a:test 121 else 122 try 123 exe 'call ' . a:test 124 catch /^\cskipped/ 125 call add(s:messages, ' Skipped') 126 call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', '')) 127 catch 128 call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint) 129 endtry 130 endif 131 132 if exists("*TearDown") 133 try 134 call TearDown() 135 catch 136 call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint) 137 endtry 138 endif 139 140 " Clear any autocommands 141 au! 142 143 " Close any extra tab pages and windows and make the current one not modified. 144 while tabpagenr('$') > 1 145 quit! 146 endwhile 147 148 while 1 149 let wincount = winnr('$') 150 if wincount == 1 151 break 152 endif 153 bwipe! 154 if wincount == winnr('$') 155 " Did not manage to close a window. 156 only! 157 break 158 endif 159 endwhile 160endfunc 161 162func AfterTheTest() 163 if len(v:errors) > 0 164 let s:fail += 1 165 call add(s:errors, 'Found errors in ' . s:test . ':') 166 call extend(s:errors, v:errors) 167 let v:errors = [] 168 endif 169endfunc 170 171" This function can be called by a test if it wants to abort testing. 172func FinishTesting() 173 call AfterTheTest() 174 175 " Don't write viminfo on exit. 176 set viminfo= 177 178 " Clean up files created by setup.vim 179 call delete('XfakeHOME', 'rf') 180 181 if s:fail == 0 182 " Success, create the .res file so that make knows it's done. 183 exe 'split ' . fnamemodify(g:testname, ':r') . '.res' 184 write 185 endif 186 187 if len(s:errors) > 0 188 " Append errors to test.log 189 split test.log 190 call append(line('$'), '') 191 call append(line('$'), 'From ' . g:testname . ':') 192 call append(line('$'), s:errors) 193 write 194 endif 195 196 let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test') 197 echo message 198 call add(s:messages, message) 199 if s:fail > 0 200 let message = s:fail . ' FAILED:' 201 echo message 202 call add(s:messages, message) 203 call extend(s:messages, s:errors) 204 endif 205 206 " Add SKIPPED messages 207 call extend(s:messages, s:skipped) 208 209 " Append messages to the file "messages" 210 split messages 211 call append(line('$'), '') 212 call append(line('$'), 'From ' . g:testname . ':') 213 call append(line('$'), s:messages) 214 write 215 216 qall! 217endfunc 218 219" Source the test script. First grab the file name, in case the script 220" navigates away. g:testname can be used by the tests. 221let g:testname = expand('%') 222let s:done = 0 223let s:fail = 0 224let s:errors = [] 225let s:messages = [] 226let s:skipped = [] 227if expand('%') =~ 'test_vimscript.vim' 228 " this test has intentional s:errors, don't use try/catch. 229 source % 230else 231 try 232 source % 233 catch 234 let s:fail += 1 235 call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint) 236 endtry 237endif 238 239" Names of flaky tests. 240let s:flaky = [ 241 \ 'Test_client_server()', 242 \ 'Test_close_and_exit_cb()', 243 \ 'Test_collapse_buffers()', 244 \ 'Test_communicate()', 245 \ 'Test_exit_callback_interval()', 246 \ 'Test_nb_basic()', 247 \ 'Test_oneshot()', 248 \ 'Test_pipe_through_sort_all()', 249 \ 'Test_pipe_through_sort_some()', 250 \ 'Test_quoteplus()', 251 \ 'Test_quotestar()', 252 \ 'Test_reltime()', 253 \ 'Test_terminal_composing_unicode()', 254 \ 'Test_terminal_noblock()', 255 \ 'Test_terminal_redir_file()', 256 \ 'Test_with_partial_callback()', 257 \ ] 258 259" Locate Test_ functions and execute them. 260redir @q 261silent function /^Test_ 262redir END 263let s:tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g')) 264 265" If there is an extra argument filter the function names against it. 266if argc() > 1 267 let s:tests = filter(s:tests, 'v:val =~ argv(1)') 268endif 269 270" Execute the tests in alphabetical order. 271for s:test in sort(s:tests) 272 " Silence, please! 273 set belloff=all 274 275 call RunTheTest(s:test) 276 277 if len(v:errors) > 0 && index(s:flaky, s:test) >= 0 278 call add(s:messages, 'Found errors in ' . s:test . ':') 279 call extend(s:messages, v:errors) 280 call add(s:messages, 'Flaky test failed, running it again') 281 let first_run = v:errors 282 283 let v:errors = [] 284 call RunTheTest(s:test) 285 if len(v:errors) > 0 286 let second_run = v:errors 287 let v:errors = ['First run:'] 288 call extend(v:errors, first_run) 289 call add(v:errors, 'Second run:') 290 call extend(v:errors, second_run) 291 endif 292 endif 293 294 call AfterTheTest() 295endfor 296 297call FinishTesting() 298 299" vim: shiftwidth=2 sts=2 expandtab 300