blob: 3f45ecc2c2253c9b11e414a90baf05d628a78089 [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
Christian Brabandt56824432024-02-28 21:24:25 +0100146 " extra info for shell variables
147 func ShellInfo()
148 let msg = ''
149 for [key, val] in items(b:)
150 if key =~ '^is_'
151 let msg ..= key .. ': ' .. val .. ', '
152 endif
153 endfor
154 if msg != ''
155 echomsg msg
156 endif
157 endfunc
158
159 au! SwapExists * call HandleSwapExists()
160 func HandleSwapExists()
161 " Ignore finding a swap file for the test input, the user might be
162 " editing it and that's OK.
163 if expand('<afile>') =~ 'input[/\\].*\..*'
164 let v:swapchoice = 'e'
165 endif
166 endfunc
167
168 func LoadFiletype(type)
169 for file in glob("ftplugin/" .. a:type .. "*.vim", 1, 1)
170 exe "source " .. file
171 endfor
172 redraw!
173 endfunc
174
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300175 func SetUpVim()
176 call cursor(1, 1)
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100177 " Defend against rogue VIM_TEST_SETUP commands.
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300178 for _ in range(20)
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100179 let lnum = search('\C\<VIM_TEST_SETUP\>', 'eW', 20)
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300180 if lnum < 1
181 break
182 endif
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100183 exe substitute(getline(lnum), '\C.*\<VIM_TEST_SETUP\>', '', '')
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300184 endfor
185 call cursor(1, 1)
186 " BEGIN [runtime/defaults.vim]
Aliaksei Budaveia2addeb2024-03-18 20:39:32 +0100187 " Also, disable italic highlighting to avoid issues on some terminals.
Aliaksei Budavei84184462024-05-21 01:10:26 +0300188 set display=lastline ruler scrolloff=5 t_ZH= t_ZR=
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300189 syntax on
190 " END [runtime/defaults.vim]
191 redraw!
192 endfunc
Aliaksei Budavei84184462024-05-21 01:10:26 +0300193
194 def ScrollToSecondPage(estate: number, op_wh: number, op_so: number)
195 if line('.') != 1 || line('w$') >= line('$')
196 return
197 endif
198 try
199 set scrolloff=0
200 # Advance mark "c"[ursor] along with the cursor.
201 norm! Lmc
202 if foldclosed('.') < 0 &&
203 (strdisplaywidth(getline('.')) + &l:fdc * winheight(1)) >= estate
204 # Make for an exit for a screenful long line.
205 norm! j^
206 return
207 else
208 # Place the cursor on the actually last visible line.
209 while winline() < op_wh
210 const lastnum: number = winline()
211 norm! gjmc
212 if lastnum > winline()
213 break
214 endif
215 endwhile
216 norm! zt
217 endif
218 finally
219 # COMPATIBILITY: Scroll up around "scrolloff" lines.
220 &scrolloff = max([1, op_so])
221 endtry
222 norm! ^
223 enddef
224
225 def ScrollToNextPage(estate: number, op_wh: number, op_so: number)
226 if line('.') == 1 || line('w$') >= line('$')
227 return
228 endif
229 try
230 set scrolloff=0
231 # Advance mark "c"[ursor] along with the cursor.
232 norm! Lmc
233 if foldclosed('.') < 0 &&
234 (strdisplaywidth(getline('.')) + &l:fdc * winheight(1)) >= estate
235 # Make for an exit for a screenful long line.
236 norm! j^
237 return
238 else
239 # Place the cursor on the actually last visible line.
240 while winline() < op_wh
241 const lastnum: number = winline()
242 norm! gjmc
243 if lastnum > winline()
244 break
245 endif
246 endwhile
247 endif
248 finally
249 # COMPATIBILITY: Scroll up/down around "scrolloff" lines.
250 &scrolloff = max([1, op_so])
251 endtry
252 norm! zt
253 const marknum: number = line("'c")
254 # Eschew &smoothscroll since line("`c") is not supported.
255 # Remember that "w0" can point to the first line of a _closed_ fold
256 # whereas the last line of a _closed_ fold can be marked.
257 if line('w0') > marknum
258 while line('w0') > marknum
259 exe "norm! \<C-y>"
260 endwhile
261 if line('w0') != marknum
262 exe "norm! \<C-e>H"
263 endif
264 # Handle non-wrapped lines.
265 elseif line('w0') < marknum
266 while line('w0') < marknum
267 exe "norm! \<C-e>"
268 endwhile
269 if line('w0') != marknum
270 exe "norm! \<C-y>H"
271 endif
272 endif
273 norm! ^
274 enddef
Christian Brabandt56824432024-02-28 21:24:25 +0100275 END
276 call writefile(lines, 'Xtestscript')
277
278 " close all but the last window
279 while winnr('$') > 1
280 close
281 endwhile
282
283 " Redraw to make sure that messages are cleared and there is enough space
284 " for the terminal window.
285 redraw
286
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300287 " Let "Xtestscript#SetUpVim()" turn the syntax on.
Aliaksei Budaveif6069a72024-03-05 22:34:36 +0300288 let prefix = '-Nu NONE -S Xtestscript'
289 let path = get(setup, root, '')
290 " Source the found setup configuration file.
291 let args = !empty(path)
292 \ ? prefix .. ' -S ' .. path
293 \ : prefix
294 let buf = RunVimInTerminal(args, {})
Christian Brabandt56824432024-02-28 21:24:25 +0100295 " edit the file only after catching the SwapExists event
296 call term_sendkeys(buf, ":edit " .. fname .. "\<CR>")
Aliaksei Budavei93edd252024-03-05 22:34:36 +0300297 " set up the testing environment
298 call term_sendkeys(buf, ":call SetUpVim()\<CR>")
Christian Brabandt56824432024-02-28 21:24:25 +0100299 " load filetype specific settings
300 call term_sendkeys(buf, ":call LoadFiletype('" .. filetype .. "')\<CR>")
301
302 if filetype == 'sh'
303 call term_sendkeys(buf, ":call ShellInfo()\<CR>")
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100304 endif
Christian Brabandt56824432024-02-28 21:24:25 +0100305
306 " Screendump at the start of the file: failed/root_00.dump
307 let root_00 = root .. '_00'
Aliaksei Budavei84184462024-05-21 01:10:26 +0300308 let in_name_and_out_name = fname .. ': failed/' .. root_00 .. '.dump'
309 call ch_log('First screendump for ' .. in_name_and_out_name)
Christian Brabandt56824432024-02-28 21:24:25 +0100310 let fail = VerifyScreenDump(buf, root_00, {})
311
Aliaksei Budavei84184462024-05-21 01:10:26 +0300312 " Clear the shell info if there are not enough lines to cause a scroll
313 if filetype == 'sh' && IsWinNumOneAtEOF(in_name_and_out_name)
Aliaksei Budaveicc5482e2024-05-21 01:12:22 +0300314 call term_sendkeys(buf, ":redraw!\<CR>")
Christian Brabandt56824432024-02-28 21:24:25 +0100315 endif
316
317 " Make a Screendump every 18 lines of the file: failed/root_NN.dump
Christian Brabandt56824432024-02-28 21:24:25 +0100318 let nr = 1
Aliaksei Budavei84184462024-05-21 01:10:26 +0300319 let root_next = printf('%s_%02d', root, nr)
320 let in_name_and_out_name = fname .. ': failed/' .. root_next .. '.dump'
321
322 if !IsWinNumOneAtEOF(in_name_and_out_name)
323 call term_sendkeys(buf, ":call ScrollToSecondPage((18 * 75 + 1), 19, 5) | redraw!\<CR>")
324 call ch_log('Next screendump for ' .. in_name_and_out_name)
Christian Brabandt56824432024-02-28 21:24:25 +0100325 let fail += VerifyScreenDump(buf, root_next, {})
326 let nr += 1
Aliaksei Budavei84184462024-05-21 01:10:26 +0300327 let root_next = printf('%s_%02d', root, nr)
328 let in_name_and_out_name = fname .. ': failed/' .. root_next .. '.dump'
329
330 while !IsWinNumOneAtEOF(in_name_and_out_name)
331 call term_sendkeys(buf, ":call ScrollToNextPage((18 * 75 + 1), 19, 5) | redraw!\<CR>")
332 call ch_log('Next screendump for ' .. in_name_and_out_name)
333 let fail += VerifyScreenDump(buf, root_next, {})
334 let nr += 1
335 let root_next = printf('%s_%02d', root, nr)
336 let in_name_and_out_name = fname .. ': failed/' .. root_next .. '.dump'
337 endwhile
338 endif
Christian Brabandt56824432024-02-28 21:24:25 +0100339
340 " Screendump at the end of the file: failed/root_99.dump
341 call term_sendkeys(buf, 'Gzb')
342 let root_last = root .. '_99'
343 call ch_log('Last screendump for ' .. fname .. ': failed/' .. root_last .. '.dump')
344 let fail += VerifyScreenDump(buf, root_last, {})
345
346 call StopVimInTerminal(buf)
347 call delete('Xtestscript')
348
349 " redraw here to avoid the following messages to get mixed up with screen
350 " output.
351 redraw
352
353 " Add any assert errors to s:messages.
354 if len(v:errors) > 0
355 call extend(s:messages, v:errors)
356 " Echo the errors here, in case the script aborts or the "messages" file
357 " is not displayed later.
358 echomsg v:errors
359 let v:errors = []
360 let fail += 1
361 endif
362
363 if fail == 0
364 call Message("Test " .. root .. " OK")
365
366 call writefile(['OK'], 'done/' .. root)
367
368 let ok_count += 1
369 else
370 call Message("Test " .. root .. " FAILED")
371
372 call delete('done/' .. root)
373
374 eval failed_tests->add(root)
375 if len(failed_tests) > MAX_FAILED_COUNT
376 call Message('')
377 call Message('Too many errors, aborting')
378 endif
379 endif
380 else
381 call Message("Test " .. root .. " skipped")
382 let skipped_count += 1
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100383 endif
Christian Brabandt56824432024-02-28 21:24:25 +0100384
385 " Append messages to the file "testdir/messages"
386 call AppendMessages('Input file ' .. fname .. ':')
387
388 if len(failed_tests) > MAX_FAILED_COUNT
389 break
390 endif
391 endfor
392
393 call Message(s:test_run_message)
394 call Message('OK: ' .. ok_count)
395 call Message('FAILED: ' .. len(failed_tests) .. ': ' .. string(failed_tests))
396 call Message('skipped: ' .. skipped_count)
397 call AppendMessages('== SUMMARY ==')
398
399 if len(failed_tests) > 0
400 " have make report an error
401 cquit
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100402 endif
Christian Brabandt56824432024-02-28 21:24:25 +0100403endfunc
Bram Moolenaar1aa5f1c2023-06-22 21:57:51 +0100404
Christian Brabandt56824432024-02-28 21:24:25 +0100405call RunTest()
Christian Brabandt627c9502024-02-10 13:02:17 +0100406
407" Matching "if 1" at the start.
408endif
409
Bram Moolenaar46acad72023-06-11 19:04:18 +0100410qall!
Christian Brabandt56824432024-02-28 21:24:25 +0100411
412" vim:ts=8