mirror of
https://github.com/mwisnowski/mtg_python_deckbuilder.git
synced 2025-12-16 15:40:12 +01:00
150 lines
5.2 KiB
Python
150 lines
5.2 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Dict, Any, List
|
|
|
|
import pytest
|
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
|
|
from code.deck_builder.phases.phase6_reporting import ReportingMixin
|
|
from code.deck_builder.summary_telemetry import get_mdfc_metrics, _reset_metrics_for_test
|
|
|
|
|
|
class DummyBuilder(ReportingMixin):
|
|
def __init__(self, card_library: Dict[str, Dict[str, Any]], colors: List[str]):
|
|
self.card_library = card_library
|
|
self.color_identity = colors
|
|
self.output_lines: List[str] = []
|
|
self.output_func = self.output_lines.append
|
|
self._full_cards_df = None
|
|
self._combined_cards_df = None
|
|
self.include_exclude_diagnostics = None
|
|
self.include_cards = []
|
|
self.exclude_cards = []
|
|
|
|
|
|
@pytest.fixture()
|
|
def sample_card_library() -> Dict[str, Dict[str, Any]]:
|
|
return {
|
|
"Mountain": {"Card Type": "Land", "Count": 35, "Mana Cost": "", "Role": "", "Tags": []},
|
|
"Branchloft Pathway // Boulderloft Pathway": {
|
|
"Card Type": "Land",
|
|
"Count": 1,
|
|
"Mana Cost": "",
|
|
"Role": "",
|
|
"Tags": [],
|
|
},
|
|
"Valakut Awakening // Valakut Stoneforge": {
|
|
"Card Type": "Instant",
|
|
"Count": 2,
|
|
"Mana Cost": "{2}{R}",
|
|
"Role": "",
|
|
"Tags": [],
|
|
},
|
|
"Cultivate": {"Card Type": "Sorcery", "Count": 1, "Mana Cost": "{2}{G}", "Role": "", "Tags": []},
|
|
}
|
|
|
|
|
|
@pytest.fixture()
|
|
def fake_matrix(monkeypatch):
|
|
matrix = {
|
|
"Mountain": {"R": 1},
|
|
"Branchloft Pathway // Boulderloft Pathway": {"G": 1, "W": 1, "_dfc_land": True},
|
|
"Valakut Awakening // Valakut Stoneforge": {
|
|
"R": 1,
|
|
"_dfc_land": True,
|
|
"_dfc_counts_as_extra": True,
|
|
},
|
|
"Cultivate": {},
|
|
}
|
|
|
|
def _fake_compute(card_library, *_):
|
|
return matrix
|
|
|
|
monkeypatch.setattr("deck_builder.builder_utils.compute_color_source_matrix", _fake_compute)
|
|
return matrix
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def reset_mdfc_metrics():
|
|
_reset_metrics_for_test()
|
|
yield
|
|
_reset_metrics_for_test()
|
|
|
|
|
|
def test_build_deck_summary_includes_mdfc_totals(sample_card_library, fake_matrix):
|
|
builder = DummyBuilder(sample_card_library, ["R", "G"])
|
|
summary = builder.build_deck_summary()
|
|
|
|
land_summary = summary.get("land_summary")
|
|
assert land_summary["traditional"] == 36
|
|
assert land_summary["dfc_lands"] == 2
|
|
assert land_summary["with_dfc"] == 38
|
|
assert land_summary["headline"] == "Lands: 36 (38 with DFC)"
|
|
|
|
dfc_cards = {card["name"]: card for card in land_summary["dfc_cards"]}
|
|
branch = dfc_cards["Branchloft Pathway // Boulderloft Pathway"]
|
|
assert branch["count"] == 1
|
|
assert set(branch["colors"]) == {"G", "W"}
|
|
assert branch["adds_extra_land"] is False
|
|
assert branch["counts_as_land"] is True
|
|
assert branch["note"] == "Counts as land slot"
|
|
assert "faces" in branch
|
|
assert isinstance(branch["faces"], list) and branch["faces"]
|
|
assert all("mana_cost" in face for face in branch["faces"])
|
|
|
|
valakut = dfc_cards["Valakut Awakening // Valakut Stoneforge"]
|
|
assert valakut["count"] == 2
|
|
assert valakut["colors"] == ["R"]
|
|
assert valakut["adds_extra_land"] is True
|
|
assert valakut["counts_as_land"] is False
|
|
assert valakut["note"] == "Adds extra land slot"
|
|
assert any(face.get("produces_mana") for face in valakut.get("faces", []))
|
|
|
|
mana_cards = summary["mana_generation"]["cards"]
|
|
red_sources = {item["name"]: item for item in mana_cards["R"]}
|
|
assert red_sources["Valakut Awakening // Valakut Stoneforge"]["dfc"] is True
|
|
assert red_sources["Mountain"]["dfc"] is False
|
|
|
|
|
|
def test_cli_summary_mentions_mdfc_totals(sample_card_library, fake_matrix):
|
|
builder = DummyBuilder(sample_card_library, ["R", "G"])
|
|
builder.print_type_summary()
|
|
joined = "\n".join(builder.output_lines)
|
|
assert "Lands: 36 (38 with DFC)" in joined
|
|
assert "MDFC sources:" in joined
|
|
|
|
|
|
def test_deck_summary_template_renders_land_copy(sample_card_library, fake_matrix):
|
|
builder = DummyBuilder(sample_card_library, ["R", "G"])
|
|
summary = builder.build_deck_summary()
|
|
|
|
env = Environment(
|
|
loader=FileSystemLoader("code/web/templates"),
|
|
autoescape=select_autoescape(["html", "xml"]),
|
|
)
|
|
template = env.get_template("partials/deck_summary.html")
|
|
html = template.render(
|
|
summary=summary,
|
|
synergies=[],
|
|
game_changers=[],
|
|
owned_set=set(),
|
|
combos=[],
|
|
commander=None,
|
|
)
|
|
|
|
assert "Lands: 36 (38 with DFC)" in html
|
|
assert "DFC land" in html
|
|
|
|
|
|
def test_deck_summary_records_mdfc_telemetry(sample_card_library, fake_matrix):
|
|
builder = DummyBuilder(sample_card_library, ["R", "G"])
|
|
builder.build_deck_summary()
|
|
|
|
metrics = get_mdfc_metrics()
|
|
assert metrics["total_builds"] == 1
|
|
assert metrics["builds_with_mdfc"] == 1
|
|
assert metrics["total_mdfc_lands"] == 2
|
|
assert metrics["last_summary"]["dfc_lands"] == 2
|
|
top_cards = metrics.get("top_cards") or {}
|
|
assert top_cards.get("Valakut Awakening // Valakut Stoneforge") == 2
|
|
assert top_cards.get("Branchloft Pathway // Boulderloft Pathway") == 1
|