-- testes/lush/builtins.lua -- Tests for shell builtins (issue #15): cd, exec, umask. print "testing shell builtins" local interp = require("lush.testutil").INTERP -- === __builtins is NOT in _G (internal, stored in registry) === do assert(__builtins == nil, "__builtins should not be in _G") 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 (tested via backtick) do local r = `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 = `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 = lush.capture("sh -c '" .. interp .. " -e \"os.exit(42)\"'") assert(r.code == 42, "subprocess exit code: " .. tostring(r.code)) end print "OK"