blob: a8b43aaed97666292a7dccaabd69e505bfb61420 [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 Moolenaar89b10422016-07-12 22:51:22 +020045" Common with all tests on all systems.
46source setup.vim
47
Bram Moolenaarc0662462015-12-30 15:49:05 +010048" For consistency run all tests with 'nocompatible' set.
49" This also enables use of line continuation.
50set nocp viminfo+=nviminfo
51
Bram Moolenaareb992cb2017-03-09 18:20:16 +010052" Use utf-8 or latin1 by default, instead of whatever the system default
Bram Moolenaarac105ed2016-07-21 20:33:32 +020053" 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
Bram Moolenaard8f27b32018-10-07 15:42:07 +020060" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for
61" the test_name.vim file itself. Replace it here with a more restrictive one,
62" so we still catch mistakes.
63let s:test_script_fname = expand('%')
64au! SwapExists * call HandleSwapExists()
65func HandleSwapExists()
66 " Only ignore finding a swap file for the test script (the user might be
67 " editing it and do ":make test_name") and the output file.
68 if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
69 let v:swapchoice = 'e'
70 endif
71endfunc
72
Bram Moolenaar7a073542017-02-01 23:17:36 +010073" Avoid stopping at the "hit enter" prompt
74set nomore
75
Bram Moolenaarc0662462015-12-30 15:49:05 +010076" Output all messages in English.
77lang mess C
78
Bram Moolenaarf60b7962016-01-16 22:47:23 +010079" Always use forward slashes.
80set shellslash
81
Bram Moolenaar28fb79d2016-01-09 22:28:33 +010082let s:srcdir = expand('%:p:h:h')
83
Bram Moolenaar8e8df252016-05-25 21:23:21 +020084" Prepare for calling test_garbagecollect_now().
Bram Moolenaarebf7dfa2016-04-14 12:46:51 +020085let v:testing = 1
86
Bram Moolenaar28fb79d2016-01-09 22:28:33 +010087" Support function: get the alloc ID by name.
88function GetAllocId(name)
89 exe 'split ' . s:srcdir . '/alloc.h'
Bram Moolenaar065ee9a2016-01-15 20:53:38 +010090 let top = search('typedef enum')
91 if top == 0
92 call add(v:errors, 'typedef not found in alloc.h')
93 endif
Bram Moolenaar28fb79d2016-01-09 22:28:33 +010094 let lnum = search('aid_' . a:name . ',')
95 if lnum == 0
96 call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
97 endif
98 close
Bram Moolenaar065ee9a2016-01-15 20:53:38 +010099 return lnum - top - 1
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100100endfunc
101
Bram Moolenaar42205552017-03-18 19:42:22 +0100102func RunTheTest(test)
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100103 echo 'Executing ' . a:test
Bram Moolenaare5f2a072017-02-01 22:31:49 +0100104
105 " Avoid stopping at the "hit enter" prompt
106 set nomore
107
108 " Avoid a three second wait when a message is about to be overwritten by the
109 " mode message.
110 set noshowmode
111
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100112 " Clear any overrides.
113 call test_override('ALL', 0)
114
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200115 " Some tests wipe out buffers. To be consistent, always wipe out all
116 " buffers.
117 %bwipe!
118
Bram Moolenaar209d3872017-11-16 21:52:51 +0100119 " The test may change the current directory. Save and restore the
120 " directory after executing the test.
121 let save_cwd = getcwd()
122
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100123 if exists("*SetUp")
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100124 try
125 call SetUp()
126 catch
127 call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
128 endtry
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100129 endif
130
131 call add(s:messages, 'Executing ' . a:test)
132 let s:done += 1
Bram Moolenaarf204e052017-10-26 17:14:01 +0200133
134 if a:test =~ 'Test_nocatch_'
135 " Function handles errors itself. This avoids skipping commands after the
136 " error.
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100137 exe 'call ' . a:test
Bram Moolenaarf204e052017-10-26 17:14:01 +0200138 else
139 try
Bram Moolenaar89036762018-06-12 14:58:39 +0200140 let s:test = a:test
141 au VimLeavePre * call EarlyExit(s:test)
Bram Moolenaarf204e052017-10-26 17:14:01 +0200142 exe 'call ' . a:test
Bram Moolenaar89036762018-06-12 14:58:39 +0200143 au! VimLeavePre
Bram Moolenaarf204e052017-10-26 17:14:01 +0200144 catch /^\cskipped/
145 call add(s:messages, ' Skipped')
146 call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
147 catch
148 call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
149 endtry
150 endif
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100151
Bram Moolenaar8ad16da2019-01-06 15:29:57 +0100152 " In case 'insertmode' was set and something went wrong, make sure it is
153 " reset to avoid trouble with anything else.
154 set noinsertmode
155
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100156 if exists("*TearDown")
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100157 try
158 call TearDown()
159 catch
160 call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
161 endtry
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100162 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200163
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200164 " Clear any autocommands
165 au!
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200166 au SwapExists * call HandleSwapExists()
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200167
Bram Moolenaarce11de82017-10-26 22:00:00 +0200168 " Close any extra tab pages and windows and make the current one not modified.
169 while tabpagenr('$') > 1
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200170 quit!
Bram Moolenaarce11de82017-10-26 22:00:00 +0200171 endwhile
172
Bram Moolenaar358308d2016-08-24 21:21:26 +0200173 while 1
174 let wincount = winnr('$')
175 if wincount == 1
176 break
177 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200178 bwipe!
Bram Moolenaar358308d2016-08-24 21:21:26 +0200179 if wincount == winnr('$')
180 " Did not manage to close a window.
181 only!
182 break
183 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200184 endwhile
Bram Moolenaar209d3872017-11-16 21:52:51 +0100185
186 exe 'cd ' . save_cwd
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100187endfunc
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100188
Bram Moolenaar42205552017-03-18 19:42:22 +0100189func AfterTheTest()
190 if len(v:errors) > 0
191 let s:fail += 1
192 call add(s:errors, 'Found errors in ' . s:test . ':')
193 call extend(s:errors, v:errors)
194 let v:errors = []
195 endif
196endfunc
197
Bram Moolenaar89036762018-06-12 14:58:39 +0200198func EarlyExit(test)
199 " It's OK for the test we use to test the quit detection.
200 if a:test != 'Test_zz_quit_detected()'
201 call add(v:errors, 'Test caused Vim to exit: ' . a:test)
202 endif
203
204 call FinishTesting()
205endfunc
206
Bram Moolenaar42205552017-03-18 19:42:22 +0100207" This function can be called by a test if it wants to abort testing.
208func FinishTesting()
209 call AfterTheTest()
210
211 " Don't write viminfo on exit.
212 set viminfo=
213
Bram Moolenaard1ee0042017-07-29 20:39:53 +0200214 " Clean up files created by setup.vim
215 call delete('XfakeHOME', 'rf')
216
Bram Moolenaar42205552017-03-18 19:42:22 +0100217 if s:fail == 0
218 " Success, create the .res file so that make knows it's done.
219 exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
220 write
221 endif
222
223 if len(s:errors) > 0
224 " Append errors to test.log
225 split test.log
226 call append(line('$'), '')
227 call append(line('$'), 'From ' . g:testname . ':')
228 call append(line('$'), s:errors)
229 write
230 endif
231
Bram Moolenaar29f9ed22018-04-10 19:20:31 +0200232 if s:done == 0
233 let message = 'NO tests executed'
234 else
235 let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
236 endif
Bram Moolenaar42205552017-03-18 19:42:22 +0100237 echo message
238 call add(s:messages, message)
239 if s:fail > 0
240 let message = s:fail . ' FAILED:'
241 echo message
242 call add(s:messages, message)
243 call extend(s:messages, s:errors)
244 endif
245
246 " Add SKIPPED messages
247 call extend(s:messages, s:skipped)
248
249 " Append messages to the file "messages"
250 split messages
251 call append(line('$'), '')
252 call append(line('$'), 'From ' . g:testname . ':')
253 call append(line('$'), s:messages)
254 write
255
256 qall!
257endfunc
258
Bram Moolenaar43345542015-11-29 17:35:35 +0100259" Source the test script. First grab the file name, in case the script
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100260" navigates away. g:testname can be used by the tests.
261let g:testname = expand('%')
262let s:done = 0
263let s:fail = 0
264let s:errors = []
265let s:messages = []
Bram Moolenaardac19472016-09-03 22:35:40 +0200266let s:skipped = []
Bram Moolenaarb544f3c2017-02-23 19:03:28 +0100267if expand('%') =~ 'test_vimscript.vim'
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100268 " this test has intentional s:errors, don't use try/catch.
Bram Moolenaar4686b322015-12-28 14:44:10 +0100269 source %
Bram Moolenaara2cce862016-01-02 19:50:04 +0100270else
271 try
272 source %
273 catch
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100274 let s:fail += 1
275 call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
Bram Moolenaara2cce862016-01-02 19:50:04 +0100276 endtry
277endif
Bram Moolenaar43345542015-11-29 17:35:35 +0100278
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100279" Names of flaky tests.
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100280let s:flaky_tests = [
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100281 \ 'Test_call()',
282 \ 'Test_channel_handler()',
Bram Moolenaar42205552017-03-18 19:42:22 +0100283 \ 'Test_client_server()',
Bram Moolenaar6fe2eb42017-01-29 21:49:51 +0100284 \ 'Test_close_and_exit_cb()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100285 \ 'Test_close_callback()',
286 \ 'Test_close_handle()',
287 \ 'Test_close_lambda()',
Bram Moolenaard80232b2018-12-15 17:46:23 +0100288 \ 'Test_close_output_buffer()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100289 \ 'Test_close_partial()',
Bram Moolenaarb2455592017-02-01 18:00:13 +0100290 \ 'Test_collapse_buffers()',
291 \ 'Test_communicate()',
Bram Moolenaar65873842018-03-25 17:12:58 +0200292 \ 'Test_cwd()',
Bram Moolenaar218959b2018-11-11 18:51:42 +0100293 \ 'Test_diff_screen()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100294 \ 'Test_exit_callback()',
Bram Moolenaar0529b3e2017-03-16 22:30:37 +0100295 \ 'Test_exit_callback_interval()',
Bram Moolenaarb2455592017-02-01 18:00:13 +0100296 \ 'Test_nb_basic()',
Bram Moolenaard512e172017-02-27 21:35:53 +0100297 \ 'Test_oneshot()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100298 \ 'Test_open_delay()',
Bram Moolenaar1eca6f12017-12-05 14:04:27 +0100299 \ 'Test_out_cb()',
Bram Moolenaar24820692017-12-02 16:38:12 +0100300 \ 'Test_paused()',
Bram Moolenaarc79d6aa2016-09-25 22:27:37 +0200301 \ 'Test_pipe_through_sort_all()',
Bram Moolenaar4e032e12017-02-01 20:48:13 +0100302 \ 'Test_pipe_through_sort_some()',
Bram Moolenaar142ae732018-08-19 17:04:01 +0200303 \ 'Test_popup_and_window_resize()',
Bram Moolenaar0fbff642017-03-05 14:30:52 +0100304 \ 'Test_quoteplus()',
Bram Moolenaar7dd48502017-03-19 20:04:22 +0100305 \ 'Test_quotestar()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100306 \ 'Test_raw_one_time_callback()',
Bram Moolenaarb2455592017-02-01 18:00:13 +0100307 \ 'Test_reltime()',
Bram Moolenaarbfbea562018-02-12 21:31:35 +0100308 \ 'Test_repeat_three()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100309 \ 'Test_server_crash()',
310 \ 'Test_terminal_ansicolors_default()',
311 \ 'Test_terminal_ansicolors_func()',
312 \ 'Test_terminal_ansicolors_global()',
Bram Moolenaarf204e052017-10-26 17:14:01 +0200313 \ 'Test_terminal_composing_unicode()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100314 \ 'Test_terminal_env()',
315 \ 'Test_terminal_hide_buffer()',
316 \ 'Test_terminal_make_change()',
Bram Moolenaar75a60f72017-09-07 22:24:41 +0200317 \ 'Test_terminal_noblock()',
Bram Moolenaar7dd88c52017-11-04 20:46:40 +0100318 \ 'Test_terminal_redir_file()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100319 \ 'Test_terminal_response_to_control_sequence()',
320 \ 'Test_terminal_scrollback()',
321 \ 'Test_terminal_split_quit()',
322 \ 'Test_terminal_termwinkey()',
323 \ 'Test_terminal_termwinsize_mininmum()',
324 \ 'Test_terminal_termwinsize_option_fixed()',
325 \ 'Test_terminal_termwinsize_option_zero()',
Bram Moolenaar24820692017-12-02 16:38:12 +0100326 \ 'Test_terminal_tmap()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100327 \ 'Test_terminal_wall()',
328 \ 'Test_terminal_wipe_buffer()',
329 \ 'Test_terminal_wqall()',
330 \ 'Test_two_channels()',
331 \ 'Test_unlet_handle()',
Bram Moolenaard09be322017-07-30 21:37:58 +0200332 \ 'Test_with_partial_callback()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100333 \ 'Test_zero_reply()',
334 \ 'Test_zz1_terminal_in_gui()',
Bram Moolenaare1c8c7a2016-09-11 16:48:50 +0200335 \ ]
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100336
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100337" Pattern indicating a common flaky test failure.
Bram Moolenaar447f6ce2018-11-16 18:50:19 +0100338let s:flaky_errors_re = 'StopVimInTerminal\|VerifyScreenDump'
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100339
Bram Moolenaar43345542015-11-29 17:35:35 +0100340" Locate Test_ functions and execute them.
341redir @q
Bram Moolenaar93bf5582016-02-18 22:25:47 +0100342silent function /^Test_
Bram Moolenaar43345542015-11-29 17:35:35 +0100343redir END
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100344let s:tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g'))
Bram Moolenaar43345542015-11-29 17:35:35 +0100345
Bram Moolenaarbefb3662016-02-20 14:41:40 +0100346" If there is an extra argument filter the function names against it.
347if argc() > 1
348 let s:tests = filter(s:tests, 'v:val =~ argv(1)')
349endif
350
Bram Moolenaarcfc0a352016-01-09 20:23:00 +0100351" Execute the tests in alphabetical order.
Bram Moolenaar93bf5582016-02-18 22:25:47 +0100352for s:test in sort(s:tests)
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +0200353 " Silence, please!
354 set belloff=all
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100355 let prev_error = ''
356 let total_errors = []
357 let run_nr = 1
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +0200358
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100359 call RunTheTest(s:test)
Bram Moolenaar43345542015-11-29 17:35:35 +0100360
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100361 " Repeat a flaky test. Give up when:
362 " - it fails again with the same message
363 " - it fails five times (with a different mesage)
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100364 if len(v:errors) > 0
365 \ && (index(s:flaky_tests, s:test) >= 0
366 \ || v:errors[0] =~ s:flaky_errors_re)
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100367 while 1
368 call add(s:messages, 'Found errors in ' . s:test . ':')
369 call extend(s:messages, v:errors)
Bram Moolenaar15e737f2017-03-18 21:22:47 +0100370
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100371 call add(total_errors, 'Run ' . run_nr . ':')
372 call extend(total_errors, v:errors)
Bram Moolenaar55058602017-11-21 15:14:51 +0100373
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100374 if run_nr == 5 || prev_error == v:errors[0]
375 call add(total_errors, 'Flaky test failed too often, giving up')
376 let v:errors = total_errors
377 break
378 endif
379
380 call add(s:messages, 'Flaky test failed, running it again')
381
382 " Flakiness is often caused by the system being very busy. Sleep a
383 " couple of seconds to have a higher chance of succeeding the second
384 " time.
385 sleep 2
386
387 let prev_error = v:errors[0]
388 let v:errors = []
389 let run_nr += 1
390
391 call RunTheTest(s:test)
392
393 if len(v:errors) == 0
394 " Test passed on rerun.
395 break
396 endif
397 endwhile
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100398 endif
Bram Moolenaar43345542015-11-29 17:35:35 +0100399
Bram Moolenaar42205552017-03-18 19:42:22 +0100400 call AfterTheTest()
Bram Moolenaar43345542015-11-29 17:35:35 +0100401endfor
402
Bram Moolenaar42205552017-03-18 19:42:22 +0100403call FinishTesting()
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100404
405" vim: shiftwidth=2 sts=2 expandtab