Files
python-tdd/src/apps/epic/tests/unit/test_utils.py
Disco DeDisco bc77296dd4
All checks were successful
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline was successful
+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>
2026-05-18 01:07:13 -04:00

55 lines
2.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.test import SimpleTestCase
from apps.epic.utils import _planet_house, top_capacitors
class PlanetHouseFallbackTest(SimpleTestCase):
def test_returns_1_when_no_cusp_matches(self):
# Pathological cusps list: all 12 cusps identical (zero-width arcs).
# No range has start < end, and the wrap-around condition is also
# never satisfied, so the loop exhausts without returning — hitting
# 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"])