Skip to content

Commit

Permalink
Add some coverage for the forum phase
Browse files Browse the repository at this point in the history
The forum phase had no test coverage, except for the code that it shares with the faction phase, so add some.
  • Loading branch information
iamlogand committed Feb 1, 2024
1 parent 18295e5 commit 0207474
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 134 deletions.
1 change: 1 addition & 0 deletions backend/rorapp/functions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# The functions module provides a collection of public functions that are intended to be used by other parts of the application.
from .faction_leader_helper import select_faction_leader, set_faction_leader # noqa: F401
from .forum_phase_starter import start_forum_phase # noqa: F401
from .game_deleter import delete_all_games # noqa: F401
from .game_generator import generate_game # noqa: F401
from .game_starter import start_game, user_start_game # noqa: F401
Expand Down
2 changes: 1 addition & 1 deletion backend/rorapp/functions/forum_phase_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


def get_next_faction_in_forum_phase(
last_faction: Faction | None = None
last_faction: Faction | None = None,
) -> Optional[Faction]:
"""
Find the faction that should take the next initiative in the forum phase.
Expand Down
40 changes: 40 additions & 0 deletions backend/rorapp/functions/forum_phase_starter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from typing import List
from rorapp.functions.action_helper import delete_old_actions
from rorapp.functions.faction_leader_helper import generate_select_faction_leader_action
from rorapp.functions.websocket_message_helper import create_websocket_message
from rorapp.models import (
Faction,
Phase,
Step,
)
from rorapp.serializers import (
StepSerializer,
PhaseSerializer,
)


def start_forum_phase(game_id) -> List[dict]:
messages_to_send = []
latest_step = Step.objects.filter(phase__turn__game=game_id).order_by("-index")[0]

# Progress to the forum phase
new_phase = Phase(
name="Forum", index=latest_step.phase.index + 1, turn=latest_step.phase.turn
)
new_phase.save()
messages_to_send.append(
create_websocket_message("phase", PhaseSerializer(new_phase).data)
)
new_step = Step(index=latest_step.index + 1, phase=new_phase)
new_step.save()
messages_to_send.append(
create_websocket_message("step", StepSerializer(new_step).data)
)

# Create actions
first_faction = Faction.objects.filter(game__id=game_id).order_by("rank").first()
messages_to_send.append(
generate_select_faction_leader_action(first_faction, new_step)
)
messages_to_send.extend(delete_old_actions(game_id))
return messages_to_send
28 changes: 2 additions & 26 deletions backend/rorapp/functions/mortality_phase_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
from typing import List
from django.conf import settings
from rest_framework.response import Response
from rorapp.functions.action_helper import delete_old_actions
from rorapp.functions.faction_leader_helper import generate_select_faction_leader_action
from rorapp.functions.forum_phase_starter import start_forum_phase
from rorapp.functions.mortality_chit_helper import draw_mortality_chits
from rorapp.functions.rank_helper import rank_senators_and_factions
from rorapp.functions.websocket_message_helper import (
Expand All @@ -14,19 +13,15 @@
from rorapp.models import (
Action,
ActionLog,
Faction,
Game,
Phase,
Senator,
SenatorActionLog,
Step,
Title,
)
from rorapp.serializers import (
ActionLogSerializer,
StepSerializer,
TitleSerializer,
PhaseSerializer,
SenatorSerializer,
SenatorActionLogSerializer,
)
Expand Down Expand Up @@ -222,25 +217,6 @@ def resolve_mortality(game_id: int, chit_codes: List[int] | None = None) -> dict
messages_to_send.extend(rank_senators_and_factions(game_id))

# Proceed to the forum phase
new_phase = Phase(
name="Forum", index=latest_step.phase.index + 1, turn=latest_step.phase.turn
)
new_phase.save()
messages_to_send.append(
create_websocket_message("phase", PhaseSerializer(new_phase).data)
)
new_step = Step(index=latest_step.index + 1, phase=new_phase)
new_step.save()
messages_to_send.append(
create_websocket_message("step", StepSerializer(new_step).data)
)

# Create actions for the forum phase
first_faction = Faction.objects.filter(game__id=game_id).order_by("rank").first()
messages_to_send.append(
generate_select_faction_leader_action(first_faction, new_step)
)

messages_to_send.extend(delete_old_actions(game.id))
messages_to_send.extend(start_forum_phase(game_id))

return messages_to_send
1 change: 1 addition & 0 deletions backend/rorapp/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .faction_phase_tests import FactionPhaseTests # noqa: F401
from .forum_phase_tests import ForumPhaseTests # noqa: F401
from .mortality_chit_tests import MortalityChitTests # noqa: F401
from .mortality_phase_tests import MortalityPhaseTests # noqa: F401
from .start_game_tests import StartGameTests # noqa: F401
Expand Down
78 changes: 20 additions & 58 deletions backend/rorapp/tests/faction_phase_tests.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import random
from typing import List
from django.test import TestCase
from rest_framework.test import APIClient
from django.contrib.auth.models import User
from rorapp.functions import delete_all_games, generate_game, start_game
from rorapp.models import Action, Faction, Phase, Senator, Title
from rorapp.tests.action_helper import (
from rorapp.models import Action, Faction, Senator, Title
from rorapp.tests.test_helper import (
check_latest_phase,
check_old_actions_deleted,
check_all_actions,
get_and_check_actions,
submit_actions,
)


Expand All @@ -23,15 +22,28 @@ def test_faction_phase(self) -> None:
for player_count in range(3, 7):
self.do_faction_phase_test(player_count)

def action_processor(self, action: Action) -> dict:
faction = Faction.objects.filter(player=action.faction.player.id).get(
game=action.faction.game.id
)
senators = Senator.objects.filter(faction=faction).order_by("name")
first_senator = senators[0]
return {"leader_id": first_senator.id}

def do_faction_phase_test(self, player_count: int) -> None:
game_id = self.setup_game_in_faction_phase(player_count)
self.check_latest_phase(game_id, 1, "Faction")
check_latest_phase(self, game_id, "Faction", 1)
potential_actions_for_all_players = get_and_check_actions(
self, game_id, False, "select_faction_leader", player_count
)
self.submit_actions(game_id, player_count, potential_actions_for_all_players)
submit_actions(
self,
game_id,
potential_actions_for_all_players,
self.action_processor,
)
self.check_faction_leader_titles(game_id, player_count)
self.check_latest_phase(game_id, 2, "Mortality")
check_latest_phase(self, game_id, "Mortality", 2)
check_old_actions_deleted(self, game_id)

def setup_game_in_faction_phase(self, player_count: int) -> int:
Expand All @@ -41,56 +53,6 @@ def setup_game_in_faction_phase(self, player_count: int) -> int:
self.assertEqual(Faction.objects.filter(game=game_id).count(), player_count)
return game_id

def check_latest_phase(
self,
game_id: int,
expected_phase_count: int,
expected_latest_phase_name: str,
) -> None:
phases = Phase.objects.filter(turn__game=game_id)
self.assertEqual(phases.count(), expected_phase_count)
latest_phase = phases[len(phases) - 1]
self.assertEqual(latest_phase.name, expected_latest_phase_name)

def submit_actions(
self,
game_id: int,
player_count: int,
potential_actions_for_all_players: List[Action],
) -> None:
for player_number in range(1, player_count + 1):
self.submit_action(
player_number, game_id, potential_actions_for_all_players
)

def submit_action(
self,
player_number: int,
game_id: int,
potential_actions_for_all_players: List[Action],
) -> None:
user = User.objects.get(username=f"TestUser{player_number}")
faction = Faction.objects.filter(player__user=user).get(game=game_id)
potential_actions = potential_actions_for_all_players.filter(faction=faction)
self.assertEqual(len(potential_actions), 1)
potential_action = potential_actions[0]
senators = Senator.objects.filter(faction=faction).order_by("name")
first_senator = senators[0]

self.client.force_authenticate(user=user)
response = self.client.post(
f"/api/games/{game_id}/submit-action/{potential_action.id}/",
data={"leader_id": first_senator.id},
)
self.assertEqual(response.status_code, 200)
check_all_actions(
self,
game_id,
"select_faction_leader",
player_number,
len(potential_actions_for_all_players),
)

def check_faction_leader_titles(self, game_id: int, player_count: int) -> None:
titles = Title.objects.filter(
senator__faction__game=game_id, name="Faction Leader"
Expand Down
91 changes: 91 additions & 0 deletions backend/rorapp/tests/forum_phase_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import random
from typing import List
from django.test import TestCase
from rest_framework.test import APIClient
from rorapp.functions import delete_all_games, generate_game, start_game
from rorapp.functions.faction_leader_helper import set_faction_leader
from rorapp.functions.forum_phase_starter import start_forum_phase
from rorapp.models import Action, Faction, Senator, Title
from rorapp.tests.test_helper import (
check_latest_phase,
check_old_actions_deleted,
get_and_check_actions,
submit_actions,
)


class ForumPhaseTests(TestCase):
"""
Ensure that players can select their faction leader during the forum phase.
"""

def test_forum_phase(self) -> None:
self.client = APIClient()
delete_all_games()
for player_count in range(3, 7):
self.do_forum_phase_test(player_count)

def action_processor(self, action: Action) -> dict:
faction = Faction.objects.filter(player=action.faction.player.id).get(
game=action.faction.game.id
)
senators = Senator.objects.filter(faction=faction).order_by("name")
first_senator = senators[0]
return {"leader_id": first_senator.id}

def do_forum_phase_test(self, player_count: int) -> None:
random.seed(1)
game_id, faction_ids_with_leadership = self.setup_game_in_forum_phase(player_count)
for _ in range(0, player_count):
check_latest_phase(self, game_id, "Forum")
potential_actions = get_and_check_actions(
self, game_id, False, "select_faction_leader", 1
)
self.assertEqual(len(potential_actions), 1)
faction_leader_titles = Title.objects.filter(
name="Faction Leader",
senator__faction=potential_actions[0].faction,
end_step=None
)

# If the faction already has a leader, then there should be no existing faction leader title.
self.assertEqual(len(faction_leader_titles), 1 if potential_actions[0].faction.id in faction_ids_with_leadership else 0)
submit_actions(
self,
game_id,
potential_actions,
self.action_processor,
)
self.assertEqual(len(potential_actions), 1)
faction_leader_titles = Title.objects.filter(
name="Faction Leader",
senator__faction=potential_actions[0].faction,
end_step=None
)
self.assertEqual(len(faction_leader_titles), 1)
check_latest_phase(self, game_id, "Mortality")
check_old_actions_deleted(self, game_id)

def setup_game_in_forum_phase(self, player_count: int) -> (int, List[int]):
game_id = generate_game(player_count)
start_game(game_id)
faction_ids_with_leadership = set_some_faction_leaders(game_id)
start_forum_phase(game_id)
return (game_id, faction_ids_with_leadership)

def set_some_faction_leaders(game_id: int) -> List[int]:
"""
Assigns faction leader titles to 2 senators then returns their faction IDs.
"""
factions = Faction.objects.filter(game=game_id)
first_faction = factions.first()
second_faction = factions.last()
senator_in_faction_1 = Senator.objects.filter(game=game_id, faction=first_faction).first()
senator_in_faction_2 = Senator.objects.filter(game=game_id, faction=second_faction).first()
set_faction_leader(senator_in_faction_1.id)
set_faction_leader(senator_in_faction_2.id)
return [
senator_in_faction_1.faction.id,
senator_in_faction_2.faction.id,
]

Loading

0 comments on commit 0207474

Please sign in to comment.