xref: /vim-8.2.3635/src/testdir/screendump.vim (revision 12ee7ff0)
1" Functions shared by tests making screen dumps.
2
3" Only load this script once.
4if exists('*CanRunVimInTerminal')
5  finish
6endif
7
8" For most tests we need to be able to run terminal Vim with 256 colors.  On
9" MS-Windows the console only has 16 colors and the GUI can't run in a
10" terminal.
11func CanRunVimInTerminal()
12  return has('terminal') && !has('win32')
13endfunc
14
15" Skip the rest if there is no terminal feature at all.
16if !has('terminal')
17  finish
18endif
19
20source shared.vim
21
22" Run Vim with "arguments" in a new terminal window.
23" By default uses a size of 20 lines and 75 columns.
24" Returns the buffer number of the terminal.
25"
26" Options is a dictionary, these items are recognized:
27" "rows" - height of the terminal window (max. 20)
28" "cols" - width of the terminal window (max. 78)
29" "statusoff" - number of lines the status is offset from default
30func RunVimInTerminal(arguments, options)
31  " If Vim doesn't exit a swap file remains, causing other tests to fail.
32  " Remove it here.
33  call delete(".swp")
34
35  if exists('$COLORFGBG')
36    " Clear $COLORFGBG to avoid 'background' being set to "dark", which will
37    " only be corrected if the response to t_RB is received, which may be too
38    " late.
39    let $COLORFGBG = ''
40  endif
41
42  " Make a horizontal and vertical split, so that we can get exactly the right
43  " size terminal window.  Works only when the current window is full width.
44  call assert_equal(&columns, winwidth(0))
45  split
46  vsplit
47
48  " Always do this with 256 colors and a light background.
49  set t_Co=256 background=light
50  hi Normal ctermfg=NONE ctermbg=NONE
51
52  " Make the window 20 lines high and 75 columns, unless told otherwise.
53  let rows = get(a:options, 'rows', 20)
54  let cols = get(a:options, 'cols', 75)
55  let statusoff = get(a:options, 'statusoff', 1)
56
57  let cmd = GetVimCommandClean()
58
59  " Add -v to have gvim run in the terminal (if possible)
60  let cmd .= ' -v ' . a:arguments
61  let buf = term_start(cmd, {
62	\ 'curwin': 1,
63	\ 'term_rows': rows,
64	\ 'term_cols': cols,
65	\ })
66  if &termwinsize == ''
67    " in the GUI we may end up with a different size, try to set it.
68    if term_getsize(buf) != [rows, cols]
69      call term_setsize(buf, rows, cols)
70    endif
71    call assert_equal([rows, cols], term_getsize(buf))
72  else
73    let rows = term_getsize(buf)[0]
74    let cols = term_getsize(buf)[1]
75  endif
76
77  " Wait for "All" or "Top" of the ruler to be shown in the last line or in
78  " the status line of the last window. This can be quite slow (e.g. when
79  " using valgrind).
80  " If it fails then show the terminal contents for debugging.
81  try
82    call WaitFor({-> len(term_getline(buf, rows)) >= cols - 1 || len(term_getline(buf, rows - statusoff)) >= cols - 1})
83  catch /timed out after/
84    let lines = map(range(1, rows), {key, val -> term_getline(buf, val)})
85    call assert_report('RunVimInTerminal() failed, screen contents: ' . join(lines, "<NL>"))
86  endtry
87
88  return buf
89endfunc
90
91" Stop a Vim running in terminal buffer "buf".
92func StopVimInTerminal(buf)
93  call assert_equal("running", term_getstatus(a:buf))
94
95  " CTRL-O : works both in Normal mode and Insert mode to start a command line.
96  " In Command-line it's inserted, the CTRL-U removes it again.
97  call term_sendkeys(a:buf, "\<C-O>:\<C-U>qa!\<cr>")
98
99  call WaitForAssert({-> assert_equal("finished", term_getstatus(a:buf))})
100  only!
101endfunc
102
103" Verify that Vim running in terminal buffer "buf" matches the screen dump.
104" "options" is passed to term_dumpwrite().
105" The file name used is "dumps/{filename}.dump".
106" Optionally an extra argument can be passed which is prepended to the error
107" message.  Use this when using the same dump file with different options.
108" Will wait for up to a second for the screen dump to match.
109" Returns non-zero when verification fails.
110func VerifyScreenDump(buf, filename, options, ...)
111  let reference = 'dumps/' . a:filename . '.dump'
112  let testfile = 'failed/' . a:filename . '.dump'
113
114  " Redraw to execut the code that updates the screen.  Otherwise we get the
115  " text and attributes only from the internal buffer.
116  redraw
117
118  let did_mkdir = 0
119  if !isdirectory('failed')
120    let did_mkdir = 1
121    call mkdir('failed')
122  endif
123
124  let i = 0
125  while 1
126    " leave some time for updating the original window
127    sleep 10m
128    call delete(testfile)
129    call term_dumpwrite(a:buf, testfile, a:options)
130    let testdump = readfile(testfile)
131    if filereadable(reference)
132      let refdump = readfile(reference)
133    else
134      " Must be a new screendump, always fail
135      let refdump = []
136    endif
137    if refdump == testdump
138      call delete(testfile)
139      if did_mkdir
140	call delete('failed', 'd')
141      endif
142      break
143    endif
144    if i == 100
145      " Leave the failed dump around for inspection.
146      if filereadable(reference)
147	let msg = 'See dump file difference: call term_dumpdiff("' . testfile . '", "' . reference . '")'
148	if a:0 == 1
149	  let msg = a:1 . ': ' . msg
150	endif
151	if len(testdump) != len(refdump)
152	  let msg = msg . '; line count is ' . len(testdump) . ' instead of ' . len(refdump)
153	endif
154      else
155	let msg = 'See new dump file: call term_dumpload("' . testfile . '")'
156      endif
157      for i in range(len(refdump))
158	if i >= len(testdump)
159	  break
160	endif
161	if testdump[i] != refdump[i]
162	  let msg = msg . '; difference in line ' . (i + 1) . ': "' . testdump[i] . '"'
163	endif
164      endfor
165      call assert_report(msg)
166      return 1
167    endif
168    let i += 1
169  endwhile
170  return 0
171endfunc
172