+52 IT/UT to close IT/UT-only coverage gaps (93% → 96%) — full suite 983 tests in 47s ; UTs in epic/tests/unit/test_models.py — TarotCardEmanationForTest (4) covers emanation_for(polarity) w. levity/gravity overrides + fallback to name_title for cards w.o a polarity split (cards 48-49 are the only polarity-split cards in the deck so this method is sparsely exercised by ITs); TarotCardReversalForTest (4) covers reversal_for(polarity) w. polarity-split + reversal_qualifier fallback + further fallthrough to emanation_for; TarotCardNameSplitTest (4) covers name_group/name_title colon-split parsing (prefix-w-colon / suffix / no-colon edge); TarotCardCautionsJsonTest (2) covers the cautions_json JSON serialiser ; UTs in epic/tests/unit/test_utils.py — PlanetHouseFallbackTest +1 happy-path test (degree=15 lands in house 1 w. sequential cusps) for the normal cusp-match branch alongside the existing pathological fallback test; TopCapacitorsTest (6) covers all top_capacitors() branches — empty dict / None / all-zero counts (the L56 max(counts.values()) <= 0 fallback that was uncovered) / single-winner / tie-clockwise-order / enriched dict {"count":N} input shape ; ITs in epic/tests/integrated/test_models.py — TarotDeckDrawTest extended w. 5 tests for remaining_count (happy + no-deck-variant fallback to 0) + draw() happy-path (returns n tuples of (TarotCard, bool) / appends to drawn_card_ids / never repeats cards across consecutive draws); existing ValueError + shuffle tests preserved ; ITs in epic/tests/integrated/test_views.py — SigEventRetractionTest (4 tests) covers the three data["retracted"] = True paths that the FT test_game_room_select_sig.py walks transitively but no IT pins directly: sig_unready retracts prior SIG_READY (L937), sig_ready retracts prior SIG_UNREADY (L907), sig_reserve action=release while ready retracts prior SIG_READY + records fresh SIG_UNREADY (L823); SigReserveInvalidCardIdTest (1) covers TarotCard.DoesNotExist → 400 (L840-841) ; SigSelectGravityContextTest (3) covers the user_polarity = 'gravity' branch (L322) + the gravity_sig_cards lookup (L357) — all existing SIG_SELECT context tests use the founder-as-PC-levity setup so these branches sat uncovered; logs in as gamers[5] (BC role) + asserts user_polarity + sig_cards match gravity_sig_cards() output ; SeaDeckViewTest (7) mirrors the test_game_room_select_sea.py FT but isolates the JSON contract — covers 403 when unseated, empty halves when seat has no deck_variant (L1255-1256 early-out), two-halves shape, ~even split, card_dict keys (id/name/arcana/corner_rank/suit_icon/name_group/name_title/reversed/qualifiers), reversed field is bool, claimed-significator exclusion via room.table_seats.exclude(significator__isnull=True) ; ITs in dashboard/tests/integrated/test_views.py — ProfileViewTest +2 (reserved-handle "adman" rejection — L116-117: username stays unchanged + redirect to /); KitBagViewTest (3) covers the kit_bag view's panel render w. TITHE-sort branch (L169-175) + login guard ; ITs in dashboard/tests/integrated/test_sky_views.py — SkyViewTest +2 (saved birth datetime renders in user's sky_birth_tz via astimezone L300-306 — 16:00 UTC → 12:00 EDT; invalid-tz string triggers ZoneInfoNotFoundError → swallowed pass → UTC fallback at 16:00) ; ITs in gameboard/tests/integrated/test_views.py — EquipTrinketViewTest +2 (POST equips trinket + returns 204 — L83-85; non-owner POST returns 404 via get_object_or_404); UnequipTrinketViewTest +2 (POST clears matching equipped_trinket — L107-110; POST of non-matching token is a 204 no-op, the implicit else branch) ; .coveragerc omit gains */reset_staging_db.py per user — mgmt cmd was the only 0%-stmt module that wasn't exercised by tests at all + we agreed it's deliberately untested staging-side code ; palette-monochrome-dark rebalance in rootvars.scss — --quiUser/--sixUser/--sepUser remapped to (secAg / quaAg / priPt) instead of (quaAg / terAg / secAg), shifting the secondary/subtle/deep-subtle anchors up the silver gradient so the palette reads more cleanly under the new sig-stage card colours from 3242873 ; uncovered remnants from earlier analysis intentionally left in place — consumers.py at 68% (channels-tag tests excluded; would need --tag=channels run), Carte Blanche slot navigation + sky_dice + tarot_deck preview view paths (the "bigger investments" tier from session triage; FT-covered + the IT setup is heavier than the immediate value), defensive except fallbacks that need contrived inputs to fire, and a handful of __str__s/pass branches not worth a test apiece — TDD
Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -649,6 +649,57 @@ class TarotDeckDrawTest(TestCase):
|
||||
td.refresh_from_db()
|
||||
self.assertEqual(td.drawn_card_ids, [])
|
||||
|
||||
def test_remaining_count_subtracts_drawn_from_total(self):
|
||||
from apps.epic.models import TarotDeck
|
||||
deck_variant = DeckVariant.objects.first()
|
||||
td = TarotDeck.objects.create(
|
||||
room=self.room,
|
||||
deck_variant=deck_variant,
|
||||
drawn_card_ids=[],
|
||||
)
|
||||
self.assertEqual(td.remaining_count, deck_variant.card_count)
|
||||
td.drawn_card_ids = list(
|
||||
TarotCard.objects.filter(deck_variant=deck_variant).values_list('id', flat=True)[:5]
|
||||
)
|
||||
td.save()
|
||||
self.assertEqual(td.remaining_count, deck_variant.card_count - 5)
|
||||
|
||||
def test_remaining_count_zero_when_no_deck_variant(self):
|
||||
from apps.epic.models import TarotDeck
|
||||
td = TarotDeck.objects.create(room=self.room, deck_variant=None)
|
||||
self.assertEqual(td.remaining_count, 0)
|
||||
|
||||
def test_draw_returns_n_tuples_of_card_and_bool(self):
|
||||
from apps.epic.models import TarotDeck
|
||||
deck_variant = DeckVariant.objects.first()
|
||||
td = TarotDeck.objects.create(room=self.room, deck_variant=deck_variant)
|
||||
drawn = td.draw(3)
|
||||
self.assertEqual(len(drawn), 3)
|
||||
for card, is_reversed in drawn:
|
||||
self.assertIsInstance(card, TarotCard)
|
||||
self.assertIsInstance(is_reversed, bool)
|
||||
|
||||
def test_draw_appends_card_ids_to_drawn_card_ids(self):
|
||||
from apps.epic.models import TarotDeck
|
||||
deck_variant = DeckVariant.objects.first()
|
||||
td = TarotDeck.objects.create(room=self.room, deck_variant=deck_variant)
|
||||
drawn = td.draw(4)
|
||||
td.refresh_from_db()
|
||||
self.assertEqual(len(td.drawn_card_ids), 4)
|
||||
for card, _ in drawn:
|
||||
self.assertIn(card.id, td.drawn_card_ids)
|
||||
|
||||
def test_draw_excludes_already_drawn_cards(self):
|
||||
"""Subsequent draws never repeat cards from the existing drawn_card_ids."""
|
||||
from apps.epic.models import TarotDeck
|
||||
deck_variant = DeckVariant.objects.first()
|
||||
td = TarotDeck.objects.create(room=self.room, deck_variant=deck_variant)
|
||||
first = td.draw(5)
|
||||
first_ids = {card.id for card, _ in first}
|
||||
second = td.draw(5)
|
||||
second_ids = {card.id for card, _ in second}
|
||||
self.assertFalse(first_ids & second_ids)
|
||||
|
||||
|
||||
# ── sig_deck_cards with no equipped deck ─────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user