Manual changes following smoke test

This commit is contained in:
Cooldude2606
2026-09-01 01:04:09 +01:00
parent 574a0a4b52
commit 59df8bdff3
18 changed files with 191 additions and 98 deletions
+167
View File
@@ -0,0 +1,167 @@
--- Tests for the assignment methods of module/control.lua
local Suite = ... --- @type Suite The suite this file adds its tests to, see env.lua
local test, check, eq, empty = Suite.test, Suite.check, Suite.eq, Suite.empty
--- alice is a moderator and bob a regular, with changes sent to the controller
local function setup(env)
local players = {
alice = env.add_player("alice"),
bob = env.add_player("bob"),
}
env.initialise{
env.assignment("alice", { "Moderator" }),
env.assignment("bob", { "Regular" }),
}
env.Roles.set_emit_events(true)
env.reset_log()
return players
end
test(".assign() applies locally and is sent to the controller", function(env)
local players = setup(env)
local moderator = env.R("Moderator")
moderator:assign(players.bob, { by_player_name = "alice" })
eq(env.sent, {
{ channel = "exp_roles:assignment_update", data = { name = "bob", assign = { moderator.id } } },
}, "the assignment is sent to the controller")
check(moderator:has_player(players.bob), "the role applies before confirmation")
eq(env.events, {
{
name = env.Roles.events.on_player_roles_changed,
tick = 1,
player_index = players.bob.index,
by_player_index = players.alice.index,
assigned = { moderator.id },
unassigned = {},
},
}, "the event carries the change")
eq(env.printed, {
{ "exp-roles.game-message-assign", "bob", "Moderator", "alice" },
}, "the change is announced")
eq(env.sounds, { "bob:utility/achievement_unlocked" }, "the assign sound plays")
local sd = env.Roles._script_data()
eq(sd.local_players.bob, { moderator.id }, "the role is held locally")
eq(sd.pending.bob, { moderator.id }, "the role is pending")
env.reset_log()
moderator:assign(players.bob)
empty(env.sent, "assigning a held role sends nothing")
empty(env.events, "assigning a held role raises nothing")
end)
test(".assign() defaults the by player to game.player", function(env)
local players = setup(env)
game.player = players.alice
env.R("Jail"):assign(players.bob, { silent = true })
eq(env.events[1].by_player_index, players.alice.index, "the acting player is game.player")
end)
test("receive_assignment_updates() releases the local hold once confirmed", function(env)
local players = setup(env)
env.R("Moderator"):assign(players.bob)
env.reset_log()
env.Roles.receive_assignment_updates{ env.assignment("bob", { "Regular", "Moderator" }) }
empty(env.events, "a confirmation raises no events")
empty(env.printed, "a confirmation announces nothing")
local sd = env.Roles._script_data()
check(sd.local_players.bob == nil and sd.pending.bob == nil, "the role is no longer held locally")
check(env.R("Moderator"):has_player(players.bob), "the role is still held after confirmation")
end)
test(".unassign() removes a synced role", function(env)
local players = setup(env)
local regular = env.R("Regular")
regular:unassign(players.bob, { by_player_name = "alice", silent = true })
eq(env.sent, {
{ channel = "exp_roles:assignment_update", data = { name = "bob", unassign = { regular.id } } },
}, "the unassignment is sent to the controller")
check(not regular:has_player(players.bob), "the role is removed locally")
eq(env.events, {
{
name = env.Roles.events.on_player_roles_changed,
tick = 1,
player_index = players.bob.index,
by_player_index = players.alice.index,
assigned = {},
unassigned = { regular.id },
},
}, "the event carries the change")
empty(env.printed, "silent suppresses the announcement")
eq(env.sounds, { "bob:utility/game_lost" }, "the unassign sound plays")
end)
test("reject_assignment() rolls the assignment back", function(env)
local players = setup(env)
local jail = env.R("Jail")
jail:assign(players.alice)
check(jail:has_player(players.alice), "the role applies before rejection")
env.reset_log()
env.Roles.reject_assignment{ name = "alice", role_ids = { jail.id } }
check(not jail:has_player(players.alice), "the rejected role is rolled back")
empty(env.sent, "the rollback is not sent to the controller")
eq(env.events, {
{
name = env.Roles.events.on_player_roles_changed,
tick = 1,
player_index = players.alice.index,
by_player_index = 0,
assigned = {},
unassigned = { jail.id },
},
}, "the rollback raises the event")
local sd = env.Roles._script_data()
check(sd.local_players.alice == nil and sd.pending.alice == nil, "the rollback clears the local state")
end)
test(".assign() with local_only never reaches the controller", function(env)
local players = setup(env)
local regular = env.R("Regular")
regular:assign(players.alice, { silent = true, local_only = true })
empty(env.sent, "the assignment is not sent")
check(regular:has_player(players.alice), "the role applies")
local sd = env.Roles._script_data()
check(sd.pending.alice == nil, "the role is not pending")
eq(sd.local_players.alice, { regular.id }, "the role is held locally")
env.Roles.receive_assignment_updates{ env.assignment("alice", { "Moderator" }) }
check(regular:has_player(players.alice), "the role survives controller updates")
env.reset_log()
regular:unassign(players.alice, { local_only = true })
check(not regular:has_player(players.alice), "the role is removed")
empty(env.sent, "the removal is not sent")
end)
test(".assign() of a higher priority role suppresses the rest", function(env)
local players = setup(env)
local jail = env.R("Jail")
jail:assign(players.alice, { by_player_name = "<server>", silent = true })
eq(Suite.names(env.Roles.get_player_roles(players.alice)), { "Jail" }, "only the jail role applies")
check(env.R("Moderator"):has_player(players.alice), "a suppressed role is still held")
check(not env.Roles.player_has_permission(players.alice, "exp_scenario.command.kill"), "permissions are lost")
check(not env.Roles.player_has_permission(players.alice, "exp_scenario.gui.readme"), "the default role is lost")
check(not env.Roles.player_outranks(players.alice, players.bob), "a jailed player no longer outranks")
eq(env.events[1].assigned, { jail.id }, "the event lists the jail role")
empty(env.events[1].unassigned, "the suppressed roles are not listed as unassigned")
env.reset_log()
jail:unassign(players.alice, { by_player_name = "<server>", silent = true })
eq(Suite.sorted(Suite.names(env.Roles.get_player_roles(players.alice))), { "Moderator", "Player" },
"unjail restores the roles")
empty(env.events[1].assigned, "the restored roles are not listed as assigned")
eq(env.events[1].unassigned, { jail.id }, "the unjail event lists the jail role")
end)
test(".assign() ignores the server", function(env)
setup(env)
env.R("Moderator"):assign(env.server)
empty(env.sent, "assigning to the server sends nothing")
empty(env.events, "assigning to the server raises nothing")
end)
return Suite.run()
+83
View File
@@ -0,0 +1,83 @@
--[[-- Test environment for module/control.lua
The module specific extension between the shared stubs and the test files: it
extends each environment with a fresh copy of the roles module and the
fixtures below, and hands each test file a suite built around that.
Run as a chunk by test/lua/runner.js, receiving the shared folder. The suite
returned here becomes `...` in each test file.
]]
local shared_root = ... --- @type string
local source = assert(debug.getinfo(1, "S")).source:gsub("\\", "/")
local plugin_root = assert(source:match("^@(.*)/test/module/env%.lua$"))
local Framework = assert(loadfile(shared_root .. "/framework.lua"))() --- @type Framework
--- Standard fixture: permission names sent once and referenced by zero based index
local permission_names = {
"core.admin", -- 0
"exp_scenario.command.kill", -- 1
"exp_scenario.command.jail", -- 2
"exp_scenario.player.admin", -- 3
"exp_scenario.gui.readme", -- 4
"exp_scenario.command.assign_role", -- 5
}
local function meta(order, extra)
local m = { id = 0, order = order }
for k, v in pairs(extra or {}) do m[k] = v end
return m
end
--- Standard fixture: the roles as the controller would send them on initialise
local function role_records()
return {
{ id = 0, name = "Cluster Admin", permissions = { 0 }, meta = meta(1, { short_hand = "SYS" }) },
{ id = 5, name = "Moderator", permissions = { 1, 2, 3, 5 }, meta = meta(2, { color = { r = 0, g = 170, b = 0 } }) },
{ id = 6, name = "Regular", permissions = { 1 }, meta = meta(3) },
{ id = 7, name = "Jail", permissions = {}, meta = meta(4, { priority = 1, block_auto_assign = true }) },
{ id = 1, name = "Player", permissions = { 4 }, meta = meta(5), is_default = true },
{ id = 9, name = "Gone", permissions = {}, meta = meta(6), is_deleted = true },
}
end
--- Fixture role ids by name, avoiding a search of the roles on every lookup
local role_ids = {}
for _, record in ipairs(role_records()) do
role_ids[record.name] = record.id
end
return Framework.suite(function(env)
env.Roles = assert(loadfile(plugin_root .. "/module/control.lua"))() --- @type ExpRoles
env.Roles.on_server_startup()
--- Get a fixture role by name, failing the test when it does not exist
--- Roles added by a test are found by a search instead
function env.R(name)
local role_id = role_ids[name]
if role_id then
return (assert(env.Roles.get_role(role_id), "No role with id " .. role_id))
end
return (assert(env.Roles.get_role_by_name(name), "No role named " .. name))
end
--- An assignment record as the controller would send it, roles by name
function env.assignment(player_name, role_names)
local ids = {}
for index, role_name in ipairs(role_names) do
ids[index] = assert(role_ids[role_name], "No fixture role named " .. role_name)
end
return { name = player_name, role_ids = ids }
end
--- Load the standard fixture and the given assignments
function env.initialise(assignments)
env.Roles.initialise{
permission_names = permission_names,
roles = role_records(),
assignments = assignments or {},
}
end
return env
end)
+68
View File
@@ -0,0 +1,68 @@
--- Tests for listing and printing to the players who hold a role
local Suite = ... --- @type Suite The suite this file adds its tests to, see test/lua/framework.lua
local test, check, eq = Suite.test, Suite.check, Suite.eq
--- alice and dave are moderators with dave offline, zed has never joined
local function setup(env)
local players = {
alice = env.add_player("alice"),
bob = env.add_player("bob"),
dave = env.add_player("dave", false),
}
env.initialise{
env.assignment("alice", { "Moderator" }),
env.assignment("bob", { "Regular" }),
env.assignment("dave", { "Moderator" }),
env.assignment("zed", { "Moderator" }),
}
env.Roles.set_emit_events(true)
return players
end
test(".get_player_names() includes players not on this map", function(env)
setup(env)
eq(Suite.sorted(env.R("Moderator"):get_player_names()), { "alice", "dave", "zed" },
"every player given the role is listed")
end)
test(".get_player_names() counts a player in both lists once", function(env)
local players = setup(env)
env.R("Regular"):assign(players.alice, { silent = true, local_only = true })
env.Roles.receive_assignment_updates{ env.assignment("alice", { "Moderator", "Regular" }) }
local sd = env.Roles._script_data()
check(sd.local_players.alice ~= nil and sd.synced_players.alice ~= nil, "the role is held in both lists")
eq(Suite.sorted(env.R("Regular"):get_player_names()), { "alice", "bob" }, "the player is counted once")
end)
test(".get_players() is limited to this map and can be filtered", function(env)
setup(env)
local moderator = env.R("Moderator")
eq(Suite.sorted(Suite.names(moderator:get_players())), { "alice", "dave" }, "players are limited to this map")
eq(Suite.names(moderator:get_players(true)), { "alice" }, "filtered to connected players")
eq(Suite.names(moderator:get_players(false)), { "dave" }, "filtered to offline players")
end)
test(".print() reaches online holders", function(env)
setup(env)
env.reset_log()
eq(env.R("Moderator"):print("hello"), 1, "print returns the number of players reached")
eq(env.printed, { { "hello", to = "alice" } }, "only online holders receive the message")
eq(env.R("Jail"):print("hello"), 0, "a role with no online holders reaches nobody")
end)
test(".print() over get_higher_roles() can repeat", function(env)
local players = setup(env)
env.R("Regular"):assign(players.alice, { silent = true, local_only = true })
env.reset_log()
for _, role in ipairs(env.Roles.get_higher_roles(env.R("Regular"))) do
role:print("hello")
end
local got = {}
for _, entry in ipairs(env.printed) do got[#got + 1] = entry.to end
-- alice holds two of the roles, so like the legacy system the message can repeat
eq(Suite.sorted(got), { "alice", "alice", "bob" }, "the online holders of each role are reached")
end)
return Suite.run()
+71
View File
@@ -0,0 +1,71 @@
--- Tests for the role lookup functions of module/control.lua
local Suite = ... --- @type Suite The suite this file adds its tests to, see test/lua/framework.lua
local test, check, eq = Suite.test, Suite.check, Suite.eq
test("get_role() returns the role with the given clusterio id", function(env)
env.initialise{}
check(env.Roles.get_role(env.R("Regular").id) == env.R("Regular"), "the role is found by id")
eq(env.Roles.get_role(9), nil, "deleted roles are not known")
end)
test("get_role_by_name() searches the roles", function(env)
env.initialise{}
check(env.Roles.get_role_by_name("Moderator") == env.R("Moderator"), "the role is found by name")
eq(env.Roles.get_role_by_name("Gone"), nil, "deleted roles are not known")
end)
test("get_roles() returns every role", function(env)
env.initialise{}
eq(Suite.sorted(Suite.names(env.Roles.get_roles())),
{ "Cluster Admin", "Jail", "Moderator", "Player", "Regular" },
"every role is returned with deleted roles skipped")
end)
test("get_ordered_roles() returns the most privileged first", function(env)
env.initialise{}
eq(Suite.names(env.Roles.get_ordered_roles()), { "Cluster Admin", "Moderator", "Regular", "Jail", "Player" },
"roles follow their order")
end)
test("sort_roles() orders most privileged first and breaks ties on the id", function(env)
env.initialise{}
local sorted = env.Roles.sort_roles{ env.R("Player"), env.R("Cluster Admin"), env.R("Regular") }
eq(Suite.names(sorted), { "Cluster Admin", "Regular", "Player" }, "the list is sorted in place")
-- A role with the same order as Regular but a higher id sorts after it
env.Roles.receive_role_updates{
{ id = 10, name = "Twin", permissions = {}, meta = { id = 0, order = env.R("Regular").order } },
}
local tied = env.Roles.sort_roles{ env.R("Twin"), env.R("Regular") }
eq(Suite.names(tied), { "Regular", "Twin" }, "order ties break on the id")
end)
test("get_default_role() follows is_default", function(env)
env.initialise{}
check(env.Roles.get_default_role() == env.R("Player"), "the default role is known")
end)
test("get_higher_roles() and get_lower_roles() include the role and exclude the default", function(env)
env.initialise{}
eq(Suite.sorted(Suite.names(env.Roles.get_higher_roles(env.R("Regular")))),
{ "Cluster Admin", "Moderator", "Regular" }, "higher roles")
eq(Suite.sorted(Suite.names(env.Roles.get_lower_roles(env.R("Regular")))),
{ "Jail", "Regular" }, "lower roles")
end)
test(".is_higher_than() and .is_lower_than() compare on order", function(env)
env.initialise{}
check(env.R("Moderator"):is_higher_than(env.R("Player")), "a lower order is more privileged")
check(env.R("Player"):is_lower_than(env.R("Moderator")), "is_lower_than is the reverse")
check(not env.R("Moderator"):is_higher_than(env.R("Moderator")), "a role is not higher than itself")
end)
test("initialise() decodes the role records", function(env)
env.initialise{}
eq(env.R("Cluster Admin").short_hand, "SYS", "short hand decoded")
eq(env.R("Moderator").short_hand, "Moderator", "short hand falls back to the name")
eq(env.R("Moderator").color, { r = 0, g = 170, b = 0 }, "color decoded")
check(env.R("Jail").priority == 1 and env.R("Jail").block_auto_assign, "priority and block auto assign decoded")
end)
return Suite.run()
+95
View File
@@ -0,0 +1,95 @@
--- Tests for the player checks of module/control.lua
local Suite = ... --- @type Suite The suite this file adds its tests to, see test/lua/framework.lua
local test, check, eq = Suite.test, Suite.check, Suite.eq
--- alice is a moderator, bob is a regular, and carol has only the default role
local function setup(env)
local players = {
alice = env.add_player("alice"),
bob = env.add_player("bob"),
carol = env.add_player("carol"),
}
env.initialise{
env.assignment("alice", { "Moderator" }),
env.assignment("bob", { "Regular" }),
}
return players
end
test("get_player_roles() includes the default role", function(env)
local players = setup(env)
eq(Suite.sorted(Suite.names(env.Roles.get_player_roles(players.alice))), { "Moderator", "Player" },
"held roles and the default role")
eq(Suite.names(env.Roles.get_player_roles(players.carol)), { "Player" },
"a player with no roles has the default role")
end)
test("get_player_roles() treats nil and index 0 as the server", function(env)
setup(env)
eq(Suite.names(env.Roles.get_player_roles(nil)), { "<server>" }, "nil is the server")
eq(Suite.names(env.Roles.get_player_roles(env.server)), { "<server>" }, "index 0 is the server")
check(env.Roles.player_has_permission(nil, "anything.at.all"), "the server has every permission")
check(not env.R("Player"):has_player(nil), "the server does not have the default role")
end)
test("get_player_highest_role() returns the most privileged role", function(env)
local players = setup(env)
check(env.Roles.get_player_highest_role(players.alice) == env.R("Moderator"), "the highest held role")
check(env.Roles.get_player_highest_role(players.carol) == env.R("Player"), "the default role when none are held")
end)
test("get_player_highest_role() errors when a player has no roles", function(env)
local players = setup(env)
env.Roles.receive_role_updates{
{ id = env.R("Player").id, name = "Player", permissions = {}, meta = { id = 0, order = 5 }, is_deleted = true },
}
Suite.throws(function()
env.Roles.get_player_highest_role(players.carol)
end, "Player has no roles", "no default role and no held roles errors")
end)
test("player_has_permission()", function(env)
local players = setup(env)
check(env.Roles.player_has_permission(players.alice, "exp_scenario.command.kill"), "granted by a held role")
check(env.Roles.player_has_permission(players.alice, "exp_scenario.gui.readme"), "granted by the default role")
check(not env.Roles.player_has_permission(players.bob, "exp_scenario.command.jail"), "not granted")
end)
test("player_has_any_permission() and player_has_all_permission()", function(env)
local players = setup(env)
local jail, kill = "exp_scenario.command.jail", "exp_scenario.command.kill"
check(env.Roles.player_has_any_permission(players.bob, jail, kill), "any passes when one is granted")
check(not env.Roles.player_has_any_permission(players.bob, jail, "exp_scenario.command.assign_role"),
"any fails when none are granted")
check(not env.Roles.player_has_any_permission(players.bob), "any of none is false")
check(env.Roles.player_has_all_permission(players.alice, jail, kill), "all passes when every one is granted")
check(not env.Roles.player_has_all_permission(players.bob, jail, kill), "all fails when one is missing")
check(env.Roles.player_has_all_permission(players.bob), "all of none is true")
check(env.Roles.player_has_any_permission(nil, "anything.at.all"), "the server passes any")
check(env.Roles.player_has_all_permission(nil, "anything.at.all", "and.this.too"), "the server passes all")
end)
test(".has_permission()", function(env)
setup(env)
check(env.R("Moderator"):has_permission("exp_scenario.command.kill"), "granted")
check(not env.R("Regular"):has_permission("exp_scenario.command.jail"), "not granted")
check(env.R("Cluster Admin"):has_permission("anything.at.all"), "core.admin grants everything")
end)
test(".has_player()", function(env)
local players = setup(env)
check(env.R("Moderator"):has_player(players.alice), "a held role")
check(not env.R("Moderator"):has_player(players.bob), "a role not held")
check(env.R("Player"):has_player(players.carol), "everyone has the default role")
end)
test("player_outranks()", function(env)
local players = setup(env)
check(env.Roles.player_outranks(players.alice, players.bob), "a higher role outranks a lower one")
check(not env.Roles.player_outranks(players.bob, players.alice), "a lower role does not outrank a higher one")
check(not env.Roles.player_outranks(players.alice, players.alice), "nobody outranks themselves")
check(env.Roles.player_outranks(nil, players.alice), "the server outranks everyone")
check(not env.Roles.player_outranks(players.alice, nil), "nobody outranks the server")
end)
return Suite.run()
+154
View File
@@ -0,0 +1,154 @@
--- Tests for the sync entry points of module/control.lua
local Suite = ... --- @type Suite The suite this file adds its tests to, see test/lua/framework.lua
local test, check, eq, empty = Suite.test, Suite.check, Suite.eq, Suite.empty
--- alice is a moderator and carol has only the default role, both connected
local function setup(env)
local players = {
alice = env.add_player("alice"),
carol = env.add_player("carol"),
}
env.admin_state = {}
env.Roles.define_permission_trigger("exp_scenario.player.admin", function(player, state)
env.admin_state[player.name] = state
end)
env.initialise{
env.assignment("alice", { "Moderator" }),
env.assignment("zed", { "Moderator", "Regular" }), -- has never joined this map
}
env.Roles.set_emit_events(true)
return players
end
test("initialise() applies triggers and raises empty events", function(env)
setup(env)
eq(env.admin_state, { alice = true, carol = false }, "triggers run for connected players")
eq(#env.events, 2, "the event is raised once per connected player")
empty(env.events[1].assigned, "the events assign nothing")
empty(env.events[1].unassigned, "the events unassign nothing")
empty(env.printed, "initialise is silent")
empty(env.sent, "initialise sends nothing")
empty(env.sounds, "initialise plays no sounds")
end)
test("initialise() skips deleted assignments", function(env)
local players = setup(env)
local record = env.assignment("carol", { "Moderator" })
record.is_deleted = true
env.initialise{ record }
check(not env.R("Moderator"):has_player(players.carol), "a deleted assignment is ignored")
end)
test("initialise() is authoritative for pending roles", function(env)
local players = setup(env)
env.R("Moderator"):assign(players.carol)
env.R("Jail"):assign(players.carol, { silent = true, local_only = true })
local sd = env.Roles._script_data()
eq(sd.pending.carol, { env.R("Moderator").id }, "the role is pending before initialise")
env.reset_log()
env.initialise{ env.assignment("alice", { "Moderator" }) }
eq(sd.pending.carol, nil, "pending roles are cleared")
check(not env.R("Moderator"):has_player(players.carol), "an unconfirmed role is given up")
eq(sd.local_players.carol, { env.R("Jail").id }, "local only roles are kept")
empty(env.sent, "initialise sends nothing")
end)
test("receive_assignment_updates() applies controller changes", function(env)
local players = setup(env)
env.reset_log()
env.Roles.receive_assignment_updates{ env.assignment("carol", { "Moderator" }) }
check(env.R("Moderator"):has_player(players.carol), "the assignment applies")
eq(env.events, {
{
name = env.Roles.events.on_player_roles_changed,
tick = 1,
player_index = players.carol.index,
by_player_index = 0,
assigned = { env.R("Moderator").id },
unassigned = {},
},
}, "the event carries the change with no by player")
eq(env.printed, {
{ "exp-roles.game-message-assign", "carol", "Moderator", "<server>" },
}, "the change is announced by the server")
check(env.admin_state.carol == true, "triggers follow the assignment")
env.reset_log()
env.Roles.receive_assignment_updates{ { name = "carol", role_ids = {}, is_deleted = true } }
check(not env.R("Moderator"):has_player(players.carol), "a removal applies")
eq(env.events[1].unassigned, { env.R("Moderator").id }, "the removal raises the event")
check(env.admin_state.carol == false, "triggers follow the removal")
end)
test("receive_assignment_updates() for players not on this map raises nothing", function(env)
setup(env)
env.reset_log()
env.Roles.receive_assignment_updates{ env.assignment("zed", { "Moderator" }) }
empty(env.events, "no event is raised")
empty(env.printed, "nothing is announced")
end)
test("receive_role_updates() applies to the holders", function(env)
setup(env)
env.reset_log()
local regular_id = env.R("Regular").id
env.Roles.receive_role_updates{
{ id = regular_id, name = "Regular", permissions = { "exp_scenario.command.jail" }, meta = { id = 0, order = 3 } },
}
check(env.R("Regular"):has_permission("exp_scenario.command.jail"), "the permission change applies")
eq(#env.events, 2, "a role change raises for every connected player")
empty(env.events[1].assigned, "role change events are empty")
env.Roles.receive_role_updates{
{ id = regular_id, name = "Regular", permissions = {}, meta = { id = 0, order = 3 }, is_deleted = true },
}
eq(env.Roles.get_role(regular_id), nil, "a deleted role is removed")
end)
test("receive_role_updates() moves the default role", function(env)
local players = setup(env)
env.Roles.receive_role_updates{
{ id = env.R("Player").id, name = "Player", permissions = {}, meta = { id = 0, order = 5 } },
{ id = 8, name = "Guest", permissions = {}, meta = { id = 0, order = 7 }, is_default = true },
}
check(env.Roles.get_default_role() == env.R("Guest"), "the new default role is known")
eq(Suite.names(env.Roles.get_player_roles(players.carol)), { "Guest" }, "players pick up the new default")
end)
test("set_emit_events() gates what is sent and defaults to enabled", function(env)
local players = setup(env)
env.Roles.set_emit_events(false)
env.reset_log()
env.R("Regular"):assign(players.alice)
empty(env.sent, "nothing is sent while disabled")
check(env.R("Regular"):has_player(players.alice), "the assignment still applies locally")
env.Roles.set_emit_events()
env.R("Jail"):assign(players.alice, { silent = true })
eq(env.sent, {
{ channel = "exp_roles:assignment_update", data = { name = "alice", assign = { env.R("Jail").id } } },
}, "no argument enables sending")
end)
test("on_load() restores the state after a save and load", function(env)
local players = setup(env)
env.R("Jail"):assign(players.carol, { silent = true, local_only = true })
env.save_load()
env.Roles.on_load()
check(env.R("Moderator"):is_higher_than(env.R("Regular")), "role methods survive through the registered metatable")
check(env.R("Moderator"):has_player(players.alice), "synced roles survive")
check(env.R("Jail"):has_player(players.carol), "local roles survive")
check(env.Roles.player_has_permission(players.alice, "exp_scenario.command.kill"), "permission checks still answer")
end)
test("on_player_joined_game() runs the triggers", function(env)
local players = setup(env)
env.admin_state.alice = nil
env.Roles.on_player_joined_game{ player_index = players.alice.index }
check(env.admin_state.alice ~= nil, "triggers run when a player joins")
end)
return Suite.run()