mud/tests/test_thing_templates.py
Jared Miller c43b3346ae
Add Thing templates, TOML loading, and spawning
ThingTemplate dataclass mirrors MobTemplate pattern. load_thing_template
and load_thing_templates parse TOML files from content/things/. spawn_thing
creates Thing instances from templates. Includes rock and fountain examples.
2026-02-11 20:01:15 -05:00

152 lines
4 KiB
Python

"""Tests for thing template loading and spawning."""
import textwrap
import pytest
from mudlib.thing import Thing
from mudlib.things import (
ThingTemplate,
load_thing_template,
load_thing_templates,
spawn_thing,
)
from mudlib.zone import Zone
@pytest.fixture
def test_zone():
terrain = [["." for _ in range(10)] for _ in range(10)]
return Zone(
name="testzone",
width=10,
height=10,
terrain=terrain,
)
# --- ThingTemplate ---
def test_thing_template_creation():
"""ThingTemplate holds definition data."""
t = ThingTemplate(
name="rock",
description="a smooth grey rock",
portable=True,
aliases=["stone"],
)
assert t.name == "rock"
assert t.description == "a smooth grey rock"
assert t.portable is True
assert t.aliases == ["stone"]
def test_thing_template_defaults():
"""ThingTemplate has sensible defaults."""
t = ThingTemplate(name="rock", description="a rock")
assert t.portable is True
assert t.aliases == []
# --- load_thing_template ---
def test_load_thing_template(tmp_path):
"""Load a thing template from a TOML file."""
toml_content = textwrap.dedent("""\
name = "rusty sword"
description = "a sword covered in rust"
portable = true
aliases = ["sword", "rusty"]
""")
p = tmp_path / "sword.toml"
p.write_text(toml_content)
template = load_thing_template(p)
assert template.name == "rusty sword"
assert template.description == "a sword covered in rust"
assert template.portable is True
assert template.aliases == ["sword", "rusty"]
def test_load_thing_template_minimal(tmp_path):
"""Load thing template with only required fields."""
toml_content = textwrap.dedent("""\
name = "rock"
description = "a rock"
""")
p = tmp_path / "rock.toml"
p.write_text(toml_content)
template = load_thing_template(p)
assert template.name == "rock"
assert template.portable is True # default
assert template.aliases == [] # default
def test_load_thing_template_non_portable(tmp_path):
"""Load a non-portable thing template."""
toml_content = textwrap.dedent("""\
name = "fountain"
description = "a stone fountain"
portable = false
""")
p = tmp_path / "fountain.toml"
p.write_text(toml_content)
template = load_thing_template(p)
assert template.portable is False
# --- load_thing_templates ---
def test_load_thing_templates(tmp_path):
"""Load all thing templates from a directory."""
for name in ["rock", "sword"]:
p = tmp_path / f"{name}.toml"
p.write_text(f'name = "{name}"\ndescription = "a {name}"\n')
templates = load_thing_templates(tmp_path)
assert "rock" in templates
assert "sword" in templates
assert len(templates) == 2
def test_load_thing_templates_empty_dir(tmp_path):
"""Empty directory returns empty dict."""
templates = load_thing_templates(tmp_path)
assert templates == {}
# --- spawn_thing ---
def test_spawn_thing_in_zone(test_zone):
"""spawn_thing creates a Thing instance in a zone."""
template = ThingTemplate(
name="rock",
description="a smooth grey rock",
portable=True,
aliases=["stone"],
)
thing = spawn_thing(template, test_zone, x=3, y=7)
assert isinstance(thing, Thing)
assert thing.name == "rock"
assert thing.description == "a smooth grey rock"
assert thing.portable is True
assert thing.aliases == ["stone"]
assert thing.location is test_zone
assert thing.x == 3
assert thing.y == 7
assert thing in test_zone.contents
def test_spawn_thing_without_coordinates(test_zone):
"""spawn_thing can create a thing without position (template/inventory)."""
template = ThingTemplate(name="gem", description="a sparkling gem")
thing = spawn_thing(template, None)
assert thing.location is None
assert thing.x is None
assert thing.y is None