mtg_python_deckbuilder/code/tests/test_include_exclude_persistence.py

174 lines
7.4 KiB
Python
Raw Normal View History

"""
Test JSON persistence functionality for include/exclude configuration.
Verifies that include/exclude configurations can be exported to JSON and then imported
back with full fidelity, supporting the persistence layer of the include/exclude system.
"""
import json
import tempfile
import os
import pytest
from headless_runner import _load_json_config
from deck_builder.builder import DeckBuilder
class TestJSONRoundTrip:
"""Test complete JSON export/import round-trip for include/exclude config."""
def test_complete_round_trip(self):
"""Test that a complete config can be exported and re-imported correctly."""
# Create initial configuration
original_config = {
"commander": "Aang, Airbending Master",
"primary_tag": "Exile Matters",
"secondary_tag": "Airbending",
"tertiary_tag": "Token Creation",
"bracket_level": 4,
"use_multi_theme": True,
"add_lands": True,
"add_creatures": True,
"add_non_creature_spells": True,
"fetch_count": 3,
"ideal_counts": {
"ramp": 8,
"lands": 35,
"basic_lands": 15,
"creatures": 25,
"removal": 10,
"wipes": 2,
"card_advantage": 10,
"protection": 8
},
"include_cards": ["Sol Ring", "Lightning Bolt", "Counterspell"],
"exclude_cards": ["Chaos Orb", "Shahrazad", "Time Walk"],
"enforcement_mode": "strict",
"allow_illegal": True,
"fuzzy_matching": False
}
with tempfile.TemporaryDirectory() as temp_dir:
# Write initial config
config_path = os.path.join(temp_dir, "test_config.json")
with open(config_path, 'w', encoding='utf-8') as f:
json.dump(original_config, f, indent=2)
# Load config using headless runner logic
loaded_config = _load_json_config(config_path)
# Verify all include/exclude fields are preserved
assert loaded_config["include_cards"] == ["Sol Ring", "Lightning Bolt", "Counterspell"]
assert loaded_config["exclude_cards"] == ["Chaos Orb", "Shahrazad", "Time Walk"]
assert loaded_config["enforcement_mode"] == "strict"
assert loaded_config["allow_illegal"] is True
assert loaded_config["fuzzy_matching"] is False
# Create a DeckBuilder with this config and export again
builder = DeckBuilder()
builder.commander_name = loaded_config["commander"]
builder.include_cards = loaded_config["include_cards"]
builder.exclude_cards = loaded_config["exclude_cards"]
builder.enforcement_mode = loaded_config["enforcement_mode"]
builder.allow_illegal = loaded_config["allow_illegal"]
builder.fuzzy_matching = loaded_config["fuzzy_matching"]
builder.bracket_level = loaded_config["bracket_level"]
# Export the configuration
exported_path = builder.export_run_config_json(directory=temp_dir, suppress_output=True)
# Load the exported config
with open(exported_path, 'r', encoding='utf-8') as f:
re_exported_config = json.load(f)
# Verify round-trip fidelity for include/exclude fields
assert re_exported_config["include_cards"] == ["Sol Ring", "Lightning Bolt", "Counterspell"]
assert re_exported_config["exclude_cards"] == ["Chaos Orb", "Shahrazad", "Time Walk"]
assert re_exported_config["enforcement_mode"] == "strict"
assert re_exported_config["allow_illegal"] is True
assert re_exported_config["fuzzy_matching"] is False
def test_empty_lists_round_trip(self):
"""Test that empty include/exclude lists are handled correctly."""
builder = DeckBuilder()
builder.commander_name = "Test Commander"
builder.include_cards = []
builder.exclude_cards = []
builder.enforcement_mode = "warn"
builder.allow_illegal = False
builder.fuzzy_matching = True
with tempfile.TemporaryDirectory() as temp_dir:
# Export configuration
exported_path = builder.export_run_config_json(directory=temp_dir, suppress_output=True)
# Load the exported config
with open(exported_path, 'r', encoding='utf-8') as f:
exported_config = json.load(f)
# Verify empty lists are preserved (not None)
assert exported_config["include_cards"] == []
assert exported_config["exclude_cards"] == []
assert exported_config["enforcement_mode"] == "warn"
assert exported_config["allow_illegal"] is False
assert exported_config["fuzzy_matching"] is True
def test_default_values_export(self):
"""Test that default values are exported correctly."""
builder = DeckBuilder()
# Only set commander, leave everything else as defaults
builder.commander_name = "Test Commander"
with tempfile.TemporaryDirectory() as temp_dir:
# Export configuration
exported_path = builder.export_run_config_json(directory=temp_dir, suppress_output=True)
# Load the exported config
with open(exported_path, 'r', encoding='utf-8') as f:
exported_config = json.load(f)
# Verify default values are exported
assert exported_config["include_cards"] == []
assert exported_config["exclude_cards"] == []
assert exported_config["enforcement_mode"] == "warn"
assert exported_config["allow_illegal"] is False
assert exported_config["fuzzy_matching"] is True
def test_backward_compatibility_no_include_exclude_fields(self):
"""Test that configs without include/exclude fields still work."""
legacy_config = {
"commander": "Legacy Commander",
"primary_tag": "Legacy Tag",
"bracket_level": 3,
"ideal_counts": {
"ramp": 8,
"lands": 35
}
}
with tempfile.TemporaryDirectory() as temp_dir:
# Write legacy config (no include/exclude fields)
config_path = os.path.join(temp_dir, "legacy_config.json")
with open(config_path, 'w', encoding='utf-8') as f:
json.dump(legacy_config, f, indent=2)
# Load config using headless runner logic
loaded_config = _load_json_config(config_path)
# Verify legacy fields are preserved
assert loaded_config["commander"] == "Legacy Commander"
assert loaded_config["primary_tag"] == "Legacy Tag"
assert loaded_config["bracket_level"] == 3
# Verify include/exclude fields are not present (will use defaults)
assert "include_cards" not in loaded_config
assert "exclude_cards" not in loaded_config
assert "enforcement_mode" not in loaded_config
assert "allow_illegal" not in loaded_config
assert "fuzzy_matching" not in loaded_config
if __name__ == "__main__":
pytest.main([__file__])