fix shadowed test classes restoring 41 dead tests; add missing coverage

SigReserveViewTest, SigReadyViewTest, SigConfirmViewTest each defined twice
in test_views.py — second (shorter) definition silently shadowed the first
comprehensive set, so ~180 lines of tests never ran.

- remove three duplicate class definitions (lines 1648–1749)
- absorb unique tests from shadowed copies: non-POST 405 guards for all
  three views; idempotent-ready path; invalid seconds_remaining fallback
- add test_release_while_ready_records_sig_unready (lines 667–679)
- add TarotDealViewTest for tarot_deal non-POST redirect (line 904)
- 609 → 650 tests, all green

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-04-21 15:56:36 -04:00
parent ebc460fe67
commit 04f0e87eba

View File

@@ -1265,8 +1265,23 @@ class SigReserveViewTest(TestCase):
response = self._reserve(action="release") response = self._reserve(action="release")
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_release_while_ready_records_sig_unready(self):
"""Releasing a ready reservation implicitly acts as WAIT NVM and records SIG_UNREADY."""
self._reserve()
res = SigReservation.objects.get(room=self.room, gamer=self.gamers[0])
res.ready = True
res.save()
self._reserve(action="release")
self.assertTrue(self.room.events.filter(
actor=self.gamers[0], verb=GameEvent.SIG_UNREADY
).exists())
# ── guards ──────────────────────────────────────────────────────────── # ── guards ────────────────────────────────────────────────────────────
def test_reserve_non_post_returns_405(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 405)
def test_reserve_requires_login(self): def test_reserve_requires_login(self):
self.client.logout() self.client.logout()
response = self._reserve() response = self._reserve()
@@ -1348,6 +1363,10 @@ class SigReadyViewTest(TestCase):
# ── guards ──────────────────────────────────────────────────────────── # ── guards ────────────────────────────────────────────────────────────
def test_sig_ready_non_post_returns_405(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 405)
def test_sig_ready_requires_login(self): def test_sig_ready_requires_login(self):
self.client.logout() self.client.logout()
response = self._post() response = self._post()
@@ -1384,6 +1403,13 @@ class SigReadyViewTest(TestCase):
response = self._post(action="ready") response = self._post(action="ready")
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_sig_ready_already_ready_is_idempotent(self):
"""Re-posting ready when already ready returns 200 without re-triggering countdown."""
self.reservations[0].ready = True
self.reservations[0].save()
response = self._post(action="ready")
self.assertEqual(response.status_code, 200)
# ── unready ────────────────────────────────────────────────────────── # ── unready ──────────────────────────────────────────────────────────
def test_sig_unready_sets_ready_false(self): def test_sig_unready_sets_ready_false(self):
@@ -1419,6 +1445,14 @@ class SigReadyViewTest(TestCase):
self._post(action="ready") self._post(action="ready")
mock_notify.assert_not_called() mock_notify.assert_not_called()
def test_sig_unready_invalid_seconds_defaults_to_12(self):
"""Non-numeric seconds_remaining falls back to 12."""
self.reservations[0].ready = True
self.reservations[0].save()
self._post(action="unready", seconds_remaining="abc")
self.reservations[0].refresh_from_db()
self.assertEqual(self.reservations[0].countdown_remaining, 12)
def test_sig_unready_saves_seconds_remaining_on_all_polarity_reservations(self): def test_sig_unready_saves_seconds_remaining_on_all_polarity_reservations(self):
for res in self.reservations: for res in self.reservations:
res.ready = True res.ready = True
@@ -1493,6 +1527,10 @@ class SigConfirmViewTest(TestCase):
# ── guards ──────────────────────────────────────────────────────────── # ── guards ────────────────────────────────────────────────────────────
def test_sig_confirm_non_post_returns_405(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 405)
def test_sig_confirm_requires_login(self): def test_sig_confirm_requires_login(self):
self.client.logout() self.client.logout()
response = self._post() response = self._post()
@@ -1645,108 +1683,6 @@ def _make_sig_room(owner, *extra_gamers):
return room, seat_map return room, seat_map
class SigReserveViewTest(TestCase):
def setUp(self):
self.user = User.objects.create(email="pc@sig.io")
self.client.force_login(self.user)
self.room, self.seats = _make_sig_room(self.user)
self.card = TarotCard.objects.first()
def test_non_post_returns_405(self):
response = self.client.get(reverse("epic:sig_reserve", kwargs={"room_id": self.room.id}))
self.assertEqual(response.status_code, 405)
def test_reserve_action_succeeds(self):
response = self.client.post(
reverse("epic:sig_reserve", kwargs={"room_id": self.room.id}),
{"action": "reserve", "card_id": str(self.card.pk)},
)
self.assertEqual(response.status_code, 200)
self.assertTrue(SigReservation.objects.filter(room=self.room, gamer=self.user).exists())
def test_release_action_removes_reservation(self):
SigReservation.objects.create(
room=self.room, gamer=self.user, card=self.card,
polarity=SigReservation.LEVITY, seat=self.seats["PC"],
)
response = self.client.post(
reverse("epic:sig_reserve", kwargs={"room_id": self.room.id}),
{"action": "release"},
)
self.assertEqual(response.status_code, 200)
self.assertFalse(SigReservation.objects.filter(room=self.room, gamer=self.user).exists())
class SigReadyViewTest(TestCase):
def setUp(self):
self.user = User.objects.create(email="pc@ready.io")
self.client.force_login(self.user)
self.room, self.seats = _make_sig_room(self.user)
self.card = (
TarotCard.objects.filter(arcana=TarotCard.MIDDLE).first()
or TarotCard.objects.first()
)
self.res = SigReservation.objects.create(
room=self.room, gamer=self.user, card=self.card,
polarity=SigReservation.LEVITY, seat=self.seats["PC"],
)
def test_non_post_returns_405(self):
response = self.client.get(reverse("epic:sig_ready", kwargs={"room_id": self.room.id}))
self.assertEqual(response.status_code, 405)
def test_ready_action_sets_ready_flag(self):
response = self.client.post(
reverse("epic:sig_ready", kwargs={"room_id": self.room.id}),
{"action": "ready"},
)
self.assertEqual(response.status_code, 200)
self.res.refresh_from_db()
self.assertTrue(self.res.ready)
def test_ready_action_idempotent_when_already_ready(self):
self.res.ready = True
self.res.save()
response = self.client.post(
reverse("epic:sig_ready", kwargs={"room_id": self.room.id}),
{"action": "ready"},
)
self.assertEqual(response.status_code, 200)
def test_unready_action_saves_seconds_remaining(self):
self.res.ready = True
self.res.save()
response = self.client.post(
reverse("epic:sig_ready", kwargs={"room_id": self.room.id}),
{"action": "unready", "seconds_remaining": "7"},
)
self.assertEqual(response.status_code, 200)
self.res.refresh_from_db()
self.assertEqual(self.res.countdown_remaining, 7)
def test_unready_action_handles_invalid_seconds_remaining(self):
self.res.ready = True
self.res.save()
response = self.client.post(
reverse("epic:sig_ready", kwargs={"room_id": self.room.id}),
{"action": "unready", "seconds_remaining": "abc"},
)
self.assertEqual(response.status_code, 200)
self.res.refresh_from_db()
self.assertEqual(self.res.countdown_remaining, 12)
class SigConfirmViewTest(TestCase):
def setUp(self):
self.user = User.objects.create(email="pc@confirm.io")
self.client.force_login(self.user)
self.room, self.seats = _make_sig_room(self.user)
def test_non_post_returns_405(self):
response = self.client.get(reverse("epic:sig_confirm", kwargs={"room_id": self.room.id}))
self.assertEqual(response.status_code, 405)
class SelectSigViewTest(TestCase): class SelectSigViewTest(TestCase):
def setUp(self): def setUp(self):
self.user = User.objects.create(email="pc@selsig.io") self.user = User.objects.create(email="pc@selsig.io")
@@ -1838,6 +1774,25 @@ class NatusPreviewViewTest(TestCase):
self.assertNotIn("Earth", data["elements"]) self.assertNotIn("Earth", data["elements"])
# ── tarot_deal ────────────────────────────────────────────────────────────────
class TarotDealViewTest(TestCase):
def setUp(self):
self.user = User.objects.create(email="dealer@test.io")
self.client.force_login(self.user)
self.room, _ = _make_sig_room(self.user)
def test_non_post_redirects_to_tarot_deck(self):
response = self.client.get(
reverse("epic:tarot_deal", kwargs={"room_id": self.room.id})
)
self.assertRedirects(
response,
reverse("epic:tarot_deck", kwargs={"room_id": self.room.id}),
fetch_redirect_response=False,
)
# ── natus_save (epic) ───────────────────────────────────────────────────────── # ── natus_save (epic) ─────────────────────────────────────────────────────────
class NatusSaveViewTest(TestCase): class NatusSaveViewTest(TestCase):