mafia / tests /test_views.py
Alfaxad's picture
Migrate Mafia game to ZeroGPU Gradio Space
c670567 verified
Raw
History Blame Contribute Delete
3.71 kB
import json
from mafia.engine.reducers import add_message, create_game, resolve_night, start_discussion, submit_night_action
from mafia.engine.state import Role, Team
from mafia.engine.views import legal_actions_for, private_event_dict, private_view, public_view
def test_public_view_does_not_leak_living_roles():
state = create_game(seed=42)
view = public_view(state)
serialized = json.dumps(view)
assert "mafia_team" not in serialized
for pid, player in state.players.items():
if player.alive:
assert view["players"][pid]["revealed_role"] is None
def test_mafia_private_view_knows_only_mafia_team():
state = create_game(seed=42)
mafia = next(pid for pid, player in state.players.items() if player.role == Role.MAFIA)
view = private_view(state, mafia)
assert "mafia_team" in view["private_info"]
assert len(view["private_info"]["mafia_team"]) == 2
def test_detective_result_is_private_not_public():
state = create_game(seed=44)
detective = next(pid for pid, player in state.players.items() if player.role == Role.DETECTIVE)
mafia = next(pid for pid, player in state.players.items() if player.role == Role.MAFIA)
submit_night_action(state, detective, "check", mafia)
resolve_night(state)
assert mafia in private_view(state, detective)["private_info"]["investigations"]
assert "is_mafia" not in json.dumps(public_view(state))
def test_dead_roles_stay_hidden_until_game_over():
state = create_game(seed=18)
mafia = next(pid for pid, player in state.players.items() if player.role == Role.MAFIA)
victim = next(pid for pid, player in state.players.items() if player.team == Team.TOWN)
assert submit_night_action(state, mafia, "kill", victim)
resolve_night(state)
view = public_view(state)
assert view["players"][victim]["alive"] is False
assert view["players"][victim]["revealed_role"] is None
assert state.players[victim].role.value not in json.dumps(view["events"])
def test_vote_start_is_moderator_owned():
state = create_game(seed=20)
resolve_night(state)
start_discussion(state)
for pid in state.alive_players():
assert "start_vote" not in legal_actions_for(state, pid)
def test_mafia_consensus_event_is_private_to_mafia():
state = create_game(seed=42)
mafia = [pid for pid, player in state.players.items() if player.role == Role.MAFIA]
town = [pid for pid, player in state.players.items() if player.team == Team.TOWN]
submit_night_action(state, mafia[0], "kill", town[0])
submit_night_action(state, mafia[1], "kill", town[1])
resolve_night(state)
event = next(event for event in state.events if event.type == "mafia_consensus")
mafia_view = private_event_dict(state, event, mafia[0])
town_view = private_event_dict(state, event, town[0])
assert mafia_view is not None
assert mafia_view["payload"]["private"] is True
assert town_view is None
def test_targeted_moderator_cue_is_private_to_target_only():
state = create_game(seed=42)
target = "p2"
other = "p3"
add_message(
state,
"moderator",
"Nora, give one concrete read.",
speech_act="floor_cue",
emotion="neutral",
source="ttt",
metadata={"target": target, "message_type": "evidence"},
)
event = state.events[-1]
assert "Nora, give one concrete read." not in json.dumps(public_view(state))
assert private_event_dict(state, event, other) is None
target_event = private_event_dict(state, event, target)
assert target_event is not None
assert target_event["type"] == "private_moderator_cue"
assert target_event["payload"]["private"] is True