mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-09-22 01:04:01 +00:00
- The controller tests run against a real Controller, which is side effect free while not started, with real users through its UserManager. The only fakes left are two spies which record broadcasts and permission pushes on their way through. Since any user update also applies auto assignment, the leave event is observed directly rather than through a role change. - raise_event fills in the name and tick of the event the way factorio does, rather than wrapping the payload, and game.players finds players by index as well as by name through a metatable. - names is generic over anything with a name property, so it lives on the suite; the save and load helper no longer calls on_load, the test calls the handler itself as it does for the other handlers. - Sent messages and events are compared whole with deep_eq, which pins the event shape, the tick, and that the unassign key is absent rather than empty. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
150 lines
6.5 KiB
Lua
150 lines
6.5 KiB
Lua
--- Tests for the assignment methods of module/control.lua
|
|
local Suite = ... --- The suite this file adds its tests to, see test/lua/framework.lua
|
|
local test, check, eq, deep_eq = Suite.test, Suite.check, Suite.eq, Suite.deep_eq
|
|
|
|
--- 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", 1),
|
|
bob = env.add_player("bob", 2),
|
|
}
|
|
env.initialise{
|
|
env.assignment("alice", { 5 }),
|
|
env.assignment("bob", { 6 }),
|
|
}
|
|
env.Roles.set_emit_events(true)
|
|
env.reset_log()
|
|
return players
|
|
end
|
|
|
|
test("role:assign applies locally and is sent to the controller", function(env)
|
|
local players = setup(env)
|
|
env.R("Moderator"):assign(players.bob, { by_player_name = "alice" })
|
|
deep_eq(env.sent, {
|
|
{ channel = "exp_roles:assignment_update", data = { name = "bob", assign = { 5 } } },
|
|
}, "the assignment is sent to the controller")
|
|
check(env.R("Moderator"):has_player(players.bob), "the role applies before confirmation")
|
|
deep_eq(env.events, {
|
|
{
|
|
name = env.Roles.events.on_player_roles_changed,
|
|
tick = 1,
|
|
player_index = 2,
|
|
by_player_index = 1,
|
|
assigned = { 5 },
|
|
unassigned = {},
|
|
},
|
|
}, "the event carries the change")
|
|
check(#env.printed == 1 and env.printed[1][1] == "exp-roles.game-message-assign", "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, { 5 }, "the role is held locally")
|
|
eq(sd.pending.bob, { 5 }, "the role is pending")
|
|
|
|
env.reset_log()
|
|
env.R("Moderator"):assign(players.bob)
|
|
check(#env.sent == 0 and #env.events == 0, "assigning a held role is a no-op")
|
|
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", { 6, 5 }) }
|
|
check(#env.events == 0 and #env.printed == 0, "a confirmation raises 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("role:unassign removes a synced role", function(env)
|
|
local players = setup(env)
|
|
env.R("Regular"):unassign(players.bob, { by_player_name = "alice", silent = true })
|
|
deep_eq(env.sent, {
|
|
{ channel = "exp_roles:assignment_update", data = { name = "bob", unassign = { 6 } } },
|
|
}, "the unassignment is sent to the controller")
|
|
check(not env.R("Regular"):has_player(players.bob), "the role is removed locally")
|
|
deep_eq(env.events, {
|
|
{
|
|
name = env.Roles.events.on_player_roles_changed,
|
|
tick = 1,
|
|
player_index = 2,
|
|
by_player_index = 1,
|
|
assigned = {},
|
|
unassigned = { 6 },
|
|
},
|
|
}, "the event carries the change")
|
|
check(#env.printed == 0, "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)
|
|
env.R("Jail"):assign(players.alice)
|
|
check(env.R("Jail"):has_player(players.alice), "the role applies before rejection")
|
|
|
|
env.reset_log()
|
|
env.Roles.reject_assignment{ name = "alice", role_ids = { 7 } }
|
|
check(not env.R("Jail"):has_player(players.alice), "the rejected role is rolled back")
|
|
check(#env.sent == 0, "the rollback is not sent to the controller")
|
|
deep_eq(env.events, {
|
|
{
|
|
name = env.Roles.events.on_player_roles_changed,
|
|
tick = 1,
|
|
player_index = 1,
|
|
by_player_index = 0,
|
|
assigned = {},
|
|
unassigned = { 7 },
|
|
},
|
|
}, "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("role:assign with local_only never reaches the controller", function(env)
|
|
local players = setup(env)
|
|
env.R("Regular"):assign(players.alice, { silent = true, local_only = true })
|
|
check(#env.sent == 0, "the assignment is not sent")
|
|
check(env.R("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, { 6 }, "the role is held locally")
|
|
|
|
env.Roles.receive_assignment_updates{ env.assignment("alice", { 5 }) }
|
|
check(env.R("Regular"):has_player(players.alice), "the role survives controller updates")
|
|
|
|
env.reset_log()
|
|
env.R("Regular"):unassign(players.alice, { local_only = true })
|
|
check(not env.R("Regular"):has_player(players.alice) and #env.sent == 0, "removed without sync")
|
|
end)
|
|
|
|
test("role:assign of a higher priority role suppresses the rest", function(env)
|
|
local players = setup(env)
|
|
env.R("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, { 7 }, "the event lists the jail role")
|
|
check(#env.events[1].unassigned == 0, "the suppressed roles are not listed as unassigned")
|
|
|
|
env.reset_log()
|
|
env.R("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")
|
|
check(#env.events[1].assigned == 0, "the restored roles are not listed as assigned")
|
|
eq(env.events[1].unassigned, { 7 }, "the unjail event lists the jail role")
|
|
end)
|
|
|
|
test("role:assign ignores the server", function(env)
|
|
setup(env)
|
|
env.R("Moderator"):assign(env.server)
|
|
check(#env.sent == 0 and #env.events == 0, "assigning to the server is a no-op")
|
|
end)
|
|
|
|
return Suite.run()
|