217 lines
8.4 KiB
Python
217 lines
8.4 KiB
Python
from datetime import timedelta
|
|
from django.db.models import Q
|
|
from django.test import TestCase
|
|
from django.urls import reverse
|
|
from django.utils import timezone
|
|
|
|
from apps.lyric.models import Token, User
|
|
from apps.epic.models import GateSlot, Room, RoomInvite, TableSeat, debit_token, select_token
|
|
|
|
|
|
class RoomCreationTest(TestCase):
|
|
def test_creating_a_room_generates_six_gate_slots(self):
|
|
owner = User.objects.create(email="founder@example.com")
|
|
room = Room.objects.create(name="Test Room", owner=owner)
|
|
self.assertEqual(GateSlot.objects.filter(room=room).count(), 6)
|
|
|
|
|
|
class DebitTokenTest(TestCase):
|
|
def setUp(self):
|
|
self.owner = User.objects.create(email="founder@example.com")
|
|
self.room = Room.objects.create(
|
|
name="Test Room",
|
|
owner=self.owner,
|
|
renewal_period=timedelta(days=7)
|
|
)
|
|
self.slot = self.room.gate_slots.get(slot_number=1)
|
|
|
|
def test_debit_free_token_consumes_token_and_fills_slot(self):
|
|
free_token = Token.objects.get(user=self.owner, token_type=Token.FREE)
|
|
debit_token(self.owner, self.slot, free_token)
|
|
self.assertFalse(Token.objects.filter(pk=free_token.pk).exists())
|
|
self.slot.refresh_from_db()
|
|
self.assertEqual(self.slot.status, GateSlot.FILLED)
|
|
self.assertEqual(self.slot.gamer, self.owner)
|
|
|
|
def test_debit_coin_does_not_consume_token(self):
|
|
coin_token = Token.objects.get(user=self.owner, token_type=Token.COIN)
|
|
debit_token(self.owner, self.slot, coin_token)
|
|
self.assertTrue(Token.objects.filter(pk=coin_token.pk).exists())
|
|
self.slot.refresh_from_db()
|
|
self.assertEqual(self.slot.status, GateSlot.FILLED)
|
|
self.assertEqual(self.slot.gamer, self.owner)
|
|
|
|
def test_debit_fills_last_slot_and_opens_gate(self):
|
|
for i in range(2, 7):
|
|
gamer = User.objects.create(email=f"g{i}@test.io")
|
|
slot = self.room.gate_slots.get(slot_number=i)
|
|
slot.gamer = gamer
|
|
slot.status = GateSlot.FILLED
|
|
slot.save()
|
|
free_token = Token.objects.get(user=self.owner, token_type=Token.FREE)
|
|
debit_token(self.owner, self.slot, free_token)
|
|
self.room.refresh_from_db()
|
|
self.assertEqual(self.room.gate_status, Room.OPEN)
|
|
|
|
|
|
class CoinTokenInUseTest(TestCase):
|
|
def setUp(self):
|
|
self.owner = User.objects.create(email="founder@example.com")
|
|
self.room = Room.objects.create(
|
|
name="Dragon's Den",
|
|
owner=self.owner,
|
|
renewal_period=timedelta(days=7),
|
|
)
|
|
self.slot = self.room.gate_slots.get(slot_number=1)
|
|
self.coin = Token.objects.get(user=self.owner, token_type=Token.COIN)
|
|
debit_token(self.owner, self.slot, self.coin)
|
|
self.coin.refresh_from_db()
|
|
|
|
def test_coin_tooltip_expiry_shows_next_ready_date(self):
|
|
expected_date = self.coin.next_ready_at.strftime("%Y-%m-%d")
|
|
self.assertIn(expected_date, self.coin.tooltip_expiry())
|
|
|
|
def test_coin_tooltip_room_html_contains_anchor(self):
|
|
room_url = reverse("epic:gatekeeper", kwargs={"room_id": self.room.id})
|
|
html = self.coin.tooltip_room_html()
|
|
self.assertIn(f'href="{room_url}"', html)
|
|
self.assertIn(self.room.name, html)
|
|
|
|
|
|
class SelectTokenTest(TestCase):
|
|
def setUp(self):
|
|
self.user = User.objects.create(email="gamer@test.io")
|
|
self.other_room = Room.objects.create(name="Other Room", owner=self.user)
|
|
self.coin = Token.objects.get(user=self.user, token_type=Token.COIN)
|
|
|
|
def test_returns_coin_when_available(self):
|
|
token = select_token(self.user)
|
|
self.assertEqual(token.token_type, Token.COIN)
|
|
|
|
def test_returns_free_token_when_coin_in_use(self):
|
|
self.coin.current_room = self.other_room
|
|
self.coin.save()
|
|
token = select_token(self.user)
|
|
self.assertEqual(token.token_type, Token.FREE)
|
|
|
|
def test_free_token_selection_is_fefo(self):
|
|
self.coin.current_room = self.other_room
|
|
self.coin.save()
|
|
Token.objects.filter(user=self.user, token_type=Token.FREE).delete()
|
|
soon = Token.objects.create(
|
|
user=self.user, token_type=Token.FREE,
|
|
expires_at=timezone.now() + timedelta(days=2),
|
|
)
|
|
Token.objects.create(
|
|
user=self.user, token_type=Token.FREE,
|
|
expires_at=timezone.now() + timedelta(days=6),
|
|
)
|
|
token = select_token(self.user)
|
|
self.assertEqual(token.pk, soon.pk)
|
|
|
|
def test_returns_tithe_when_coin_in_use_and_no_free_tokens(self):
|
|
self.coin.current_room = self.other_room
|
|
self.coin.save()
|
|
Token.objects.filter(user=self.user, token_type=Token.FREE).delete()
|
|
tithe = Token.objects.create(user=self.user, token_type=Token.TITHE)
|
|
token = select_token(self.user)
|
|
self.assertEqual(token.pk, tithe.pk)
|
|
|
|
def test_returns_none_when_all_depleted(self):
|
|
self.coin.current_room = self.other_room
|
|
self.coin.save()
|
|
Token.objects.filter(user=self.user, token_type=Token.FREE).delete()
|
|
token = select_token(self.user)
|
|
self.assertIsNone(token)
|
|
|
|
def test_returns_pass_for_staff(self):
|
|
self.user.is_staff = True
|
|
self.user.save()
|
|
pass_token = Token.objects.create(user=self.user, token_type=Token.PASS)
|
|
token = select_token(self.user)
|
|
self.assertEqual(token.token_type, Token.PASS)
|
|
|
|
|
|
class RoomTableStatusTest(TestCase):
|
|
def setUp(self):
|
|
self.owner = User.objects.create(email="founder@test.io")
|
|
self.room = Room.objects.create(name="Test Room", owner=self.owner)
|
|
|
|
def test_table_status_defaults_to_blank(self):
|
|
self.room.refresh_from_db()
|
|
self.assertFalse(self.room.table_status)
|
|
|
|
def test_room_has_role_select_constant(self):
|
|
self.assertEqual(Room.ROLE_SELECT, "ROLE_SELECT")
|
|
|
|
def test_room_has_sig_select_constant(self):
|
|
self.assertEqual(Room.SIG_SELECT, "SIG_SELECT")
|
|
|
|
def test_room_has_in_game_constant(self):
|
|
self.assertEqual(Room.IN_GAME, "IN_GAME")
|
|
|
|
def test_table_status_accepts_role_select(self):
|
|
self.room.table_status = Room.ROLE_SELECT
|
|
self.room.save()
|
|
self.room.refresh_from_db()
|
|
self.assertEqual(self.room.table_status, Room.ROLE_SELECT)
|
|
|
|
|
|
class TableSeatModelTest(TestCase):
|
|
def setUp(self):
|
|
self.owner = User.objects.create(email="founder@test.io")
|
|
self.room = Room.objects.create(name="Test Room", owner=self.owner)
|
|
|
|
def test_table_seat_can_be_created(self):
|
|
seat = TableSeat.objects.create(
|
|
room=self.room,
|
|
gamer=self.owner,
|
|
slot_number=1,
|
|
)
|
|
self.assertEqual(seat.slot_number, 1)
|
|
self.assertIsNone(seat.role)
|
|
self.assertFalse(seat.role_revealed)
|
|
self.assertIsNone(seat.seat_position)
|
|
|
|
def test_table_seat_role_choices_cover_all_six(self):
|
|
role_codes = [c[0] for c in TableSeat.ROLE_CHOICES]
|
|
for code in ["PC", "BC", "SC", "AC", "NC", "EC"]:
|
|
self.assertIn(code, role_codes)
|
|
|
|
def test_partner_map_pairs_are_mutual(self):
|
|
for a, b in [(TableSeat.PC, TableSeat.BC), (TableSeat.SC, TableSeat.AC), (TableSeat.NC, TableSeat.EC)]:
|
|
self.assertEqual(TableSeat.PARTNER_MAP[a], b)
|
|
self.assertEqual(TableSeat.PARTNER_MAP[b], a)
|
|
|
|
def test_room_table_seats_reverse_relation(self):
|
|
TableSeat.objects.create(room=self.room, gamer=self.owner, slot_number=1)
|
|
self.assertEqual(self.room.table_seats.count(), 1)
|
|
|
|
|
|
class RoomInviteTest(TestCase):
|
|
def setUp(self):
|
|
self.founder = User.objects.create(email="founder@example.com")
|
|
self.room = Room.objects.create(name="Dragon's Den", owner=self.founder)
|
|
|
|
def test_founder_can_invite_by_email(self):
|
|
invite = RoomInvite.objects.create(
|
|
room=self.room,
|
|
inviter=self.founder,
|
|
invitee_email="friend@example.com",
|
|
)
|
|
self.assertEqual(invite.status, RoomInvite.PENDING)
|
|
|
|
def test_invited_room_appears_in_my_games_queryset(self):
|
|
friend = User.objects.create(email="friend@example.com")
|
|
RoomInvite.objects.create(
|
|
room=self.room,
|
|
inviter=self.founder,
|
|
invitee_email=friend.email,
|
|
)
|
|
rooms = Room.objects.filter(
|
|
Q(owner=friend) |
|
|
Q(gate_slots__gamer=friend) |
|
|
Q(invites__invitee_email=friend.email, invites__status=RoomInvite.PENDING)
|
|
).distinct()
|
|
self.assertIn(self.room, rooms)
|