mud/tests/test_furnish.py

263 lines
7.9 KiB
Python

"""Tests for furnish and unfurnish commands."""
from unittest.mock import AsyncMock, MagicMock
import pytest
from mudlib.housing import init_housing
from mudlib.player import Player
from mudlib.thing import Thing
from mudlib.zone import Zone
from mudlib.zones import register_zone, zone_registry
@pytest.fixture(autouse=True)
def _clean_registries():
"""Clear zone registry between tests."""
saved = dict(zone_registry)
zone_registry.clear()
yield
zone_registry.clear()
zone_registry.update(saved)
def _make_zone(name="overworld", width=20, height=20):
"""Create a zone for testing."""
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):
"""Create a player with mock writer."""
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_furnish_places_item(tmp_path):
"""furnish moves an item from inventory to the zone at player position."""
from mudlib.commands.furnish import cmd_furnish
init_housing(tmp_path)
# Create home zone and player
home_zone = _make_zone("home:alice", width=9, height=9)
player = _make_player("alice", zone=home_zone, x=4, y=4)
player.home_zone = "home:alice"
# Give player a chair
chair = Thing(name="chair", description="A wooden chair")
chair.move_to(player)
# Furnish the chair
await cmd_furnish(player, "chair")
# Chair should be in the zone at player position
assert chair.location is home_zone
assert chair.x == 4
assert chair.y == 4
assert chair not in player.contents
# Player should get feedback
player.writer.write.assert_called()
output = "".join(call.args[0] for call in player.writer.write.call_args_list)
assert "chair" in output.lower()
@pytest.mark.asyncio
async def test_furnish_not_in_home_zone():
"""furnish fails if player is not in their home zone."""
from mudlib.commands.furnish import cmd_furnish
overworld = _make_zone("overworld")
player = _make_player("alice", zone=overworld)
player.home_zone = "home:alice"
chair = Thing(name="chair")
chair.move_to(player)
await cmd_furnish(player, "chair")
# Chair should still be in inventory
assert chair.location is player
assert chair in player.contents
# Player should get error message
player.writer.write.assert_called()
output = "".join(call.args[0] for call in player.writer.write.call_args_list)
assert "home zone" in output.lower()
@pytest.mark.asyncio
async def test_furnish_item_not_in_inventory():
"""furnish fails if item is not in player inventory."""
from mudlib.commands.furnish import cmd_furnish
home_zone = _make_zone("home:alice", width=9, height=9)
player = _make_player("alice", zone=home_zone)
player.home_zone = "home:alice"
await cmd_furnish(player, "chair")
# Player should get error message
player.writer.write.assert_called()
output = "".join(call.args[0] for call in player.writer.write.call_args_list)
assert "don't have" in output.lower() or "not carrying" in output.lower()
@pytest.mark.asyncio
async def test_furnish_no_args():
"""furnish fails with usage message if no args provided."""
from mudlib.commands.furnish import cmd_furnish
home_zone = _make_zone("home:alice", width=9, height=9)
player = _make_player("alice", zone=home_zone)
player.home_zone = "home:alice"
await cmd_furnish(player, "")
# Player should get usage message
player.writer.write.assert_called()
output = "".join(call.args[0] for call in player.writer.write.call_args_list)
assert "usage" in output.lower() or "furnish" in output.lower()
@pytest.mark.asyncio
async def test_unfurnish_picks_up_item(tmp_path):
"""unfurnish moves furniture from zone to player inventory."""
from mudlib.commands.furnish import cmd_unfurnish
init_housing(tmp_path)
# Create home zone with furniture
home_zone = _make_zone("home:bob", width=9, height=9)
player = _make_player("bob", zone=home_zone, x=4, y=4)
player.home_zone = "home:bob"
# Place a table at player position
table = Thing(name="table", description="A wooden table")
table.move_to(home_zone, x=4, y=4)
# Unfurnish the table
await cmd_unfurnish(player, "table")
# Table should be in inventory
assert table.location is player
assert table in player.contents
assert table not in home_zone._contents
# Player should get feedback
player.writer.write.assert_called()
output = "".join(call.args[0] for call in player.writer.write.call_args_list)
assert "table" in output.lower()
@pytest.mark.asyncio
async def test_unfurnish_not_in_home_zone():
"""unfurnish fails if player is not in their home zone."""
from mudlib.commands.furnish import cmd_unfurnish
overworld = _make_zone("overworld")
player = _make_player("bob", zone=overworld)
player.home_zone = "home:bob"
# Place a table
table = Thing(name="table")
table.move_to(overworld, x=5, y=5)
await cmd_unfurnish(player, "table")
# Table should still be on ground
assert table.location is overworld
assert table not in player.contents
# Player should get error message
player.writer.write.assert_called()
output = "".join(call.args[0] for call in player.writer.write.call_args_list)
assert "home zone" in output.lower()
@pytest.mark.asyncio
async def test_unfurnish_nothing_at_position():
"""unfurnish fails if no matching furniture at player position."""
from mudlib.commands.furnish import cmd_unfurnish
home_zone = _make_zone("home:bob", width=9, height=9)
player = _make_player("bob", zone=home_zone, x=4, y=4)
player.home_zone = "home:bob"
# No furniture at position
await cmd_unfurnish(player, "table")
# Player should get error message
player.writer.write.assert_called()
output = "".join(call.args[0] for call in player.writer.write.call_args_list)
assert (
"no" in output.lower()
or "don't see" in output.lower()
or "can't find" in output.lower()
)
@pytest.mark.asyncio
async def test_unfurnish_no_args():
"""unfurnish fails with usage message if no args provided."""
from mudlib.commands.furnish import cmd_unfurnish
home_zone = _make_zone("home:bob", width=9, height=9)
player = _make_player("bob", zone=home_zone)
player.home_zone = "home:bob"
await cmd_unfurnish(player, "")
# Player should get usage message
player.writer.write.assert_called()
output = "".join(call.args[0] for call in player.writer.write.call_args_list)
assert "usage" in output.lower() or "unfurnish" in output.lower()
@pytest.mark.asyncio
async def test_furnish_saves_zone(tmp_path):
"""furnish persists furniture to the zone TOML file."""
import tomllib
from mudlib.commands.furnish import cmd_furnish
init_housing(tmp_path)
# Create home zone and player
home_zone = _make_zone("home:charlie", width=9, height=9)
player = _make_player("charlie", zone=home_zone, x=4, y=4)
player.home_zone = "home:charlie"
# Give player a lamp
lamp = Thing(name="lamp", description="A brass lamp")
lamp.move_to(player)
# Furnish it
await cmd_furnish(player, "lamp")
# Check TOML file
zone_file = tmp_path / "charlie.toml"
assert zone_file.exists()
with open(zone_file, "rb") as f:
data = tomllib.load(f)
# Should have furniture entry
furniture = data.get("furniture", [])
assert len(furniture) == 1
assert furniture[0]["template"] == "lamp"
assert furniture[0]["x"] == 4
assert furniture[0]["y"] == 4