Files
commander-ai-lab/tests/deck_builder/test_adapter.py
T
rgriffithandClaude Opus 4.6 9eaa41a4ae feat: deck dropdown, user-decks pipeline, deckgen fixes, gpt-oss removal
- Add user-decks/ directory and USER_DECKS_DIR config for exported decks
- Update export-to-sim to write to user-decks/ with static mount in lab_api
- Replace import/paste UI with API-backed "My Decks" dropdown in LAN client
  and AI Lab, fetching from GET /api/lab/decks with source grouping
- Fix GET /api/lab/decks to JOIN deck_cards for totalCards count
- Fix deckgenerator: add missing DOM elements (dg-strategy-bar, dg-stats-bar,
  dg-card-groups) inside #dg-results, null guards on render functions,
  fix setLoading always hiding results
- Replace gpt-oss:20b with claude-opus-4-20250514 across all files
- Add user-decks/ to _BUILTIN_DECK_DIRS in deck_service.py
- Enrich missing type_line from Forge card cache in DB deck path
- Collapse import bar behind <details> toggle in AI Lab

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 01:17:30 -04:00

105 lines
4.0 KiB
Python

"""Tests for DeckBuilderAdapter — the bridge between Ollama pipeline and legacy API."""
import pytest
from unittest.mock import patch, MagicMock
from types import SimpleNamespace
from src.commander_ai_lab.deck_builder.adapter import DeckBuilderAdapter
from src.commander_ai_lab.deck_builder.core.models import (
BuildResult,
CardEntry,
CommanderDeck,
DeckRatios,
)
def _fake_build_result():
"""Return a minimal BuildResult for mocking build_deck."""
cmdr = CardEntry(name="Atraxa", color_identity=["W", "U", "B", "G"])
basics = ["Plains", "Island", "Swamp", "Mountain", "Forest"]
cards = [
CardEntry(name=basics[i % 5], quantity=1, category="lands", color_identity={"W", "U", "B", "G"})
for i in range(99)
]
deck = CommanderDeck(commander=cmdr, cards=cards)
return BuildResult(
deck=deck,
warnings=["test warning"],
sources_consulted=["scryfall", "edhrec"],
build_time_seconds=1.23,
)
class TestDeckBuilderAdapter:
def test_init_defaults(self):
adapter = DeckBuilderAdapter()
assert adapter.model == "claude-opus-4-20250514"
assert adapter.db_conn_factory is None
@patch("src.commander_ai_lab.deck_builder.adapter.build_deck")
def test_generate_deck_returns_expected_shape(self, mock_build):
mock_build.return_value = _fake_build_result()
adapter = DeckBuilderAdapter()
result = adapter.generate_deck("Atraxa", strategy="superfriends")
assert "commander" in result
assert result["commander"]["name"] == "Atraxa"
assert "cards" in result
assert "stats" in result
assert result["model"] == "claude-opus-4-20250514"
assert result["build_time_seconds"] == 1.23
assert "scryfall" in result["reasoning"]["sources"]
@patch("src.commander_ai_lab.deck_builder.adapter.build_deck")
def test_generate_deck_fills_to_100(self, mock_build):
mock_build.return_value = _fake_build_result()
adapter = DeckBuilderAdapter()
result = adapter.generate_deck("Atraxa")
total = sum(c.get("count", 1) for c in result["cards"])
assert total == 100 # 99 cards + commander fills to 100
@patch("src.commander_ai_lab.deck_builder.adapter.build_deck")
def test_ownership_without_db(self, mock_build):
mock_build.return_value = _fake_build_result()
adapter = DeckBuilderAdapter(db_conn_factory=None)
result = adapter.generate_deck("Atraxa")
for card in result["cards"]:
assert card["owned"] is False
assert card["from_collection"] is False
class TestRunSubstitution:
def test_no_op_returns_namespace(self):
adapter = DeckBuilderAdapter()
cards = [
{"name": "Sol Ring", "owned": True},
{"name": "Mana Crypt", "owned": False},
]
result = adapter.run_substitution(cards, commander="Atraxa")
assert isinstance(result, SimpleNamespace)
assert result.owned_count == 1
assert result.substituted_count == 0
assert result.missing_count == 1
class TestHelpers:
def test_fill_basic_lands_adds_missing(self):
cards = [{"name": "Sol Ring", "count": 1, "category": "ramp"}]
filled = DeckBuilderAdapter._fill_basic_lands(cards, ["W", "U"], target_total=5)
total = sum(c.get("count", 1) for c in filled)
assert total == 5
def test_fill_basic_lands_no_excess(self):
cards = [{"name": f"Card{i}", "count": 1} for i in range(100)]
filled = DeckBuilderAdapter._fill_basic_lands(cards, ["W"], target_total=100)
assert len(filled) == 100
def test_compute_stats(self):
cards = [
{"name": "Sol Ring", "count": 1, "category": "ramp", "cmc": 1},
{"name": "Plains", "count": 36, "category": "lands", "cmc": 0},
]
stats = DeckBuilderAdapter._compute_stats(cards)
assert stats["total_cards"] == 37
assert stats["land_count"] == 36
assert stats["average_cmc"] == 1.0