Lots of content
This commit is contained in:
Executable
+122
@@ -0,0 +1,122 @@
|
||||
-- Isolated tests for real claim commands, persistence, and wrapper protection.
|
||||
local target = assert(arg[1], "init.lua path required")
|
||||
local saved = {claims = {}, homes = {}, access = {}}
|
||||
local writes, commands, particles = {}, {}, {}
|
||||
local players = {}
|
||||
local function copy(value)
|
||||
if type(value) ~= "table" then return value end
|
||||
local result = {}; for k, v in pairs(value) do result[k] = copy(v) end; return result
|
||||
end
|
||||
for _, name in ipairs({"owner", "housemate", "keeper", "outsider", "another-owner"}) do
|
||||
local player = {name = name, pos = {x = 0, y = 10, z = 0}}
|
||||
function player:get_player_name() return self.name end
|
||||
function player:get_pos() return self.pos end
|
||||
players[name] = player
|
||||
end
|
||||
core = {
|
||||
registered_nodes = {},
|
||||
get_modpath = function() return "/hearth" end,
|
||||
get_mod_storage = function() return {} end,
|
||||
get_player_by_name = function(name) return players[name] end,
|
||||
register_chatcommand = function(name, def) commands[name] = def end,
|
||||
is_protected = function() return false end,
|
||||
record_protection_violation = function() end,
|
||||
chat_send_player = function() end,
|
||||
add_particle = function(spec) particles[#particles + 1] = spec end,
|
||||
}
|
||||
vector = {round = function(p) return {x = math.floor(p.x + 0.5), y = math.floor(p.y + 0.5), z = math.floor(p.z + 0.5)} end}
|
||||
local persistence = {
|
||||
load_world = function(kind) return copy(saved[kind]) end,
|
||||
save_world = function(kind, value) saved[kind] = copy(value); writes[#writes + 1] = kind end,
|
||||
}
|
||||
local original_dofile = dofile
|
||||
local loaded, character_marker = {}, {}
|
||||
dofile = function(path)
|
||||
local name = path:match("([^/\\]+%.lua)$")
|
||||
loaded[#loaded + 1] = name
|
||||
if name == "character.lua" then return function(h, api)
|
||||
assert(h == hearth and api == core); return character_marker
|
||||
end end
|
||||
if name == "interface.lua" or name == "players.lua" then
|
||||
assert(hearth.character == character_marker, "Character factory must precede UI and players")
|
||||
end
|
||||
if name == "model.lua" then return {location = function() return true end} end
|
||||
if name == "schema.lua" then return {} end
|
||||
if name == "persistence.lua" then return function() return persistence end end
|
||||
if name == "access.lua" then
|
||||
local source = path:match("[/\\]init%.lua$") and path:gsub("init%.lua$", "access.lua") or "/hearth/access.lua"
|
||||
return original_dofile(source)
|
||||
end
|
||||
if name == "movement.lua" or name == "combat.lua" then return {} end
|
||||
return true -- Remaining bootstrap modules are intentionally inert in this suite.
|
||||
end
|
||||
|
||||
local total = 0
|
||||
local function test(name, fn)
|
||||
local ok, err = pcall(fn)
|
||||
assert(ok, name .. ": " .. tostring(err))
|
||||
total = total + 1
|
||||
print("ok " .. total .. " - " .. name)
|
||||
end
|
||||
local function command(param, name)
|
||||
return commands.claim.func(name or "owner", param or "")
|
||||
end
|
||||
original_dofile(target)
|
||||
|
||||
test("character factory loads once before interface and player initialization", function()
|
||||
local positions = {}
|
||||
for i, name in ipairs(loaded) do
|
||||
assert(not positions[name], "Duplicate module load: " .. name); positions[name] = i
|
||||
end
|
||||
assert(hearth.character == character_marker)
|
||||
assert(positions["character.lua"] < positions["interface.lua"] and positions["character.lua"] < positions["players.lua"])
|
||||
assert(positions["presentation.lua"] < positions["players.lua"])
|
||||
end)
|
||||
test("claim creation, boundaries, and world persistence are owner-scoped", function()
|
||||
local ok = command("")
|
||||
assert(ok and saved.claims.owner.x == 0 and saved.claims.owner.y == 10)
|
||||
assert(hearth.claim_role_at({x = 0, y = 10, z = 0}, "owner") == "owner")
|
||||
assert(hearth.claim_allowed({x = 12, y = 34, z = 12}, "owner", "build"))
|
||||
assert(not hearth.claim_allowed({x = 12, y = 10, z = 0}, "outsider", "build"))
|
||||
local shown, message = command("show")
|
||||
assert(shown and message:find("X %-12%.%.12") and #particles >= 40)
|
||||
local listed = command("list")
|
||||
assert(listed and #writes == 1)
|
||||
end)
|
||||
test("resident and storekeeper roles are least-privilege and immediately persisted", function()
|
||||
assert(command("share housemate resident"))
|
||||
assert(hearth.claim_allowed({x = 0, y = 10, z = 0}, "housemate", "build"))
|
||||
assert(hearth.claim_allowed({x = 0, y = 10, z = 0}, "housemate", "dig"))
|
||||
assert(hearth.claim_allowed({x = 0, y = 10, z = 0}, "housemate", "use"))
|
||||
assert(not hearth.claim_allowed({x = 0, y = 10, z = 0}, "housemate", "combat"))
|
||||
assert(command("share keeper storekeeper"))
|
||||
assert(hearth.claim_allowed({x = 0, y = 10, z = 0}, "keeper", "storage"))
|
||||
for _, action in ipairs({"build", "dig", "use", "combat"}) do
|
||||
assert(not hearth.claim_allowed({x = 0, y = 10, z = 0}, "keeper", action), action)
|
||||
end
|
||||
local ok, members = command("list")
|
||||
assert(ok and members:find("housemate %(resident%)") and members:find("keeper %(storekeeper%)"))
|
||||
end)
|
||||
test("invalid grants, outsider mutations, and revoked permissions fail closed", function()
|
||||
players["another-owner"].pos = {x = 100, y = 10, z = 0}
|
||||
assert(command("", "another-owner"))
|
||||
for _, param in ipairs({"share bad/name resident", "share outsider admin", "share owner resident",
|
||||
"share another-owner resident", "unshare bad/name"}) do
|
||||
assert(not command(param), param)
|
||||
end
|
||||
assert(not command("share outsider resident", "outsider"))
|
||||
assert(command("unshare housemate"))
|
||||
assert(not hearth.claim_allowed({x = 0, y = 10, z = 0}, "housemate", "build"))
|
||||
assert(not command("share " .. string.rep("a", 33) .. " resident"))
|
||||
for i = 1, 15 do assert(command("share crew" .. i .. " resident")) end
|
||||
assert(not command("share overflow resident"))
|
||||
end)
|
||||
test("claim release revokes grants and removes the owner's saved home", function()
|
||||
assert(hearth.in_own_claim({x = 0, y = 10, z = 0}, "owner"))
|
||||
hearth.store_home("owner", {x = 0, y = 10, z = 0})
|
||||
assert(hearth.home_for("owner"))
|
||||
assert(command("remove"))
|
||||
assert(not saved.claims.owner and not saved.access.owner and not hearth.home_for("owner"))
|
||||
assert(hearth.claim_allowed({x = 0, y = 10, z = 0}, "outsider", "build"))
|
||||
end)
|
||||
print("PASS " .. total .. " claim service tests")
|
||||
Reference in New Issue
Block a user