from django.test import TestCase from django.db import IntegrityError from apps.drama.models import GameEvent, ScrollPosition, record from apps.epic.models import Room from apps.lyric.models import User class GameEventModelTest(TestCase): def setUp(self): self.user = User.objects.create(email="actor@test.io") self.room = Room.objects.create(name="Test Room", owner=self.user) def test_record_creates_game_event(self): event = record(self.room, GameEvent.SLOT_FILLED, actor=self.user, slot_number=1, token_type="tithe") self.assertEqual(GameEvent.objects.count(), 1) self.assertEqual(event.room, self.room) self.assertEqual(event.actor, self.user) self.assertEqual(event.verb, GameEvent.SLOT_FILLED) self.assertEqual(event.data, {"slot_number": 1, "token_type": "tithe"}) def test_record_without_actor(self): event = record(self.room, GameEvent.ROOM_CREATED) self.assertIsNone(event.actor) self.assertEqual(event.verb, GameEvent.ROOM_CREATED) def test_events_ordered_by_timestamp(self): record(self.room, GameEvent.ROOM_CREATED) record(self.room, GameEvent.SLOT_RESERVED, actor=self.user) record(self.room, GameEvent.SLOT_FILLED, actor=self.user) verbs = list(GameEvent.objects.values_list("verb", flat=True)) self.assertEqual(verbs, [ GameEvent.ROOM_CREATED, GameEvent.SLOT_RESERVED, GameEvent.SLOT_FILLED, ]) def test_str_includes_actor_and_verb(self): event = record(self.room, GameEvent.ROLE_SELECTED, actor=self.user, role="PC") self.assertIn("actor@test.io", str(event)) self.assertIn(GameEvent.ROLE_SELECTED, str(event)) # ── to_prose — ROLE_SELECTED ────────────────────────────────────────── def test_role_selected_prose_uses_ordinal_chair(self): for role, ordinal in [("PC", "1st"), ("NC", "2nd"), ("EC", "3rd"), ("SC", "4th"), ("AC", "5th"), ("BC", "6th")]: with self.subTest(role=role): event = record(self.room, GameEvent.ROLE_SELECTED, actor=self.user, role=role, role_display="") self.assertIn(f"assumes {ordinal} Chair", event.to_prose()) def test_role_selected_prose_includes_role_name(self): event = record(self.room, GameEvent.ROLE_SELECTED, actor=self.user, role="PC", role_display="Player") prose = event.to_prose() self.assertIn("Player", prose) self.assertIn("yo will start the game", prose) # ── to_prose — SIG_READY ───────────────────────────────────────────── def test_sig_ready_prose_embodies_card_with_rank_and_icon(self): event = record(self.room, GameEvent.SIG_READY, actor=self.user, card_name="Maid of Brands", corner_rank="M", suit_icon="fa-wand-sparkles") prose = event.to_prose() self.assertIn("embodies as yos Significator the Maid of Brands", prose) self.assertIn("(M", prose) self.assertIn("fa-wand-sparkles", prose) def test_sig_ready_prose_omits_icon_when_none(self): event = record(self.room, GameEvent.SIG_READY, actor=self.user, card_name="The Wanderer", corner_rank="0", suit_icon="") prose = event.to_prose() self.assertIn("embodies as yos Significator the The Wanderer (0)", prose) self.assertNotIn("fa-", prose) def test_sig_ready_prose_degrades_without_corner_rank(self): # Old events recorded before this change have no corner_rank key event = record(self.room, GameEvent.SIG_READY, actor=self.user, card_name="Maid of Brands") prose = event.to_prose() self.assertIn("embodies as yos Significator the Maid of Brands", prose) self.assertNotIn("(", prose) def test_str_without_actor_shows_system(self): event = record(self.room, GameEvent.ROLES_REVEALED) self.assertIn("system", str(event)) class ScrollPositionModelTest(TestCase): def setUp(self): self.user = User.objects.create(email="reader@test.io") self.room = Room.objects.create(name="Test Room", owner=self.user) def test_can_save_scroll_position(self): sp = ScrollPosition.objects.create(user=self.user, room=self.room, position=150) self.assertEqual(ScrollPosition.objects.count(), 1) self.assertEqual(sp.position, 150) def test_default_position_is_zero(self): sp = ScrollPosition.objects.create(user=self.user, room=self.room) self.assertEqual(sp.position, 0) def test_unique_per_user_and_room(self): ScrollPosition.objects.create(user=self.user, room=self.room, position=50) with self.assertRaises(IntegrityError): ScrollPosition.objects.create(user=self.user, room=self.room, position=100) def test_upsert_updates_existing_position(self): ScrollPosition.objects.create(user=self.user, room=self.room, position=50) ScrollPosition.objects.update_or_create( user=self.user, room=self.room, defaults={"position": 200}, ) self.assertEqual(ScrollPosition.objects.get(user=self.user, room=self.room).position, 200)