mud/tests/test_command_describe.py
Jared Miller 5b6c808050
Add describe command for home zone descriptions
Allows players to set custom descriptions for their home zones.
Only works in the player's own home zone. Saves to TOML file.
2026-02-14 17:58:47 -05:00

151 lines
4.2 KiB
Python

"""Tests for the describe command."""
from unittest.mock import AsyncMock, MagicMock
import pytest
from mudlib.commands.describe import cmd_describe
from mudlib.housing import init_housing
from mudlib.player import Player
from mudlib.zone import Zone
from mudlib.zones import register_zone, zone_registry
@pytest.fixture(autouse=True)
def _clean_registries():
saved = dict(zone_registry)
zone_registry.clear()
yield
zone_registry.clear()
zone_registry.update(saved)
@pytest.fixture
def _init_housing(tmp_path):
from mudlib.store import create_account, init_db
init_housing(tmp_path / "player_zones")
init_db(tmp_path / "test.db")
# Create accounts for test players
for name in ["alice", "bob", "charlie"]:
create_account(name, "testpass")
def _make_home_zone(player_name="alice"):
name = f"home:{player_name}"
terrain = []
for y in range(9):
row = []
for x in range(9):
if x == 0 or x == 8 or y == 0 or y == 8:
row.append("#")
else:
row.append(".")
terrain.append(row)
zone = Zone(
name=name,
description=f"{player_name}'s home",
width=9,
height=9,
terrain=terrain,
toroidal=False,
impassable={"#", "^", "~"},
spawn_x=4,
spawn_y=4,
safe=True,
)
register_zone(name, zone)
return zone
def _make_player(name="alice", zone=None, x=4, y=4):
mock_writer = MagicMock()
mock_writer.write = MagicMock()
mock_writer.drain = AsyncMock()
p = Player(name=name, location=zone, x=x, y=y, writer=mock_writer)
p.home_zone = f"home:{name}"
return p
@pytest.mark.asyncio
async def test_describe_sets_description(_init_housing):
"""describe <text> sets zone.description."""
home = _make_home_zone("alice")
player = _make_player("alice", zone=home)
await cmd_describe(player, "a cozy cottage by the sea")
assert home.description == "a cozy cottage by the sea"
@pytest.mark.asyncio
async def test_describe_not_in_home_zone(_init_housing):
"""describe fails if not in player's own home zone."""
_make_home_zone("alice")
other_zone = Zone(
name="overworld",
description="The world",
width=20,
height=20,
terrain=[["." for _ in range(20)] for _ in range(20)],
toroidal=True,
)
register_zone("overworld", other_zone)
player = _make_player("alice", zone=other_zone)
await cmd_describe(player, "trying to describe the overworld")
# Should show error message
assert player.writer.write.called
output = "".join(c[0][0] for c in player.writer.write.call_args_list)
assert "only" in output.lower() and "home" in output.lower()
@pytest.mark.asyncio
async def test_describe_no_args_shows_current(_init_housing):
"""describe with no args shows current description."""
home = _make_home_zone("alice")
home.description = "a warm and welcoming place"
player = _make_player("alice", zone=home)
await cmd_describe(player, "")
assert player.writer.write.called
output = "".join(c[0][0] for c in player.writer.write.call_args_list)
assert "a warm and welcoming place" in output
@pytest.mark.asyncio
async def test_describe_saves_zone(_init_housing):
"""describe saves the zone to disk."""
import tomllib
from mudlib.housing import _zone_path
home = _make_home_zone("alice")
player = _make_player("alice", zone=home)
await cmd_describe(player, "a newly described home")
# Check TOML file was saved
zone_path = _zone_path("alice")
assert zone_path.exists()
with open(zone_path, "rb") as f:
data = tomllib.load(f)
assert data["description"] == "a newly described home"
@pytest.mark.asyncio
async def test_describe_multiword(_init_housing):
"""describe handles multiword descriptions."""
home = _make_home_zone("bob")
player = _make_player("bob", zone=home)
await cmd_describe(player, "a cozy cottage with warm lighting")
assert home.description == "a cozy cottage with warm lighting"
assert player.writer.write.called
output = "".join(c[0][0] for c in player.writer.write.call_args_list)
assert "description" in output.lower() or "set" in output.lower()