mirror of
https://github.com/mwisnowski/mtg_python_deckbuilder.git
synced 2025-12-16 23:50:12 +01:00
web: DRY Step 5 and alternatives (partial+macro), centralize start_ctx/owned_set, adopt builder_*
This commit is contained in:
parent
fe9aabbce9
commit
014bcc37b7
24 changed files with 1200 additions and 766 deletions
60
code/tests/test_build_utils_ctx.py
Normal file
60
code/tests/test_build_utils_ctx.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from code.web.services.build_utils import start_ctx_from_session, owned_set, owned_names
|
||||
|
||||
|
||||
def _fake_session(**kw):
|
||||
# Provide minimal session keys used by start_ctx_from_session
|
||||
base = {
|
||||
"commander": "Cmdr",
|
||||
"tags": ["Aggro", "Spells"],
|
||||
"bracket": 3,
|
||||
"ideals": {"creatures": 25},
|
||||
"tag_mode": "AND",
|
||||
"use_owned_only": False,
|
||||
"prefer_owned": False,
|
||||
"locks": [],
|
||||
"custom_export_base": "TestDeck",
|
||||
"multi_copy": None,
|
||||
"prefer_combos": False,
|
||||
"combo_target_count": 2,
|
||||
"combo_balance": "mix",
|
||||
}
|
||||
base.update(kw)
|
||||
return base
|
||||
|
||||
|
||||
def test_owned_helpers_do_not_crash():
|
||||
# These reflect over the owned store; they should be resilient
|
||||
s = owned_set()
|
||||
assert isinstance(s, set)
|
||||
n = owned_names()
|
||||
assert isinstance(n, list)
|
||||
|
||||
|
||||
def test_start_ctx_from_session_minimal(monkeypatch):
|
||||
# Avoid integration dependency by faking orchestrator.start_build_ctx
|
||||
calls = {}
|
||||
def _fake_start_build_ctx(**kwargs):
|
||||
calls.update(kwargs)
|
||||
return {"builder": object(), "stages": [], "idx": 0, "last_visible_idx": 0}
|
||||
import code.web.services.build_utils as bu
|
||||
monkeypatch.setattr(bu.orch, "start_build_ctx", _fake_start_build_ctx)
|
||||
|
||||
sess = _fake_session()
|
||||
ctx = start_ctx_from_session(sess, set_on_session=False)
|
||||
assert isinstance(ctx, dict)
|
||||
assert "builder" in ctx
|
||||
assert "stages" in ctx
|
||||
assert "idx" in ctx
|
||||
|
||||
|
||||
def test_start_ctx_from_session_sets_on_session(monkeypatch):
|
||||
def _fake_start_build_ctx(**kwargs):
|
||||
return {"builder": object(), "stages": [], "idx": 0}
|
||||
import code.web.services.build_utils as bu
|
||||
monkeypatch.setattr(bu.orch, "start_build_ctx", _fake_start_build_ctx)
|
||||
|
||||
sess = _fake_session()
|
||||
ctx = start_ctx_from_session(sess, set_on_session=True)
|
||||
assert sess.get("build_ctx") == ctx
|
||||
19
code/tests/test_orchestrator_staleness.py
Normal file
19
code/tests/test_orchestrator_staleness.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from code.web.services.orchestrator import is_setup_ready, is_setup_stale
|
||||
|
||||
|
||||
def test_is_setup_ready_false_when_missing():
|
||||
# On a clean checkout without csv_files, this should be False
|
||||
assert is_setup_ready() in (False, True) # Function exists and returns a bool
|
||||
|
||||
|
||||
def test_is_setup_stale_never_when_disabled_env(monkeypatch):
|
||||
monkeypatch.setenv("WEB_AUTO_REFRESH_DAYS", "0")
|
||||
assert is_setup_stale() is False
|
||||
|
||||
|
||||
def test_is_setup_stale_is_bool():
|
||||
# We don't assert specific timing behavior in unit tests; just type/robustness
|
||||
res = is_setup_stale()
|
||||
assert res in (False, True)
|
||||
76
code/tests/test_step5_error_ctx.py
Normal file
76
code/tests/test_step5_error_ctx.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from types import SimpleNamespace
|
||||
|
||||
from code.web.services.build_utils import step5_error_ctx
|
||||
|
||||
|
||||
class _Req(SimpleNamespace):
|
||||
# minimal object to satisfy template context needs
|
||||
pass
|
||||
|
||||
|
||||
def test_step5_error_ctx_shape():
|
||||
req = _Req()
|
||||
sess = {
|
||||
"commander": "Atraxa, Praetors' Voice",
|
||||
"tags": ["+1/+1 Counters"],
|
||||
"bracket": 3,
|
||||
"ideals": {"lands": 36},
|
||||
"use_owned_only": False,
|
||||
"prefer_owned": False,
|
||||
"replace_mode": True,
|
||||
"locks": ["sol ring"],
|
||||
}
|
||||
ctx = step5_error_ctx(req, sess, "Boom")
|
||||
# Ensure required keys for _step5.html are present with safe defaults
|
||||
for k in (
|
||||
"request",
|
||||
"commander",
|
||||
"tags",
|
||||
"bracket",
|
||||
"values",
|
||||
"owned_only",
|
||||
"prefer_owned",
|
||||
"owned_set",
|
||||
"game_changers",
|
||||
"replace_mode",
|
||||
"prefer_combos",
|
||||
"combo_target_count",
|
||||
"combo_balance",
|
||||
"status",
|
||||
"stage_label",
|
||||
"log",
|
||||
"added_cards",
|
||||
"i",
|
||||
"n",
|
||||
"csv_path",
|
||||
"txt_path",
|
||||
"summary",
|
||||
"show_skipped",
|
||||
"total_cards",
|
||||
"added_total",
|
||||
"skipped",
|
||||
):
|
||||
assert k in ctx
|
||||
assert ctx["status"] == "Error"
|
||||
assert isinstance(ctx["added_cards"], list)
|
||||
assert ctx["show_skipped"] is False
|
||||
|
||||
|
||||
def test_step5_error_ctx_respects_flags():
|
||||
req = _Req()
|
||||
sess = {
|
||||
"use_owned_only": True,
|
||||
"prefer_owned": True,
|
||||
"combo_target_count": 3,
|
||||
"combo_balance": "early",
|
||||
}
|
||||
ctx = step5_error_ctx(req, sess, "Oops", include_name=False, include_locks=False)
|
||||
assert "name" not in ctx
|
||||
assert "locks" not in ctx
|
||||
# Flags should flow through
|
||||
assert ctx["owned_only"] is True
|
||||
assert ctx["prefer_owned"] is True
|
||||
assert ctx["combo_target_count"] == 3
|
||||
assert ctx["combo_balance"] == "early"
|
||||
31
code/tests/test_summary_utils.py
Normal file
31
code/tests/test_summary_utils.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from code.web.services.summary_utils import summary_ctx
|
||||
|
||||
|
||||
def test_summary_ctx_empty_summary():
|
||||
ctx = summary_ctx(summary=None, commander="Test Commander", tags=["Aggro"])
|
||||
assert isinstance(ctx, dict)
|
||||
assert ctx.get("owned_set") is not None
|
||||
assert isinstance(ctx.get("combos"), list)
|
||||
assert isinstance(ctx.get("synergies"), list)
|
||||
assert ctx.get("versions") == {}
|
||||
assert ctx.get("commander") == "Test Commander"
|
||||
assert ctx.get("tags") == ["Aggro"]
|
||||
|
||||
|
||||
def test_summary_ctx_with_summary_basic():
|
||||
# Minimal fake summary structure sufficient for detect_for_summary to accept
|
||||
summary = {
|
||||
"type_breakdown": {"counts": {}, "order": [], "cards": {}, "total": 0},
|
||||
"pip_distribution": {"counts": {}, "weights": {}},
|
||||
"mana_generation": {},
|
||||
"mana_curve": {"total_spells": 0},
|
||||
"colors": [],
|
||||
}
|
||||
ctx = summary_ctx(summary=summary, commander="Cmdr", tags=["Spells"])
|
||||
assert "owned_set" in ctx and isinstance(ctx["owned_set"], set)
|
||||
assert "game_changers" in ctx
|
||||
assert "combos" in ctx and isinstance(ctx["combos"], list)
|
||||
assert "synergies" in ctx and isinstance(ctx["synergies"], list)
|
||||
assert "versions" in ctx and isinstance(ctx["versions"], dict)
|
||||
Loading…
Add table
Add a link
Reference in a new issue