tabras / tests /test_draft.py
vvennelakanti's picture
Build Tabras card duel prototype
6bbf552
Raw
History Blame Contribute Delete
4.35 kB
import pytest
from random import Random
from draft import backbone_deck, draft_anchor_indexes, draft_deck, draft_deck_from_packs, draft_order, validated_pack_choice
class DraftClient:
# Initialize call tracking for draft generation.
def __init__(self) -> None:
self.calls = 0
self.deck_sizes: list[int] = []
# Return one legal earth card and record deck-aware call order.
def create_card(self, payload: dict[str, object]) -> dict[str, object]:
self.calls += 1
self.deck_sizes.append(len(payload["current_deck"])) # type: ignore[arg-type]
return {"name": f"Ward {self.calls}", "effects": [{"primitive_id": "ward"}]}
class DraftPackClient:
# Initialize call tracking for pack generation.
def __init__(self) -> None:
self.calls = 0
self.deck_sizes: list[int] = []
self.anchor_sizes: list[int] = []
# Return one legal earth pack and record deck-aware call order.
def create_pack(self, payload: dict[str, object]) -> dict[str, object]:
self.calls += 1
self.deck_sizes.append(len(payload["current_deck"])) # type: ignore[arg-type]
self.anchor_sizes.append(len(payload["draft_anchors"])) # type: ignore[arg-type]
return {
"cards": [
{"name": f"Ward {self.calls}A", "effects": [{"primitive_id": "ward"}]},
{"name": f"Ward {self.calls}B", "effects": [{"primitive_id": "block"}]},
{"name": f"Ward {self.calls}C", "effects": [{"primitive_id": "conditional"}]},
]
}
# Verify backbone decks are six fixed text cards.
def test_backbone_deck_has_standard_cards() -> None:
deck = backbone_deck("ice", "cyberpunk")
assert len(deck) == 6
assert deck[0].name == "Attack (weak)"
assert deck[0].school == "ice"
assert deck[5].rules_text() == "Draw 1 card."
# Verify synergy drafting makes nine deck-aware model calls.
def test_draft_deck_adds_nine_synergy_cards() -> None:
client = DraftClient()
deck = draft_deck(client, "earth", "dark fantasy", (1, 2, 3, 4, 5, 1, 2, 3, 4))
assert len(deck) == 15
assert client.deck_sizes == [6, 7, 8, 9, 10, 11, 12, 13, 14]
assert deck[-1].name == "Ward 9"
# Verify pack drafting adds the selected candidate from each pack.
def test_draft_deck_from_packs_adds_selected_cards() -> None:
client = DraftPackClient()
choices: list[int] = []
# Always choose the second card in the pack.
def choose_index(current_deck: tuple[object, ...], pack: tuple[object, ...]) -> int:
assert len(pack) == 3
choices.append(len(current_deck))
return 1
deck = draft_deck_from_packs(client, "earth", "dark fantasy", (1, 2, 3, 4, 5, 1, 2, 3, 4), choose_index, rng=Random(0))
assert len(deck) == 15
assert client.deck_sizes == [6, 7, 8, 9, 10, 11, 12, 13, 14]
assert client.anchor_sizes[:2] == [0, 1]
assert client.anchor_sizes[2:] == [2, 2, 2, 2, 2, 2, 2]
assert choices == [6, 7, 8, 9, 10, 11, 12, 13, 14]
assert deck[-1].name == "Ward 9B"
# Verify anchor indexes are two random synergy positions.
def test_draft_anchor_indexes() -> None:
anchors = draft_anchor_indexes(9, Random(0))
assert len(anchors) == 2
assert anchors <= set(range(9))
with pytest.raises(ValueError, match="at least two"):
draft_anchor_indexes(1, Random(0))
# Verify draft order drafts anchors before remaining cards.
def test_draft_order_starts_with_anchors() -> None:
assert draft_order(5, frozenset((3, 1))) == (1, 3, 0, 2, 4)
# Verify draft rejects incomplete synergy cost schedules.
def test_draft_deck_requires_nine_costs() -> None:
with pytest.raises(ValueError, match="exactly nine"):
draft_deck(DraftClient(), "earth", "dark fantasy", (1,))
with pytest.raises(ValueError, match="exactly nine"):
draft_deck_from_packs(DraftPackClient(), "earth", "dark fantasy", (1,), lambda _, __: 0)
# Verify draft pack choices must point into the pack.
def test_validated_pack_choice_rejects_bad_index() -> None:
pack = backbone_deck("earth", "dark fantasy")[:3]
assert validated_pack_choice(2, pack) == 2
with pytest.raises(ValueError, match="outside"):
validated_pack_choice(3, pack)
with pytest.raises(ValueError, match="outside"):
validated_pack_choice(-1, pack)