blob: 02d4d20e340a38491c221a6a50cb023031479c81 [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 Moolenaar30276f22019-01-24 17:59:39 +010052" Use utf-8 by default, instead of whatever the system default happens to be.
Bram Moolenaared79d1e2019-02-22 14:38:58 +010053" Individual tests can overrule this at the top of the file and use
54" g:orig_encoding if needed.
55let g:orig_encoding = &encoding
Bram Moolenaar30276f22019-01-24 17:59:39 +010056set encoding=utf-8
Bram Moolenaarac105ed2016-07-21 20:33:32 +020057
Bram Moolenaard8f27b32018-10-07 15:42:07 +020058" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for
59" the test_name.vim file itself. Replace it here with a more restrictive one,
60" so we still catch mistakes.
61let s:test_script_fname = expand('%')
62au! SwapExists * call HandleSwapExists()
63func HandleSwapExists()
64 " Only ignore finding a swap file for the test script (the user might be
65 " editing it and do ":make test_name") and the output file.
66 if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
67 let v:swapchoice = 'e'
68 endif
69endfunc
70
Bram Moolenaar7a073542017-02-01 23:17:36 +010071" Avoid stopping at the "hit enter" prompt
72set nomore
73
Bram Moolenaarc0662462015-12-30 15:49:05 +010074" Output all messages in English.
75lang mess C
76
Bram Moolenaarf60b7962016-01-16 22:47:23 +010077" Always use forward slashes.
78set shellslash
79
Bram Moolenaar28fb79d2016-01-09 22:28:33 +010080let s:srcdir = expand('%:p:h:h')
81
Bram Moolenaar8e8df252016-05-25 21:23:21 +020082" Prepare for calling test_garbagecollect_now().
Bram Moolenaarebf7dfa2016-04-14 12:46:51 +020083let v:testing = 1
84
Bram Moolenaar28fb79d2016-01-09 22:28:33 +010085" Support function: get the alloc ID by name.
86function GetAllocId(name)
87 exe 'split ' . s:srcdir . '/alloc.h'
Bram Moolenaar065ee9a2016-01-15 20:53:38 +010088 let top = search('typedef enum')
89 if top == 0
90 call add(v:errors, 'typedef not found in alloc.h')
91 endif
Bram Moolenaar28fb79d2016-01-09 22:28:33 +010092 let lnum = search('aid_' . a:name . ',')
93 if lnum == 0
94 call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
95 endif
96 close
Bram Moolenaar065ee9a2016-01-15 20:53:38 +010097 return lnum - top - 1
Bram Moolenaar28fb79d2016-01-09 22:28:33 +010098endfunc
99
Bram Moolenaar42205552017-03-18 19:42:22 +0100100func RunTheTest(test)
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100101 echo 'Executing ' . a:test
Bram Moolenaare5f2a072017-02-01 22:31:49 +0100102
103 " Avoid stopping at the "hit enter" prompt
104 set nomore
105
106 " Avoid a three second wait when a message is about to be overwritten by the
107 " mode message.
108 set noshowmode
109
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100110 " Clear any overrides.
111 call test_override('ALL', 0)
112
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200113 " Some tests wipe out buffers. To be consistent, always wipe out all
114 " buffers.
115 %bwipe!
116
Bram Moolenaar209d3872017-11-16 21:52:51 +0100117 " The test may change the current directory. Save and restore the
118 " directory after executing the test.
119 let save_cwd = getcwd()
120
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100121 if exists("*SetUp")
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100122 try
123 call SetUp()
124 catch
125 call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
126 endtry
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100127 endif
128
129 call add(s:messages, 'Executing ' . a:test)
130 let s:done += 1
Bram Moolenaarf204e052017-10-26 17:14:01 +0200131
132 if a:test =~ 'Test_nocatch_'
133 " Function handles errors itself. This avoids skipping commands after the
134 " error.
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100135 exe 'call ' . a:test
Bram Moolenaarf204e052017-10-26 17:14:01 +0200136 else
137 try
Bram Moolenaar89036762018-06-12 14:58:39 +0200138 let s:test = a:test
139 au VimLeavePre * call EarlyExit(s:test)
Bram Moolenaarf204e052017-10-26 17:14:01 +0200140 exe 'call ' . a:test
Bram Moolenaar89036762018-06-12 14:58:39 +0200141 au! VimLeavePre
Bram Moolenaarf204e052017-10-26 17:14:01 +0200142 catch /^\cskipped/
143 call add(s:messages, ' Skipped')
144 call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
145 catch
146 call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
147 endtry
148 endif
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100149
Bram Moolenaar8ad16da2019-01-06 15:29:57 +0100150 " In case 'insertmode' was set and something went wrong, make sure it is
151 " reset to avoid trouble with anything else.
152 set noinsertmode
153
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100154 if exists("*TearDown")
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100155 try
156 call TearDown()
157 catch
158 call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
159 endtry
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100160 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200161
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200162 " Clear any autocommands
163 au!
Bram Moolenaard8f27b32018-10-07 15:42:07 +0200164 au SwapExists * call HandleSwapExists()
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200165
Bram Moolenaarce11de82017-10-26 22:00:00 +0200166 " Close any extra tab pages and windows and make the current one not modified.
167 while tabpagenr('$') > 1
Bram Moolenaarcf1ba352017-10-27 00:55:04 +0200168 quit!
Bram Moolenaarce11de82017-10-26 22:00:00 +0200169 endwhile
170
Bram Moolenaar358308d2016-08-24 21:21:26 +0200171 while 1
172 let wincount = winnr('$')
173 if wincount == 1
174 break
175 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200176 bwipe!
Bram Moolenaar358308d2016-08-24 21:21:26 +0200177 if wincount == winnr('$')
178 " Did not manage to close a window.
179 only!
180 break
181 endif
Bram Moolenaar7cba71d2016-08-02 23:04:49 +0200182 endwhile
Bram Moolenaar209d3872017-11-16 21:52:51 +0100183
184 exe 'cd ' . save_cwd
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100185endfunc
Bram Moolenaar28fb79d2016-01-09 22:28:33 +0100186
Bram Moolenaar42205552017-03-18 19:42:22 +0100187func AfterTheTest()
188 if len(v:errors) > 0
189 let s:fail += 1
190 call add(s:errors, 'Found errors in ' . s:test . ':')
191 call extend(s:errors, v:errors)
192 let v:errors = []
193 endif
194endfunc
195
Bram Moolenaar89036762018-06-12 14:58:39 +0200196func EarlyExit(test)
197 " It's OK for the test we use to test the quit detection.
198 if a:test != 'Test_zz_quit_detected()'
199 call add(v:errors, 'Test caused Vim to exit: ' . a:test)
200 endif
201
202 call FinishTesting()
203endfunc
204
Bram Moolenaar42205552017-03-18 19:42:22 +0100205" This function can be called by a test if it wants to abort testing.
206func FinishTesting()
207 call AfterTheTest()
208
209 " Don't write viminfo on exit.
210 set viminfo=
211
Bram Moolenaard1ee0042017-07-29 20:39:53 +0200212 " Clean up files created by setup.vim
213 call delete('XfakeHOME', 'rf')
214
Bram Moolenaar42205552017-03-18 19:42:22 +0100215 if s:fail == 0
216 " Success, create the .res file so that make knows it's done.
217 exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
218 write
219 endif
220
221 if len(s:errors) > 0
222 " Append errors to test.log
223 split test.log
224 call append(line('$'), '')
225 call append(line('$'), 'From ' . g:testname . ':')
226 call append(line('$'), s:errors)
227 write
228 endif
229
Bram Moolenaar29f9ed22018-04-10 19:20:31 +0200230 if s:done == 0
231 let message = 'NO tests executed'
232 else
233 let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
234 endif
Bram Moolenaar42205552017-03-18 19:42:22 +0100235 echo message
236 call add(s:messages, message)
237 if s:fail > 0
238 let message = s:fail . ' FAILED:'
239 echo message
240 call add(s:messages, message)
241 call extend(s:messages, s:errors)
242 endif
243
244 " Add SKIPPED messages
245 call extend(s:messages, s:skipped)
246
247 " Append messages to the file "messages"
248 split messages
249 call append(line('$'), '')
250 call append(line('$'), 'From ' . g:testname . ':')
251 call append(line('$'), s:messages)
252 write
253
254 qall!
255endfunc
256
Bram Moolenaar43345542015-11-29 17:35:35 +0100257" Source the test script. First grab the file name, in case the script
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100258" navigates away. g:testname can be used by the tests.
259let g:testname = expand('%')
260let s:done = 0
261let s:fail = 0
262let s:errors = []
263let s:messages = []
Bram Moolenaardac19472016-09-03 22:35:40 +0200264let s:skipped = []
Bram Moolenaarb544f3c2017-02-23 19:03:28 +0100265if expand('%') =~ 'test_vimscript.vim'
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100266 " this test has intentional s:errors, don't use try/catch.
Bram Moolenaar4686b322015-12-28 14:44:10 +0100267 source %
Bram Moolenaara2cce862016-01-02 19:50:04 +0100268else
269 try
270 source %
Bram Moolenaar9c0cec62019-06-06 13:38:15 +0200271 catch /^\cskipped/
272 call add(s:messages, ' Skipped')
273 call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
Bram Moolenaara2cce862016-01-02 19:50:04 +0100274 catch
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100275 let s:fail += 1
276 call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
Bram Moolenaara2cce862016-01-02 19:50:04 +0100277 endtry
278endif
Bram Moolenaar43345542015-11-29 17:35:35 +0100279
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100280" Names of flaky tests.
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100281let s:flaky_tests = [
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100282 \ 'Test_call()',
283 \ 'Test_channel_handler()',
Bram Moolenaar42205552017-03-18 19:42:22 +0100284 \ 'Test_client_server()',
Bram Moolenaar6fe2eb42017-01-29 21:49:51 +0100285 \ 'Test_close_and_exit_cb()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100286 \ 'Test_close_callback()',
287 \ 'Test_close_handle()',
288 \ 'Test_close_lambda()',
Bram Moolenaard80232b2018-12-15 17:46:23 +0100289 \ 'Test_close_output_buffer()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100290 \ 'Test_close_partial()',
Bram Moolenaarb2455592017-02-01 18:00:13 +0100291 \ 'Test_collapse_buffers()',
292 \ 'Test_communicate()',
Bram Moolenaar65873842018-03-25 17:12:58 +0200293 \ 'Test_cwd()',
Bram Moolenaar218959b2018-11-11 18:51:42 +0100294 \ 'Test_diff_screen()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100295 \ 'Test_exit_callback()',
Bram Moolenaar0529b3e2017-03-16 22:30:37 +0100296 \ 'Test_exit_callback_interval()',
Bram Moolenaarb2455592017-02-01 18:00:13 +0100297 \ 'Test_nb_basic()',
Bram Moolenaard512e172017-02-27 21:35:53 +0100298 \ 'Test_oneshot()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100299 \ 'Test_open_delay()',
Bram Moolenaar1eca6f12017-12-05 14:04:27 +0100300 \ 'Test_out_cb()',
Bram Moolenaar24820692017-12-02 16:38:12 +0100301 \ 'Test_paused()',
Bram Moolenaarc79d6aa2016-09-25 22:27:37 +0200302 \ 'Test_pipe_through_sort_all()',
Bram Moolenaar4e032e12017-02-01 20:48:13 +0100303 \ 'Test_pipe_through_sort_some()',
Bram Moolenaar142ae732018-08-19 17:04:01 +0200304 \ 'Test_popup_and_window_resize()',
Bram Moolenaar0fbff642017-03-05 14:30:52 +0100305 \ 'Test_quoteplus()',
Bram Moolenaar7dd48502017-03-19 20:04:22 +0100306 \ 'Test_quotestar()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100307 \ 'Test_raw_one_time_callback()',
Bram Moolenaarb2455592017-02-01 18:00:13 +0100308 \ 'Test_reltime()',
Bram Moolenaarbfbea562018-02-12 21:31:35 +0100309 \ 'Test_repeat_three()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100310 \ 'Test_server_crash()',
311 \ 'Test_terminal_ansicolors_default()',
312 \ 'Test_terminal_ansicolors_func()',
313 \ 'Test_terminal_ansicolors_global()',
Bram Moolenaarf204e052017-10-26 17:14:01 +0200314 \ 'Test_terminal_composing_unicode()',
Bram Moolenaar38767892019-02-21 18:17:14 +0100315 \ 'Test_terminal_does_not_truncate_last_newlines()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100316 \ 'Test_terminal_env()',
317 \ 'Test_terminal_hide_buffer()',
318 \ 'Test_terminal_make_change()',
Bram Moolenaar3615abb2019-02-10 23:04:12 +0100319 \ 'Test_terminal_no_cmd()',
Bram Moolenaar75a60f72017-09-07 22:24:41 +0200320 \ 'Test_terminal_noblock()',
Bram Moolenaar7dd88c52017-11-04 20:46:40 +0100321 \ 'Test_terminal_redir_file()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100322 \ 'Test_terminal_response_to_control_sequence()',
323 \ 'Test_terminal_scrollback()',
324 \ 'Test_terminal_split_quit()',
325 \ 'Test_terminal_termwinkey()',
326 \ 'Test_terminal_termwinsize_mininmum()',
327 \ 'Test_terminal_termwinsize_option_fixed()',
328 \ 'Test_terminal_termwinsize_option_zero()',
Bram Moolenaar24820692017-12-02 16:38:12 +0100329 \ 'Test_terminal_tmap()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100330 \ 'Test_terminal_wall()',
331 \ 'Test_terminal_wipe_buffer()',
332 \ 'Test_terminal_wqall()',
333 \ 'Test_two_channels()',
334 \ 'Test_unlet_handle()',
Bram Moolenaard09be322017-07-30 21:37:58 +0200335 \ 'Test_with_partial_callback()',
Bram Moolenaarc0f05d02018-11-16 17:44:48 +0100336 \ 'Test_zero_reply()',
337 \ 'Test_zz1_terminal_in_gui()',
Bram Moolenaare1c8c7a2016-09-11 16:48:50 +0200338 \ ]
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100339
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100340" Pattern indicating a common flaky test failure.
Bram Moolenaar447f6ce2018-11-16 18:50:19 +0100341let s:flaky_errors_re = 'StopVimInTerminal\|VerifyScreenDump'
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100342
Bram Moolenaar43345542015-11-29 17:35:35 +0100343" Locate Test_ functions and execute them.
344redir @q
Bram Moolenaar93bf5582016-02-18 22:25:47 +0100345silent function /^Test_
Bram Moolenaar43345542015-11-29 17:35:35 +0100346redir END
Bram Moolenaar00af60b2016-02-13 14:06:14 +0100347let s:tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g'))
Bram Moolenaar43345542015-11-29 17:35:35 +0100348
Bram Moolenaarbefb3662016-02-20 14:41:40 +0100349" If there is an extra argument filter the function names against it.
350if argc() > 1
351 let s:tests = filter(s:tests, 'v:val =~ argv(1)')
352endif
353
Bram Moolenaarcfc0a352016-01-09 20:23:00 +0100354" Execute the tests in alphabetical order.
Bram Moolenaar93bf5582016-02-18 22:25:47 +0100355for s:test in sort(s:tests)
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +0200356 " Silence, please!
357 set belloff=all
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100358 let prev_error = ''
359 let total_errors = []
360 let run_nr = 1
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +0200361
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100362 call RunTheTest(s:test)
Bram Moolenaar43345542015-11-29 17:35:35 +0100363
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100364 " Repeat a flaky test. Give up when:
365 " - it fails again with the same message
366 " - it fails five times (with a different mesage)
Bram Moolenaardbc0d212018-11-16 18:22:45 +0100367 if len(v:errors) > 0
368 \ && (index(s:flaky_tests, s:test) >= 0
369 \ || v:errors[0] =~ s:flaky_errors_re)
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100370 while 1
371 call add(s:messages, 'Found errors in ' . s:test . ':')
372 call extend(s:messages, v:errors)
Bram Moolenaar15e737f2017-03-18 21:22:47 +0100373
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100374 call add(total_errors, 'Run ' . run_nr . ':')
375 call extend(total_errors, v:errors)
Bram Moolenaar55058602017-11-21 15:14:51 +0100376
Bram Moolenaarf77af0e2018-11-16 16:52:16 +0100377 if run_nr == 5 || prev_error == v:errors[0]
378 call add(total_errors, 'Flaky test failed too often, giving up')
379 let v:errors = total_errors
380 break
381 endif
382
383 call add(s:messages, 'Flaky test failed, running it again')
384
385 " Flakiness is often caused by the system being very busy. Sleep a
386 " couple of seconds to have a higher chance of succeeding the second
387 " time.
388 sleep 2
389
390 let prev_error = v:errors[0]
391 let v:errors = []
392 let run_nr += 1
393
394 call RunTheTest(s:test)
395
396 if len(v:errors) == 0
397 " Test passed on rerun.
398 break
399 endif
400 endwhile
Bram Moolenaarb5760a12016-03-03 13:10:44 +0100401 endif
Bram Moolenaar43345542015-11-29 17:35:35 +0100402
Bram Moolenaar42205552017-03-18 19:42:22 +0100403 call AfterTheTest()
Bram Moolenaar43345542015-11-29 17:35:35 +0100404endfor
405
Bram Moolenaar42205552017-03-18 19:42:22 +0100406call FinishTesting()
Bram Moolenaarcc28e2d2016-11-17 17:56:13 +0100407
408" vim: shiftwidth=2 sts=2 expandtab