xref: /vim-8.2.3635/src/testdir/runtest.vim (revision fb094e14)
1" 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"
5" 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"
10" 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.
27"
28" When debugging a test it can be useful to add messages to v:errors:
29" 	call add(v:errors, "this happened")
30
31
32" Without the +eval feature we can't run these tests, bail out.
33so small.vim
34
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
45" Common with all tests on all systems.
46source setup.vim
47
48" For consistency run all tests with 'nocompatible' set.
49" This also enables use of line continuation.
50set nocp viminfo+=nviminfo
51
52" Use utf-8 or latin1 by default, instead of whatever the system default
53" 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
60" Avoid stopping at the "hit enter" prompt
61set nomore
62
63" Output all messages in English.
64lang mess C
65
66" Always use forward slashes.
67set shellslash
68
69let s:srcdir = expand('%:p:h:h')
70
71" Prepare for calling test_garbagecollect_now().
72let v:testing = 1
73
74" Support function: get the alloc ID by name.
75function GetAllocId(name)
76  exe 'split ' . s:srcdir . '/alloc.h'
77  let top = search('typedef enum')
78  if top == 0
79    call add(v:errors, 'typedef not found in alloc.h')
80  endif
81  let lnum = search('aid_' . a:name . ',')
82  if lnum == 0
83    call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
84  endif
85  close
86  return lnum - top - 1
87endfunc
88
89func RunTheTest(test)
90  echo 'Executing ' . a:test
91
92  " Avoid stopping at the "hit enter" prompt
93  set nomore
94
95  " Avoid a three second wait when a message is about to be overwritten by the
96  " mode message.
97  set noshowmode
98
99  " Clear any overrides.
100  call test_override('ALL', 0)
101
102  " Some tests wipe out buffers.  To be consistent, always wipe out all
103  " buffers.
104  %bwipe!
105
106  if exists("*SetUp")
107    try
108      call SetUp()
109    catch
110      call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
111    endtry
112  endif
113
114  call add(s:messages, 'Executing ' . a:test)
115  let s:done += 1
116
117  if a:test =~ 'Test_nocatch_'
118    " Function handles errors itself.  This avoids skipping commands after the
119    " error.
120    exe 'call ' . a:test
121  else
122    try
123      exe 'call ' . a:test
124    catch /^\cskipped/
125      call add(s:messages, '    Skipped')
126      call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '',  ''))
127    catch
128      call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
129    endtry
130  endif
131
132  if exists("*TearDown")
133    try
134      call TearDown()
135    catch
136      call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
137    endtry
138  endif
139
140  " Clear any autocommands
141  au!
142
143  " Close any extra tab pages and windows and make the current one not modified.
144  while tabpagenr('$') > 1
145    quit!
146  endwhile
147
148  while 1
149    let wincount = winnr('$')
150    if wincount == 1
151      break
152    endif
153    bwipe!
154    if wincount == winnr('$')
155      " Did not manage to close a window.
156      only!
157      break
158    endif
159  endwhile
160endfunc
161
162func AfterTheTest()
163  if len(v:errors) > 0
164    let s:fail += 1
165    call add(s:errors, 'Found errors in ' . s:test . ':')
166    call extend(s:errors, v:errors)
167    let v:errors = []
168  endif
169endfunc
170
171" This function can be called by a test if it wants to abort testing.
172func FinishTesting()
173  call AfterTheTest()
174
175  " Don't write viminfo on exit.
176  set viminfo=
177
178  " Clean up files created by setup.vim
179  call delete('XfakeHOME', 'rf')
180
181  if s:fail == 0
182    " Success, create the .res file so that make knows it's done.
183    exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
184    write
185  endif
186
187  if len(s:errors) > 0
188    " Append errors to test.log
189    split test.log
190    call append(line('$'), '')
191    call append(line('$'), 'From ' . g:testname . ':')
192    call append(line('$'), s:errors)
193    write
194  endif
195
196  let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
197  echo message
198  call add(s:messages, message)
199  if s:fail > 0
200    let message = s:fail . ' FAILED:'
201    echo message
202    call add(s:messages, message)
203    call extend(s:messages, s:errors)
204  endif
205
206  " Add SKIPPED messages
207  call extend(s:messages, s:skipped)
208
209  " Append messages to the file "messages"
210  split messages
211  call append(line('$'), '')
212  call append(line('$'), 'From ' . g:testname . ':')
213  call append(line('$'), s:messages)
214  write
215
216  qall!
217endfunc
218
219" Source the test script.  First grab the file name, in case the script
220" navigates away.  g:testname can be used by the tests.
221let g:testname = expand('%')
222let s:done = 0
223let s:fail = 0
224let s:errors = []
225let s:messages = []
226let s:skipped = []
227if expand('%') =~ 'test_vimscript.vim'
228  " this test has intentional s:errors, don't use try/catch.
229  source %
230else
231  try
232    source %
233  catch
234    let s:fail += 1
235    call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
236  endtry
237endif
238
239" Names of flaky tests.
240let s:flaky = [
241      \ 'Test_client_server()',
242      \ 'Test_close_and_exit_cb()',
243      \ 'Test_collapse_buffers()',
244      \ 'Test_communicate()',
245      \ 'Test_exit_callback_interval()',
246      \ 'Test_nb_basic()',
247      \ 'Test_oneshot()',
248      \ 'Test_pipe_through_sort_all()',
249      \ 'Test_pipe_through_sort_some()',
250      \ 'Test_quoteplus()',
251      \ 'Test_quotestar()',
252      \ 'Test_reltime()',
253      \ 'Test_terminal_composing_unicode()',
254      \ 'Test_terminal_noblock()',
255      \ 'Test_terminal_redir_file()',
256      \ 'Test_with_partial_callback()',
257      \ ]
258
259" Locate Test_ functions and execute them.
260redir @q
261silent function /^Test_
262redir END
263let s:tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g'))
264
265" If there is an extra argument filter the function names against it.
266if argc() > 1
267  let s:tests = filter(s:tests, 'v:val =~ argv(1)')
268endif
269
270" Execute the tests in alphabetical order.
271for s:test in sort(s:tests)
272  " Silence, please!
273  set belloff=all
274
275  call RunTheTest(s:test)
276
277  if len(v:errors) > 0 && index(s:flaky, s:test) >= 0
278    call add(s:messages, 'Found errors in ' . s:test . ':')
279    call extend(s:messages, v:errors)
280    call add(s:messages, 'Flaky test failed, running it again')
281    let first_run = v:errors
282
283    let v:errors = []
284    call RunTheTest(s:test)
285    if len(v:errors) > 0
286      let second_run = v:errors
287      let v:errors = ['First run:']
288      call extend(v:errors, first_run)
289      call add(v:errors, 'Second run:')
290      call extend(v:errors, second_run)
291    endif
292  endif
293
294  call AfterTheTest()
295endfor
296
297call FinishTesting()
298
299" vim: shiftwidth=2 sts=2 expandtab
300