271 lines
6.7 KiB
Python
271 lines
6.7 KiB
Python
"""Tests for furniture persistence in home zones."""
|
|
|
|
import logging
|
|
import tomllib
|
|
|
|
import pytest
|
|
|
|
from mudlib.entity import Entity
|
|
from mudlib.housing import (
|
|
create_home_zone,
|
|
init_housing,
|
|
load_home_zone,
|
|
save_home_zone,
|
|
)
|
|
from mudlib.portal import Portal
|
|
from mudlib.thing import Thing
|
|
from mudlib.things import ThingTemplate, spawn_thing, thing_templates
|
|
from mudlib.zones import zone_registry
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _clean_registries():
|
|
"""Clear registries between tests."""
|
|
saved_zones = dict(zone_registry)
|
|
saved_templates = dict(thing_templates)
|
|
zone_registry.clear()
|
|
thing_templates.clear()
|
|
yield
|
|
zone_registry.clear()
|
|
zone_registry.update(saved_zones)
|
|
thing_templates.clear()
|
|
thing_templates.update(saved_templates)
|
|
|
|
|
|
def test_save_furniture_in_zone_toml(tmp_path):
|
|
"""save_home_zone() writes furniture to TOML."""
|
|
init_housing(tmp_path)
|
|
|
|
# Create zone
|
|
zone = create_home_zone("Alice")
|
|
|
|
# Add a thing template
|
|
table_template = ThingTemplate(
|
|
name="table",
|
|
description="A wooden table",
|
|
portable=False,
|
|
)
|
|
thing_templates["table"] = table_template
|
|
|
|
# Spawn furniture in the zone
|
|
spawn_thing(table_template, zone, x=3, y=4)
|
|
|
|
# Save
|
|
save_home_zone("Alice", zone)
|
|
|
|
# Read the TOML file
|
|
zone_file = tmp_path / "alice.toml"
|
|
with open(zone_file, "rb") as f:
|
|
data = tomllib.load(f)
|
|
|
|
# Check furniture section
|
|
assert "furniture" in data
|
|
assert len(data["furniture"]) == 1
|
|
assert data["furniture"][0]["template"] == "table"
|
|
assert data["furniture"][0]["x"] == 3
|
|
assert data["furniture"][0]["y"] == 4
|
|
|
|
|
|
def test_load_furniture_from_toml(tmp_path):
|
|
"""load_home_zone() spawns furniture from TOML."""
|
|
init_housing(tmp_path)
|
|
|
|
# Create zone to get the file
|
|
_ = create_home_zone("Bob")
|
|
zone_file = tmp_path / "bob.toml"
|
|
|
|
# Add furniture entries to the TOML
|
|
with open(zone_file) as f:
|
|
content = f.read()
|
|
content += """
|
|
[[furniture]]
|
|
template = "chair"
|
|
x = 5
|
|
y = 6
|
|
"""
|
|
with open(zone_file, "w") as f:
|
|
f.write(content)
|
|
|
|
# Add template
|
|
chair_template = ThingTemplate(
|
|
name="chair",
|
|
description="A wooden chair",
|
|
portable=True,
|
|
)
|
|
thing_templates["chair"] = chair_template
|
|
|
|
# Clear registry and load
|
|
zone_registry.clear()
|
|
loaded = load_home_zone("Bob")
|
|
|
|
assert loaded is not None
|
|
|
|
# Check that furniture was spawned
|
|
chairs = [
|
|
obj
|
|
for obj in loaded._contents
|
|
if isinstance(obj, Thing) and obj.name == "chair"
|
|
]
|
|
assert len(chairs) == 1
|
|
assert chairs[0].x == 5
|
|
assert chairs[0].y == 6
|
|
assert chairs[0].description == "A wooden chair"
|
|
|
|
|
|
def test_furniture_round_trip(tmp_path):
|
|
"""Furniture survives save -> load cycle."""
|
|
init_housing(tmp_path)
|
|
|
|
# Create zone
|
|
zone = create_home_zone("Charlie")
|
|
|
|
# Add templates
|
|
table_template = ThingTemplate(name="table", description="A table", portable=False)
|
|
chair_template = ThingTemplate(name="chair", description="A chair", portable=True)
|
|
thing_templates["table"] = table_template
|
|
thing_templates["chair"] = chair_template
|
|
|
|
# Spawn furniture
|
|
spawn_thing(table_template, zone, x=3, y=4)
|
|
spawn_thing(chair_template, zone, x=3, y=5)
|
|
|
|
# Save
|
|
save_home_zone("Charlie", zone)
|
|
|
|
# Clear registry and load
|
|
zone_registry.clear()
|
|
loaded = load_home_zone("Charlie")
|
|
|
|
assert loaded is not None
|
|
|
|
# Check furniture
|
|
tables = [obj for obj in loaded._contents if obj.name == "table"]
|
|
chairs = [obj for obj in loaded._contents if obj.name == "chair"]
|
|
|
|
assert len(tables) == 1
|
|
assert tables[0].x == 3
|
|
assert tables[0].y == 4
|
|
|
|
assert len(chairs) == 1
|
|
assert chairs[0].x == 3
|
|
assert chairs[0].y == 5
|
|
|
|
|
|
def test_multiple_furniture_items(tmp_path):
|
|
"""Multiple furniture items save and load correctly."""
|
|
init_housing(tmp_path)
|
|
|
|
zone = create_home_zone("Dave")
|
|
|
|
# Add templates
|
|
chair_template = ThingTemplate(name="chair", description="A chair", portable=True)
|
|
thing_templates["chair"] = chair_template
|
|
|
|
# Spawn multiple chairs
|
|
spawn_thing(chair_template, zone, x=2, y=2)
|
|
spawn_thing(chair_template, zone, x=3, y=2)
|
|
spawn_thing(chair_template, zone, x=4, y=2)
|
|
|
|
# Save
|
|
save_home_zone("Dave", zone)
|
|
|
|
# Load
|
|
zone_registry.clear()
|
|
loaded = load_home_zone("Dave")
|
|
|
|
assert loaded is not None
|
|
|
|
chairs = [obj for obj in loaded._contents if obj.name == "chair"]
|
|
assert len(chairs) == 3
|
|
|
|
# Check positions
|
|
positions = {(c.x, c.y) for c in chairs}
|
|
assert positions == {(2, 2), (3, 2), (4, 2)}
|
|
|
|
|
|
def test_load_unknown_template_skips(tmp_path, caplog):
|
|
"""Unknown template name in TOML is skipped with warning."""
|
|
caplog.set_level(logging.WARNING)
|
|
init_housing(tmp_path)
|
|
|
|
# Create zone
|
|
_ = create_home_zone("Eve")
|
|
zone_file = tmp_path / "eve.toml"
|
|
|
|
# Add furniture with unknown template
|
|
with open(zone_file) as f:
|
|
content = f.read()
|
|
content += """
|
|
[[furniture]]
|
|
template = "unknown_thing"
|
|
x = 1
|
|
y = 1
|
|
"""
|
|
with open(zone_file, "w") as f:
|
|
f.write(content)
|
|
|
|
# Load
|
|
zone_registry.clear()
|
|
loaded = load_home_zone("Eve")
|
|
|
|
assert loaded is not None
|
|
|
|
# Check that no furniture was spawned
|
|
things = [obj for obj in loaded._contents if isinstance(obj, Thing)]
|
|
assert len(things) == 0
|
|
|
|
# Check that warning was logged
|
|
assert "unknown_thing" in caplog.text.lower()
|
|
|
|
|
|
def test_save_excludes_entities(tmp_path):
|
|
"""Entities in zone are NOT saved as furniture."""
|
|
init_housing(tmp_path)
|
|
|
|
zone = create_home_zone("Frank")
|
|
|
|
# Add an entity to the zone
|
|
_ = Entity(name="test_mob", location=zone, x=5, y=5)
|
|
|
|
# Save
|
|
save_home_zone("Frank", zone)
|
|
|
|
# Read the TOML
|
|
zone_file = tmp_path / "frank.toml"
|
|
with open(zone_file, "rb") as f:
|
|
data = tomllib.load(f)
|
|
|
|
# Furniture section should not exist or be empty
|
|
furniture = data.get("furniture", [])
|
|
assert len(furniture) == 0
|
|
|
|
|
|
def test_save_excludes_portals(tmp_path):
|
|
"""Portals are NOT saved as furniture."""
|
|
init_housing(tmp_path)
|
|
|
|
zone = create_home_zone("Grace")
|
|
|
|
# Add a portal to the zone
|
|
_ = Portal(
|
|
name="exit",
|
|
description="An exit",
|
|
location=zone,
|
|
x=1,
|
|
y=1,
|
|
target_zone="overworld",
|
|
target_x=10,
|
|
target_y=10,
|
|
)
|
|
|
|
# Save
|
|
save_home_zone("Grace", zone)
|
|
|
|
# Read the TOML
|
|
zone_file = tmp_path / "grace.toml"
|
|
with open(zone_file, "rb") as f:
|
|
data = tomllib.load(f)
|
|
|
|
# Furniture section should not exist or be empty
|
|
furniture = data.get("furniture", [])
|
|
assert len(furniture) == 0
|