"""Tests for the home command.""" from unittest.mock import AsyncMock, MagicMock import pytest from mudlib.commands.home import cmd_home from mudlib.housing import init_housing from mudlib.player import Player from mudlib.zone import Zone from mudlib.zones import get_zone, register_zone, zone_registry @pytest.fixture(autouse=True) def _clean_zone_registry(): saved = dict(zone_registry) 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", "diane", "eve", "frank", "grace"]: create_account(name, "testpass") def _make_zone(name="overworld", width=20, height=20): terrain = [["." for _ in range(width)] for _ in range(height)] zone = Zone( name=name, description=name, width=width, height=height, terrain=terrain, toroidal=True, ) register_zone(name, zone) return zone def _make_player(name="tester", zone=None, x=5, y=5): mock_writer = MagicMock() mock_writer.write = MagicMock() mock_writer.drain = AsyncMock() return Player(name=name, location=zone, x=x, y=y, writer=mock_writer) @pytest.mark.asyncio async def test_home_creates_zone(_init_housing): """Player with no home calls home and gets teleported to new zone.""" overworld = _make_zone("overworld") player = _make_player("alice", zone=overworld) # Initially no home zone exists assert get_zone("home:alice") is None await cmd_home(player, "") # Now home zone exists and player is in it home = get_zone("home:alice") assert home is not None assert player.location is home assert player.home_zone == "home:alice" assert player.return_location == ("overworld", 5, 5) @pytest.mark.asyncio async def test_home_return(_init_housing): """Player goes home then home return, ends up back where they were.""" overworld = _make_zone("overworld") player = _make_player("bob", zone=overworld, x=10, y=15) # Go home await cmd_home(player, "") home = get_zone("home:bob") assert player.location is home # Return await cmd_home(player, "return") assert player.location is overworld assert player.x == 10 assert player.y == 15 assert player.return_location is None @pytest.mark.asyncio async def test_home_return_without_location(_init_housing): """home return with no saved location shows error.""" overworld = _make_zone("overworld") player = _make_player("charlie", zone=overworld) # No return location set assert player.return_location is None await cmd_home(player, "return") # Should get error message assert player.writer.write.called output = "".join(c[0][0] for c in player.writer.write.call_args_list) assert "nowhere" in output.lower() @pytest.mark.asyncio async def test_home_already_at_home(_init_housing): """Calling home while already at home doesn't overwrite return_location.""" overworld = _make_zone("overworld") player = _make_player("diane", zone=overworld, x=7, y=8) # Go home first time await cmd_home(player, "") assert player.return_location == ("overworld", 7, 8) # Call home again while at home await cmd_home(player, "") # return_location should still point to overworld, not home assert player.return_location == ("overworld", 7, 8) @pytest.mark.asyncio async def test_home_invalid_args(_init_housing): """home foo shows usage.""" overworld = _make_zone("overworld") player = _make_player("eve", zone=overworld) await cmd_home(player, "foo") assert player.writer.write.called output = "".join(c[0][0] for c in player.writer.write.call_args_list) assert "usage" in output.lower() @pytest.mark.asyncio async def test_home_departure_arrival_messages(_init_housing): """Check nearby messages are sent.""" from mudlib.player import players players.clear() overworld = _make_zone("overworld") player = _make_player("frank", zone=overworld, x=10, y=10) other = _make_player("grace", zone=overworld, x=10, y=10) players["frank"] = player players["grace"] = other # Go home await cmd_home(player, "") # Other player should have seen departure message assert other.writer.write.called output = "".join(c[0][0] for c in other.writer.write.call_args_list) assert "frank" in output.lower() assert "vanishes" in output.lower() players.clear()