Add builtin dispatch in lcmd.c that checks __builtins table before fork(), so cd/exec/umask operate on the shell process itself.
161 lines
3.9 KiB
Lua
161 lines
3.9 KiB
Lua
-- testes/lush/builtins.lua
|
|
-- Tests for shell builtins (issue #15): cd, exec, umask.
|
|
|
|
print "testing shell builtins"
|
|
|
|
-- === __builtins table ===
|
|
|
|
do
|
|
assert(type(__builtins) == "table")
|
|
assert(type(__builtins.cd) == "function")
|
|
assert(type(__builtins.exec) == "function")
|
|
assert(type(__builtins.umask) == "function")
|
|
end
|
|
|
|
|
|
-- === cd ===
|
|
|
|
-- cd to absolute path
|
|
do
|
|
local before = `pwd`.stdout:gsub("\n$", "")
|
|
local r = `cd /tmp`
|
|
assert(r.code == 0, "cd /tmp failed: " .. r.stderr)
|
|
local after = `pwd`.stdout:gsub("\n$", "")
|
|
assert(after == "/private/tmp" or after == "/tmp",
|
|
"expected /tmp, got: " .. after)
|
|
`cd ${before}`
|
|
end
|
|
|
|
-- cd with no arg goes to $HOME
|
|
do
|
|
local before = `pwd`.stdout:gsub("\n$", "")
|
|
local home = os.getenv("HOME")
|
|
local r = `cd`
|
|
assert(r.code == 0, "cd (no arg) failed: " .. r.stderr)
|
|
local after = `pwd`.stdout:gsub("\n$", "")
|
|
assert(after == home, "expected HOME=" .. home .. ", got: " .. after)
|
|
`cd ${before}`
|
|
end
|
|
|
|
-- cd - goes to OLDPWD
|
|
do
|
|
local start = `pwd`.stdout:gsub("\n$", "")
|
|
`cd /tmp`
|
|
local r = `cd -`
|
|
assert(r.code == 0, "cd - failed: " .. r.stderr)
|
|
local after = `pwd`.stdout:gsub("\n$", "")
|
|
assert(after == start, "expected " .. start .. ", got: " .. after)
|
|
`cd ${start}`
|
|
end
|
|
|
|
-- cd updates $PWD and $OLDPWD
|
|
do
|
|
local before = `pwd`.stdout:gsub("\n$", "")
|
|
`cd /tmp`
|
|
local pwd = os.getenv("PWD")
|
|
local oldpwd = os.getenv("OLDPWD")
|
|
assert(pwd == "/private/tmp" or pwd == "/tmp",
|
|
"PWD not updated: " .. tostring(pwd))
|
|
assert(oldpwd == before,
|
|
"OLDPWD not updated: expected " .. before .. ", got: " .. tostring(oldpwd))
|
|
`cd ${before}`
|
|
end
|
|
|
|
-- cd to nonexistent directory returns error
|
|
do
|
|
local r = `cd /nonexistent_dir_xyz_999`
|
|
assert(r.code == 1)
|
|
assert(r.stderr:find("cd:"), "expected cd error, got: " .. r.stderr)
|
|
end
|
|
|
|
-- cd to relative path
|
|
do
|
|
local before = `pwd`.stdout:gsub("\n$", "")
|
|
`cd /tmp`
|
|
os.execute("mkdir -p /tmp/_lush_test_cd")
|
|
local r = `cd _lush_test_cd`
|
|
assert(r.code == 0, "cd relative failed: " .. r.stderr)
|
|
local after = `pwd`.stdout:gsub("\n$", "")
|
|
assert(after:find("_lush_test_cd"),
|
|
"expected to be in _lush_test_cd, got: " .. after)
|
|
`cd ${before}`
|
|
os.execute("rmdir /tmp/_lush_test_cd")
|
|
end
|
|
|
|
|
|
-- === umask ===
|
|
|
|
-- query umask (no arg)
|
|
do
|
|
local r = `umask`
|
|
assert(r.code == 0, "umask query failed: " .. r.stderr)
|
|
assert(r.stdout:match("^%d+"), "expected octal, got: " .. r.stdout)
|
|
end
|
|
|
|
-- set and restore umask
|
|
do
|
|
local orig = `umask`.stdout:gsub("%s+$", "")
|
|
local r = `umask 0077`
|
|
assert(r.code == 0, "umask set failed: " .. r.stderr)
|
|
local now = `umask`.stdout:gsub("%s+$", "")
|
|
assert(now == "0077", "expected 0077, got: " .. now)
|
|
-- restore original
|
|
`umask ${orig}`
|
|
local restored = `umask`.stdout:gsub("%s+$", "")
|
|
assert(restored == orig,
|
|
"expected " .. orig .. ", got: " .. restored)
|
|
end
|
|
|
|
-- invalid octal
|
|
do
|
|
local r = `umask banana`
|
|
assert(r.code == 1)
|
|
assert(r.stderr:find("invalid mode"),
|
|
"expected 'invalid mode', got: " .. r.stderr)
|
|
end
|
|
|
|
|
|
-- === exec ===
|
|
|
|
-- exec with no command returns error
|
|
do
|
|
local r = __builtins.exec("exec")
|
|
assert(r.code == 1)
|
|
assert(r.stderr:find("command required"),
|
|
"expected 'command required', got: " .. r.stderr)
|
|
end
|
|
|
|
-- exec nonexistent command returns error
|
|
do
|
|
local r = __builtins.exec("exec", "nonexistent_cmd_xyz_999")
|
|
assert(r.code == 1)
|
|
assert(r.stderr:find("exec:"),
|
|
"expected exec error, got: " .. r.stderr)
|
|
end
|
|
|
|
-- exec replaces process (test in subprocess)
|
|
do
|
|
local r = `sh -c './lua -e "os.exit(42)"'`
|
|
assert(r.code == 42, "subprocess exit code: " .. tostring(r.code))
|
|
end
|
|
|
|
|
|
-- === builtins are overridable ===
|
|
|
|
do
|
|
local old_cd = __builtins.cd
|
|
local called = false
|
|
__builtins.cd = function(...)
|
|
called = true
|
|
return old_cd(...)
|
|
end
|
|
local before = `pwd`.stdout:gsub("\n$", "")
|
|
`cd /tmp`
|
|
assert(called, "custom cd was not called")
|
|
__builtins.cd = old_cd
|
|
`cd ${before}`
|
|
end
|
|
|
|
|
|
print "OK"
|