blob: 1cdeeef5aaa195e7355aaffafea88b9f9e19e97a [file] [log] [blame]
Bram Moolenaar43345542015-11-29 17:35:35 +01001" 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"
Bram Moolenaarbefb3662016-02-20 14:41:40 +01005" To execute only specific test functions, add a second argument. It will be
Bram Moolenaare219f732019-11-30 15:34:08 +01006" matched against the names of the Test_ function. E.g.:
Bram Moolenaarbefb3662016-02-20 14:41:40 +01007" ../vim -u NONE -S runtest.vim test_channel.vim open_delay
8" The output can be found in the "messages" file.
9"
Bram Moolenaarce436de2020-03-21 15:17:20 +010010" If the environment variable $TEST_FILTER is set then only test functions
11" matching this pattern are executed. E.g. for sh/bash:
12" export TEST_FILTER=Test_channel
13" For csh:
14" setenv TEST_FILTER Test_channel
15"
Bram Moolenaardae453f2021-08-07 17:20:16 +020016" If the environment variable $TEST_SKIP_PAT is set then test functions
17" matching this pattern will be skipped. It's the opposite of $TEST_FILTER.
18"
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +020019" While working on a test you can make $TEST_NO_RETRY non-empty to not retry:
20" export TEST_NO_RETRY=yes
21"
Bram Moolenaarce436de2020-03-21 15:17:20 +010022" To ignore failure for tests that are known to fail in a certain environment,
23" set $TEST_MAY_FAIL to a comma separated list of function names. E.g. for
24" sh/bash:
25" export TEST_MAY_FAIL=Test_channel_one,Test_channel_other
26" The failure report will then not be included in the test.log file and
27" "make test" will not fail.
28"
Bram Moolenaar43345542015-11-29 17:35:35 +010029" The test script may contain anything, only functions that start with
30" "Test_" are special. These will be invoked and should contain assert
31" functions. See test_assert.vim for an example.
32"
33" It is possible to source other files that contain "Test_" functions. This
34" can speed up testing, since Vim does not need to restart. But be careful
35" that the tests do not interfere with each other.
36"
37" If an error cannot be detected properly with an assert function add the
38" error to the v:errors list:
39" call add(v:errors, 'test foo failed: Cannot find xyz')
40"
41" If preparation for each Test_ function is needed, define a SetUp function.
42" It will be called before each Test_ function.
43"
44" If cleanup after each Test_ function is needed, define a TearDown function.
45" It will be called after each Test_ function.
Bram Moolenaar00af60b2016-02-13 14:06:14 +010046"
47" When debugging a test it can be useful to add messages to v:errors:
Bram Moolenaar8ad16da2019-01-06 15:29:57 +010048" call add(v:errors, "this happened")
Bram Moolenaar00af60b2016-02-13 14:06:14 +010049
Bram Moolenaar43345542015-11-29 17:35:35 +010050
51" Without the +eval feature we can't run these tests, bail out.
Bram Moolenaarb96a32e2020-08-13 18:59:55 +020052silent! while 0
53 qa!
54silent! endwhile
Bram Moolenaar43345542015-11-29 17:35:35 +010055
Bram Moolenaar18aa13d2020-07-11 13:09:36 +020056" In the GUI we can always change the screen size.
57if has('gui_running')
58 set columns=80 lines=25
59endif
60
Bram Moolenaar43345542015-11-29 17:35:35 +010061" Check that the screen size is at least 24 x 80 characters.
Bram Moolenaar94722c52023-01-28 19:19:03 +000062if &lines < 24 || &columns < 80
Bram Moolenaar0b5dc642019-08-11 22:56:15 +020063 let error = 'Screen size too small! Tests require at least 24 lines with 80 characters, got ' .. &lines .. ' lines with ' .. &columns .. ' characters'
Bram Moolenaar43345542015-11-29 17:35:35 +010064 echoerr error
65 split test.log
66 $put =error
Bram Moolenaar45aa07d2019-06-15 18:20:38 +020067 write
68 split messages
Bram Moolenaar0b5dc642019-08-11 22:56:15 +020069 call append(line('$'), '')
70 call append(line('$'), 'From ' . expand('%') . ':')
Bram Moolenaar45aa07d2019-06-15 18:20:38 +020071 call append(line('$'), error)
72 write
73 qa!
Bram Moolenaar43345542015-11-29 17:35:35 +010074endif
75
Bram Moolenaar75ee5442019-06-06 18:05:25 +020076if has('reltime')
Bram Moolenaarb9093d52022-09-23 19:42:31 +010077 let s:run_start_time = reltime()
78
79 if !filereadable('starttime')
80 " first test, store the overall test starting time
81 let s:test_start_time = localtime()
82 call writefile([string(s:test_start_time)], 'starttime')
83 else
84 " second or later test, read the overall test starting time
85 let s:test_start_time = readfile('starttime')[0]->str2nr()
86 endif
Bram Moolenaar75ee5442019-06-06 18:05:25 +020087endif
88
Bakudankun29f3a452021-12-11 12:28:08 +000089" Always use forward slashes.
90set shellslash
91
Bram Moolenaar89b10422016-07-12 22:51:22 +020092" Common with all tests on all systems.
93source setup.vim
94
Bram Moolenaarc0662462015-12-30 15:49:05 +010095" For consistency run all tests with 'nocompatible' set.
96" This also enables use of line continuation.
97set nocp viminfo+=nviminfo
98
Bram Moolenaar30276f22019-01-24 17:59:39 +010099" Use utf-8 by default, instead of whatever the system default happens to be.
Bram Moolenaared79d1e2019-02-22 14:38:58 +0100100" Individual tests can overrule this at the top of the file and use
101" g:orig_encoding if needed.
102let g:orig_encoding = &encoding
Bram Moolenaar30276f22019-01-24 17:59:39 +0100103set encoding=utf-8
Bram Moolenaarac105ed2016-07-21 20:33:32 +0200104
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200105" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for
106" the test_name.vim file itself. Replace it here with a more restrictive one,
107" so we still catch mistakes.
Christian Brabandt4b2c8042021-11-03 22:31:44 +0000108if has("win32")
109 " replace any '/' directory separators by '\\'
110 let s:test_script_fname = substitute(expand('%'), '/', '\\', 'g')
111else
112 let s:test_script_fname = expand('%')
113endif
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200114au! SwapExists * call HandleSwapExists()
115func HandleSwapExists()
Bram Moolenaar8ce4b7e2020-08-07 18:12:18 +0200116 if exists('g:ignoreSwapExists')
117 return
118 endif
Bram Moolenaarb073da82019-07-13 14:47:26 +0200119 " Ignore finding a swap file for the test script (the user might be
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200120 " editing it and do ":make test_name") and the output file.
Bram Moolenaarb073da82019-07-13 14:47:26 +0200121 " Report finding another swap file and chose 'q' to avoid getting stuck.
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200122 if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
123 let v:swapchoice = 'e'
Bram Moolenaarb073da82019-07-13 14:47:26 +0200124 else
125 call assert_report('Unexpected swap file: ' .. v:swapname)
126 let v:swapchoice = 'q'
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200127 endif
128endfunc
129
Bram Moolenaar7a073542017-02-01 23:17:36 +0100130" Avoid stopping at the "hit enter" prompt
131set nomore
132
Bram Moolenaarc0662462015-12-30 15:49:05 +0100133" Output all messages in English.
134lang mess C
135
Bram Moolenaar10e1d012020-07-18 22:03:11 +0200136" suppress menu translation
137if has('gui_running') && exists('did_install_default_menus')
138 source $VIMRUNTIME/delmenu.vim
139 set langmenu=none
140 source $VIMRUNTIME/menu.vim
141endif
142
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100143let s:srcdir = expand('%:p:h:h')
144
Bram Moolenaar2690b5a2020-07-22 18:14:58 +0200145if has('win32')
146 " avoid prompt that is long or contains a line break
147 let $PROMPT = '$P$G'
Bram Moolenaar45df2a02020-07-29 15:03:01 +0200148 " On MS-Windows t_md and t_me are Vim specific escape sequences.
149 let s:t_bold = "\x1b[1m"
150 let s:t_normal = "\x1b[m"
151else
152 let s:t_bold = &t_md
153 let s:t_normal = &t_me
Bram Moolenaar2690b5a2020-07-22 18:14:58 +0200154endif
155
Bram Moolenaar4b2ce122020-11-21 21:41:41 +0100156if has('mac')
Dominique Pelle923dce22021-11-21 11:36:04 +0000157 " In macOS, when starting a shell in a terminal, a bash deprecation warning
Bram Moolenaar4b2ce122020-11-21 21:41:41 +0100158 " message is displayed. This breaks the terminal test. Disable the warning
159 " message.
160 let $BASH_SILENCE_DEPRECATION_WARNING = 1
161endif
162
Bram Moolenaarc216a7a2022-12-05 13:50:55 +0000163
Bram Moolenaar8e8df252016-05-25 21:23:21 +0200164" Prepare for calling test_garbagecollect_now().
Bram Moolenaarebf7dfa2016-04-14 12:46:51 +0200165let v:testing = 1
166
Bram Moolenaarfa4873c2022-06-30 22:13:59 +0100167" By default, copy each buffer line into allocated memory, so that valgrind can
168" detect accessing memory before and after it.
169call test_override('alloc_lines', 1)
170
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100171" Support function: get the alloc ID by name.
172function GetAllocId(name)
173 exe 'split ' . s:srcdir . '/alloc.h'
Bram Moolenaar065ee9a2016-01-15 20:53:38 +0100174 let top = search('typedef enum')
175 if top == 0
176 call add(v:errors, 'typedef not found in alloc.h')
177 endif
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100178 let lnum = search('aid_' . a:name . ',')
179 if lnum == 0
180 call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
181 endif
182 close
Bram Moolenaar065ee9a2016-01-15 20:53:38 +0100183 return lnum - top - 1
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100184endfunc
185
Bram Moolenaarb9093d52022-09-23 19:42:31 +0100186if has('reltime')
187 let g:func_start = reltime()
188endif
Bram Moolenaardaaa3d92022-09-22 15:13:00 +0100189
Bram Moolenaarc216a7a2022-12-05 13:50:55 +0000190" Get the list of swap files in the current directory.
191func s:GetSwapFileList()
192 let save_dir = &directory
193 let &directory = '.'
194 let files = swapfilelist()
195 let &directory = save_dir
196
197 " remove a match with runtest.vim
198 let idx = indexof(files, 'v:val =~ "runtest.vim."')
199 if idx >= 0
200 call remove(files, idx)
201 endif
202
203 return files
204endfunc
205
Bram Moolenaar6572a902022-12-06 14:21:09 +0000206" A previous (failed) test run may have left swap files behind. Delete them
207" before running tests again, they might interfere.
208for name in s:GetSwapFileList()
209 call delete(name)
210endfor
Bram Moolenaard6e74f52022-12-06 15:07:56 +0000211unlet name
Bram Moolenaar6572a902022-12-06 14:21:09 +0000212
213
Bram Moolenaar3bcd0dd2022-09-23 20:25:55 +0100214" Invoked when a test takes too much time.
215func TestTimeout(id)
216 split test.log
217 call append(line('$'), '')
218 call append(line('$'), 'Test timed out: ' .. g:testfunc)
219 write
220 call add(v:errors, 'Test timed out: ' . g:testfunc)
221
222 cquit! 42
223endfunc
224
Bram Moolenaar42205552017-03-18 19:42:22 +0100225func RunTheTest(test)
Bram Moolenaardaaa3d92022-09-22 15:13:00 +0100226 let prefix = ''
Bram Moolenaar75ee5442019-06-06 18:05:25 +0200227 if has('reltime')
Bram Moolenaarb9093d52022-09-23 19:42:31 +0100228 let prefix = strftime('%M:%S', localtime() - s:test_start_time) .. ' '
Bram Moolenaardaaa3d92022-09-22 15:13:00 +0100229 let g:func_start = reltime()
Bram Moolenaar75ee5442019-06-06 18:05:25 +0200230 endif
Bram Moolenaardaaa3d92022-09-22 15:13:00 +0100231 echoconsole prefix .. 'Executing ' .. a:test
Bram Moolenaare5f2a072017-02-01 22:31:49 +0100232
Bram Moolenaar3bcd0dd2022-09-23 20:25:55 +0100233 if has('timers')
234 " No test should take longer than 30 seconds. If it takes longer we
235 " assume we are stuck and need to break out.
236 let test_timeout_timer = timer_start(30000, 'TestTimeout')
237 endif
238
Bram Moolenaare5f2a072017-02-01 22:31:49 +0100239 " Avoid stopping at the "hit enter" prompt
240 set nomore
241
242 " Avoid a three second wait when a message is about to be overwritten by the
243 " mode message.
244 set noshowmode
245
Bram Moolenaarfa4873c2022-06-30 22:13:59 +0100246 " Clear any overrides, except "alloc_lines".
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100247 call test_override('ALL', 0)
248
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200249 " Some tests wipe out buffers. To be consistent, always wipe out all
250 " buffers.
251 %bwipe!
252
Bram Moolenaar209d3872017-11-16 21:52:51 +0100253 " The test may change the current directory. Save and restore the
254 " directory after executing the test.
255 let save_cwd = getcwd()
256
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100257 if exists("*SetUp")
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100258 try
259 call SetUp()
260 catch
261 call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
262 endtry
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100263 endif
264
Bram Moolenaar8bea1712022-06-15 20:49:35 +0100265 au VimLeavePre * call EarlyExit(g:testfunc)
Bram Moolenaarf204e052017-10-26 17:14:01 +0200266 if a:test =~ 'Test_nocatch_'
267 " Function handles errors itself. This avoids skipping commands after the
268 " error.
Bram Moolenaar776b9542021-03-10 22:27:48 +0100269 let g:skipped_reason = ''
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100270 exe 'call ' . a:test
Bram Moolenaar776b9542021-03-10 22:27:48 +0100271 if g:skipped_reason != ''
272 call add(s:messages, ' Skipped')
273 call add(s:skipped, 'SKIPPED ' . a:test . ': ' . g:skipped_reason)
274 endif
Bram Moolenaarf204e052017-10-26 17:14:01 +0200275 else
276 try
277 exe 'call ' . a:test
278 catch /^\cskipped/
279 call add(s:messages, ' Skipped')
280 call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
281 catch
282 call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
283 endtry
284 endif
Bram Moolenaar8bea1712022-06-15 20:49:35 +0100285 au! VimLeavePre
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100286
Bram Moolenaara22c56a2022-09-20 15:10:31 +0100287 if a:test =~ '_terminal_'
288 " Terminal tests sometimes hang, give extra information
289 echoconsole 'After executing ' .. a:test
290 endif
291
Bram Moolenaar8ad16da2019-01-06 15:29:57 +0100292 " In case 'insertmode' was set and something went wrong, make sure it is
293 " reset to avoid trouble with anything else.
294 set noinsertmode
295
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100296 if exists("*TearDown")
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100297 try
298 call TearDown()
299 catch
300 call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
301 endtry
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100302 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200303
Bram Moolenaar3bcd0dd2022-09-23 20:25:55 +0100304 if has('timers')
305 call timer_stop(test_timeout_timer)
306 endif
307
Bram Moolenaar0b5dc642019-08-11 22:56:15 +0200308 " Clear any autocommands and put back the catch-all for SwapExists.
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200309 au!
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200310 au SwapExists * call HandleSwapExists()
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200311
Bram Moolenaaref6b9792020-05-13 16:34:15 +0200312 " Check for and close any stray popup windows.
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100313 if has('popupwin')
Bram Moolenaarf05a1e52022-08-02 11:48:53 +0100314 call assert_equal([], popup_list(), 'Popup is still present')
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200315 call popup_clear(1)
Bram Moolenaarae943152019-06-16 22:54:14 +0200316 endif
317
Bram Moolenaar2d12c252022-06-13 21:42:45 +0100318 if filereadable('guidialogfile')
Bram Moolenaar217ea512022-06-14 17:13:59 +0100319 call add(v:errors, "Unexpected dialog: " .. readfile('guidialogfile')->join('<NL>'))
Bram Moolenaar2d12c252022-06-13 21:42:45 +0100320 call delete('guidialogfile')
321 endif
322
Bram Moolenaarce11de82017-10-26 22:00:00 +0200323 " Close any extra tab pages and windows and make the current one not modified.
324 while tabpagenr('$') > 1
Bram Moolenaarbdf931c2020-10-01 22:37:40 +0200325 let winid = win_getid()
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200326 quit!
Bram Moolenaarbdf931c2020-10-01 22:37:40 +0200327 if winid == win_getid()
328 echoerr 'Could not quit window'
329 break
330 endif
Bram Moolenaarce11de82017-10-26 22:00:00 +0200331 endwhile
332
Bram Moolenaar358308d2016-08-24 21:21:26 +0200333 while 1
334 let wincount = winnr('$')
335 if wincount == 1
336 break
337 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200338 bwipe!
Bram Moolenaar358308d2016-08-24 21:21:26 +0200339 if wincount == winnr('$')
340 " Did not manage to close a window.
341 only!
342 break
343 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200344 endwhile
Bram Moolenaar209d3872017-11-16 21:52:51 +0100345
346 exe 'cd ' . save_cwd
Bram Moolenaar640d4f02019-06-10 17:43:46 +0200347
Bram Moolenaara22c56a2022-09-20 15:10:31 +0100348 if a:test =~ '_terminal_'
349 " Terminal tests sometimes hang, give extra information
350 echoconsole 'Finished ' . a:test
351 endif
352
Bram Moolenaar640d4f02019-06-10 17:43:46 +0200353 let message = 'Executed ' . a:test
354 if has('reltime')
Bram Moolenaar8d943792020-06-21 20:39:37 +0200355 let message ..= repeat(' ', 50 - len(message))
Bram Moolenaardaaa3d92022-09-22 15:13:00 +0100356 let time = reltime(g:func_start)
Bram Moolenaar73e28dc2022-09-17 21:08:33 +0100357 if reltimefloat(time) > 0.1
Bram Moolenaar45df2a02020-07-29 15:03:01 +0200358 let message = s:t_bold .. message
Bram Moolenaar8d943792020-06-21 20:39:37 +0200359 endif
360 let message ..= ' in ' .. reltimestr(time) .. ' seconds'
Bram Moolenaar73e28dc2022-09-17 21:08:33 +0100361 if reltimefloat(time) > 0.1
Bram Moolenaar45df2a02020-07-29 15:03:01 +0200362 let message ..= s:t_normal
Bram Moolenaar8d943792020-06-21 20:39:37 +0200363 endif
Bram Moolenaar640d4f02019-06-10 17:43:46 +0200364 endif
365 call add(s:messages, message)
366 let s:done += 1
Bram Moolenaarc216a7a2022-12-05 13:50:55 +0000367
Bram Moolenaare5eae822022-12-08 16:30:16 +0000368 " close any split windows
369 while winnr('$') > 1
370 bwipe!
371 endwhile
372
Bram Moolenaar23526d22022-12-05 15:50:41 +0000373 " May be editing some buffer, wipe it out. Then we may end up in another
374 " buffer, continue until we end up in an empty no-name buffer without a swap
375 " file.
376 while bufname() != '' || execute('swapname') !~ 'No swap file'
Bram Moolenaarfa2533c2022-12-05 20:58:04 +0000377 let bn = bufnr()
378
379 noswapfile bwipe!
380
381 if bn == bufnr()
382 " avoid getting stuck in the same buffer
383 break
384 endif
Bram Moolenaar23526d22022-12-05 15:50:41 +0000385 endwhile
386
Bram Moolenaarc216a7a2022-12-05 13:50:55 +0000387 " Check if the test has left any swap files behind. Delete them before
388 " running tests again, they might interfere.
389 let swapfiles = s:GetSwapFileList()
390 if len(swapfiles) > 0
391 call add(s:messages, "Found swap files: " .. string(swapfiles))
392 for name in swapfiles
393 call delete(name)
394 endfor
395 endif
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100396endfunc
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100397
Bram Moolenaarce436de2020-03-21 15:17:20 +0100398func AfterTheTest(func_name)
Bram Moolenaar42205552017-03-18 19:42:22 +0100399 if len(v:errors) > 0
Bram Moolenaarce436de2020-03-21 15:17:20 +0100400 if match(s:may_fail_list, '^' .. a:func_name) >= 0
401 let s:fail_expected += 1
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200402 call add(s:errors_expected, 'Found errors in ' . g:testfunc . ':')
Bram Moolenaarce436de2020-03-21 15:17:20 +0100403 call extend(s:errors_expected, v:errors)
404 else
405 let s:fail += 1
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200406 call add(s:errors, 'Found errors in ' . g:testfunc . ':')
Bram Moolenaarce436de2020-03-21 15:17:20 +0100407 call extend(s:errors, v:errors)
408 endif
Bram Moolenaar42205552017-03-18 19:42:22 +0100409 let v:errors = []
410 endif
411endfunc
412
Bram Moolenaar89036762018-06-12 14:58:39 +0200413func EarlyExit(test)
414 " It's OK for the test we use to test the quit detection.
415 if a:test != 'Test_zz_quit_detected()'
Bram Moolenaar1c67f3a2021-12-30 13:32:09 +0000416 call add(v:errors, v:errmsg)
Bram Moolenaar89036762018-06-12 14:58:39 +0200417 call add(v:errors, 'Test caused Vim to exit: ' . a:test)
418 endif
419
420 call FinishTesting()
421endfunc
422
Bram Moolenaar42205552017-03-18 19:42:22 +0100423" This function can be called by a test if it wants to abort testing.
424func FinishTesting()
Bram Moolenaarce436de2020-03-21 15:17:20 +0100425 call AfterTheTest('')
Bram Moolenaar42205552017-03-18 19:42:22 +0100426
427 " Don't write viminfo on exit.
428 set viminfo=
429
Bram Moolenaard1ee0042017-07-29 20:39:53 +0200430 " Clean up files created by setup.vim
431 call delete('XfakeHOME', 'rf')
432
Bram Moolenaarce436de2020-03-21 15:17:20 +0100433 if s:fail == 0 && s:fail_expected == 0
Bram Moolenaar42205552017-03-18 19:42:22 +0100434 " Success, create the .res file so that make knows it's done.
435 exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
436 write
437 endif
438
439 if len(s:errors) > 0
440 " Append errors to test.log
441 split test.log
442 call append(line('$'), '')
443 call append(line('$'), 'From ' . g:testname . ':')
444 call append(line('$'), s:errors)
445 write
446 endif
447
Bram Moolenaar29f9ed22018-04-10 19:20:31 +0200448 if s:done == 0
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200449 if s:filtered > 0
Bram Moolenaardae453f2021-08-07 17:20:16 +0200450 if $TEST_FILTER != ''
451 let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'"
452 else
453 let message = "ALL tests match $TEST_SKIP_PAT: '" .. $TEST_SKIP_PAT .. "'"
454 endif
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200455 else
456 let message = 'NO tests executed'
457 endif
Bram Moolenaar29f9ed22018-04-10 19:20:31 +0200458 else
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200459 if s:filtered > 0
Bram Moolenaardae453f2021-08-07 17:20:16 +0200460 call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER and $TEST_SKIP_PAT")
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200461 endif
Bram Moolenaar29f9ed22018-04-10 19:20:31 +0200462 let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
463 endif
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200464 if s:done > 0 && has('reltime')
Bram Moolenaar45df2a02020-07-29 15:03:01 +0200465 let message = s:t_bold .. message .. repeat(' ', 40 - len(message))
Bram Moolenaarb9093d52022-09-23 19:42:31 +0100466 let message ..= ' in ' .. reltimestr(reltime(s:run_start_time)) .. ' seconds'
Bram Moolenaar45df2a02020-07-29 15:03:01 +0200467 let message ..= s:t_normal
Bram Moolenaar75ee5442019-06-06 18:05:25 +0200468 endif
Bram Moolenaar42205552017-03-18 19:42:22 +0100469 echo message
470 call add(s:messages, message)
471 if s:fail > 0
472 let message = s:fail . ' FAILED:'
473 echo message
474 call add(s:messages, message)
475 call extend(s:messages, s:errors)
476 endif
Bram Moolenaarce436de2020-03-21 15:17:20 +0100477 if s:fail_expected > 0
478 let message = s:fail_expected . ' FAILED (matching $TEST_MAY_FAIL):'
479 echo message
480 call add(s:messages, message)
481 call extend(s:messages, s:errors_expected)
482 endif
Bram Moolenaar42205552017-03-18 19:42:22 +0100483
484 " Add SKIPPED messages
485 call extend(s:messages, s:skipped)
486
487 " Append messages to the file "messages"
488 split messages
489 call append(line('$'), '')
490 call append(line('$'), 'From ' . g:testname . ':')
491 call append(line('$'), s:messages)
492 write
493
494 qall!
495endfunc
496
Bram Moolenaar43345542015-11-29 17:35:35 +0100497" Source the test script. First grab the file name, in case the script
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100498" navigates away. g:testname can be used by the tests.
499let g:testname = expand('%')
500let s:done = 0
501let s:fail = 0
Bram Moolenaarce436de2020-03-21 15:17:20 +0100502let s:fail_expected = 0
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100503let s:errors = []
Bram Moolenaarce436de2020-03-21 15:17:20 +0100504let s:errors_expected = []
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100505let s:messages = []
Bram Moolenaardac19472016-09-03 22:35:40 +0200506let s:skipped = []
Bram Moolenaarb544f3c2017-02-23 19:03:28 +0100507if expand('%') =~ 'test_vimscript.vim'
Bram Moolenaarce436de2020-03-21 15:17:20 +0100508 " this test has intentional errors, don't use try/catch.
Bram Moolenaar4686b322015-12-28 14:44:10 +0100509 source %
Bram Moolenaara2cce862016-01-02 19:50:04 +0100510else
511 try
512 source %
Bram Moolenaar9c0cec62019-06-06 13:38:15 +0200513 catch /^\cskipped/
514 call add(s:messages, ' Skipped')
515 call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
Bram Moolenaara2cce862016-01-02 19:50:04 +0100516 catch
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100517 let s:fail += 1
518 call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
Bram Moolenaara2cce862016-01-02 19:50:04 +0100519 endtry
520endif
Bram Moolenaar43345542015-11-29 17:35:35 +0100521
Bram Moolenaar7e0be3e2022-03-20 13:40:41 +0000522" Delete the .res file, it may change behavior for completion
523call delete(fnamemodify(g:testname, ':r') .. '.res')
524
Bram Moolenaar43345542015-11-29 17:35:35 +0100525" Locate Test_ functions and execute them.
526redir @q
Bram Moolenaar93bf5582016-02-18 22:25:47 +0100527silent function /^Test_
Bram Moolenaar43345542015-11-29 17:35:35 +0100528redir END
Bram Moolenaar61a6d4e2020-03-01 23:32:25 +0100529let s:tests = split(substitute(@q, '\(function\|def\) \(\k*()\)', '\2', 'g'))
Bram Moolenaar43345542015-11-29 17:35:35 +0100530
Bram Moolenaarbefb3662016-02-20 14:41:40 +0100531" If there is an extra argument filter the function names against it.
532if argc() > 1
533 let s:tests = filter(s:tests, 'v:val =~ argv(1)')
534endif
535
Bram Moolenaara7f6c3c2019-09-27 15:34:16 +0200536" If the environment variable $TEST_FILTER is set then filter the function
537" names against it.
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200538let s:filtered = 0
Bram Moolenaara7f6c3c2019-09-27 15:34:16 +0200539if $TEST_FILTER != ''
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200540 let s:filtered = len(s:tests)
Bram Moolenaara7f6c3c2019-09-27 15:34:16 +0200541 let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER')
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200542 let s:filtered -= len(s:tests)
Bram Moolenaara7f6c3c2019-09-27 15:34:16 +0200543endif
544
Bram Moolenaarce436de2020-03-21 15:17:20 +0100545let s:may_fail_list = []
546if $TEST_MAY_FAIL != ''
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200547 " Split the list at commas and add () to make it match g:testfunc.
Bram Moolenaarce436de2020-03-21 15:17:20 +0100548 let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'})
549endif
550
Bram Moolenaarcfc0a352016-01-09 20:23:00 +0100551" Execute the tests in alphabetical order.
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200552for g:testfunc in sort(s:tests)
Bram Moolenaardae453f2021-08-07 17:20:16 +0200553 if $TEST_SKIP_PAT != '' && g:testfunc =~ $TEST_SKIP_PAT
554 call add(s:messages, g:testfunc .. ' matches $TEST_SKIP_PAT')
555 let s:filtered += 1
556 continue
557 endif
558
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +0200559 " Silence, please!
560 set belloff=all
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100561 let prev_error = ''
562 let total_errors = []
Bram Moolenaar3ed9efc2020-03-26 16:50:57 +0100563 let g:run_nr = 1
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +0200564
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200565 " A test can set g:test_is_flaky to retry running the test.
566 let g:test_is_flaky = 0
Bram Moolenaar3cdcb092020-03-18 19:18:10 +0100567
Bram Moolenaar5fbbec12022-09-03 22:08:11 +0100568 let starttime = strftime("%H:%M:%S")
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200569 call RunTheTest(g:testfunc)
Bram Moolenaar43345542015-11-29 17:35:35 +0100570
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100571 " Repeat a flaky test. Give up when:
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200572 " - $TEST_NO_RETRY is not empty
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100573 " - it fails again with the same message
Bram Moolenaar1bc353b2019-09-01 14:45:28 +0200574 " - it fails five times (with a different message)
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100575 if len(v:errors) > 0
Bram Moolenaar622b3562020-07-27 20:02:41 +0200576 \ && $TEST_NO_RETRY == ''
Bram Moolenaarf08b0eb2021-10-16 13:00:14 +0100577 \ && g:test_is_flaky
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100578 while 1
Bram Moolenaar06d32a02022-09-03 13:58:47 +0100579 call add(s:messages, 'Found errors in ' .. g:testfunc .. ':')
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100580 call extend(s:messages, v:errors)
Bram Moolenaar15e737f2017-03-18 21:22:47 +0100581
Bram Moolenaar65258d32022-09-09 15:09:59 +0100582 let endtime = strftime("%H:%M:%S")
583 call add(total_errors, $'Run {g:run_nr}, {starttime} - {endtime}:')
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100584 call extend(total_errors, v:errors)
Bram Moolenaar55058602017-11-21 15:14:51 +0100585
Bram Moolenaar96ba25a2022-07-04 17:34:33 +0100586 if g:run_nr >= 5 || prev_error == v:errors[0]
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100587 call add(total_errors, 'Flaky test failed too often, giving up')
588 let v:errors = total_errors
589 break
590 endif
591
592 call add(s:messages, 'Flaky test failed, running it again')
593
594 " Flakiness is often caused by the system being very busy. Sleep a
595 " couple of seconds to have a higher chance of succeeding the second
596 " time.
597 sleep 2
598
599 let prev_error = v:errors[0]
600 let v:errors = []
Bram Moolenaar3ed9efc2020-03-26 16:50:57 +0100601 let g:run_nr += 1
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100602
Bram Moolenaar5fbbec12022-09-03 22:08:11 +0100603 let starttime = strftime("%H:%M:%S")
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200604 call RunTheTest(g:testfunc)
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100605
606 if len(v:errors) == 0
607 " Test passed on rerun.
608 break
609 endif
610 endwhile
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100611 endif
Bram Moolenaar43345542015-11-29 17:35:35 +0100612
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200613 call AfterTheTest(g:testfunc)
Bram Moolenaar43345542015-11-29 17:35:35 +0100614endfor
615
Bram Moolenaar42205552017-03-18 19:42:22 +0100616call FinishTesting()
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100617
618" vim: shiftwidth=2 sts=2 expandtab