feat: add supplemental theme catalog tooling, additional theme selection, and custom theme selection

This commit is contained in:
matt 2025-10-03 10:43:24 -07:00
parent 3a1b011dbc
commit 9428e09cef
39 changed files with 3643 additions and 198 deletions

View file

@ -0,0 +1,145 @@
from __future__ import annotations
from typing import Dict, Iterable, Sequence
import pytest
from deck_builder.theme_resolution import ThemeResolutionInfo
from web.services import custom_theme_manager as ctm
def _make_info(
requested: Sequence[str],
*,
resolved: Sequence[str] | None = None,
matches: Sequence[Dict[str, object]] | None = None,
unresolved: Sequence[Dict[str, object]] | None = None,
mode: str = "permissive",
) -> ThemeResolutionInfo:
return ThemeResolutionInfo(
requested=list(requested),
mode=mode,
catalog_version="test-cat",
resolved=list(resolved or []),
matches=list(matches or []),
unresolved=list(unresolved or []),
fuzzy_corrections={},
)
def test_add_theme_exact_smoke(monkeypatch: pytest.MonkeyPatch) -> None:
session: Dict[str, object] = {}
def fake_resolve(requested: Sequence[str], mode: str, *, commander_tags: Iterable[str] = ()) -> ThemeResolutionInfo:
assert list(requested) == ["Lifegain"]
assert mode == "permissive"
return _make_info(
requested,
resolved=["Lifegain"],
matches=[{"input": "Lifegain", "matched": "Lifegain", "score": 100.0, "reason": "exact", "suggestions": []}],
)
monkeypatch.setattr(ctm, "resolve_additional_theme_inputs", fake_resolve)
info, message, level = ctm.add_theme(
session,
"Lifegain",
commander_tags=(),
mode="permissive",
limit=ctm.DEFAULT_THEME_LIMIT,
)
assert info is not None
assert info.resolved == ["Lifegain"]
assert session["custom_theme_inputs"] == ["Lifegain"]
assert session["additional_themes"] == ["Lifegain"]
assert message == "Added theme 'Lifegain'."
assert level == "success"
def test_add_theme_choose_suggestion_smoke(monkeypatch: pytest.MonkeyPatch) -> None:
session: Dict[str, object] = {}
def fake_resolve(requested: Sequence[str], mode: str, *, commander_tags: Iterable[str] = ()) -> ThemeResolutionInfo:
inputs = list(requested)
if inputs == ["lifgian"]:
return _make_info(
inputs,
resolved=[],
matches=[],
unresolved=[
{
"input": "lifgian",
"reason": "suggestions",
"score": 72.0,
"suggestions": [{"theme": "Lifegain", "score": 91.2}],
}
],
)
if inputs == ["Lifegain"]:
return _make_info(
inputs,
resolved=["Lifegain"],
matches=[
{
"input": "lifgian",
"matched": "Lifegain",
"score": 91.2,
"reason": "suggestion",
"suggestions": [],
}
],
)
pytest.fail(f"Unexpected inputs {inputs}")
monkeypatch.setattr(ctm, "resolve_additional_theme_inputs", fake_resolve)
info, message, level = ctm.add_theme(
session,
"lifgian",
commander_tags=(),
mode="permissive",
limit=ctm.DEFAULT_THEME_LIMIT,
)
assert info is not None
assert not info.resolved
assert session["custom_theme_inputs"] == ["lifgian"]
assert message == "Added theme 'lifgian'."
assert level == "success"
info, message, level = ctm.choose_suggestion(
session,
"lifgian",
"Lifegain",
commander_tags=(),
mode="permissive",
)
assert info is not None
assert info.resolved == ["Lifegain"]
assert session["custom_theme_inputs"] == ["Lifegain"]
assert session["additional_themes"] == ["Lifegain"]
assert message == "Updated 'lifgian' to 'Lifegain'."
assert level == "success"
def test_remove_theme_smoke(monkeypatch: pytest.MonkeyPatch) -> None:
session: Dict[str, object] = {"custom_theme_inputs": ["Lifegain"], "additional_themes": ["Lifegain"]}
def fake_resolve(requested: Sequence[str], mode: str, *, commander_tags: Iterable[str] = ()) -> ThemeResolutionInfo:
assert requested == []
return _make_info(requested, resolved=[], matches=[], unresolved=[])
monkeypatch.setattr(ctm, "resolve_additional_theme_inputs", fake_resolve)
info, message, level = ctm.remove_theme(
session,
"Lifegain",
commander_tags=(),
mode="permissive",
)
assert info is not None
assert session["custom_theme_inputs"] == []
assert session["additional_themes"] == []
assert message == "Theme removed."
assert level == "success"