def test_name_changes_state(update_mock, db_session): """ Join two players to a game and confirm that a) the second one joining changes the game hash and b) the second one changing their name changes the game hash """ g = WurwolvesGame(GAME_ID) g.join(USER_ID) update_mock.assert_called() update_mock.reset_mock() game_hash_1 = g.get_game().update_tag new_user_id = uuid() g.join(new_user_id) update_mock.assert_called() update_mock.reset_mock() game_hash_2 = g.get_game().update_tag WurwolvesGame.set_user_name(new_user_id, "Stinky Smelly") update_mock.assert_called() update_mock.reset_mock() game_hash_3 = g.get_game().update_tag assert game_hash_1 != game_hash_2 assert game_hash_1 != game_hash_3 assert game_hash_2 != game_hash_3
def test_seer_saved_no_fail(mock_roles, db_session): game = WurwolvesGame("test_game") wolf_id = uuid() medic_id = uuid() seer_id = uuid() villager_id = uuid() game.join(wolf_id) game.join(medic_id) game.join(seer_id) game.join(villager_id) game.join(uuid()) game.join(uuid()) game.start_game() game.seer_night_action(seer_id, wolf_id) game.wolf_night_action(wolf_id, seer_id) game.medic_night_action(medic_id, seer_id) assert game.get_player_model(seer_id).state == PlayerState.ALIVE summary = get_summary_of_chat(game, seer_id) assert re.search(r"they are a wolf", summary)
def test_killed_twice(db_session): game = WurwolvesGame(GAME_ID) # Add four players player_ids = [uuid() for _ in range(4)] roles = [ PlayerRole.VILLAGER, PlayerRole.VILLAGER, PlayerRole.VIGILANTE, PlayerRole.WOLF, ] for p in player_ids: game.join(p) game.start_game() for p, r in zip(player_ids, roles): game.set_player_role(game.get_player_id(p), r) villager1_id = player_ids[0] villager2_id = player_ids[1] vigilante_id = player_ids[2] wolf_id = player_ids[3] # Kill a villager with the vigilante game.vigilante_night_action(vigilante_id, villager1_id) # ...and the wolf game.wolf_night_action(wolf_id, villager1_id) # Check that the player retains their role db_session.expire_all() assert game.get_player_model( villager1_id).previous_role != PlayerRole.SPECTATOR
def five_player_game(db_session) -> WurwolvesGame: g = WurwolvesGame(GAME_ID) # Make players user_ids = [uuid() for _ in range(5)] roles = [ PlayerRole.WOLF, PlayerRole.MEDIC, PlayerRole.SEER, PlayerRole.VILLAGER, PlayerRole.VILLAGER, ] names = ["Wolf", "Medic", "Seer", "Villager 1", "Villager 2"] for i, id in enumerate(user_ids): g.join(id) g.start_game() # Override the roles for id, role, name in zip(user_ids, roles, names): u = g.get_player(id) u.role = role g.set_user_name(id, name) g._session.commit() roles_map = {name: user_id for name, user_id in zip(names, user_ids)} return g, roles_map
def factory(): random_id = str(uuid()) g = WurwolvesGame(random_id) # You need at least three players for start_game() to work g.join(USER_ID) g.join(uuid()) g.join(uuid()) return g
def demo_game(db_session) -> WurwolvesGame: g = WurwolvesGame(GAME_ID) # You need at least three players for start_game() to work ids = [USER_ID, uuid(), uuid()] for i, id in enumerate(ids): g.join(id) g.set_user_name(id, f"Player {i}") return g
def test_name_player(db_session): g = WurwolvesGame(GAME_ID) g.join(USER_ID) assert len(db_session.query(User).all()) == 1 u = db_session.query(User).filter(User.id == USER_ID).first() assert u.name_is_generated g.set_user_name(USER_ID, "Charles") db_session.expire_all() u = db_session.query(User).filter(User.id == USER_ID).first() assert not u.name_is_generated assert u.name == "Charles"
def test_masons_announced(mock_roles, db_session): game = WurwolvesGame("test_game") wolf_id = uuid() mason_1_id = uuid() mason_2_id = uuid() villager_id = uuid() game.join(wolf_id) game.join(mason_1_id) game.join(mason_2_id) game.join(villager_id) game.join(uuid()) game.join(uuid()) game.start_game() mason_1_name = game.get_user_name(mason_1_id) mason_2_name = game.get_user_name(mason_2_id) assert f"Your fellow masons are {mason_2_name}" in get_summary_of_chat( game, mason_1_id) assert f"Your fellow masons are {mason_1_name}" in get_summary_of_chat( game, mason_2_id) assert "Your fellow masons are" not in get_summary_of_chat(game, wolf_id) assert "Your fellow masons are" not in get_summary_of_chat( game, villager_id)
def test_priest_works(mock_roles, db_session): game = WurwolvesGame("test_game") wolf_id = uuid() priest_id = uuid() villager1_id = uuid() villager2_id = uuid() game.join(wolf_id) game.join(priest_id) game.join(villager1_id) game.join(villager2_id) game.join(uuid()) game.join(uuid()) game.start_game() with pytest.raises(HTTPException): game.priest_night_action(priest_id, villager1_id) game.wolf_night_action(wolf_id, villager1_id) assert game.get_player_model(villager1_id).state == PlayerState.WOLFED game._set_stage(GameStage.NIGHT) game.priest_night_action(priest_id, villager1_id) game.wolf_night_action(wolf_id, villager2_id) summary = get_summary_of_chat(game, priest_id) assert re.search(r"You remember that .+ was a Villager", summary)
def test_kick(db_session): game = WurwolvesGame(GAME_ID) # Add three players player_ids = [uuid() for _ in range(3)] for p in player_ids: game.join(p) db_session = game._session # Set one to have joined ages ago timeout_player_id = player_ids[0] timeout_player = game.get_player(timeout_player_id) game.set_user_name(timeout_player_id, "timeout player") db_session.add(timeout_player) timeout_player.last_seen = datetime(1, 1, 1) db_session.commit() db_session.expire_all() # Get the game tag tag = game.get_game_model().update_tag timeout_player = game.get_player(timeout_player_id) db_session.add(timeout_player) assert timeout_player.state == PlayerState.SPECTATING # Keepalive one of the other players, which should kick the idler game.player_keepalive(player_ids[1]) db_session.expire_all() # Check that the idler is gone assert not game.get_player(timeout_player_id) # And that they're not in the rendered state state = game.parse_game_to_state(player_ids[1]) assert "timeout player" not in state.json() # Also check the tag changed assert tag != game.get_game_model().update_tag tag = game.get_game_model().update_tag # Bring the idler back game.player_keepalive(timeout_player_id) assert game.get_player(timeout_player_id) assert tag != game.get_game_model().update_tag
def test_prostitute_prevents_seer(mock_roles, db_session): game = WurwolvesGame("test_game") wolf_id = uuid() seer_id = uuid() prostitute_id = uuid() villager_id = uuid() game.join(wolf_id) game.join(seer_id) game.join(prostitute_id) game.join(villager_id) game.join(uuid()) game.join(uuid()) game.start_game() # Seer checks villager but prostitute sleeps with seer. # Wolf kills villager, so villager dies game.prostitute_night_action(prostitute_id, seer_id) game.seer_night_action(seer_id, villager_id) game.wolf_night_action(wolf_id, villager_id) assert game.get_player_model(villager_id).state == PlayerState.WOLFED summary = get_summary_of_chat(game, seer_id) assert re.search(r"you couldn't concentrate", summary)
def func(num_players): import random random.seed(123) g = WurwolvesGame(GAME_ID) # You need at least three players for start_game() to work g.join(USER_ID) for _ in range(num_players - 1): g.join(uuid()) return g
def test_fool_no_mention_seer(empty_game): from unittest.mock import patch import backend from backend.roles import DistributionSettings game = WurwolvesGame("test_game") # Make some players in a game num_players = 10 user_ids = [uuid() for _ in range(num_players)] [game.join(u) for u in user_ids] # Customise the probabilitites to get a fool settings = DistributionSettings(role_weights={PlayerRole.FOOL: 1000000}) game.set_game_config(settings) game.start_game() # Find the fool (there's almost certainly one) fool_player = [p for p in game.get_players() if p.role == PlayerRole.FOOL] assert len(fool_player) == 1 fool_id = fool_player[0].user_id game.set_user_name(fool_id, "The one who isn't the seer") game._session.commit() # Confirm that the fool's state doesn't mention the fool anywhere def fool_in_state(fool_state): # Unfortunately, it does in one place: the function call. A savvy user could # therefore cheat. I should change it so that all player actions call the # same function in game. The game would then pass the call on to the # appropriate method, depending on the player's role. # For now, so this test passes, remove that reference fool_state_filtered = fool_state.dict() fool_state_filtered["controls_state"]["button_submit_func"] = "removed" fool_state = type(fool_state).parse_obj(fool_state_filtered) print("Fool state:") from pprint import pprint pprint(fool_state.dict()) return "fool" in fool_state.json().lower() game._set_stage(GameStage.NIGHT) fool_state = game.parse_game_to_state(fool_id) assert not fool_in_state(fool_state) game._set_stage(GameStage.VOTING) fool_state = game.parse_game_to_state(fool_id) assert not fool_in_state(fool_state) game._set_stage(GameStage.DAY) fool_state = game.parse_game_to_state(fool_id) assert not fool_in_state(fool_state) # Move to the end of the game and confirm that the fool is revealed game._set_stage(GameStage.ENDED) fool_state = game.parse_game_to_state(fool_id) assert fool_in_state(fool_state)
def test_not_kicked_during_game(db_session): game = WurwolvesGame(GAME_ID) # Add four players player_ids = [uuid() for _ in range(4)] roles = [ PlayerRole.MEDIC, PlayerRole.VILLAGER, PlayerRole.SPECTATOR, PlayerRole.WOLF, ] for p in player_ids: game.join(p) db_session = game._session game.start_game() for p, r in zip(player_ids, roles): game.set_player_role(game.get_player_id(p), r) timeout_player_id = player_ids[0] villager_id = player_ids[1] spectator_id = player_ids[2] wolf_id = player_ids[3] # Kill the medic with the wolf game.wolf_night_action(wolf_id, timeout_player_id) # Have the idler do something too game.medic_night_action(timeout_player_id, wolf_id) # Set medic to have joined ages ago timeout_player = game.get_player(timeout_player_id) db_session.add(timeout_player) timeout_player.last_seen = datetime(1, 1, 1) db_session.commit() db_session.expire_all() # Keepalive one of the other players, which should not kick the idler since it's a game game.player_keepalive(wolf_id) db_session.expire_all() assert game.get_player(timeout_player_id)
def test_prostitute_not_choose_self(mock_roles, db_session): game = WurwolvesGame("test_game") wolf_id = uuid() medic_id = uuid() prostitute_id = uuid() villager_id = uuid() game.join(wolf_id) game.join(medic_id) game.join(prostitute_id) game.join(villager_id) game.join(uuid()) game.join(uuid()) game.start_game() # Check that the pristitute can't sleep with themselves with pytest.raises(HTTPException): game.prostitute_night_action(prostitute_id, prostitute_id)
def test_end_game(api_client, db_session): from uuid import uuid4 as uuid g = WurwolvesGame(GAME_ID) with api_client as s: r = s.post(f"/api/{GAME_ID}/join") assert r.ok for _ in range(4): g.join(uuid()) g.start_game() assert g.get_game_model().stage == GameStage.NIGHT r = s.post(f"/api/{GAME_ID}/end_game") assert r.ok assert g.get_game_model().stage == GameStage.ENDED
def test_start_game(db_session): g = WurwolvesGame(GAME_ID) g.join(USER_ID) g.join(uuid()) g.join(uuid()) db_game = get_game(db_session, GAME_ID) assert db_game.stage == GameStage.LOBBY p: Player for p in db_game.players: assert p.role == PlayerRole.SPECTATOR assert p.state == PlayerState.SPECTATING g.start_game() db_session.expire_all() assert db_game.stage == GameStage.NIGHT p: Player for p in db_game.players: assert p.role != PlayerRole.SPECTATOR assert p.state == PlayerState.ALIVE new_user_id = uuid() g.join(new_user_id) db_session.expire_all() p = get_player(db_session, GAME_ID, new_user_id) assert p.role == PlayerRole.SPECTATOR
def test_add_player(db_session): g = WurwolvesGame(GAME_ID) g.join(USER_ID) assert len(db_session.query(Game).all()) == 1 assert len(db_session.query(User).all()) == 1 db_game = db_session.query(Game).first() assert len( db_session.query(Player).filter(Player.game == db_game).all()) == 1 game_hash = g.get_game_model().update_tag g.join(uuid()) assert len(db_session.query(Game).all()) == 1 assert len(db_session.query(User).all()) == 2 assert len( db_session.query(Player).filter(Player.game == db_game).all()) == 2 assert game_hash != g.get_game_model().update_tag game_hash = g.get_game_model().update_tag g.join(USER_ID) assert len(db_session.query(Game).all()) == 1 assert len(db_session.query(User).all()) == 2 assert len( db_session.query(Player).filter(Player.game == db_game).all()) == 2 assert game_hash == g.get_game_model().update_tag
def test_prostitute_saves_villager(mock_roles, db_session): game = WurwolvesGame("test_game") wolf_id = uuid() prostitute_id = uuid() villager_id = uuid() game.join(wolf_id) game.join(prostitute_id) game.join(villager_id) game.join(uuid()) game.join(uuid()) game.join(uuid()) game.start_game() # Prostitute sleep with villager, wolf attacks villager. # Villager isn't home, so doesn't die game.prostitute_night_action(prostitute_id, villager_id) game.wolf_night_action(wolf_id, villager_id) assert game.get_player_model(villager_id).state == PlayerState.ALIVE
def test_prostitute_dooms_villager(mock_roles, db_session): game = WurwolvesGame("test_game") wolf_id = uuid() prostitute_id = uuid() villager_id = uuid() game.join(wolf_id) game.join(prostitute_id) game.join(villager_id) game.join(uuid()) game.join(uuid()) game.join(uuid()) game.start_game() # Prostitute sleeps with villager, wolf attacks prostitute. # Both die. game.prostitute_night_action(prostitute_id, villager_id) game.wolf_night_action(wolf_id, prostitute_id) assert game.get_player_model(villager_id).state == PlayerState.WOLFED assert game.get_player_model(prostitute_id).state == PlayerState.WOLFED
def test_announced_to_wolves(mock_roles, db_session, role, search): game = WurwolvesGame("test_game") wolf_id = uuid() game.join(wolf_id) game.join(uuid()) game.join(uuid()) game.join(uuid()) game.join(uuid()) game.join(uuid()) game.start_game() summary = get_summary_of_chat(game, wolf_id) assert f"There's {search} in the game" in summary
def test_prostitute_prevents_only_one_wolf_alt(mock_roles, db_session): game = WurwolvesGame("test_game") wolf_1_id = uuid() wolf_2_id = uuid() prostitute_id = uuid() villager_id = uuid() game.join(wolf_1_id) game.join(wolf_2_id) game.join(prostitute_id) game.join(villager_id) game.join(uuid()) game.join(uuid()) game.join(uuid()) game.start_game() # Prostitute sleep with wolf 1, wolves attack villager. # First wolf if disabled but second wolf kills game.prostitute_night_action(prostitute_id, wolf_1_id) game.wolf_night_action(wolf_2_id, villager_id) assert game.get_player_model(villager_id).state == PlayerState.WOLFED
def test_prostitute_prevents_medic(mock_roles, db_session): game = WurwolvesGame("test_game") wolf_id = uuid() medic_id = uuid() prostitute_id = uuid() villager_id = uuid() game.join(wolf_id) game.join(medic_id) game.join(prostitute_id) game.join(villager_id) game.join(uuid()) game.join(uuid()) game.start_game() # Medic saves villager but prostitute sleeps with medic. # Wolf kills villager, so villager dies game.prostitute_night_action(prostitute_id, medic_id) game.medic_night_action(medic_id, villager_id) game.wolf_night_action(wolf_id, villager_id) assert game.get_player_model(villager_id).state == PlayerState.WOLFED
def test_wolves_announced(mock_roles, db_session): game = WurwolvesGame("test_game") wolf_id = uuid() villager_1_id = uuid() game.join(wolf_id) game.join(villager_1_id) game.join(uuid()) game.join(uuid()) game.join(uuid()) game.join(uuid()) game.start_game() assert "There is only one wolf in the game" in get_summary_of_chat( game, villager_1_id) assert "There is only one wolf in the game" in get_summary_of_chat( game, wolf_id)
def test_miller_works(mock_roles, db_session): game = WurwolvesGame("test_game") wolf_id = uuid() seer_id = uuid() miller_id = uuid() villager_id = uuid() game.join(wolf_id) game.join(seer_id) game.join(miller_id) game.join(villager_id) game.join(uuid()) game.join(uuid()) game.start_game() game.seer_night_action(seer_id, miller_id) game.wolf_night_action(wolf_id, villager_id) summary = get_summary_of_chat(game, seer_id) assert "they are a wolf!" in summary
def test_kick_with_actions(db_session): game = WurwolvesGame(GAME_ID) # Add four players player_ids = [uuid() for _ in range(4)] roles = [ PlayerRole.MEDIC, PlayerRole.VILLAGER, PlayerRole.SPECTATOR, PlayerRole.WOLF, ] for p in player_ids: game.join(p) db_session = game._session game.start_game() for p, r in zip(player_ids, roles): game.set_player_role(game.get_player_id(p), r) timeout_player_id = player_ids[0] villager_id = player_ids[1] spectator_id = player_ids[2] wolf_id = player_ids[3] # Set one to have joined ages ago timeout_player = game.get_player(timeout_player_id) db_session.add(timeout_player) timeout_player.last_seen = datetime(1, 1, 1) db_session.commit() db_session.expire_all() timeout_player = game.get_player(timeout_player_id) db_session.add(timeout_player) assert timeout_player.state == PlayerState.ALIVE # Keepalive one of the other players, which should not kick the idler since it's a game game.player_keepalive(wolf_id) db_session.expire_all() assert game.get_player(timeout_player_id) # Kill the idler with the wolf game.wolf_night_action(wolf_id, timeout_player_id) # Have the idler do something too game.medic_night_action(timeout_player_id, wolf_id) db_session.expire_all() # Check game ended assert game.get_game_model().stage == GameStage.ENDED # Keepalive someone else game.player_keepalive(wolf_id) # Player should not yet be kicked db_session.expire_all() g = game.get_player(timeout_player_id) assert g # Put their timeout back into the past timeout_player.last_seen = datetime(1, 1, 1) db_session.commit() db_session.expire_all() # Keepalive someone else game.player_keepalive(wolf_id) # They still should be visible, but marked as inactive now db_session.expire_all() assert game.get_player(timeout_player_id) assert not game.get_player_model(timeout_player_id).active # Vote to start a new game game.wolf_ended_action(wolf_id) # Check a new game started db_session.expire_all() assert game.get_game_model().stage == GameStage.LOBBY # Check the idler was kicked after the next keepalive game.player_keepalive(wolf_id) assert not game.get_player(timeout_player_id)