test_shell.vim (10091B)
1 " Test for the shell related options ('shell', 'shellcmdflag', 'shellpipe', 2 " 'shellquote', 'shellredir', 'shellxescape', and 'shellxquote') 3 4 source check.vim 5 source shared.vim 6 7 func Test_shell_options() 8 if has('win32') 9 " FIXME: This test is flaky on MS-Windows. 10 let g:test_is_flaky = 1 11 endif 12 13 " The expected value of 'shellcmdflag', 'shellpipe', 'shellquote', 14 " 'shellredir', 'shellxescape', 'shellxquote' for the supported shells. 15 let shells = [] 16 if has('unix') 17 let shells += [['sh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 18 \ ['ksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 19 \ ['mksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 20 \ ['zsh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 21 \ ['zsh-beta', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 22 \ ['bash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 23 \ ['fish', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 24 \ ['ash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 25 \ ['dash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 26 \ ['csh', '-c', '|& tee', '', '>&', '', ''], 27 \ ['tcsh', '-c', '|& tee', '', '>&', '', '']] 28 endif 29 if has('win32') 30 let shells += [['cmd', '/s /c', '2>&1| tee', '', '>%s 2>&1', '', '"']] 31 endif 32 33 " start a new Vim instance with 'shell' set to each of the supported shells 34 " and check the default shell option settings 35 let after =<< trim END 36 let l = [&shell, &shellcmdflag, &shellpipe, &shellquote] 37 let l += [&shellredir, &shellxescape, &shellxquote] 38 call writefile([json_encode(l)], 'Xtestout') 39 qall! 40 END 41 for e in shells 42 if RunVim([], after, '--cmd "set shell=' .. e[0] .. '"') 43 call assert_equal(e, json_decode(readfile('Xtestout')[0])) 44 endif 45 endfor 46 47 " Test shellescape() for each of the shells. 48 for e in shells 49 exe 'set shell=' .. e[0] 50 if e[0] =~# '.*csh$' || e[0] =~# '.*csh.exe$' 51 let str1 = "'cmd \"arg1\" '\\''arg2'\\'' \\!%#'" 52 let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\\\!\\%\\#'" 53 elseif e[0] =~# '.*powershell$' || e[0] =~# '.*powershell.exe$' 54 let str1 = "'cmd \"arg1\" ''arg2'' !%#'" 55 let str2 = "'cmd \"arg1\" ''arg2'' \\!\\%\\#'" 56 else 57 let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%#'" 58 let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\#'" 59 endif 60 call assert_equal(str1, shellescape("cmd \"arg1\" 'arg2' !%#"), e[0]) 61 call assert_equal(str2, shellescape("cmd \"arg1\" 'arg2' !%#", 1), e[0]) 62 63 " Try running an external command with the shell. 64 if executable(e[0]) 65 " set the shell options for the current 'shell' 66 let [&shellcmdflag, &shellpipe, &shellquote, &shellredir, 67 \ &shellxescape, &shellxquote] = e[1:6] 68 new 69 r !echo hello 70 call assert_equal('hello', substitute(getline(2), '\W', '', 'g'), e[0]) 71 bwipe! 72 endif 73 endfor 74 set shell& shellcmdflag& shellpipe& shellquote& 75 set shellredir& shellxescape& shellxquote& 76 call delete('Xtestout') 77 endfunc 78 79 " Test for the 'shell' option 80 func Test_shell() 81 throw 'Skipped: Nvim missing :shell currently' 82 CheckUnix 83 let save_shell = &shell 84 set shell= 85 let caught_e91 = 0 86 try 87 shell 88 catch /E91:/ 89 let caught_e91 = 1 90 endtry 91 call assert_equal(1, caught_e91) 92 let &shell = save_shell 93 endfunc 94 95 " Test for the 'shellquote' option 96 func Test_shellquote() 97 CheckUnix 98 set shellquote=# 99 set verbose=20 100 redir => v 101 silent! !echo Hello 102 redir END 103 set verbose& 104 set shellquote& 105 call assert_match(': "#echo Hello#"', v) 106 endfunc 107 108 " Test for the 'shellescape' option 109 func Test_shellescape() 110 let save_shell = &shell 111 set shell=bash 112 call assert_equal("'text'", shellescape('text')) 113 call assert_equal("'te\"xt'", 'te"xt'->shellescape()) 114 call assert_equal("'te'\\''xt'", shellescape("te'xt")) 115 116 call assert_equal("'te%xt'", shellescape("te%xt")) 117 call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) 118 call assert_equal("'te#xt'", shellescape("te#xt")) 119 call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) 120 call assert_equal("'te!xt'", shellescape("te!xt")) 121 call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) 122 call assert_equal("'te<cword>xt'", shellescape("te<cword>xt")) 123 call assert_equal("'te\\<cword>xt'", shellescape("te<cword>xt", 1)) 124 call assert_equal("'te<cword>%xt'", shellescape("te<cword>%xt")) 125 call assert_equal("'te\\<cword>\\%xt'", shellescape("te<cword>%xt", 1)) 126 127 call assert_equal("'te\nxt'", shellescape("te\nxt")) 128 call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1)) 129 set shell=tcsh 130 call assert_equal("'te\\!xt'", shellescape("te!xt")) 131 call assert_equal("'te\\\\!xt'", shellescape("te!xt", 1)) 132 call assert_equal("'te\\\nxt'", shellescape("te\nxt")) 133 call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1)) 134 135 set shell=fish 136 call assert_equal("'text'", shellescape('text')) 137 call assert_equal("'te\"xt'", shellescape('te"xt')) 138 call assert_equal("'te'\\''xt'", shellescape("te'xt")) 139 140 call assert_equal("'te%xt'", shellescape("te%xt")) 141 call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) 142 call assert_equal("'te#xt'", shellescape("te#xt")) 143 call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) 144 call assert_equal("'te!xt'", shellescape("te!xt")) 145 call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) 146 147 call assert_equal("'te\\\\xt'", shellescape("te\\xt")) 148 call assert_equal("'te\\\\xt'", shellescape("te\\xt", 1)) 149 call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt")) 150 call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt", 1)) 151 call assert_equal("'te\\\\!xt'", shellescape("te\\!xt")) 152 call assert_equal("'te\\\\\\!xt'", shellescape("te\\!xt", 1)) 153 call assert_equal("'te\\\\%xt'", shellescape("te\\%xt")) 154 call assert_equal("'te\\\\\\%xt'", shellescape("te\\%xt", 1)) 155 call assert_equal("'te\\\\#xt'", shellescape("te\\#xt")) 156 call assert_equal("'te\\\\\\#xt'", shellescape("te\\#xt", 1)) 157 158 let &shell = save_shell 159 endfunc 160 161 " Test for 'shellslash' 162 func Test_shellslash() 163 CheckOption shellslash 164 let save_shellslash = &shellslash 165 " The shell and cmdflag, and expected slash in tempname with shellslash set or 166 " unset. The assert checks the file separator before the leafname. 167 " ".*\\\\[^\\\\]*$" 168 let shells = [['cmd', '/c', '/', '/'], 169 \ ['powershell', '-Command', '/', '/'], 170 \ ['sh', '-c', '/', '/']] 171 for e in shells 172 exe 'set shell=' .. e[0] .. ' | set shellcmdflag=' .. e[1] 173 set noshellslash 174 let file = tempname() 175 call assert_match('^.\+' .. e[2] .. '[^' .. e[2] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' nossl') 176 set shellslash 177 let file = tempname() 178 call assert_match('^.\+' .. e[3] .. '[^' .. e[3] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' ssl') 179 endfor 180 let &shellslash = save_shellslash 181 endfunc 182 183 " Test for 'shellxquote' 184 func Test_shellxquote() 185 CheckUnix 186 187 let save_shell = &shell 188 let save_sxq = &shellxquote 189 let save_sxe = &shellxescape 190 191 call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell', 'D') 192 call setfperm('Xtestshell', "r-x------") 193 set shell=./Xtestshell 194 195 set shellxquote=\\" 196 call feedkeys(":!pwd\<CR>\<CR>", 'xt') 197 call assert_equal(['Cmd: [-c "pwd"]'], readfile('Xlog')) 198 199 set shellxquote=( 200 call feedkeys(":!pwd\<CR>\<CR>", 'xt') 201 call assert_equal(['Cmd: [-c (pwd)]'], readfile('Xlog')) 202 203 set shellxquote=\\"( 204 call feedkeys(":!pwd\<CR>\<CR>", 'xt') 205 call assert_equal(['Cmd: [-c "(pwd)"]'], readfile('Xlog')) 206 207 set shellxescape=\"&<<()@^ 208 set shellxquote=( 209 call feedkeys(":!pwd\"&<<{}@^\<CR>\<CR>", 'xt') 210 call assert_equal(['Cmd: [-c (pwd^"^&^<^<{}^@^^)]'], readfile('Xlog')) 211 212 let &shell = save_shell 213 let &shellxquote = save_sxq 214 let &shellxescape = save_sxe 215 call delete('Xlog') 216 endfunc 217 218 " Test for using the shell set in the $SHELL environment variable 219 func Test_set_shell() 220 let after =<< trim [CODE] 221 call writefile([&shell], "Xtestout") 222 quit! 223 [CODE] 224 225 if has('win32') 226 let $SHELL = 'C:\with space\cmd.exe' 227 let expected = '"C:\with space\cmd.exe"' 228 else 229 let $SHELL = '/bin/with space/sh' 230 let expected = '"/bin/with space/sh"' 231 endif 232 233 if RunVimPiped([], after, '', '') 234 let lines = readfile('Xtestout') 235 call assert_equal(expected, lines[0]) 236 endif 237 call delete('Xtestout') 238 endfunc 239 240 func Test_shell_repeat() 241 CheckUnix 242 243 let save_shell = &shell 244 245 call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell', 'D') 246 call setfperm('Xtestshell', "r-x------") 247 set shell=./Xtestshell 248 defer delete('Xlog') 249 250 call feedkeys(":!echo coconut\<CR>", 'xt') " Run command 251 call assert_equal(['Cmd: [-c echo coconut]'], readfile('Xlog')) 252 253 call feedkeys(":!!\<CR>", 'xt') " Re-run previous 254 call assert_equal(['Cmd: [-c echo coconut]'], readfile('Xlog')) 255 256 call writefile(['empty'], 'Xlog') 257 call feedkeys(":!\<CR>", 'xt') " :! 258 call assert_equal(['Cmd: [-c ]'], readfile('Xlog')) 259 260 call feedkeys(":!!\<CR>", 'xt') " :! doesn't clear previous command 261 call assert_equal(['Cmd: [-c echo coconut]'], readfile('Xlog')) 262 263 call feedkeys(":!echo banana\<CR>", 'xt') " Make sure setting previous command keeps working after a :! no-op 264 call assert_equal(['Cmd: [-c echo banana]'], readfile('Xlog')) 265 call feedkeys(":!!\<CR>", 'xt') 266 call assert_equal(['Cmd: [-c echo banana]'], readfile('Xlog')) 267 268 let &shell = save_shell 269 endfunc 270 271 func Test_shell_no_prevcmd() 272 " this doesn't do anything, just check it doesn't crash 273 let after =<< trim END 274 exe "normal !!\<CR>" 275 call writefile([v:errmsg, 'done'], 'Xtestdone') 276 qall! 277 END 278 if RunVim([], after, '--clean') 279 call assert_equal(['E34: No previous command', 'done'], readfile('Xtestdone')) 280 endif 281 call delete('Xtestdone') 282 endfunc 283 284 func Test_shell_filter_buffer_with_nul_bytes() 285 CheckUnix 286 new 287 set noshelltemp 288 " \n is a NUL byte 289 let lines = ["aaa\nbbb\nccc\nddd\neee", "fff\nggg\nhhh\niii\njjj"] 290 call setline(1, lines) 291 %!cat 292 call assert_equal(lines, getline(1, '$')) 293 294 set shelltemp& 295 bwipe! 296 endfunc 297 298 " vim: shiftwidth=2 sts=2 expandtab