hopefully plugged pipeline fail for FT to assert stock card deck version; 11 new test_models ITs & 12 new test_views ITs in apps.epic.tests
This commit is contained in:
@@ -5,7 +5,10 @@ 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
|
||||
from apps.epic.models import (
|
||||
DeckVariant, GateSlot, Room, RoomInvite, TableSeat, TarotCard,
|
||||
debit_token, select_token, sig_deck_cards, sig_seat_order, active_sig_seat,
|
||||
)
|
||||
|
||||
|
||||
class RoomCreationTest(TestCase):
|
||||
@@ -214,3 +217,168 @@ class RoomInviteTest(TestCase):
|
||||
Q(invites__invitee_email=friend.email, invites__status=RoomInvite.PENDING)
|
||||
).distinct()
|
||||
self.assertIn(self.room, rooms)
|
||||
|
||||
|
||||
# ── Significator deck helpers ─────────────────────────────────────────────────
|
||||
|
||||
SIG_SEAT_ORDER = ["PC", "NC", "EC", "SC", "AC", "BC"]
|
||||
|
||||
|
||||
def _make_sig_cards(deck):
|
||||
"""Create the 18 unique TarotCard types used in the Significator deck."""
|
||||
for suit in ["WANDS", "CUPS", "SWORDS", "PENTACLES"]:
|
||||
for number, court in [(11, "Maid"), (12, "Jack"), (13, "Queen"), (14, "King")]:
|
||||
TarotCard.objects.create(
|
||||
deck_variant=deck, arcana="MINOR", suit=suit, number=number,
|
||||
name=f"{court} of {suit.capitalize()}",
|
||||
slug=f"{court.lower()}-of-{suit.lower()}-em",
|
||||
keywords_upright=[], keywords_reversed=[],
|
||||
)
|
||||
TarotCard.objects.create(
|
||||
deck_variant=deck, arcana="MAJOR", number=0,
|
||||
name="The Schiz", slug="the-schiz",
|
||||
keywords_upright=[], keywords_reversed=[],
|
||||
)
|
||||
TarotCard.objects.create(
|
||||
deck_variant=deck, arcana="MAJOR", number=1,
|
||||
name="Pope 1: Chancellor", slug="pope-1-chancellor",
|
||||
keywords_upright=[], keywords_reversed=[],
|
||||
)
|
||||
|
||||
|
||||
def _full_sig_room(name="Sig Room", role_order=None):
|
||||
"""Return (room, gamers, earthman) with all 6 seats filled, roles assigned,
|
||||
table_status=SIG_SELECT, and every gamer's equipped_deck set to Earthman."""
|
||||
if role_order is None:
|
||||
role_order = SIG_SEAT_ORDER[:]
|
||||
earthman = DeckVariant.objects.create(
|
||||
slug="earthman", name="Earthman Deck", card_count=108, is_default=True
|
||||
)
|
||||
_make_sig_cards(earthman)
|
||||
owner = User.objects.create(email="founder@sig.io")
|
||||
gamers = [owner]
|
||||
for i in range(2, 7):
|
||||
gamers.append(User.objects.create(email=f"g{i}@sig.io"))
|
||||
for gamer in gamers:
|
||||
gamer.equipped_deck = earthman
|
||||
gamer.save(update_fields=["equipped_deck"])
|
||||
room = Room.objects.create(name=name, owner=owner)
|
||||
for i, (gamer, role) in enumerate(zip(gamers, role_order), start=1):
|
||||
slot = room.gate_slots.get(slot_number=i)
|
||||
slot.gamer = gamer
|
||||
slot.status = GateSlot.FILLED
|
||||
slot.save()
|
||||
TableSeat.objects.create(
|
||||
room=room, gamer=gamer, slot_number=i,
|
||||
role=role, role_revealed=True,
|
||||
)
|
||||
room.table_status = Room.SIG_SELECT
|
||||
room.save()
|
||||
return room, gamers, earthman
|
||||
|
||||
|
||||
class SigDeckCompositionTest(TestCase):
|
||||
"""sig_deck_cards(room) returns exactly 36 cards with correct suit/arcana split."""
|
||||
|
||||
def setUp(self):
|
||||
self.room, self.gamers, self.earthman = _full_sig_room()
|
||||
|
||||
def test_sig_deck_returns_36_cards(self):
|
||||
cards = sig_deck_cards(self.room)
|
||||
self.assertEqual(len(cards), 36)
|
||||
|
||||
def test_sc_ac_contribute_court_cards_of_swords_and_cups(self):
|
||||
cards = sig_deck_cards(self.room)
|
||||
sc_ac = [c for c in cards if c.suit in ("SWORDS", "CUPS")]
|
||||
# M/J/Q/K × 2 suits × 2 roles = 16
|
||||
self.assertEqual(len(sc_ac), 16)
|
||||
self.assertTrue(all(c.number in (11, 12, 13, 14) for c in sc_ac))
|
||||
|
||||
def test_pc_bc_contribute_court_cards_of_wands_and_pentacles(self):
|
||||
cards = sig_deck_cards(self.room)
|
||||
pc_bc = [c for c in cards if c.suit in ("WANDS", "PENTACLES")]
|
||||
self.assertEqual(len(pc_bc), 16)
|
||||
self.assertTrue(all(c.number in (11, 12, 13, 14) for c in pc_bc))
|
||||
|
||||
def test_nc_ec_contribute_schiz_and_chancellor(self):
|
||||
cards = sig_deck_cards(self.room)
|
||||
major = [c for c in cards if c.arcana == "MAJOR"]
|
||||
self.assertEqual(len(major), 4)
|
||||
self.assertEqual(sorted(c.number for c in major), [0, 0, 1, 1])
|
||||
|
||||
def test_each_card_appears_twice_once_per_pile(self):
|
||||
"""18 unique card specs × 2 (levity + gravity) = 36 total."""
|
||||
cards = sig_deck_cards(self.room)
|
||||
slugs = [c.slug for c in cards]
|
||||
unique_slugs = set(slugs)
|
||||
self.assertEqual(len(unique_slugs), 18)
|
||||
self.assertTrue(all(slugs.count(s) == 2 for s in unique_slugs))
|
||||
|
||||
|
||||
class SigSeatOrderTest(TestCase):
|
||||
"""sig_seat_order() and active_sig_seat() return seats in PC→NC→EC→SC→AC→BC order."""
|
||||
|
||||
def setUp(self):
|
||||
# Assign roles in reverse of canonical order to prove reordering works
|
||||
self.room, self.gamers, _ = _full_sig_room(
|
||||
name="Order Room",
|
||||
role_order=["BC", "AC", "SC", "EC", "NC", "PC"],
|
||||
)
|
||||
|
||||
def test_sig_seat_order_returns_canonical_role_sequence(self):
|
||||
seats = sig_seat_order(self.room)
|
||||
self.assertEqual([s.role for s in seats], SIG_SEAT_ORDER)
|
||||
|
||||
def test_active_sig_seat_is_first_seat_without_significator(self):
|
||||
seat = active_sig_seat(self.room)
|
||||
self.assertEqual(seat.role, "PC")
|
||||
|
||||
def test_active_sig_seat_advances_after_significator_set(self):
|
||||
pc_seat = TableSeat.objects.get(room=self.room, role="PC")
|
||||
earthman = DeckVariant.objects.get(slug="earthman")
|
||||
card = TarotCard.objects.filter(deck_variant=earthman, arcana="MINOR").first()
|
||||
pc_seat.significator = card
|
||||
pc_seat.save()
|
||||
seat = active_sig_seat(self.room)
|
||||
self.assertEqual(seat.role, "NC")
|
||||
|
||||
def test_active_sig_seat_is_none_when_all_chosen(self):
|
||||
earthman = DeckVariant.objects.get(slug="earthman")
|
||||
cards = list(TarotCard.objects.filter(deck_variant=earthman))
|
||||
for i, seat in enumerate(TableSeat.objects.filter(room=self.room)):
|
||||
seat.significator = cards[i]
|
||||
seat.save()
|
||||
self.assertIsNone(active_sig_seat(self.room))
|
||||
|
||||
|
||||
class SigCardFieldTest(TestCase):
|
||||
"""TableSeat.significator FK to TarotCard — default null, assignable."""
|
||||
|
||||
def setUp(self):
|
||||
earthman = DeckVariant.objects.create(
|
||||
slug="earthman", name="Earthman Deck", card_count=108, is_default=True
|
||||
)
|
||||
self.card = TarotCard.objects.create(
|
||||
deck_variant=earthman, arcana="MINOR", suit="WANDS", number=11,
|
||||
name="Maid of Wands", slug="maid-of-wands-em",
|
||||
keywords_upright=[], keywords_reversed=[],
|
||||
)
|
||||
owner = User.objects.create(email="owner@test.io")
|
||||
room = Room.objects.create(name="Field Test", owner=owner)
|
||||
self.seat = TableSeat.objects.create(room=room, gamer=owner, slot_number=1, role="PC")
|
||||
|
||||
def test_significator_defaults_to_none(self):
|
||||
self.assertIsNone(self.seat.significator)
|
||||
|
||||
def test_significator_can_be_assigned(self):
|
||||
self.seat.significator = self.card
|
||||
self.seat.save()
|
||||
self.seat.refresh_from_db()
|
||||
self.assertEqual(self.seat.significator, self.card)
|
||||
|
||||
def test_significator_nullable_on_delete(self):
|
||||
self.seat.significator = self.card
|
||||
self.seat.save()
|
||||
self.card.delete()
|
||||
self.seat.refresh_from_db()
|
||||
self.assertIsNone(self.seat.significator)
|
||||
|
||||
Reference in New Issue
Block a user