+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
All checks were successful
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline was successful

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:
Disco DeDisco
2026-05-18 01:07:13 -04:00
parent 3242873625
commit bc77296dd4
9 changed files with 526 additions and 4 deletions

View File

@@ -1,6 +1,6 @@
from django.test import SimpleTestCase
from apps.epic.utils import _planet_house
from apps.epic.utils import _planet_house, top_capacitors
class PlanetHouseFallbackTest(SimpleTestCase):
@@ -11,3 +11,44 @@ class PlanetHouseFallbackTest(SimpleTestCase):
# the fallback `return 1`.
cusps = [0.0] * 12
self.assertEqual(_planet_house(180.0, cusps), 1)
def test_returns_1_when_degree_in_first_house_normal(self):
# Standard, sequential cusps: degree=15 should land in house 1 (030).
cusps = [i * 30.0 for i in range(12)]
self.assertEqual(_planet_house(15.0, cusps), 1)
class TopCapacitorsTest(SimpleTestCase):
"""top_capacitors — capacitor names tied for the highest element count."""
def test_returns_empty_when_elements_is_empty(self):
self.assertEqual(top_capacitors({}), [])
def test_returns_empty_when_elements_is_none(self):
self.assertEqual(top_capacitors(None), [])
def test_returns_empty_when_all_counts_are_zero(self):
"""All-zero counts (e.g. a brand-new chart with no planets) → empty list,
not an Ardor-by-default. Exercises the `max(counts.values()) <= 0` branch."""
self.assertEqual(
top_capacitors({"Fire": 0, "Stone": 0, "Time": 0, "Space": 0, "Air": 0, "Water": 0}),
[],
)
def test_returns_single_top_capacitor_when_one_element_wins(self):
# Stone has highest count → Ossum
result = top_capacitors({"Fire": 1, "Stone": 5, "Time": 2})
self.assertEqual(result, ["Ossum"])
def test_returns_multiple_capacitors_on_tie_in_clockwise_order(self):
# Fire + Stone tied at 3 → order follows ELEMENT_ORDER (Fire first).
result = top_capacitors({"Fire": 3, "Stone": 3, "Time": 2})
self.assertEqual(result, ["Ardor", "Ossum"])
def test_accepts_dict_values_with_count_key(self):
"""`elements` may carry enriched dicts like {"count": N, ...}."""
result = top_capacitors({
"Fire": {"count": 1, "sign": "Aries"},
"Stone": {"count": 4, "sign": "Taurus"},
})
self.assertEqual(result, ["Ossum"])