1" Test for the shell related options ('shell', 'shellcmdflag', 'shellpipe', 2" 'shellquote', 'shellredir', 'shellxescape', and 'shellxquote') 3 4source check.vim 5source shared.vim 6 7func Test_shell_options() 8 " The expected value of 'shellcmdflag', 'shellpipe', 'shellquote', 9 " 'shellredir', 'shellxescape', 'shellxquote' for the supported shells. 10 let shells = [] 11 if has('unix') 12 let shells += [['sh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 13 \ ['ksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 14 \ ['mksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 15 \ ['zsh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 16 \ ['zsh-beta', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 17 \ ['bash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 18 \ ['fish', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 19 \ ['ash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 20 \ ['dash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], 21 \ ['csh', '-c', '|& tee', '', '>&', '', ''], 22 \ ['tcsh', '-c', '|& tee', '', '>&', '', ''], 23 \ ['pwsh', '-c', '>%s 2>&1', '', '>%s 2>&1', '', '']] 24 endif 25 if has('win32') 26 let shells += [['cmd', '/c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', ''], 27 \ ['cmd.exe', '/c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '('], 28 \ ['powershell.exe', '-Command', '2>&1 | Out-File -Encoding default', 29 \ '', '2>&1 | Out-File -Encoding default', '"&|<>()@^', '"'], 30 \ ['powershell', '-Command', '2>&1 | Out-File -Encoding default', '', 31 \ '2>&1 | Out-File -Encoding default', '"&|<>()@^', '"'], 32 \ ['pwsh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], 33 \ ['pwsh', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], 34 \ ['sh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], 35 \ ['ksh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], 36 \ ['mksh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], 37 \ ['pdksh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], 38 \ ['zsh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], 39 \ ['zsh-beta.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], 40 \ ['bash.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], 41 \ ['dash.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], 42 \ ['csh.exe', '-c', '>&', '', '>&', '"&|<>()@^', '"'], 43 \ ['tcsh.exe', '-c', '>&', '', '>&', '"&|<>()@^', '"']] 44 endif 45 46 " start a new Vim instance with 'shell' set to each of the supported shells 47 " and check the default shell option settings 48 let after =<< trim END 49 let l = [&shell, &shellcmdflag, &shellpipe, &shellquote] 50 let l += [&shellredir, &shellxescape, &shellxquote] 51 call writefile([json_encode(l)], 'Xtestout') 52 qall! 53 END 54 for e in shells 55 if RunVim([], after, '--cmd "set shell=' .. e[0] .. '"') 56 call assert_equal(e, json_decode(readfile('Xtestout')[0])) 57 endif 58 endfor 59 60 " Test shellescape() for each of the shells. 61 for e in shells 62 exe 'set shell=' .. e[0] 63 if e[0] =~# '.*csh$' || e[0] =~# '.*csh.exe$' 64 let str1 = "'cmd \"arg1\" '\\''arg2'\\'' \\!%# \\'" 65 let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\\\!\\%\\# \\'" 66 elseif e[0] =~# '.*powershell$' || e[0] =~# '.*powershell.exe$' 67 \ || e[0] =~# '.*pwsh$' || e[0] =~# '.*pwsh.exe$' 68 let str1 = "'cmd \"arg1\" ''arg2'' !%# \\'" 69 let str2 = "'cmd \"arg1\" ''arg2'' \\!\\%\\# \\'" 70 elseif e[0] =~# '.*fish$' || e[0] =~# '.*fish.exe$' 71 let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%# \\\\'" 72 let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\# \\\\'" 73 else 74 let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%# \\'" 75 let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\# \\'" 76 endif 77 call assert_equal(str1, shellescape("cmd \"arg1\" 'arg2' !%# \\"), e[0]) 78 call assert_equal(str2, shellescape("cmd \"arg1\" 'arg2' !%# \\", 1), e[0]) 79 80 " Try running an external command with the shell. 81 if executable(e[0]) 82 " set the shell options for the current 'shell' 83 let [&shellcmdflag, &shellpipe, &shellquote, &shellredir, 84 \ &shellxescape, &shellxquote] = e[1:6] 85 new 86 try 87 r !echo hello 88 call assert_equal('hello', substitute(getline(2), '\W', '', 'g'), e[0]) 89 catch 90 call assert_report('Failed to run shell command, shell: ' .. e[0] 91 \ .. ', caught ' .. v:exception) 92 finally 93 bwipe! 94 endtry 95 endif 96 endfor 97 set shell& shellcmdflag& shellpipe& shellquote& 98 set shellredir& shellxescape& shellxquote& 99 call delete('Xtestout') 100endfunc 101 102" Test for the 'shell' option 103func Test_shell() 104 CheckUnix 105 let save_shell = &shell 106 set shell= 107 let caught_e91 = 0 108 try 109 shell 110 catch /E91:/ 111 let caught_e91 = 1 112 endtry 113 call assert_equal(1, caught_e91) 114 let &shell = save_shell 115endfunc 116 117" Test for the 'shellquote' option 118func Test_shellquote() 119 CheckUnix 120 set shellquote=# 121 set verbose=20 122 redir => v 123 silent! !echo Hello 124 redir END 125 set verbose& 126 set shellquote& 127 call assert_match(': "#echo Hello#"', v) 128endfunc 129 130" Test for the 'shellescape' option 131func Test_shellescape() 132 let save_shell = &shell 133 set shell=bash 134 call assert_equal("'text'", shellescape('text')) 135 call assert_equal("'te\"xt'", 'te"xt'->shellescape()) 136 call assert_equal("'te'\\''xt'", shellescape("te'xt")) 137 138 call assert_equal("'te%xt'", shellescape("te%xt")) 139 call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) 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 145 call assert_equal("'te\nxt'", shellescape("te\nxt")) 146 call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1)) 147 set shell=tcsh 148 call assert_equal("'te\\!xt'", shellescape("te!xt")) 149 call assert_equal("'te\\\\!xt'", shellescape("te!xt", 1)) 150 call assert_equal("'te\\\nxt'", shellescape("te\nxt")) 151 call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1)) 152 153 let &shell = save_shell 154endfunc 155 156" Test for 'shellslash' 157func Test_shellslash() 158 CheckOption shellslash 159 let save_shellslash = &shellslash 160 " The shell and cmdflag, and expected slash in tempname with shellslash set or 161 " unset. The assert checks the file separator before the leafname. 162 " ".*\\\\[^\\\\]*$" 163 let shells = [['cmd', '/c', '\\', '/'], 164 \ ['powershell', '-Command', '\\', '/'], 165 \ ['pwsh', '-Command', '\\', '/'], 166 \ ['pwsh', '-c', '\\', '/'], 167 \ ['sh', '-c', '/', '/']] 168 for e in shells 169 exe 'set shell=' .. e[0] .. ' | set shellcmdflag=' .. e[1] 170 set noshellslash 171 let file = tempname() 172 call assert_match('^.\+' .. e[2] .. '[^' .. e[2] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' nossl') 173 set shellslash 174 let file = tempname() 175 call assert_match('^.\+' .. e[3] .. '[^' .. e[3] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' ssl') 176 endfor 177 let &shellslash = save_shellslash 178endfunc 179 180" Test for 'shellxquote' 181func Test_shellxquote() 182 CheckUnix 183 184 let save_shell = &shell 185 let save_sxq = &shellxquote 186 let save_sxe = &shellxescape 187 188 call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell') 189 call setfperm('Xtestshell', "r-x------") 190 set shell=./Xtestshell 191 192 set shellxquote=\\" 193 call feedkeys(":!pwd\<CR>\<CR>", 'xt') 194 call assert_equal(['Cmd: [-c "pwd"]'], readfile('Xlog')) 195 196 set shellxquote=( 197 call feedkeys(":!pwd\<CR>\<CR>", 'xt') 198 call assert_equal(['Cmd: [-c (pwd)]'], readfile('Xlog')) 199 200 set shellxquote=\\"( 201 call feedkeys(":!pwd\<CR>\<CR>", 'xt') 202 call assert_equal(['Cmd: [-c "(pwd)"]'], readfile('Xlog')) 203 204 set shellxescape=\"&<<()@^ 205 set shellxquote=( 206 call feedkeys(":!pwd\"&<<{}@^\<CR>\<CR>", 'xt') 207 call assert_equal(['Cmd: [-c (pwd^"^&^<^<{}^@^^)]'], readfile('Xlog')) 208 209 let &shell = save_shell 210 let &shellxquote = save_sxq 211 let &shellxescape = save_sxe 212 call delete('Xtestshell') 213 call delete('Xlog') 214endfunc 215 216" Test for using the shell set in the $SHELL environment variable 217func Test_set_shell() 218 let after =<< trim [CODE] 219 call writefile([&shell], "Xtestout") 220 quit! 221 [CODE] 222 223 if has('win32') 224 let $SHELL = 'C:\with space\cmd.exe' 225 let expected = '"C:\with space\cmd.exe"' 226 else 227 let $SHELL = '/bin/with space/sh' 228 let expected = '/bin/with\ space/sh' 229 endif 230 231 if RunVimPiped([], after, '', '') 232 let lines = readfile('Xtestout') 233 call assert_equal(expected, lines[0]) 234 endif 235 call delete('Xtestout') 236endfunc 237 238" vim: shiftwidth=2 sts=2 expandtab 239