mud/tests/test_verb_dispatch.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

180 lines
5.2 KiB
Python

"""Tests for verb dispatch fallback in command system."""
import pytest
from mudlib.commands import dispatch
from mudlib.player import Player
from mudlib.thing import Thing
from mudlib.verbs import verb
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)
@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,
)
class Fountain(Thing):
"""Test object with drink verb."""
@verb("drink")
async def drink(self, player, args):
await player.send("You drink from the fountain.\r\n")
@verb("splash")
async def splash(self, player, args):
await player.send(f"You splash the fountain{' ' + args if args else ''}.\r\n")
@pytest.mark.asyncio
async def test_verb_dispatch_simple(player, test_zone):
"""Test 'drink fountain' dispatches to fountain's drink verb."""
_fountain = Fountain(
name="fountain",
description="a stone fountain",
portable=False,
location=test_zone,
x=5,
y=5,
)
await dispatch(player, "drink fountain")
player.writer.write.assert_called_once_with("You drink from the fountain.\r\n")
player.writer.drain.assert_awaited_once()
@pytest.mark.asyncio
async def test_verb_dispatch_with_extra_args(player, test_zone):
"""Test 'splash fountain hard' passes 'hard' as extra args."""
_fountain = Fountain(
name="fountain",
description="a stone fountain",
portable=False,
location=test_zone,
x=5,
y=5,
)
await dispatch(player, "splash fountain hard")
player.writer.write.assert_called_once_with("You splash the fountain hard.\r\n")
player.writer.drain.assert_awaited_once()
@pytest.mark.asyncio
async def test_verb_dispatch_object_lacks_verb(player, test_zone):
"""Test 'drink rock' fails if rock doesn't have drink verb."""
_rock = Thing(
name="rock",
description="a plain rock",
portable=True,
location=test_zone,
x=5,
y=5,
)
await dispatch(player, "drink rock")
player.writer.write.assert_called_once_with("Unknown command: drink\r\n")
player.writer.drain.assert_awaited_once()
@pytest.mark.asyncio
async def test_verb_dispatch_object_not_found(player, test_zone):
"""Test 'drink flurb' fails if flurb doesn't exist."""
await dispatch(player, "drink flurb")
player.writer.write.assert_called_once_with("Unknown command: drink\r\n")
player.writer.drain.assert_awaited_once()
@pytest.mark.asyncio
async def test_verb_dispatch_no_args(player, test_zone):
"""Test 'drink' with no args doesn't try verb dispatch."""
await dispatch(player, "drink")
player.writer.write.assert_called_once_with("Unknown command: drink\r\n")
player.writer.drain.assert_awaited_once()
@pytest.mark.asyncio
async def test_verb_dispatch_doesnt_intercept_real_commands(player, test_zone):
"""Test that verb dispatch doesn't interfere with registered commands."""
from mudlib.commands import CommandDefinition, register, unregister
called = False
async def test_command(player, args):
nonlocal called
called = True
await player.send("Real command executed.\r\n")
register(CommandDefinition("test", test_command))
try:
await dispatch(player, "test something")
assert called
player.writer.write.assert_called_once_with("Real command executed.\r\n")
finally:
unregister("test")
@pytest.mark.asyncio
async def test_verb_dispatch_finds_inventory_object(player, test_zone):
"""Test verb dispatch finds object in inventory."""
class Potion(Thing):
@verb("drink")
async def drink(self, player, args):
await player.send("You drink the potion.\r\n")
_potion = Potion(
name="potion",
description="a health potion",
portable=True,
location=player,
)
await dispatch(player, "drink potion")
player.writer.write.assert_called_once_with("You drink the potion.\r\n")
player.writer.drain.assert_awaited_once()
@pytest.mark.asyncio
async def test_verb_dispatch_doesnt_fire_on_ambiguous_command(player, test_zone):
"""Test verb dispatch doesn't fire when command is ambiguous."""
from mudlib.commands import CommandDefinition, register, unregister
async def test_one(player, args):
await player.send("test one\r\n")
async def test_two(player, args):
await player.send("test two\r\n")
register(CommandDefinition("testone", test_one))
register(CommandDefinition("testtwo", test_two))
try:
# "test" matches both testone and testtwo
await dispatch(player, "test something")
# Should get ambiguous command message, not verb dispatch
written_text = player.writer.write.call_args[0][0].lower()
# The ambiguous message is "testone or testtwo?" not "ambiguous"
assert "or" in written_text and "?" in written_text
finally:
unregister("testone")
unregister("testtwo")