system_spec.lua (5258B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 4 local clear = n.clear 5 local exec_lua = n.exec_lua 6 local eq = t.eq 7 8 local function system_sync(cmd, opts) 9 return exec_lua(function() 10 local obj = vim.system(cmd, opts) 11 12 if opts and opts.timeout then 13 -- Minor delay before calling wait() so the timeout uv timer can have a headstart over the 14 -- internal call to vim.wait() in wait(). 15 vim.wait(10) 16 end 17 18 local res = obj:wait() 19 20 -- Check the process is no longer running 21 assert(not vim.api.nvim_get_proc(obj.pid), 'process still exists') 22 23 return res 24 end) 25 end 26 27 local function system_async(cmd, opts) 28 return exec_lua(function() 29 local done = false 30 local res --- @type vim.SystemCompleted? 31 local obj = vim.system(cmd, opts, function(obj) 32 done = true 33 res = obj 34 end) 35 36 local ok = vim.wait(10000, function() 37 return done 38 end) 39 40 assert(ok, 'process did not exit') 41 42 -- Check the process is no longer running 43 assert(not vim.api.nvim_get_proc(obj.pid), 'process still exists') 44 45 return res 46 end) 47 end 48 49 describe('vim.system', function() 50 before_each(function() 51 clear() 52 end) 53 54 for name, system in pairs { sync = system_sync, async = system_async } do 55 describe('(' .. name .. ')', function() 56 it('failure modes', function() 57 t.matches( 58 "ENOENT%: no such file .* %(cmd%): 'non%-existent%-cmd'", 59 t.pcall_err(system, { 'non-existent-cmd', 'arg1', 'arg2' }, { text = true }) 60 ) 61 62 t.matches( 63 "ENOENT%: no such file .* %(cwd%): 'non%-existent%-cwd'", 64 t.pcall_err(system, { 'echo', 'hello' }, { cwd = 'non-existent-cwd', text = true }) 65 ) 66 end) 67 68 it('can run simple commands', function() 69 eq('hello\n', system({ 'echo', 'hello' }, { text = true }).stdout) 70 end) 71 72 it('handle input', function() 73 eq('hellocat', system({ 'cat' }, { stdin = 'hellocat', text = true }).stdout) 74 end) 75 76 it('can set environment', function() 77 local function test_env(opt) 78 eq('TESTVAL', system({ n.testprg('printenv-test'), 'TEST' }, opt).stdout) 79 end 80 81 test_env({ env = { TEST = 'TESTVAL' }, text = true }) 82 test_env({ clear_env = true, env = { TEST = 'TESTVAL' }, text = true }) 83 end) 84 85 it('can set environment with clear_env = true and env = nil', function() 86 exec_lua(function() 87 vim.env.TEST = 'TESTVAL' 88 end) 89 90 -- Not passing env with clear_env should not clear the environment 91 eq( 92 'TESTVAL', 93 system({ n.testprg('printenv-test'), 'TEST' }, { clear_env = true, text = true }).stdout 94 ) 95 96 -- Passing env = {} with clear_env should clear the environment 97 eq( 98 '', 99 system( 100 { n.testprg('printenv-test'), 'TEST' }, 101 { env = {}, clear_env = true, text = true } 102 ).stdout 103 ) 104 end) 105 106 it('supports timeout', function() 107 eq({ 108 code = 124, 109 signal = 15, 110 stdout = '', 111 stderr = '', 112 }, system({ 'sleep', '10' }, { timeout = 1000 })) 113 end) 114 end) 115 end 116 117 it('kill processes', function() 118 exec_lua(function() 119 local signal --- @type integer? 120 local cmd = vim.system({ 'cat', '-' }, { stdin = true }, function(r) 121 signal = r.signal 122 end) -- run forever 123 124 cmd:kill('sigint') 125 126 -- wait for the process not to exist 127 local done = vim.wait(2000, function() 128 return signal ~= nil 129 end) 130 131 assert(done, 'process did not exit') 132 133 -- Check the process is no longer running 134 local proc = vim.api.nvim_get_proc(cmd.pid) 135 assert(not proc, 'process still exists') 136 137 assert(signal == 2) 138 end) 139 end) 140 141 it('SystemObj:wait() does not process non-fast events #27292', function() 142 eq( 143 false, 144 exec_lua(function() 145 _G.processed = false 146 local cmd = vim.system({ 'sleep', '1' }) 147 vim.schedule(function() 148 _G.processed = true 149 end) 150 cmd:wait() 151 return _G.processed 152 end) 153 ) 154 eq(true, exec_lua([[return _G.processed]])) 155 end) 156 157 if t.is_os('win') then 158 it('can resolve windows command extensions', function() 159 t.write_file('test.bat', 'echo hello world') 160 system_sync({ 'chmod', '+x', 'test.bat' }) 161 system_sync({ './test' }) 162 end) 163 end 164 165 it('always captures all content of stdout/stderr #30846', function() 166 t.skip(n.fn.executable('git') == 0, 'missing "git" command') 167 t.skip(n.fn.isdirectory('.git') == 0, 'missing ".git" directory') 168 eq( 169 0, 170 exec_lua(function() 171 local done = 0 172 local fail = 0 173 for _ = 1, 200 do 174 vim.system( 175 { 'git', 'show', ':0:test/functional/plugin/lsp_spec.lua' }, 176 { text = true }, 177 function(o) 178 if o.code ~= 0 or #o.stdout == 0 then 179 fail = fail + 1 180 end 181 done = done + 1 182 end 183 ) 184 end 185 186 local ok = vim.wait(10000, function() 187 return done == 200 188 end, 200) 189 return fail + (ok and 0 or 1) 190 end) 191 ) 192 end) 193 end)