mud/tests/test_toml_verbs.py
Jared Miller 9c480f8d47
Remove duplicate mock_writer/mock_reader fixtures
Removed identical local copies from 45 test files. These fixtures
are already defined in conftest.py.
2026-02-16 15:29:21 -05:00

231 lines
6.7 KiB
Python

"""Tests for TOML verb support in thing templates."""
import textwrap
import pytest
from mudlib.player import Player
from mudlib.things import (
Container,
ThingTemplate,
load_thing_template,
spawn_thing,
)
from mudlib.zone import Zone
# Test handler functions
async def _test_verb_handler(obj, player, args):
"""Test verb handler that sends a message."""
await player.send(f"verb on {obj.name} with args={args}\r\n")
async def _another_test_handler(obj, player, args):
"""Another test handler."""
await player.send(f"another verb on {obj.name}\r\n")
@pytest.fixture
def test_zone():
terrain = [["." for _ in range(10)] for _ in range(10)]
return Zone(name="testzone", width=10, height=10, terrain=terrain)
@pytest.fixture
def player(mock_reader, mock_writer, test_zone):
return Player(
name="TestPlayer",
x=5,
y=5,
reader=mock_reader,
writer=mock_writer,
location=test_zone,
)
def test_thing_template_default_empty_verbs():
"""ThingTemplate has empty verbs dict by default."""
template = ThingTemplate(name="test", description="a test")
assert template.verbs == {}
def test_load_template_with_verbs(tmp_path):
"""load_thing_template parses [verbs] section from TOML."""
toml = tmp_path / "key.toml"
toml.write_text(
textwrap.dedent("""\
name = "key"
description = "a brass key"
[verbs]
unlock = "tests.test_toml_verbs:_test_verb_handler"
""")
)
template = load_thing_template(toml)
assert template.verbs == {"unlock": "tests.test_toml_verbs:_test_verb_handler"}
def test_load_template_without_verbs_section(tmp_path):
"""load_thing_template works without [verbs] section (backwards compatible)."""
toml = tmp_path / "rock.toml"
toml.write_text(
textwrap.dedent("""\
name = "rock"
description = "a smooth stone"
portable = true
""")
)
template = load_thing_template(toml)
assert template.verbs == {}
def test_load_template_with_multiple_verbs(tmp_path):
"""load_thing_template handles multiple verbs."""
toml = tmp_path / "multi.toml"
toml.write_text(
textwrap.dedent("""\
name = "door"
description = "a wooden door"
[verbs]
unlock = "tests.test_toml_verbs:_test_verb_handler"
open = "tests.test_toml_verbs:_another_test_handler"
""")
)
template = load_thing_template(toml)
assert len(template.verbs) == 2
assert "unlock" in template.verbs
assert "open" in template.verbs
def test_spawn_thing_registers_verbs(test_zone, tmp_path):
"""spawn_thing registers verbs on spawned instance."""
toml = tmp_path / "key.toml"
toml.write_text(
textwrap.dedent("""\
name = "key"
description = "a brass key"
[verbs]
unlock = "tests.test_toml_verbs:_test_verb_handler"
""")
)
template = load_thing_template(toml)
thing = spawn_thing(template, test_zone, x=5, y=5)
assert thing.has_verb("unlock")
def test_spawn_container_registers_verbs(test_zone, tmp_path):
"""spawn_thing registers verbs on Container instances too."""
toml = tmp_path / "chest.toml"
toml.write_text(
textwrap.dedent("""\
name = "chest"
description = "a wooden chest"
capacity = 10
[verbs]
unlock = "tests.test_toml_verbs:_test_verb_handler"
""")
)
template = load_thing_template(toml)
container = spawn_thing(template, test_zone, x=5, y=5)
assert isinstance(container, Container)
assert container.has_verb("unlock")
@pytest.mark.asyncio
async def test_spawned_verb_handler_receives_correct_args(test_zone, player, tmp_path):
"""Spawned thing's verb handler can be called and receives (player, args)."""
toml = tmp_path / "key.toml"
toml.write_text(
textwrap.dedent("""\
name = "key"
description = "a brass key"
[verbs]
unlock = "tests.test_toml_verbs:_test_verb_handler"
""")
)
template = load_thing_template(toml)
thing = spawn_thing(template, test_zone, x=5, y=5)
# Call the verb handler
handler = thing.get_verb("unlock")
assert handler is not None
await handler(player, "door")
# Check that the message was sent
player.writer.write.assert_called()
call_args = player.writer.write.call_args[0][0]
assert "verb on key with args=door" in call_args
@pytest.mark.asyncio
async def test_verb_handler_receives_correct_object_instance(
test_zone, player, tmp_path
):
"""Handler receives the correct object instance as first arg (via partial)."""
toml = tmp_path / "key.toml"
toml.write_text(
textwrap.dedent("""\
name = "brass key"
description = "a brass key"
[verbs]
unlock = "tests.test_toml_verbs:_test_verb_handler"
""")
)
template = load_thing_template(toml)
thing = spawn_thing(template, test_zone, x=5, y=5)
# Call the verb handler
handler = thing.get_verb("unlock")
assert handler is not None
await handler(player, "chest")
# Check that the object name appears in the message (verifying correct object)
player.writer.write.assert_called()
call_args = player.writer.write.call_args[0][0]
assert "verb on brass key with args=chest" in call_args
@pytest.mark.asyncio
async def test_multiple_verbs_all_registered(test_zone, player, tmp_path):
"""Multiple verbs in TOML all get registered."""
toml = tmp_path / "door.toml"
toml.write_text(
textwrap.dedent("""\
name = "door"
description = "a wooden door"
[verbs]
unlock = "tests.test_toml_verbs:_test_verb_handler"
open = "tests.test_toml_verbs:_another_test_handler"
""")
)
template = load_thing_template(toml)
thing = spawn_thing(template, test_zone, x=5, y=5)
# Both verbs should be registered
assert thing.has_verb("unlock")
assert thing.has_verb("open")
# Both should work
unlock_handler = thing.get_verb("unlock")
assert unlock_handler is not None
await unlock_handler(player, "test1")
player.writer.write.assert_called()
open_handler = thing.get_verb("open")
assert open_handler is not None
await open_handler(player, "test2")
call_args = player.writer.write.call_args[0][0]
assert "another verb on door" in call_args
def test_bad_handler_ref_skipped(test_zone):
"""A TOML verb with bad handler ref is skipped, not a crash."""
template = ThingTemplate(
name="bad",
description="oops",
portable=True,
verbs={"zap": "nonexistent.module:fake_handler"},
)
thing = spawn_thing(template, test_zone, x=5, y=5)
assert not thing.has_verb("zap")