Files
lush/testes/lush/builtins.lua
Cormac Shannon 4cc352cbec Implement shell builtins: cd, exec, umask (issue #15)
Add builtin dispatch in lcmd.c that checks __builtins table before
fork(), so cd/exec/umask operate on the shell process itself.
2026-03-04 19:20:42 +00:00

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"