blob: 7ad8539c93b4a79c745c1ef5269ec54951420b98 [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 Moolenaarabc81302023-06-04 16:55:27 +0100114
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200115au! SwapExists * call HandleSwapExists()
116func HandleSwapExists()
Bram Moolenaar8ce4b7e2020-08-07 18:12:18 +0200117 if exists('g:ignoreSwapExists')
Bram Moolenaarabc81302023-06-04 16:55:27 +0100118 if type(g:ignoreSwapExists) == v:t_string
119 let v:swapchoice = g:ignoreSwapExists
120 endif
Bram Moolenaar8ce4b7e2020-08-07 18:12:18 +0200121 return
122 endif
Bram Moolenaarb073da82019-07-13 14:47:26 +0200123 " Ignore finding a swap file for the test script (the user might be
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200124 " editing it and do ":make test_name") and the output file.
Bram Moolenaarb073da82019-07-13 14:47:26 +0200125 " Report finding another swap file and chose 'q' to avoid getting stuck.
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200126 if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
127 let v:swapchoice = 'e'
Bram Moolenaarb073da82019-07-13 14:47:26 +0200128 else
129 call assert_report('Unexpected swap file: ' .. v:swapname)
130 let v:swapchoice = 'q'
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200131 endif
132endfunc
133
Bram Moolenaar7a073542017-02-01 23:17:36 +0100134" Avoid stopping at the "hit enter" prompt
135set nomore
136
Bram Moolenaarc0662462015-12-30 15:49:05 +0100137" Output all messages in English.
138lang mess C
139
Bram Moolenaar10e1d012020-07-18 22:03:11 +0200140" suppress menu translation
141if has('gui_running') && exists('did_install_default_menus')
142 source $VIMRUNTIME/delmenu.vim
143 set langmenu=none
144 source $VIMRUNTIME/menu.vim
145endif
146
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100147let s:srcdir = expand('%:p:h:h')
148
Bram Moolenaar2690b5a2020-07-22 18:14:58 +0200149if has('win32')
150 " avoid prompt that is long or contains a line break
151 let $PROMPT = '$P$G'
Bram Moolenaar45df2a02020-07-29 15:03:01 +0200152 " On MS-Windows t_md and t_me are Vim specific escape sequences.
153 let s:t_bold = "\x1b[1m"
154 let s:t_normal = "\x1b[m"
155else
156 let s:t_bold = &t_md
157 let s:t_normal = &t_me
Bram Moolenaar2690b5a2020-07-22 18:14:58 +0200158endif
159
Bram Moolenaar4b2ce122020-11-21 21:41:41 +0100160if has('mac')
Dominique Pelle923dce22021-11-21 11:36:04 +0000161 " In macOS, when starting a shell in a terminal, a bash deprecation warning
Bram Moolenaar4b2ce122020-11-21 21:41:41 +0100162 " message is displayed. This breaks the terminal test. Disable the warning
163 " message.
164 let $BASH_SILENCE_DEPRECATION_WARNING = 1
165endif
166
Bram Moolenaarc216a7a2022-12-05 13:50:55 +0000167
Bram Moolenaar8e8df252016-05-25 21:23:21 +0200168" Prepare for calling test_garbagecollect_now().
Bram Moolenaarebf7dfa2016-04-14 12:46:51 +0200169let v:testing = 1
170
Bram Moolenaarfa4873c2022-06-30 22:13:59 +0100171" By default, copy each buffer line into allocated memory, so that valgrind can
172" detect accessing memory before and after it.
173call test_override('alloc_lines', 1)
174
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100175" Support function: get the alloc ID by name.
176function GetAllocId(name)
177 exe 'split ' . s:srcdir . '/alloc.h'
Bram Moolenaar065ee9a2016-01-15 20:53:38 +0100178 let top = search('typedef enum')
179 if top == 0
180 call add(v:errors, 'typedef not found in alloc.h')
181 endif
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100182 let lnum = search('aid_' . a:name . ',')
183 if lnum == 0
184 call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
185 endif
186 close
Bram Moolenaar065ee9a2016-01-15 20:53:38 +0100187 return lnum - top - 1
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100188endfunc
189
Bram Moolenaarb9093d52022-09-23 19:42:31 +0100190if has('reltime')
191 let g:func_start = reltime()
192endif
Bram Moolenaardaaa3d92022-09-22 15:13:00 +0100193
Bram Moolenaarc216a7a2022-12-05 13:50:55 +0000194" Get the list of swap files in the current directory.
195func s:GetSwapFileList()
196 let save_dir = &directory
197 let &directory = '.'
198 let files = swapfilelist()
199 let &directory = save_dir
200
201 " remove a match with runtest.vim
202 let idx = indexof(files, 'v:val =~ "runtest.vim."')
203 if idx >= 0
204 call remove(files, idx)
205 endif
206
207 return files
208endfunc
209
Bram Moolenaar6572a902022-12-06 14:21:09 +0000210" A previous (failed) test run may have left swap files behind. Delete them
211" before running tests again, they might interfere.
212for name in s:GetSwapFileList()
213 call delete(name)
214endfor
Bram Moolenaard6e74f52022-12-06 15:07:56 +0000215unlet name
Bram Moolenaar6572a902022-12-06 14:21:09 +0000216
217
Bram Moolenaar3bcd0dd2022-09-23 20:25:55 +0100218" Invoked when a test takes too much time.
219func TestTimeout(id)
220 split test.log
221 call append(line('$'), '')
222 call append(line('$'), 'Test timed out: ' .. g:testfunc)
223 write
224 call add(v:errors, 'Test timed out: ' . g:testfunc)
225
226 cquit! 42
227endfunc
228
Bram Moolenaar42205552017-03-18 19:42:22 +0100229func RunTheTest(test)
Bram Moolenaardaaa3d92022-09-22 15:13:00 +0100230 let prefix = ''
Bram Moolenaar75ee5442019-06-06 18:05:25 +0200231 if has('reltime')
Bram Moolenaarb9093d52022-09-23 19:42:31 +0100232 let prefix = strftime('%M:%S', localtime() - s:test_start_time) .. ' '
Bram Moolenaardaaa3d92022-09-22 15:13:00 +0100233 let g:func_start = reltime()
Bram Moolenaar75ee5442019-06-06 18:05:25 +0200234 endif
Bram Moolenaardaaa3d92022-09-22 15:13:00 +0100235 echoconsole prefix .. 'Executing ' .. a:test
Bram Moolenaare5f2a072017-02-01 22:31:49 +0100236
Bram Moolenaar3bcd0dd2022-09-23 20:25:55 +0100237 if has('timers')
238 " No test should take longer than 30 seconds. If it takes longer we
239 " assume we are stuck and need to break out.
240 let test_timeout_timer = timer_start(30000, 'TestTimeout')
241 endif
242
Bram Moolenaare5f2a072017-02-01 22:31:49 +0100243 " Avoid stopping at the "hit enter" prompt
244 set nomore
245
246 " Avoid a three second wait when a message is about to be overwritten by the
247 " mode message.
248 set noshowmode
249
Bram Moolenaarfa4873c2022-06-30 22:13:59 +0100250 " Clear any overrides, except "alloc_lines".
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100251 call test_override('ALL', 0)
252
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200253 " Some tests wipe out buffers. To be consistent, always wipe out all
254 " buffers.
255 %bwipe!
256
Bram Moolenaar209d3872017-11-16 21:52:51 +0100257 " The test may change the current directory. Save and restore the
258 " directory after executing the test.
259 let save_cwd = getcwd()
260
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100261 if exists("*SetUp")
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100262 try
263 call SetUp()
264 catch
265 call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
266 endtry
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100267 endif
268
Bram Moolenaar8bea1712022-06-15 20:49:35 +0100269 au VimLeavePre * call EarlyExit(g:testfunc)
Bram Moolenaarf204e052017-10-26 17:14:01 +0200270 if a:test =~ 'Test_nocatch_'
271 " Function handles errors itself. This avoids skipping commands after the
272 " error.
Bram Moolenaar776b9542021-03-10 22:27:48 +0100273 let g:skipped_reason = ''
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100274 exe 'call ' . a:test
Bram Moolenaar776b9542021-03-10 22:27:48 +0100275 if g:skipped_reason != ''
276 call add(s:messages, ' Skipped')
277 call add(s:skipped, 'SKIPPED ' . a:test . ': ' . g:skipped_reason)
278 endif
Bram Moolenaarf204e052017-10-26 17:14:01 +0200279 else
280 try
281 exe 'call ' . a:test
282 catch /^\cskipped/
283 call add(s:messages, ' Skipped')
284 call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
285 catch
286 call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
287 endtry
288 endif
Bram Moolenaar8bea1712022-06-15 20:49:35 +0100289 au! VimLeavePre
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100290
Bram Moolenaara22c56a2022-09-20 15:10:31 +0100291 if a:test =~ '_terminal_'
292 " Terminal tests sometimes hang, give extra information
293 echoconsole 'After executing ' .. a:test
294 endif
295
Bram Moolenaar8ad16da2019-01-06 15:29:57 +0100296 " In case 'insertmode' was set and something went wrong, make sure it is
297 " reset to avoid trouble with anything else.
298 set noinsertmode
299
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100300 if exists("*TearDown")
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100301 try
302 call TearDown()
303 catch
304 call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
305 endtry
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100306 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200307
Bram Moolenaar3bcd0dd2022-09-23 20:25:55 +0100308 if has('timers')
309 call timer_stop(test_timeout_timer)
310 endif
311
Bram Moolenaar0b5dc642019-08-11 22:56:15 +0200312 " Clear any autocommands and put back the catch-all for SwapExists.
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200313 au!
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200314 au SwapExists * call HandleSwapExists()
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200315
Bram Moolenaaref6b9792020-05-13 16:34:15 +0200316 " Check for and close any stray popup windows.
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100317 if has('popupwin')
Bram Moolenaarf05a1e52022-08-02 11:48:53 +0100318 call assert_equal([], popup_list(), 'Popup is still present')
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200319 call popup_clear(1)
Bram Moolenaarae943152019-06-16 22:54:14 +0200320 endif
321
Bram Moolenaar2d12c252022-06-13 21:42:45 +0100322 if filereadable('guidialogfile')
Bram Moolenaar217ea512022-06-14 17:13:59 +0100323 call add(v:errors, "Unexpected dialog: " .. readfile('guidialogfile')->join('<NL>'))
Bram Moolenaar2d12c252022-06-13 21:42:45 +0100324 call delete('guidialogfile')
325 endif
326
Bram Moolenaarce11de82017-10-26 22:00:00 +0200327 " Close any extra tab pages and windows and make the current one not modified.
328 while tabpagenr('$') > 1
Bram Moolenaarbdf931c2020-10-01 22:37:40 +0200329 let winid = win_getid()
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200330 quit!
Bram Moolenaarbdf931c2020-10-01 22:37:40 +0200331 if winid == win_getid()
332 echoerr 'Could not quit window'
333 break
334 endif
Bram Moolenaarce11de82017-10-26 22:00:00 +0200335 endwhile
336
Bram Moolenaar358308d2016-08-24 21:21:26 +0200337 while 1
338 let wincount = winnr('$')
339 if wincount == 1
340 break
341 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200342 bwipe!
Bram Moolenaar358308d2016-08-24 21:21:26 +0200343 if wincount == winnr('$')
344 " Did not manage to close a window.
345 only!
346 break
347 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200348 endwhile
Bram Moolenaar209d3872017-11-16 21:52:51 +0100349
350 exe 'cd ' . save_cwd
Bram Moolenaar640d4f02019-06-10 17:43:46 +0200351
Bram Moolenaara22c56a2022-09-20 15:10:31 +0100352 if a:test =~ '_terminal_'
353 " Terminal tests sometimes hang, give extra information
354 echoconsole 'Finished ' . a:test
355 endif
356
Bram Moolenaar640d4f02019-06-10 17:43:46 +0200357 let message = 'Executed ' . a:test
358 if has('reltime')
Bram Moolenaar8d943792020-06-21 20:39:37 +0200359 let message ..= repeat(' ', 50 - len(message))
Bram Moolenaardaaa3d92022-09-22 15:13:00 +0100360 let time = reltime(g:func_start)
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_bold .. message
Bram Moolenaar8d943792020-06-21 20:39:37 +0200363 endif
364 let message ..= ' in ' .. reltimestr(time) .. ' seconds'
Bram Moolenaar73e28dc2022-09-17 21:08:33 +0100365 if reltimefloat(time) > 0.1
Bram Moolenaar45df2a02020-07-29 15:03:01 +0200366 let message ..= s:t_normal
Bram Moolenaar8d943792020-06-21 20:39:37 +0200367 endif
Bram Moolenaar640d4f02019-06-10 17:43:46 +0200368 endif
369 call add(s:messages, message)
370 let s:done += 1
Bram Moolenaarc216a7a2022-12-05 13:50:55 +0000371
Bram Moolenaare5eae822022-12-08 16:30:16 +0000372 " close any split windows
373 while winnr('$') > 1
374 bwipe!
375 endwhile
376
Bram Moolenaar23526d22022-12-05 15:50:41 +0000377 " May be editing some buffer, wipe it out. Then we may end up in another
378 " buffer, continue until we end up in an empty no-name buffer without a swap
379 " file.
380 while bufname() != '' || execute('swapname') !~ 'No swap file'
Bram Moolenaarfa2533c2022-12-05 20:58:04 +0000381 let bn = bufnr()
382
383 noswapfile bwipe!
384
385 if bn == bufnr()
386 " avoid getting stuck in the same buffer
387 break
388 endif
Bram Moolenaar23526d22022-12-05 15:50:41 +0000389 endwhile
390
Bram Moolenaarc216a7a2022-12-05 13:50:55 +0000391 " Check if the test has left any swap files behind. Delete them before
392 " running tests again, they might interfere.
393 let swapfiles = s:GetSwapFileList()
394 if len(swapfiles) > 0
395 call add(s:messages, "Found swap files: " .. string(swapfiles))
396 for name in swapfiles
397 call delete(name)
398 endfor
399 endif
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100400endfunc
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100401
Bram Moolenaarce436de2020-03-21 15:17:20 +0100402func AfterTheTest(func_name)
Bram Moolenaar42205552017-03-18 19:42:22 +0100403 if len(v:errors) > 0
Bram Moolenaarce436de2020-03-21 15:17:20 +0100404 if match(s:may_fail_list, '^' .. a:func_name) >= 0
405 let s:fail_expected += 1
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200406 call add(s:errors_expected, 'Found errors in ' . g:testfunc . ':')
Bram Moolenaarce436de2020-03-21 15:17:20 +0100407 call extend(s:errors_expected, v:errors)
408 else
409 let s:fail += 1
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200410 call add(s:errors, 'Found errors in ' . g:testfunc . ':')
Bram Moolenaarce436de2020-03-21 15:17:20 +0100411 call extend(s:errors, v:errors)
412 endif
Bram Moolenaar42205552017-03-18 19:42:22 +0100413 let v:errors = []
414 endif
415endfunc
416
Bram Moolenaar89036762018-06-12 14:58:39 +0200417func EarlyExit(test)
418 " It's OK for the test we use to test the quit detection.
419 if a:test != 'Test_zz_quit_detected()'
Bram Moolenaar1c67f3a2021-12-30 13:32:09 +0000420 call add(v:errors, v:errmsg)
Bram Moolenaar89036762018-06-12 14:58:39 +0200421 call add(v:errors, 'Test caused Vim to exit: ' . a:test)
422 endif
423
424 call FinishTesting()
425endfunc
426
Bram Moolenaar42205552017-03-18 19:42:22 +0100427" This function can be called by a test if it wants to abort testing.
428func FinishTesting()
Bram Moolenaarce436de2020-03-21 15:17:20 +0100429 call AfterTheTest('')
Bram Moolenaar42205552017-03-18 19:42:22 +0100430
431 " Don't write viminfo on exit.
432 set viminfo=
433
Bram Moolenaard1ee0042017-07-29 20:39:53 +0200434 " Clean up files created by setup.vim
435 call delete('XfakeHOME', 'rf')
436
Bram Moolenaarce436de2020-03-21 15:17:20 +0100437 if s:fail == 0 && s:fail_expected == 0
Bram Moolenaar42205552017-03-18 19:42:22 +0100438 " Success, create the .res file so that make knows it's done.
439 exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
440 write
441 endif
442
443 if len(s:errors) > 0
444 " Append errors to test.log
445 split test.log
446 call append(line('$'), '')
447 call append(line('$'), 'From ' . g:testname . ':')
448 call append(line('$'), s:errors)
449 write
450 endif
451
Bram Moolenaar29f9ed22018-04-10 19:20:31 +0200452 if s:done == 0
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200453 if s:filtered > 0
Bram Moolenaardae453f2021-08-07 17:20:16 +0200454 if $TEST_FILTER != ''
455 let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'"
456 else
457 let message = "ALL tests match $TEST_SKIP_PAT: '" .. $TEST_SKIP_PAT .. "'"
458 endif
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200459 else
460 let message = 'NO tests executed'
461 endif
Bram Moolenaar29f9ed22018-04-10 19:20:31 +0200462 else
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200463 if s:filtered > 0
Bram Moolenaardae453f2021-08-07 17:20:16 +0200464 call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER and $TEST_SKIP_PAT")
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200465 endif
Bram Moolenaar29f9ed22018-04-10 19:20:31 +0200466 let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
467 endif
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200468 if s:done > 0 && has('reltime')
Bram Moolenaar45df2a02020-07-29 15:03:01 +0200469 let message = s:t_bold .. message .. repeat(' ', 40 - len(message))
Bram Moolenaarb9093d52022-09-23 19:42:31 +0100470 let message ..= ' in ' .. reltimestr(reltime(s:run_start_time)) .. ' seconds'
Bram Moolenaar45df2a02020-07-29 15:03:01 +0200471 let message ..= s:t_normal
Bram Moolenaar75ee5442019-06-06 18:05:25 +0200472 endif
Bram Moolenaar42205552017-03-18 19:42:22 +0100473 echo message
474 call add(s:messages, message)
475 if s:fail > 0
476 let message = s:fail . ' FAILED:'
477 echo message
478 call add(s:messages, message)
479 call extend(s:messages, s:errors)
480 endif
Bram Moolenaarce436de2020-03-21 15:17:20 +0100481 if s:fail_expected > 0
482 let message = s:fail_expected . ' FAILED (matching $TEST_MAY_FAIL):'
483 echo message
484 call add(s:messages, message)
485 call extend(s:messages, s:errors_expected)
486 endif
Bram Moolenaar42205552017-03-18 19:42:22 +0100487
488 " Add SKIPPED messages
489 call extend(s:messages, s:skipped)
490
491 " Append messages to the file "messages"
492 split messages
493 call append(line('$'), '')
494 call append(line('$'), 'From ' . g:testname . ':')
495 call append(line('$'), s:messages)
496 write
497
498 qall!
499endfunc
500
Bram Moolenaar43345542015-11-29 17:35:35 +0100501" Source the test script. First grab the file name, in case the script
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100502" navigates away. g:testname can be used by the tests.
503let g:testname = expand('%')
504let s:done = 0
505let s:fail = 0
Bram Moolenaarce436de2020-03-21 15:17:20 +0100506let s:fail_expected = 0
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100507let s:errors = []
Bram Moolenaarce436de2020-03-21 15:17:20 +0100508let s:errors_expected = []
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100509let s:messages = []
Bram Moolenaardac19472016-09-03 22:35:40 +0200510let s:skipped = []
Bram Moolenaarb544f3c2017-02-23 19:03:28 +0100511if expand('%') =~ 'test_vimscript.vim'
Bram Moolenaarce436de2020-03-21 15:17:20 +0100512 " this test has intentional errors, don't use try/catch.
Bram Moolenaar4686b322015-12-28 14:44:10 +0100513 source %
Bram Moolenaara2cce862016-01-02 19:50:04 +0100514else
515 try
516 source %
Bram Moolenaar9c0cec62019-06-06 13:38:15 +0200517 catch /^\cskipped/
518 call add(s:messages, ' Skipped')
519 call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
Bram Moolenaara2cce862016-01-02 19:50:04 +0100520 catch
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100521 let s:fail += 1
522 call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
Bram Moolenaara2cce862016-01-02 19:50:04 +0100523 endtry
524endif
Bram Moolenaar43345542015-11-29 17:35:35 +0100525
Bram Moolenaar7e0be3e2022-03-20 13:40:41 +0000526" Delete the .res file, it may change behavior for completion
527call delete(fnamemodify(g:testname, ':r') .. '.res')
528
Bram Moolenaar43345542015-11-29 17:35:35 +0100529" Locate Test_ functions and execute them.
530redir @q
Bram Moolenaar93bf5582016-02-18 22:25:47 +0100531silent function /^Test_
Bram Moolenaar43345542015-11-29 17:35:35 +0100532redir END
Bram Moolenaar61a6d4e2020-03-01 23:32:25 +0100533let s:tests = split(substitute(@q, '\(function\|def\) \(\k*()\)', '\2', 'g'))
Bram Moolenaar43345542015-11-29 17:35:35 +0100534
Bram Moolenaarbefb3662016-02-20 14:41:40 +0100535" If there is an extra argument filter the function names against it.
536if argc() > 1
537 let s:tests = filter(s:tests, 'v:val =~ argv(1)')
538endif
539
Bram Moolenaara7f6c3c2019-09-27 15:34:16 +0200540" If the environment variable $TEST_FILTER is set then filter the function
541" names against it.
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200542let s:filtered = 0
Bram Moolenaara7f6c3c2019-09-27 15:34:16 +0200543if $TEST_FILTER != ''
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200544 let s:filtered = len(s:tests)
Bram Moolenaara7f6c3c2019-09-27 15:34:16 +0200545 let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER')
Bram Moolenaar7b666c72019-09-27 21:25:00 +0200546 let s:filtered -= len(s:tests)
Bram Moolenaara7f6c3c2019-09-27 15:34:16 +0200547endif
548
Bram Moolenaarce436de2020-03-21 15:17:20 +0100549let s:may_fail_list = []
550if $TEST_MAY_FAIL != ''
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200551 " Split the list at commas and add () to make it match g:testfunc.
Bram Moolenaarce436de2020-03-21 15:17:20 +0100552 let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'})
553endif
554
Bram Moolenaarcfc0a352016-01-09 20:23:00 +0100555" Execute the tests in alphabetical order.
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200556for g:testfunc in sort(s:tests)
Bram Moolenaardae453f2021-08-07 17:20:16 +0200557 if $TEST_SKIP_PAT != '' && g:testfunc =~ $TEST_SKIP_PAT
558 call add(s:messages, g:testfunc .. ' matches $TEST_SKIP_PAT')
559 let s:filtered += 1
560 continue
561 endif
562
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +0200563 " Silence, please!
564 set belloff=all
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100565 let prev_error = ''
566 let total_errors = []
Bram Moolenaar3ed9efc2020-03-26 16:50:57 +0100567 let g:run_nr = 1
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +0200568
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200569 " A test can set g:test_is_flaky to retry running the test.
570 let g:test_is_flaky = 0
Bram Moolenaar3cdcb092020-03-18 19:18:10 +0100571
Bram Moolenaar5fbbec12022-09-03 22:08:11 +0100572 let starttime = strftime("%H:%M:%S")
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200573 call RunTheTest(g:testfunc)
Bram Moolenaar43345542015-11-29 17:35:35 +0100574
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100575 " Repeat a flaky test. Give up when:
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200576 " - $TEST_NO_RETRY is not empty
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100577 " - it fails again with the same message
Bram Moolenaar1bc353b2019-09-01 14:45:28 +0200578 " - it fails five times (with a different message)
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100579 if len(v:errors) > 0
Bram Moolenaar622b3562020-07-27 20:02:41 +0200580 \ && $TEST_NO_RETRY == ''
Bram Moolenaarf08b0eb2021-10-16 13:00:14 +0100581 \ && g:test_is_flaky
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100582 while 1
Bram Moolenaar06d32a02022-09-03 13:58:47 +0100583 call add(s:messages, 'Found errors in ' .. g:testfunc .. ':')
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100584 call extend(s:messages, v:errors)
Bram Moolenaar15e737f2017-03-18 21:22:47 +0100585
Bram Moolenaar65258d32022-09-09 15:09:59 +0100586 let endtime = strftime("%H:%M:%S")
587 call add(total_errors, $'Run {g:run_nr}, {starttime} - {endtime}:')
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100588 call extend(total_errors, v:errors)
Bram Moolenaar55058602017-11-21 15:14:51 +0100589
Bram Moolenaar96ba25a2022-07-04 17:34:33 +0100590 if g:run_nr >= 5 || prev_error == v:errors[0]
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100591 call add(total_errors, 'Flaky test failed too often, giving up')
592 let v:errors = total_errors
593 break
594 endif
595
596 call add(s:messages, 'Flaky test failed, running it again')
597
598 " Flakiness is often caused by the system being very busy. Sleep a
599 " couple of seconds to have a higher chance of succeeding the second
600 " time.
601 sleep 2
602
603 let prev_error = v:errors[0]
604 let v:errors = []
Bram Moolenaar3ed9efc2020-03-26 16:50:57 +0100605 let g:run_nr += 1
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100606
Bram Moolenaar5fbbec12022-09-03 22:08:11 +0100607 let starttime = strftime("%H:%M:%S")
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200608 call RunTheTest(g:testfunc)
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100609
610 if len(v:errors) == 0
611 " Test passed on rerun.
612 break
613 endif
614 endwhile
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100615 endif
Bram Moolenaar43345542015-11-29 17:35:35 +0100616
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +0200617 call AfterTheTest(g:testfunc)
Bram Moolenaar43345542015-11-29 17:35:35 +0100618endfor
619
Bram Moolenaar42205552017-03-18 19:42:22 +0100620call FinishTesting()
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100621
622" vim: shiftwidth=2 sts=2 expandtab