cmd_spec.lua
local sh = require 'lsh'
local helper = require 'helper'
describe('cmd', function()
local dir
before_each(function() dir = helper.tmpdir() end)
after_each(function() helper.rmtree(dir) end)
it('clones', function()
local cmd = sh.cmd('echo', 1):workdir(dir):stdout('/dev/null')
assert.are.equal(tostring(cmd), tostring(cmd:clone()))
end)
it('builds arguments', function()
local cmd = sh.cmd('echo')
cmd:args({'1', sh.path('/tmp')})
assert.are.equal('echo 1 /tmp', tostring(cmd))
cmd:arg('bla')
assert.are.equal('echo 1 /tmp bla', tostring(cmd))
end)
it('runs a command', function()
assert.is_true(sh.cmd('true'):run():success())
assert.is_false(sh.cmd('false'):run():success())
assert.are.equal(3, sh.cmd('sh', '-c', 'exit 3'):run():code())
end)
it('reports a signal as failure', function()
local status = sh.cmd('sh', '-c', 'kill -9 $$'):run()
assert.is_false(status:success())
assert.are.equal(9, status:code())
end)
it('does not block in try_wait', function()
local child = sh.cmd('sleep', 1):spawn()
assert.is_false(child:try_wait())
assert(child:kill())
assert.is_false(child:wait():success())
end)
it('returns the same status on each wait', function()
local child = sh.cmd('true'):spawn()
local status
repeat status = child:try_wait() until status
assert.is_true(status:success())
assert.are.equal(status, child:wait())
assert.are.equal(0, child:wait():code())
end)
it('exits the child with 127 when exec fails', function()
local out = sh.cmd('lsh-no-such-program'):output()
assert.are.equal(127, out.status:code())
assert.are.equal('lsh-no-such-program: exec: No such file or directory', tostring(out.stderr))
assert.are.equal('', tostring(out.stdout))
end)
it('exits the child with 127 when the workdir is missing', function()
local status = sh.cmd('true'):workdir(dir / 'none'):run()
assert.are.equal(127, status:code())
end)
it('does not flush parent stdio buffers from a failed child', function()
local script = [[
local sh = require 'lsh'
io.stdout:setvbuf('full')
io.stdout:write('mark\n')
sh.cmd('cat'):stdin('/lsh-no-such-file'):stderr('/dev/null'):run()
sh.cmd('lsh-no-such-program'):stderr('/dev/null'):run()
]]
local out = sh.cmd('luajit', '-e', script):env({LUA_PATH = package.path}):output()
assert.are.equal('mark', tostring(out.stdout))
end)
it('sets environment variables', function()
local out = sh.cmd('printenv', 'MYENV'):env({MYENV = 'test'}):output()
assert.are.equal('test', tostring(out.stdout))
end)
it('removes environment variables', function()
local out = sh.cmd('printenv', 'MYENV'):env({MYENV = 'test'})
:env_remove('MYENV')
:output()
assert.is_false(out.status:success())
end)
it('runs in the working directory', function()
local out = sh.cmd('pwd'):workdir(dir):output()
assert.are.equal(tostring(dir), tostring(out.stdout))
end)
it('passes 100k arguments', function()
local cmd = sh.cmd('echo'):stdout('/dev/null')
for i=1,100000 do cmd:arg(("arg%d"):format(i)) end
assert.is_true(cmd:run():success())
end)
it('redirects stdout and stdin to files', function()
local file = dir / 'out'
assert.is_true(sh.cmd('echo', 'hello'):stdout(file):run():success())
assert.are.equal('hello', helper.read(file))
local out = sh.cmd('cat'):stdin(file):output()
assert.are.equal('hello', tostring(out.stdout))
end)
it('captures stdout and stderr', function()
local out = sh.cmd('sh', '-c', 'echo out; echo err >&2'):output()
assert.are.equal('out', tostring(out.stdout))
assert.are.equal('err', tostring(out.stderr))
end)
it('rejects a non-cmd table in child.new', function()
local child = require 'lsh.cmd.child'
assert.has_error(function() child.new(sh.pipeline()) end)
end)
describe('argument errors', function()
it('reports the type of args', function()
local ok, err = pcall(function() sh.cmd('ls'):args(1) end)
assert.is_false(ok)
assert.matches("^spec/cmd_spec.lua:%d+: bad argument #2 to 'args' %(table expected, got number%)", err)
end)
it('points to the caller for an invalid args entry', function()
local ok, err = pcall(function() sh.cmd('ls'):args({{}}) end)
assert.is_false(ok)
assert.matches('^spec/cmd_spec.lua:%d+: bad argument #2 at index #1', err)
end)
end)
end)