local helpers = require('test.functional.helpers')(after_each) local nvim_dir = helpers.nvim_dir local eq, call, clear, eval, feed_command, feed, nvim = helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.feed_command, helpers.feed, helpers.nvim local command = helpers.command local exc_exec = helpers.exc_exec local iswin = helpers.iswin local Screen = require('test.functional.ui.screen') local function create_file_with_nuls(name) return function() feed('ipart1000part2000part3:w '..name..'') eval('1') -- wait for the file to be created end end local function delete_file(name) return function() eval("delete('"..name.."')") end end -- Some tests require the xclip program and a x server. local xclip = nil do if os.getenv('DISPLAY') then xclip = (os.execute('command -v xclip > /dev/null 2>&1') == 0) end end describe('system()', function() before_each(clear) describe('command passed as a List', function() local function printargs_path() return nvim_dir..'/printargs-test' .. (iswin() and '.exe' or '') end it('sets v:shell_error if cmd[0] is not executable', function() call('system', { 'this-should-not-exist' }) eq(-1, eval('v:shell_error')) end) it('parameter validation does NOT modify v:shell_error', function() -- 1. Call system() with invalid parameters. -- 2. Assert that v:shell_error was NOT set. feed_command('call system({})') eq('E475: Invalid argument: expected String or List', eval('v:errmsg')) eq(0, eval('v:shell_error')) feed_command('call system([])') eq('E474: Invalid argument', eval('v:errmsg')) eq(0, eval('v:shell_error')) -- Provoke a non-zero v:shell_error. call('system', { 'this-should-not-exist' }) local old_val = eval('v:shell_error') eq(-1, old_val) -- 1. Call system() with invalid parameters. -- 2. Assert that v:shell_error was NOT modified. feed_command('call system({})') eq(old_val, eval('v:shell_error')) feed_command('call system([])') eq(old_val, eval('v:shell_error')) end) it('quotes arguments correctly #5280', function() local out = call('system', { printargs_path(), [[1]], [[2 "3]], [[4 ' 5]], [[6 ' 7']] }) eq(0, eval('v:shell_error')) eq([[arg1=1;arg2=2 "3;arg3=4 ' 5;arg4=6 ' 7';]], out) out = call('system', { printargs_path(), [['1]], [[2 "3]] }) eq(0, eval('v:shell_error')) eq([[arg1='1;arg2=2 "3;]], out) out = call('system', { printargs_path(), "A\nB" }) eq(0, eval('v:shell_error')) eq("arg1=A\nB;", out) end) it('calls executable in $PATH', function() if 0 == eval("executable('python')") then pending("missing `python`") end eq("foo\n", eval([[system(['python', '-c', 'print("foo")'])]])) eq(0, eval('v:shell_error')) end) it('does NOT run in shell', function() if iswin() then eq("%PATH%\n", eval("system(['powershell', '-NoProfile', '-NoLogo', '-ExecutionPolicy', 'RemoteSigned', '-Command', 'echo', '%PATH%'])")) else eq("* $PATH %PATH%\n", eval("system(['echo', '*', '$PATH', '%PATH%'])")) end end) end) it('sets v:shell_error', function() if iswin() then eval([[system("cmd.exe /c exit")]]) eq(0, eval('v:shell_error')) eval([[system("cmd.exe /c exit 1")]]) eq(1, eval('v:shell_error')) eval([[system("cmd.exe /c exit 5")]]) eq(5, eval('v:shell_error')) eval([[system('this-should-not-exist')]]) eq(1, eval('v:shell_error')) else eval([[system("sh -c 'exit'")]]) eq(0, eval('v:shell_error')) eval([[system("sh -c 'exit 1'")]]) eq(1, eval('v:shell_error')) eval([[system("sh -c 'exit 5'")]]) eq(5, eval('v:shell_error')) eval([[system('this-should-not-exist')]]) eq(127, eval('v:shell_error')) end end) describe('executes shell function', function() local screen before_each(function() screen = Screen.new() screen:attach() end) after_each(function() screen:detach() end) if iswin() then local function test_more() eq('root = true', eval([[get(split(system('"more" ".editorconfig"'), "\n"), 0, '')]])) end local function test_shell_unquoting() eval([[system('"ping" "-n" "1" "127.0.0.1"')]]) eq(0, eval('v:shell_error')) eq('"a b"\n', eval([[system('cmd /s/c "cmd /s/c "cmd /s/c "echo "a b""""')]])) eq('"a b"\n', eval([[system('powershell -NoProfile -NoLogo -ExecutionPolicy RemoteSigned -Command echo ''\^"a b\^"''')]])) end it('with shell=cmd.exe', function() command('set shell=cmd.exe') eq('""\n', eval([[system('echo ""')]])) eq('"a b"\n', eval([[system('echo "a b"')]])) eq('a \nb\n', eval([[system('echo a & echo b')]])) eq('a \n', eval([[system('echo a 2>&1')]])) test_more() eval([[system('cd "C:\Program Files"')]]) eq(0, eval('v:shell_error')) test_shell_unquoting() end) it('with shell=cmd', function() command('set shell=cmd') eq('"a b"\n', eval([[system('echo "a b"')]])) test_more() test_shell_unquoting() end) it('with shell=$COMSPEC', function() local comspecshell = eval("fnamemodify($COMSPEC, ':t')") if comspecshell == 'cmd.exe' then command('set shell=$COMSPEC') eq('"a b"\n', eval([[system('echo "a b"')]])) test_more() test_shell_unquoting() else pending('$COMSPEC is not cmd.exe: ' .. comspecshell) end end) it('works with powershell', function() helpers.set_shell_powershell() eq('a\nb\n', eval([[system('echo a b')]])) eq('C:\\\n', eval([[system('cd c:\; (Get-Location).Path')]])) eq('a b\n', eval([[system('echo "a b"')]])) end) end it('`echo` and waits for its return', function() feed(':call system("echo")') screen:expect([[ ^ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | :call system("echo") | ]]) end) it('prints verbose information', function() screen:try_resize(72, 14) feed(':4verbose echo system("echo hi")') if iswin() then screen:expect{any=[[Executing command: "'cmd.exe' '/s' '/c' '"echo hi"'"]]} else screen:expect{any=[[Executing command: "'/[^']*sh' '%-c' 'echo hi'"]]} end feed('') end) it('self and total time recorded separately', function() local tempfile = helpers.tmpname() feed(':function! AlmostNoSelfTime()') feed('echo system("echo hi")') feed('endfunction') feed(':profile start ' .. tempfile .. '') feed(':profile func AlmostNoSelfTime') feed(':call AlmostNoSelfTime()') feed(':profile dump') feed(':edit ' .. tempfile .. '') local command_total_time = tonumber(helpers.funcs.split(helpers.funcs.getline(7))[2]) local command_self_time = tonumber(helpers.funcs.split(helpers.funcs.getline(7))[3]) helpers.neq(nil, command_total_time) helpers.neq(nil, command_self_time) end) it('`yes` interrupted with CTRL-C', function() feed(':call system("' .. (iswin() and 'for /L %I in (1,0,2) do @echo y' or 'yes') .. '")') screen:expect([[ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ]] .. (iswin() and [[ :call system("for /L %I in (1,0,2) do @echo y") |]] or [[ :call system("yes") |]])) feed('') screen:expect([[ ^ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | Type :qa! and press ') screen:expect([[ ^ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | :call systemlist("echo") | ]]) end) it('`yes` interrupted with CTRL-C', function() feed(':call systemlist("yes | xargs")') screen:expect([[ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | :call systemlist("yes | xargs") | ]]) feed('') screen:expect([[ ^ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | Type :qa! and press