blob: 7c48b3fb17e5de1509f22f9437da7ce288917a03 [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})}, {})
118
Aliaksei Budaveid2f49872024-05-24 19:14:16 +0300119 if exists("$VIM_SYNTAX_SELF_TESTING")
120 let dirpath = 'input/selftestdir/'
121 let fnames = readdir(dirpath, {fname -> fname !~ '^README.txt$'})
122 else
123 let dirpath = 'input/'
124 let fnames = readdir(dirpath, {fname -> fname !~ '\~$' && fname =~ '^.\+\..\+$'})
125 endif
Bram Moolenaar7d0dbd02023-06-24 00:56:50 +0100126
Aliaksei Budaveid2f49872024-05-24 19:14:16 +0300127 for fname in fnames
128 let root = fnamemodify(fname, ':r')
129 let fname = dirpath .. fname
Christian Brabandt56824432024-02-28 21:24:25 +0100130 let filetype = substitute(root, '\([^_.]*\)[_.].*', '\1', '')
131 let failed_root = 'failed/' .. root
Bram Moolenaar46acad72023-06-11 19:04:18 +0100132
Christian Brabandt56824432024-02-28 21:24:25 +0100133 " Execute the test if the "done" file does not exist or when the input file
134 " is newer.
135 let in_time = getftime(fname)
136 let out_time = getftime('done/' .. root)
137 if out_time < 0 || in_time > out_time
138 call ch_log('running tests for: ' .. fname)
Bram Moolenaar7d0dbd02023-06-24 00:56:50 +0100139
Christian Brabandt56824432024-02-28 21:24:25 +0100140 for dumpname in glob(failed_root .. '_\d*\.dump', 1, 1)
141 call delete(dumpname)
142 endfor
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100143 call delete('done/' .. root)
144
Christian Brabandt56824432024-02-28 21:24:25 +0100145 let lines =<< trim END
Aliaksei Budavei71971432024-07-05 21:30:02 +0300146 " Track the cursor progress through a syntax test file so that any
147 " degenerate input can be reported. Each file will have its own cursor.
148 let s:cursor = 1
149
Christian Brabandt56824432024-02-28 21:24:25 +0100150 " extra info for shell variables
151 func ShellInfo()
152 let msg = ''
153 for [key, val] in items(b:)
154 if key =~ '^is_'
155 let msg ..= key .. ': ' .. val .. ', '
156 endif
157 endfor
158 if msg != ''
159 echomsg msg
160 endif
161 endfunc
162
163 au! SwapExists * call HandleSwapExists()
164 func HandleSwapExists()
165 " Ignore finding a swap file for the test input, the user might be
166 " editing it and that's OK.
167 if expand('<afile>') =~ 'input[/\\].*\..*'
168 let v:swapchoice = 'e'
169 endif
170 endfunc
171
172 func LoadFiletype(type)
173 for file in glob("ftplugin/" .. a:type .. "*.vim", 1, 1)
174 exe "source " .. file
175 endfor
176 redraw!
177 endfunc
178
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300179 func SetUpVim()
180 call cursor(1, 1)
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100181 " Defend against rogue VIM_TEST_SETUP commands.
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300182 for _ in range(20)
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100183 let lnum = search('\C\<VIM_TEST_SETUP\>', 'eW', 20)
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300184 if lnum < 1
185 break
186 endif
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100187 exe substitute(getline(lnum), '\C.*\<VIM_TEST_SETUP\>', '', '')
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300188 endfor
189 call cursor(1, 1)
190 " BEGIN [runtime/defaults.vim]
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100191 " Also, disable italic highlighting to avoid issues on some terminals.
Aliaksei Budavei84184462024-05-21 01:10:26 +0300192 set display=lastline ruler scrolloff=5 t_ZH= t_ZR=
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300193 syntax on
194 " END [runtime/defaults.vim]
195 redraw!
196 endfunc
Aliaksei Budavei84184462024-05-21 01:10:26 +0300197
Aliaksei Budavei71971432024-07-05 21:30:02 +0300198 def s:AssertCursorForwardProgress(): bool
199 const curnum: number = line('.')
200 if curnum <= cursor
201 # Use "actions/upload-artifact@v4" of ci.yml for delivery.
202 writefile([printf('No cursor progress: %d <= %d (%s). Please file an issue.',
203 curnum,
204 cursor,
205 bufname('%'))],
206 'failed/00-FIXME',
207 'a')
208 bwipeout!
209 endif
210 cursor = curnum
211 return true
212 enddef
213
214 def ScrollToSecondPage(estate: number, op_wh: number, op_so: number): bool
Aliaksei Budavei84184462024-05-21 01:10:26 +0300215 if line('.') != 1 || line('w$') >= line('$')
Aliaksei Budavei71971432024-07-05 21:30:02 +0300216 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300217 endif
218 try
219 set scrolloff=0
220 # Advance mark "c"[ursor] along with the cursor.
221 norm! Lmc
222 if foldclosed('.') < 0 &&
223 (strdisplaywidth(getline('.')) + &l:fdc * winheight(1)) >= estate
224 # Make for an exit for a screenful long line.
225 norm! j^
Aliaksei Budavei71971432024-07-05 21:30:02 +0300226 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300227 else
228 # Place the cursor on the actually last visible line.
229 while winline() < op_wh
230 const lastnum: number = winline()
231 norm! gjmc
232 if lastnum > winline()
233 break
234 endif
235 endwhile
236 norm! zt
237 endif
238 finally
239 # COMPATIBILITY: Scroll up around "scrolloff" lines.
240 &scrolloff = max([1, op_so])
241 endtry
242 norm! ^
Aliaksei Budavei71971432024-07-05 21:30:02 +0300243 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300244 enddef
245
Aliaksei Budavei71971432024-07-05 21:30:02 +0300246 def ScrollToNextPage(estate: number, op_wh: number, op_so: number): bool
Aliaksei Budavei84184462024-05-21 01:10:26 +0300247 if line('.') == 1 || line('w$') >= line('$')
Aliaksei Budavei71971432024-07-05 21:30:02 +0300248 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300249 endif
250 try
251 set scrolloff=0
252 # Advance mark "c"[ursor] along with the cursor.
253 norm! Lmc
254 if foldclosed('.') < 0 &&
255 (strdisplaywidth(getline('.')) + &l:fdc * winheight(1)) >= estate
256 # Make for an exit for a screenful long line.
257 norm! j^
Aliaksei Budavei71971432024-07-05 21:30:02 +0300258 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300259 else
260 # Place the cursor on the actually last visible line.
261 while winline() < op_wh
262 const lastnum: number = winline()
263 norm! gjmc
264 if lastnum > winline()
265 break
266 endif
267 endwhile
268 endif
269 finally
270 # COMPATIBILITY: Scroll up/down around "scrolloff" lines.
271 &scrolloff = max([1, op_so])
272 endtry
273 norm! zt
274 const marknum: number = line("'c")
275 # Eschew &smoothscroll since line("`c") is not supported.
276 # Remember that "w0" can point to the first line of a _closed_ fold
277 # whereas the last line of a _closed_ fold can be marked.
278 if line('w0') > marknum
279 while line('w0') > marknum
280 exe "norm! \<C-y>"
281 endwhile
282 if line('w0') != marknum
283 exe "norm! \<C-e>H"
284 endif
285 # Handle non-wrapped lines.
286 elseif line('w0') < marknum
287 while line('w0') < marknum
288 exe "norm! \<C-e>"
289 endwhile
290 if line('w0') != marknum
291 exe "norm! \<C-y>H"
292 endif
293 endif
294 norm! ^
Aliaksei Budavei71971432024-07-05 21:30:02 +0300295 return AssertCursorForwardProgress()
Aliaksei Budavei84184462024-05-21 01:10:26 +0300296 enddef
Christian Brabandt56824432024-02-28 21:24:25 +0100297 END
298 call writefile(lines, 'Xtestscript')
299
300 " close all but the last window
301 while winnr('$') > 1
302 close
303 endwhile
304
305 " Redraw to make sure that messages are cleared and there is enough space
306 " for the terminal window.
307 redraw
308
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300309 " Let "Xtestscript#SetUpVim()" turn the syntax on.
Aliaksei Budaveif6069a72024-03-05 22:34:36 +0300310 let prefix = '-Nu NONE -S Xtestscript'
311 let path = get(setup, root, '')
312 " Source the found setup configuration file.
313 let args = !empty(path)
314 \ ? prefix .. ' -S ' .. path
315 \ : prefix
316 let buf = RunVimInTerminal(args, {})
Christian Brabandt56824432024-02-28 21:24:25 +0100317 " edit the file only after catching the SwapExists event
318 call term_sendkeys(buf, ":edit " .. fname .. "\<CR>")
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300319 " set up the testing environment
320 call term_sendkeys(buf, ":call SetUpVim()\<CR>")
Christian Brabandt56824432024-02-28 21:24:25 +0100321 " load filetype specific settings
322 call term_sendkeys(buf, ":call LoadFiletype('" .. filetype .. "')\<CR>")
323
324 if filetype == 'sh'
325 call term_sendkeys(buf, ":call ShellInfo()\<CR>")
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100326 endif
Christian Brabandt56824432024-02-28 21:24:25 +0100327
328 " Screendump at the start of the file: failed/root_00.dump
329 let root_00 = root .. '_00'
Aliaksei Budavei84184462024-05-21 01:10:26 +0300330 let in_name_and_out_name = fname .. ': failed/' .. root_00 .. '.dump'
331 call ch_log('First screendump for ' .. in_name_and_out_name)
Christian Brabandt56824432024-02-28 21:24:25 +0100332 let fail = VerifyScreenDump(buf, root_00, {})
333
Christian Brabandt56824432024-02-28 21:24:25 +0100334 " Make a Screendump every 18 lines of the file: failed/root_NN.dump
Christian Brabandt56824432024-02-28 21:24:25 +0100335 let nr = 1
Aliaksei Budavei84184462024-05-21 01:10:26 +0300336 let root_next = printf('%s_%02d', root, nr)
337 let in_name_and_out_name = fname .. ': failed/' .. root_next .. '.dump'
338
Aliaksei Budavei71971432024-07-05 21:30:02 +0300339 " Accommodate the next code block to "buf"'s contingency for self
340 " wipe-out.
341 try
342 if !IsWinNumOneAtEOF(in_name_and_out_name)
343 call term_sendkeys(buf, ":call ScrollToSecondPage((18 * 75 + 1), 19, 5) | redraw!\<CR>")
Aliaksei Budavei84184462024-05-21 01:10:26 +0300344 call ch_log('Next screendump for ' .. in_name_and_out_name)
345 let fail += VerifyScreenDump(buf, root_next, {})
346 let nr += 1
347 let root_next = printf('%s_%02d', root, nr)
348 let in_name_and_out_name = fname .. ': failed/' .. root_next .. '.dump'
Christian Brabandt56824432024-02-28 21:24:25 +0100349
Aliaksei Budavei71971432024-07-05 21:30:02 +0300350 while !IsWinNumOneAtEOF(in_name_and_out_name)
351 call term_sendkeys(buf, ":call ScrollToNextPage((18 * 75 + 1), 19, 5) | redraw!\<CR>")
352 call ch_log('Next screendump for ' .. in_name_and_out_name)
353 let fail += VerifyScreenDump(buf, root_next, {})
354 let nr += 1
355 let root_next = printf('%s_%02d', root, nr)
356 let in_name_and_out_name = fname .. ': failed/' .. root_next .. '.dump'
357 endwhile
358 endif
Aliaksei Budavei71971432024-07-05 21:30:02 +0300359 call StopVimInTerminal(buf)
360 finally
361 call delete('Xtestscript')
362 endtry
Christian Brabandt56824432024-02-28 21:24:25 +0100363
364 " redraw here to avoid the following messages to get mixed up with screen
365 " output.
366 redraw
367
368 " Add any assert errors to s:messages.
369 if len(v:errors) > 0
370 call extend(s:messages, v:errors)
371 " Echo the errors here, in case the script aborts or the "messages" file
372 " is not displayed later.
373 echomsg v:errors
374 let v:errors = []
375 let fail += 1
376 endif
377
378 if fail == 0
379 call Message("Test " .. root .. " OK")
380
381 call writefile(['OK'], 'done/' .. root)
382
383 let ok_count += 1
384 else
385 call Message("Test " .. root .. " FAILED")
386
387 call delete('done/' .. root)
388
389 eval failed_tests->add(root)
390 if len(failed_tests) > MAX_FAILED_COUNT
391 call Message('')
392 call Message('Too many errors, aborting')
393 endif
394 endif
395 else
396 call Message("Test " .. root .. " skipped")
397 let skipped_count += 1
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100398 endif
Christian Brabandt56824432024-02-28 21:24:25 +0100399
400 " Append messages to the file "testdir/messages"
401 call AppendMessages('Input file ' .. fname .. ':')
402
403 if len(failed_tests) > MAX_FAILED_COUNT
404 break
405 endif
406 endfor
407
408 call Message(s:test_run_message)
409 call Message('OK: ' .. ok_count)
410 call Message('FAILED: ' .. len(failed_tests) .. ': ' .. string(failed_tests))
411 call Message('skipped: ' .. skipped_count)
412 call AppendMessages('== SUMMARY ==')
413
414 if len(failed_tests) > 0
415 " have make report an error
416 cquit
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100417 endif
Christian Brabandt56824432024-02-28 21:24:25 +0100418endfunc
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100419
Christian Brabandt56824432024-02-28 21:24:25 +0100420call RunTest()
Christian Brabandt627c9502024-02-10 13:02:17 +0100421
422" Matching "if 1" at the start.
423endif
424
Bram Moolenaar46acad72023-06-11 19:04:18 +0100425qall!
Christian Brabandt56824432024-02-28 21:24:25 +0100426
427" vim:ts=8