blob: 0758bcbfa5e7edf807b2a301e213902cfafb95cb [file] [log] [blame]
Bram Moolenaar46acad72023-06-11 19:04:18 +01001" Runs all the syntax tests for which there is no "done/name" file.
2"
3" Current directory must be runtime/syntax.
4
5" Only do this with the +eval feature
6if 1
7
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +01008" Remember the directory where we started. Will change to "testdir" below.
9let syntaxDir = getcwd()
10
11let s:messagesFname = fnameescape(syntaxDir .. '/testdir/messages')
12
13let s:messages = []
14
15" Add one message to the list of messages
16func Message(msg)
17 echomsg a:msg
18 call add(s:messages, a:msg)
19endfunc
20
21" Report a fatal message and exit
22func Fatal(msg)
23 echoerr a:msg
24 call AppendMessages(a:msg)
25 qall!
26endfunc
27
28" Append s:messages to the messages file and make it empty.
29func AppendMessages(header)
30 exe 'split ' .. s:messagesFname
31 call append(line('$'), '')
32 call append(line('$'), a:header)
33 call append(line('$'), s:messages)
34 let s:messages = []
35 wq
36endfunc
37
38" Relevant messages are written to the "messages" file.
39" If the file already exists it is appended to.
40exe 'split ' .. s:messagesFname
41call append(line('$'), repeat('=-', 70))
42call append(line('$'), '')
Bram Moolenaar031d6322023-06-22 22:38:54 +010043let s:test_run_message = 'Test run on ' .. strftime("%Y %b %d %H:%M:%S")
44call append(line('$'), s:test_run_message)
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +010045wq
46
47if syntaxDir !~ '[/\\]runtime[/\\]syntax\>'
48 call Fatal('Current directory must be "runtime/syntax"')
Bram Moolenaar46acad72023-06-11 19:04:18 +010049endif
50if !isdirectory('testdir')
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +010051 call Fatal('"testdir" directory not found')
Bram Moolenaar46acad72023-06-11 19:04:18 +010052endif
53
54" Use the script for source code screendump testing. It sources other scripts,
55" therefore we must "cd" there.
56cd ../../src/testdir
57source screendump.vim
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +010058exe 'cd ' .. fnameescape(syntaxDir)
Bram Moolenaar46acad72023-06-11 19:04:18 +010059
60" For these tests we need to be able to run terminal Vim with 256 colors. On
61" MS-Windows the console only has 16 colors and the GUI can't run in a
62" terminal.
63if !CanRunVimInTerminal()
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +010064 call Fatal('Cannot make screendumps, aborting')
Bram Moolenaar46acad72023-06-11 19:04:18 +010065endif
66
67cd testdir
68if !isdirectory('done')
69 call mkdir('done')
70endif
71
72set nocp
73set nowrapscan
74set report=9999
75set modeline
76set debug=throw
77set nomore
78
79au! SwapExists * call HandleSwapExists()
80func HandleSwapExists()
81 " Ignore finding a swap file for the test input, the user might be editing
82 " it and that's OK.
83 if expand('<afile>') =~ 'input[/\\].*\..*'
84 let v:swapchoice = 'e'
85 endif
86endfunc
87
Aliaksei Budavei84184462024-05-21 01:10:26 +030088def IsWinNumOneAtEOF(in_name_and_out_name: string): bool
89 # Expect defaults from term_util#RunVimInTerminal().
90 if winwidth(1) != 75 || winheight(1) != 20
91 ch_log(printf('Aborting for %s: (75 x 20) != (%d x %d)',
92 in_name_and_out_name,
93 winwidth(1),
94 winheight(1)))
95 return true
96 endif
97 # A two-fold role: (1) redraw whenever the first test file is of 19 lines or
98 # less long (not applicable to c.c); (2) redraw in case the terminal buffer
99 # cannot redraw itself just yet (else expect extra files generated).
100 redraw
101 const pos: string = join([
102 screenstring(20, 71),
103 screenstring(20, 72),
104 screenstring(20, 73),
105 screenstring(20, 74),
106 screenstring(20, 75)], '')
107 return (pos == ' All ' || pos == ' Bot ')
108enddef
109
Christian Brabandt56824432024-02-28 21:24:25 +0100110func RunTest()
111 let ok_count = 0
112 let failed_tests = []
113 let skipped_count = 0
114 let MAX_FAILED_COUNT = 5
Aliaksei Budaveif6069a72024-03-05 22:34:36 +0300115 " Create a map of setup configuration filenames with their basenames as keys.
116 let setup = glob('input/setup/*.vim', 1, 1)
117 \ ->reduce({d, f -> extend(d, {fnamemodify(f, ':t:r'): f})}, {})
Aliaksei Budaveiec022942024-10-06 16:57:33 +0200118 " Turn a subset of filenames etc. requested for testing into a pattern.
119 let filter = filereadable('../testdir/Xfilter')
120 \ ? readfile('../testdir/Xfilter')
121 \ ->map({_, v -> (v =~ '\.' ? '^' : '\.') .. v .. '$'})
122 \ ->join('\|')
123 \ : ''
Aliaksei Budaveif6069a72024-03-05 22:34:36 +0300124
Aliaksei Budaveiec022942024-10-06 16:57:33 +0200125 " Treat "\.self-testing$" as a string NOT as a regexp.
126 if filter ==# '\.self-testing$'
Aliaksei Budaveid2f49872024-05-24 19:14:16 +0300127 let dirpath = 'input/selftestdir/'
Aliaksei Budaveid33afe12024-08-12 18:37:15 +0200128 let fnames = readdir(dirpath, {fname -> fname !~ '^README\.txt$'})
Aliaksei Budaveid2f49872024-05-24 19:14:16 +0300129 else
130 let dirpath = 'input/'
Aliaksei Budaveiec022942024-10-06 16:57:33 +0200131 let filter ..= exists("$VIM_SYNTAX_TEST_FILTER") &&
132 \ !empty($VIM_SYNTAX_TEST_FILTER)
133 \ ? (empty(filter) ? '' : '\|') .. $VIM_SYNTAX_TEST_FILTER
134 \ : ''
135 let fnames = readdir(dirpath,
136 \ {subset -> {fname -> fname !~ '\~$' && fname =~# subset}}(
137 \ empty(filter) ? '^.\+\..\+$' : filter))
Aliaksei Budaveid2f49872024-05-24 19:14:16 +0300138 endif
Bram Moolenaar7d0dbd02023-06-24 00:56:50 +0100139
Aliaksei Budaveid2f49872024-05-24 19:14:16 +0300140 for fname in fnames
141 let root = fnamemodify(fname, ':r')
142 let fname = dirpath .. fname
Christian Brabandt56824432024-02-28 21:24:25 +0100143 let filetype = substitute(root, '\([^_.]*\)[_.].*', '\1', '')
144 let failed_root = 'failed/' .. root
Bram Moolenaar46acad72023-06-11 19:04:18 +0100145
Christian Brabandt56824432024-02-28 21:24:25 +0100146 " Execute the test if the "done" file does not exist or when the input file
147 " is newer.
148 let in_time = getftime(fname)
149 let out_time = getftime('done/' .. root)
150 if out_time < 0 || in_time > out_time
151 call ch_log('running tests for: ' .. fname)
Bram Moolenaar7d0dbd02023-06-24 00:56:50 +0100152
Christian Brabandt56824432024-02-28 21:24:25 +0100153 for dumpname in glob(failed_root .. '_\d*\.dump', 1, 1)
154 call delete(dumpname)
155 endfor
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100156 call delete('done/' .. root)
157
Christian Brabandt56824432024-02-28 21:24:25 +0100158 let lines =<< trim END
Aliaksei Budavei71971432024-07-05 21:30:02 +0300159 " Track the cursor progress through a syntax test file so that any
160 " degenerate input can be reported. Each file will have its own cursor.
161 let s:cursor = 1
162
Christian Brabandt56824432024-02-28 21:24:25 +0100163 " extra info for shell variables
164 func ShellInfo()
165 let msg = ''
166 for [key, val] in items(b:)
167 if key =~ '^is_'
168 let msg ..= key .. ': ' .. val .. ', '
169 endif
170 endfor
171 if msg != ''
172 echomsg msg
173 endif
174 endfunc
175
176 au! SwapExists * call HandleSwapExists()
177 func HandleSwapExists()
178 " Ignore finding a swap file for the test input, the user might be
179 " editing it and that's OK.
180 if expand('<afile>') =~ 'input[/\\].*\..*'
181 let v:swapchoice = 'e'
182 endif
183 endfunc
184
185 func LoadFiletype(type)
186 for file in glob("ftplugin/" .. a:type .. "*.vim", 1, 1)
187 exe "source " .. file
188 endfor
189 redraw!
190 endfunc
191
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300192 func SetUpVim()
193 call cursor(1, 1)
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100194 " Defend against rogue VIM_TEST_SETUP commands.
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300195 for _ in range(20)
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100196 let lnum = search('\C\<VIM_TEST_SETUP\>', 'eW', 20)
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300197 if lnum < 1
198 break
199 endif
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100200 exe substitute(getline(lnum), '\C.*\<VIM_TEST_SETUP\>', '', '')
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300201 endfor
202 call cursor(1, 1)
203 " BEGIN [runtime/defaults.vim]
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100204 " Also, disable italic highlighting to avoid issues on some terminals.
Aliaksei Budavei84184462024-05-21 01:10:26 +0300205 set display=lastline ruler scrolloff=5 t_ZH= t_ZR=
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300206 syntax on
207 " END [runtime/defaults.vim]
208 redraw!
209 endfunc
Aliaksei Budavei84184462024-05-21 01:10:26 +0300210
Aliaksei Budavei71971432024-07-05 21:30:02 +0300211 def s:AssertCursorForwardProgress(): bool
212 const curnum: number = line('.')
213 if curnum <= cursor
214 # Use "actions/upload-artifact@v4" of ci.yml for delivery.
215 writefile([printf('No cursor progress: %d <= %d (%s). Please file an issue.',
216 curnum,
217 cursor,
218 bufname('%'))],
219 'failed/00-FIXME',
220 'a')
221 bwipeout!
222 endif
223 cursor = curnum
224 return true
225 enddef
226
227 def ScrollToSecondPage(estate: number, op_wh: number, op_so: number): bool
Aliaksei Budavei84184462024-05-21 01:10:26 +0300228 if line('.') != 1 || line('w$') >= line('$')
Aliaksei Budavei71971432024-07-05 21:30:02 +0300229 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300230 endif
231 try
232 set scrolloff=0
233 # Advance mark "c"[ursor] along with the cursor.
234 norm! Lmc
235 if foldclosed('.') < 0 &&
236 (strdisplaywidth(getline('.')) + &l:fdc * winheight(1)) >= estate
237 # Make for an exit for a screenful long line.
238 norm! j^
Aliaksei Budavei71971432024-07-05 21:30:02 +0300239 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300240 else
241 # Place the cursor on the actually last visible line.
242 while winline() < op_wh
243 const lastnum: number = winline()
244 norm! gjmc
245 if lastnum > winline()
246 break
247 endif
248 endwhile
249 norm! zt
250 endif
251 finally
252 # COMPATIBILITY: Scroll up around "scrolloff" lines.
253 &scrolloff = max([1, op_so])
254 endtry
255 norm! ^
Aliaksei Budavei71971432024-07-05 21:30:02 +0300256 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300257 enddef
258
Aliaksei Budavei71971432024-07-05 21:30:02 +0300259 def ScrollToNextPage(estate: number, op_wh: number, op_so: number): bool
Aliaksei Budavei84184462024-05-21 01:10:26 +0300260 if line('.') == 1 || line('w$') >= line('$')
Aliaksei Budavei71971432024-07-05 21:30:02 +0300261 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300262 endif
263 try
264 set scrolloff=0
265 # Advance mark "c"[ursor] along with the cursor.
266 norm! Lmc
267 if foldclosed('.') < 0 &&
268 (strdisplaywidth(getline('.')) + &l:fdc * winheight(1)) >= estate
269 # Make for an exit for a screenful long line.
270 norm! j^
Aliaksei Budavei71971432024-07-05 21:30:02 +0300271 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300272 else
273 # Place the cursor on the actually last visible line.
274 while winline() < op_wh
275 const lastnum: number = winline()
276 norm! gjmc
277 if lastnum > winline()
278 break
279 endif
280 endwhile
281 endif
282 finally
283 # COMPATIBILITY: Scroll up/down around "scrolloff" lines.
284 &scrolloff = max([1, op_so])
285 endtry
286 norm! zt
287 const marknum: number = line("'c")
288 # Eschew &smoothscroll since line("`c") is not supported.
289 # Remember that "w0" can point to the first line of a _closed_ fold
290 # whereas the last line of a _closed_ fold can be marked.
291 if line('w0') > marknum
292 while line('w0') > marknum
293 exe "norm! \<C-y>"
294 endwhile
295 if line('w0') != marknum
296 exe "norm! \<C-e>H"
297 endif
298 # Handle non-wrapped lines.
299 elseif line('w0') < marknum
300 while line('w0') < marknum
301 exe "norm! \<C-e>"
302 endwhile
303 if line('w0') != marknum
304 exe "norm! \<C-y>H"
305 endif
306 endif
307 norm! ^
Aliaksei Budavei71971432024-07-05 21:30:02 +0300308 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300309 enddef
Christian Brabandt56824432024-02-28 21:24:25 +0100310 END
311 call writefile(lines, 'Xtestscript')
312
313 " close all but the last window
314 while winnr('$') > 1
315 close
316 endwhile
317
318 " Redraw to make sure that messages are cleared and there is enough space
319 " for the terminal window.
320 redraw
321
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300322 " Let "Xtestscript#SetUpVim()" turn the syntax on.
Aliaksei Budaveif6069a72024-03-05 22:34:36 +0300323 let prefix = '-Nu NONE -S Xtestscript'
324 let path = get(setup, root, '')
325 " Source the found setup configuration file.
326 let args = !empty(path)
327 \ ? prefix .. ' -S ' .. path
328 \ : prefix
329 let buf = RunVimInTerminal(args, {})
Christian Brabandt56824432024-02-28 21:24:25 +0100330 " edit the file only after catching the SwapExists event
331 call term_sendkeys(buf, ":edit " .. fname .. "\<CR>")
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300332 " set up the testing environment
333 call term_sendkeys(buf, ":call SetUpVim()\<CR>")
Christian Brabandt56824432024-02-28 21:24:25 +0100334 " load filetype specific settings
335 call term_sendkeys(buf, ":call LoadFiletype('" .. filetype .. "')\<CR>")
336
337 if filetype == 'sh'
338 call term_sendkeys(buf, ":call ShellInfo()\<CR>")
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100339 endif
Christian Brabandt56824432024-02-28 21:24:25 +0100340
341 " Screendump at the start of the file: failed/root_00.dump
342 let root_00 = root .. '_00'
Aliaksei Budavei84184462024-05-21 01:10:26 +0300343 let in_name_and_out_name = fname .. ': failed/' .. root_00 .. '.dump'
344 call ch_log('First screendump for ' .. in_name_and_out_name)
Christian Brabandt56824432024-02-28 21:24:25 +0100345 let fail = VerifyScreenDump(buf, root_00, {})
346
Christian Brabandt56824432024-02-28 21:24:25 +0100347 " Make a Screendump every 18 lines of the file: failed/root_NN.dump
Christian Brabandt56824432024-02-28 21:24:25 +0100348 let nr = 1
Aliaksei Budavei84184462024-05-21 01:10:26 +0300349 let root_next = printf('%s_%02d', root, nr)
350 let in_name_and_out_name = fname .. ': failed/' .. root_next .. '.dump'
351
Aliaksei Budavei71971432024-07-05 21:30:02 +0300352 " Accommodate the next code block to "buf"'s contingency for self
353 " wipe-out.
354 try
355 if !IsWinNumOneAtEOF(in_name_and_out_name)
356 call term_sendkeys(buf, ":call ScrollToSecondPage((18 * 75 + 1), 19, 5) | redraw!\<CR>")
Aliaksei Budavei84184462024-05-21 01:10:26 +0300357 call ch_log('Next screendump for ' .. in_name_and_out_name)
358 let fail += VerifyScreenDump(buf, root_next, {})
359 let nr += 1
360 let root_next = printf('%s_%02d', root, nr)
361 let in_name_and_out_name = fname .. ': failed/' .. root_next .. '.dump'
Christian Brabandt56824432024-02-28 21:24:25 +0100362
Aliaksei Budavei71971432024-07-05 21:30:02 +0300363 while !IsWinNumOneAtEOF(in_name_and_out_name)
364 call term_sendkeys(buf, ":call ScrollToNextPage((18 * 75 + 1), 19, 5) | redraw!\<CR>")
365 call ch_log('Next screendump for ' .. in_name_and_out_name)
366 let fail += VerifyScreenDump(buf, root_next, {})
367 let nr += 1
368 let root_next = printf('%s_%02d', root, nr)
369 let in_name_and_out_name = fname .. ': failed/' .. root_next .. '.dump'
370 endwhile
371 endif
Aliaksei Budavei71971432024-07-05 21:30:02 +0300372 call StopVimInTerminal(buf)
373 finally
374 call delete('Xtestscript')
375 endtry
Christian Brabandt56824432024-02-28 21:24:25 +0100376
377 " redraw here to avoid the following messages to get mixed up with screen
378 " output.
379 redraw
380
381 " Add any assert errors to s:messages.
382 if len(v:errors) > 0
383 call extend(s:messages, v:errors)
384 " Echo the errors here, in case the script aborts or the "messages" file
385 " is not displayed later.
386 echomsg v:errors
387 let v:errors = []
388 let fail += 1
389 endif
390
391 if fail == 0
392 call Message("Test " .. root .. " OK")
393
394 call writefile(['OK'], 'done/' .. root)
395
396 let ok_count += 1
397 else
398 call Message("Test " .. root .. " FAILED")
399
400 call delete('done/' .. root)
401
402 eval failed_tests->add(root)
403 if len(failed_tests) > MAX_FAILED_COUNT
404 call Message('')
405 call Message('Too many errors, aborting')
406 endif
407 endif
408 else
409 call Message("Test " .. root .. " skipped")
410 let skipped_count += 1
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100411 endif
Christian Brabandt56824432024-02-28 21:24:25 +0100412
413 " Append messages to the file "testdir/messages"
414 call AppendMessages('Input file ' .. fname .. ':')
415
416 if len(failed_tests) > MAX_FAILED_COUNT
417 break
418 endif
419 endfor
420
421 call Message(s:test_run_message)
422 call Message('OK: ' .. ok_count)
423 call Message('FAILED: ' .. len(failed_tests) .. ': ' .. string(failed_tests))
424 call Message('skipped: ' .. skipped_count)
Aliaksei Budaveid33afe12024-08-12 18:37:15 +0200425
426 if !empty(failed_tests)
427 call Message('')
428 call Message('View generated screendumps with "../../src/vim --clean -S testdir/viewdumps.vim"')
429 endif
430
Christian Brabandt56824432024-02-28 21:24:25 +0100431 call AppendMessages('== SUMMARY ==')
432
433 if len(failed_tests) > 0
434 " have make report an error
435 cquit
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100436 endif
Christian Brabandt56824432024-02-28 21:24:25 +0100437endfunc
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100438
Christian Brabandt56824432024-02-28 21:24:25 +0100439call RunTest()
Christian Brabandt627c9502024-02-10 13:02:17 +0100440
441" Matching "if 1" at the start.
442endif
443
Bram Moolenaar46acad72023-06-11 19:04:18 +0100444qall!
Christian Brabandt56824432024-02-28 21:24:25 +0100445
446" vim:ts=8