"""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 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()