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