blob: f855f6800525ee5b0ca187df655c99a6d9594caf [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
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"
Bram Moolenaar43345542015-11-29 17:35:35 +010010" 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.
Bram Moolenaar00af60b2016-02-13 14:06:14 +010027"
28" When debugging a test it can be useful to add messages to v:errors:
Bram Moolenaar8ad16da2019-01-06 15:29:57 +010029" call add(v:errors, "this happened")
Bram Moolenaar00af60b2016-02-13 14:06:14 +010030
Bram Moolenaar43345542015-11-29 17:35:35 +010031
32" Without the +eval feature we can't run these tests, bail out.
Bram Moolenaar4686b322015-12-28 14:44:10 +010033so small.vim
Bram Moolenaar43345542015-11-29 17:35:35 +010034
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
Bram Moolenaar75ee5442019-06-06 18:05:25 +020045if has('reltime')
46 let s:start_time = reltime()
47endif
48
Bram Moolenaar89b10422016-07-12 22:51:22 +020049" Common with all tests on all systems.
50source setup.vim
51
Bram Moolenaarc0662462015-12-30 15:49:05 +010052" For consistency run all tests with 'nocompatible' set.
53" This also enables use of line continuation.
54set nocp viminfo+=nviminfo
55
Bram Moolenaar30276f22019-01-24 17:59:39 +010056" Use utf-8 by default, instead of whatever the system default happens to be.
Bram Moolenaared79d1e2019-02-22 14:38:58 +010057" Individual tests can overrule this at the top of the file and use
58" g:orig_encoding if needed.
59let g:orig_encoding = &encoding
Bram Moolenaar30276f22019-01-24 17:59:39 +010060set encoding=utf-8
Bram Moolenaarac105ed2016-07-21 20:33:32 +020061
Bram Moolenaard8f27b32018-10-07 15:42:07 +020062" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for
63" the test_name.vim file itself. Replace it here with a more restrictive one,
64" so we still catch mistakes.
65let s:test_script_fname = expand('%')
66au! SwapExists * call HandleSwapExists()
67func HandleSwapExists()
68 " Only ignore finding a swap file for the test script (the user might be
69 " editing it and do ":make test_name") and the output file.
70 if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
71 let v:swapchoice = 'e'
72 endif
73endfunc
74
Bram Moolenaar7a073542017-02-01 23:17:36 +010075" Avoid stopping at the "hit enter" prompt
76set nomore
77
Bram Moolenaarc0662462015-12-30 15:49:05 +010078" Output all messages in English.
79lang mess C
80
Bram Moolenaarf60b7962016-01-16 22:47:23 +010081" Always use forward slashes.
82set shellslash
83
Bram Moolenaar28fb79d2016-01-09 22:28:33 +010084let s:srcdir = expand('%:p:h:h')
85
Bram Moolenaar8e8df252016-05-25 21:23:21 +020086" Prepare for calling test_garbagecollect_now().
Bram Moolenaarebf7dfa2016-04-14 12:46:51 +020087let v:testing = 1
88
Bram Moolenaar28fb79d2016-01-09 22:28:33 +010089" Support function: get the alloc ID by name.
90function GetAllocId(name)
91 exe 'split ' . s:srcdir . '/alloc.h'
Bram Moolenaar065ee9a2016-01-15 20:53:38 +010092 let top = search('typedef enum')
93 if top == 0
94 call add(v:errors, 'typedef not found in alloc.h')
95 endif
Bram Moolenaar28fb79d2016-01-09 22:28:33 +010096 let lnum = search('aid_' . a:name . ',')
97 if lnum == 0
98 call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
99 endif
100 close
Bram Moolenaar065ee9a2016-01-15 20:53:38 +0100101 return lnum - top - 1
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100102endfunc
103
Bram Moolenaar42205552017-03-18 19:42:22 +0100104func RunTheTest(test)
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100105 echo 'Executing ' . a:test
Bram Moolenaar75ee5442019-06-06 18:05:25 +0200106 if has('reltime')
107 let func_start = reltime()
108 endif
Bram Moolenaare5f2a072017-02-01 22:31:49 +0100109
110 " Avoid stopping at the "hit enter" prompt
111 set nomore
112
113 " Avoid a three second wait when a message is about to be overwritten by the
114 " mode message.
115 set noshowmode
116
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100117 " Clear any overrides.
118 call test_override('ALL', 0)
119
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200120 " Some tests wipe out buffers. To be consistent, always wipe out all
121 " buffers.
122 %bwipe!
123
Bram Moolenaar209d3872017-11-16 21:52:51 +0100124 " The test may change the current directory. Save and restore the
125 " directory after executing the test.
126 let save_cwd = getcwd()
127
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100128 if exists("*SetUp")
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100129 try
130 call SetUp()
131 catch
132 call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
133 endtry
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100134 endif
135
Bram Moolenaar75ee5442019-06-06 18:05:25 +0200136 let message = 'Executed ' . a:test
137 if has('reltime')
138 let message ..= ' in ' .. reltimestr(reltime(func_start)) .. ' seconds'
139 endif
140 call add(s:messages, message)
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100141 let s:done += 1
Bram Moolenaarf204e052017-10-26 17:14:01 +0200142
143 if a:test =~ 'Test_nocatch_'
144 " Function handles errors itself. This avoids skipping commands after the
145 " error.
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100146 exe 'call ' . a:test
Bram Moolenaarf204e052017-10-26 17:14:01 +0200147 else
148 try
Bram Moolenaar89036762018-06-12 14:58:39 +0200149 let s:test = a:test
150 au VimLeavePre * call EarlyExit(s:test)
Bram Moolenaarf204e052017-10-26 17:14:01 +0200151 exe 'call ' . a:test
Bram Moolenaar89036762018-06-12 14:58:39 +0200152 au! VimLeavePre
Bram Moolenaarf204e052017-10-26 17:14:01 +0200153 catch /^\cskipped/
154 call add(s:messages, ' Skipped')
155 call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
156 catch
157 call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
158 endtry
159 endif
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100160
Bram Moolenaar8ad16da2019-01-06 15:29:57 +0100161 " In case 'insertmode' was set and something went wrong, make sure it is
162 " reset to avoid trouble with anything else.
163 set noinsertmode
164
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100165 if exists("*TearDown")
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100166 try
167 call TearDown()
168 catch
169 call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
170 endtry
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100171 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200172
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200173 " Clear any autocommands
174 au!
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200175 au SwapExists * call HandleSwapExists()
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200176
Bram Moolenaarce11de82017-10-26 22:00:00 +0200177 " Close any extra tab pages and windows and make the current one not modified.
178 while tabpagenr('$') > 1
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200179 quit!
Bram Moolenaarce11de82017-10-26 22:00:00 +0200180 endwhile
181
Bram Moolenaar358308d2016-08-24 21:21:26 +0200182 while 1
183 let wincount = winnr('$')
184 if wincount == 1
185 break
186 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200187 bwipe!
Bram Moolenaar358308d2016-08-24 21:21:26 +0200188 if wincount == winnr('$')
189 " Did not manage to close a window.
190 only!
191 break
192 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200193 endwhile
Bram Moolenaar209d3872017-11-16 21:52:51 +0100194
195 exe 'cd ' . save_cwd
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100196endfunc
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100197
Bram Moolenaar42205552017-03-18 19:42:22 +0100198func AfterTheTest()
199 if len(v:errors) > 0
200 let s:fail += 1
201 call add(s:errors, 'Found errors in ' . s:test . ':')
202 call extend(s:errors, v:errors)
203 let v:errors = []
204 endif
205endfunc
206
Bram Moolenaar89036762018-06-12 14:58:39 +0200207func EarlyExit(test)
208 " It's OK for the test we use to test the quit detection.
209 if a:test != 'Test_zz_quit_detected()'
210 call add(v:errors, 'Test caused Vim to exit: ' . a:test)
211 endif
212
213 call FinishTesting()
214endfunc
215
Bram Moolenaar42205552017-03-18 19:42:22 +0100216" This function can be called by a test if it wants to abort testing.
217func FinishTesting()
218 call AfterTheTest()
219
220 " Don't write viminfo on exit.
221 set viminfo=
222
Bram Moolenaard1ee0042017-07-29 20:39:53 +0200223 " Clean up files created by setup.vim
224 call delete('XfakeHOME', 'rf')
225
Bram Moolenaar42205552017-03-18 19:42:22 +0100226 if s:fail == 0
227 " Success, create the .res file so that make knows it's done.
228 exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
229 write
230 endif
231
232 if len(s:errors) > 0
233 " Append errors to test.log
234 split test.log
235 call append(line('$'), '')
236 call append(line('$'), 'From ' . g:testname . ':')
237 call append(line('$'), s:errors)
238 write
239 endif
240
Bram Moolenaar29f9ed22018-04-10 19:20:31 +0200241 if s:done == 0
242 let message = 'NO tests executed'
243 else
244 let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
245 endif
Bram Moolenaar75ee5442019-06-06 18:05:25 +0200246 if has('reltime')
247 let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds'
248 endif
Bram Moolenaar42205552017-03-18 19:42:22 +0100249 echo message
250 call add(s:messages, message)
251 if s:fail > 0
252 let message = s:fail . ' FAILED:'
253 echo message
254 call add(s:messages, message)
255 call extend(s:messages, s:errors)
256 endif
257
258 " Add SKIPPED messages
259 call extend(s:messages, s:skipped)
260
261 " Append messages to the file "messages"
262 split messages
263 call append(line('$'), '')
264 call append(line('$'), 'From ' . g:testname . ':')
265 call append(line('$'), s:messages)
266 write
267
268 qall!
269endfunc
270
Bram Moolenaar43345542015-11-29 17:35:35 +0100271" Source the test script. First grab the file name, in case the script
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100272" navigates away. g:testname can be used by the tests.
273let g:testname = expand('%')
274let s:done = 0
275let s:fail = 0
276let s:errors = []
277let s:messages = []
Bram Moolenaardac19472016-09-03 22:35:40 +0200278let s:skipped = []
Bram Moolenaarb544f3c2017-02-23 19:03:28 +0100279if expand('%') =~ 'test_vimscript.vim'
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100280 " this test has intentional s:errors, don't use try/catch.
Bram Moolenaar4686b322015-12-28 14:44:10 +0100281 source %
Bram Moolenaara2cce862016-01-02 19:50:04 +0100282else
283 try
284 source %
Bram Moolenaar9c0cec62019-06-06 13:38:15 +0200285 catch /^\cskipped/
286 call add(s:messages, ' Skipped')
287 call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
Bram Moolenaara2cce862016-01-02 19:50:04 +0100288 catch
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100289 let s:fail += 1
290 call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
Bram Moolenaara2cce862016-01-02 19:50:04 +0100291 endtry
292endif
Bram Moolenaar43345542015-11-29 17:35:35 +0100293
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100294" Names of flaky tests.
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100295let s:flaky_tests = [
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100296 \ 'Test_call()',
297 \ 'Test_channel_handler()',
Bram Moolenaar42205552017-03-18 19:42:22 +0100298 \ 'Test_client_server()',
Bram Moolenaar6fe2eb42017-01-29 21:49:51 +0100299 \ 'Test_close_and_exit_cb()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100300 \ 'Test_close_callback()',
301 \ 'Test_close_handle()',
302 \ 'Test_close_lambda()',
Bram Moolenaard80232b2018-12-15 17:46:23 +0100303 \ 'Test_close_output_buffer()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100304 \ 'Test_close_partial()',
Bram Moolenaarb2455592017-02-01 18:00:13 +0100305 \ 'Test_collapse_buffers()',
306 \ 'Test_communicate()',
Bram Moolenaar65873842018-03-25 17:12:58 +0200307 \ 'Test_cwd()',
Bram Moolenaar218959b2018-11-11 18:51:42 +0100308 \ 'Test_diff_screen()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100309 \ 'Test_exit_callback()',
Bram Moolenaar0529b3e2017-03-16 22:30:37 +0100310 \ 'Test_exit_callback_interval()',
Bram Moolenaarb2455592017-02-01 18:00:13 +0100311 \ 'Test_nb_basic()',
Bram Moolenaard512e172017-02-27 21:35:53 +0100312 \ 'Test_oneshot()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100313 \ 'Test_open_delay()',
Bram Moolenaar1eca6f12017-12-05 14:04:27 +0100314 \ 'Test_out_cb()',
Bram Moolenaar24820692017-12-02 16:38:12 +0100315 \ 'Test_paused()',
Bram Moolenaarc79d6aa2016-09-25 22:27:37 +0200316 \ 'Test_pipe_through_sort_all()',
Bram Moolenaar4e032e12017-02-01 20:48:13 +0100317 \ 'Test_pipe_through_sort_some()',
Bram Moolenaar142ae732018-08-19 17:04:01 +0200318 \ 'Test_popup_and_window_resize()',
Bram Moolenaar0fbff642017-03-05 14:30:52 +0100319 \ 'Test_quoteplus()',
Bram Moolenaar7dd48502017-03-19 20:04:22 +0100320 \ 'Test_quotestar()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100321 \ 'Test_raw_one_time_callback()',
Bram Moolenaarb2455592017-02-01 18:00:13 +0100322 \ 'Test_reltime()',
Bram Moolenaarbfbea562018-02-12 21:31:35 +0100323 \ 'Test_repeat_three()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100324 \ 'Test_server_crash()',
325 \ 'Test_terminal_ansicolors_default()',
326 \ 'Test_terminal_ansicolors_func()',
327 \ 'Test_terminal_ansicolors_global()',
Bram Moolenaarf204e052017-10-26 17:14:01 +0200328 \ 'Test_terminal_composing_unicode()',
Bram Moolenaar38767892019-02-21 18:17:14 +0100329 \ 'Test_terminal_does_not_truncate_last_newlines()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100330 \ 'Test_terminal_env()',
331 \ 'Test_terminal_hide_buffer()',
332 \ 'Test_terminal_make_change()',
Bram Moolenaar3615abb2019-02-10 23:04:12 +0100333 \ 'Test_terminal_no_cmd()',
Bram Moolenaar75a60f72017-09-07 22:24:41 +0200334 \ 'Test_terminal_noblock()',
Bram Moolenaar7dd88c52017-11-04 20:46:40 +0100335 \ 'Test_terminal_redir_file()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100336 \ 'Test_terminal_response_to_control_sequence()',
337 \ 'Test_terminal_scrollback()',
338 \ 'Test_terminal_split_quit()',
339 \ 'Test_terminal_termwinkey()',
340 \ 'Test_terminal_termwinsize_mininmum()',
341 \ 'Test_terminal_termwinsize_option_fixed()',
342 \ 'Test_terminal_termwinsize_option_zero()',
Bram Moolenaar24820692017-12-02 16:38:12 +0100343 \ 'Test_terminal_tmap()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100344 \ 'Test_terminal_wall()',
345 \ 'Test_terminal_wipe_buffer()',
346 \ 'Test_terminal_wqall()',
347 \ 'Test_two_channels()',
348 \ 'Test_unlet_handle()',
Bram Moolenaard09be322017-07-30 21:37:58 +0200349 \ 'Test_with_partial_callback()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100350 \ 'Test_zero_reply()',
351 \ 'Test_zz1_terminal_in_gui()',
Bram Moolenaare1c8c7a2016-09-11 16:48:50 +0200352 \ ]
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100353
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100354" Pattern indicating a common flaky test failure.
Bram Moolenaar447f6ce2018-11-16 18:50:19 +0100355let s:flaky_errors_re = 'StopVimInTerminal\|VerifyScreenDump'
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100356
Bram Moolenaar43345542015-11-29 17:35:35 +0100357" Locate Test_ functions and execute them.
358redir @q
Bram Moolenaar93bf5582016-02-18 22:25:47 +0100359silent function /^Test_
Bram Moolenaar43345542015-11-29 17:35:35 +0100360redir END
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100361let s:tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g'))
Bram Moolenaar43345542015-11-29 17:35:35 +0100362
Bram Moolenaarbefb3662016-02-20 14:41:40 +0100363" If there is an extra argument filter the function names against it.
364if argc() > 1
365 let s:tests = filter(s:tests, 'v:val =~ argv(1)')
366endif
367
Bram Moolenaarcfc0a352016-01-09 20:23:00 +0100368" Execute the tests in alphabetical order.
Bram Moolenaar93bf5582016-02-18 22:25:47 +0100369for s:test in sort(s:tests)
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +0200370 " Silence, please!
371 set belloff=all
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100372 let prev_error = ''
373 let total_errors = []
374 let run_nr = 1
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +0200375
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100376 call RunTheTest(s:test)
Bram Moolenaar43345542015-11-29 17:35:35 +0100377
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100378 " Repeat a flaky test. Give up when:
379 " - it fails again with the same message
380 " - it fails five times (with a different mesage)
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100381 if len(v:errors) > 0
382 \ && (index(s:flaky_tests, s:test) >= 0
383 \ || v:errors[0] =~ s:flaky_errors_re)
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100384 while 1
385 call add(s:messages, 'Found errors in ' . s:test . ':')
386 call extend(s:messages, v:errors)
Bram Moolenaar15e737f2017-03-18 21:22:47 +0100387
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100388 call add(total_errors, 'Run ' . run_nr . ':')
389 call extend(total_errors, v:errors)
Bram Moolenaar55058602017-11-21 15:14:51 +0100390
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100391 if run_nr == 5 || prev_error == v:errors[0]
392 call add(total_errors, 'Flaky test failed too often, giving up')
393 let v:errors = total_errors
394 break
395 endif
396
397 call add(s:messages, 'Flaky test failed, running it again')
398
399 " Flakiness is often caused by the system being very busy. Sleep a
400 " couple of seconds to have a higher chance of succeeding the second
401 " time.
402 sleep 2
403
404 let prev_error = v:errors[0]
405 let v:errors = []
406 let run_nr += 1
407
408 call RunTheTest(s:test)
409
410 if len(v:errors) == 0
411 " Test passed on rerun.
412 break
413 endif
414 endwhile
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100415 endif
Bram Moolenaar43345542015-11-29 17:35:35 +0100416
Bram Moolenaar42205552017-03-18 19:42:22 +0100417 call AfterTheTest()
Bram Moolenaar43345542015-11-29 17:35:35 +0100418endfor
419
Bram Moolenaar42205552017-03-18 19:42:22 +0100420call FinishTesting()
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100421
422" vim: shiftwidth=2 sts=2 expandtab