263 lines
7.9 KiB
Python
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
|