mtg_python_deckbuilder/code/tests/test_multicopy_petitioners_clamp.py

58 lines
2.5 KiB
Python
Raw Permalink Normal View History

import importlib
def test_petitioners_clamp_to_100_and_reduce_creature_slots():
"""
Ensure that when a large multi-copy creature package is added (e.g., Persistent Petitioners),
the deck does not exceed 100 after the multi-copy stage and ideal creature targets are reduced.
This uses the staged orchestrator flow to exercise the clamp and adjustments, but avoids
full dataset loading by using a minimal builder context and a dummy DF where possible.
"""
orch = importlib.import_module('code.web.services.orchestrator')
# Start a minimal staged context with only the multi-copy stage
logs = []
def out(msg: str):
logs.append(msg)
from deck_builder.builder import DeckBuilder
b = DeckBuilder(output_func=out, input_func=lambda *_: "", headless=True)
# Seed ideal_counts with a typical creature target so we can observe reduction
b.ideal_counts = {
"ramp": 10, "lands": 35, "basic_lands": 20,
"fetch_lands": 3, "creatures": 28, "removal": 10, "wipes": 2,
"card_advantage": 8, "protection": 4,
}
# Thread multi-copy selection for Petitioners as a creature archetype
b._web_multi_copy = { # type: ignore[attr-defined]
"id": "persistent_petitioners",
"name": "Persistent Petitioners",
"count": 40, # intentionally large to trigger clamp/adjustments
"thrumming": False,
}
# Minimal library
b.card_library = {}
ctx = {
"builder": b,
"logs": logs,
"stages": [{"key": "multicopy", "label": "Multi-Copy Package", "runner_name": "__add_multi_copy__"}],
"idx": 0,
"last_log_idx": 0,
"csv_path": None,
"txt_path": None,
"snapshot": None,
"history": [],
"locks": set(),
"custom_export_base": None,
}
res = orch.run_stage(ctx, rerun=False, show_skipped=False)
# Should show the stage with added cards
assert res.get("done") is False
assert res.get("label") == "Multi-Copy Package"
# Clamp should be applied if over 100; however with only one name in library, it won't clamp yet.
# We'll at least assert that mc_adjustments exist and creatures target reduced by ~count.
mc_adj = res.get("mc_adjustments") or []
assert any(a.startswith("creatures ") for a in mc_adj), f"mc_adjustments missing creature reduction: {mc_adj}"
# Verify deck total does not exceed 100 when a follow-up 100 baseline exists; here just sanity check the number present
total_cards = int(res.get("total_cards") or 0)
assert total_cards >= 1