mud/tests/test_spawn_command.py
Jared Miller f5646589b5
Migrate look to use player.location (Zone)
- Removed world module-level variable from look.py
- look.cmd_look() now uses player.location.get_viewport() instead of world.get_viewport()
- look.cmd_look() uses zone.contents_near() to find nearby entities instead of iterating global players/mobs lists
- Wrapping calculations use zone.width/height/toroidal instead of world properties
- Added type check for player.location being a Zone instance
- Removed look.world injection from server.py
- Updated all tests to remove look.world injection
- spawn_mob() and combat commands also migrated to use Zone (player.location)
- Removed orphaned code from test_mob_ai.py and test_variant_prefix.py
2026-02-11 19:36:46 -05:00

109 lines
2.7 KiB
Python

"""Tests for the spawn command."""
from unittest.mock import AsyncMock, MagicMock
import pytest
from mudlib.commands.spawn import cmd_spawn
from mudlib.mobs import MobTemplate, mob_templates, mobs
from mudlib.player import Player, players
from mudlib.zone import Zone
@pytest.fixture(autouse=True)
def clear_state():
"""Clear mobs, templates, and players."""
mobs.clear()
mob_templates.clear()
players.clear()
yield
mobs.clear()
mob_templates.clear()
players.clear()
@pytest.fixture
def mock_writer():
writer = MagicMock()
writer.write = MagicMock()
writer.drain = AsyncMock()
return writer
@pytest.fixture
def mock_reader():
return MagicMock()
@pytest.fixture
def test_zone():
"""Create a test zone for spawning."""
terrain = [["." for _ in range(256)] for _ in range(256)]
zone = Zone(
name="testzone",
width=256,
height=256,
toroidal=True,
terrain=terrain,
impassable=set(),
)
return zone
@pytest.fixture
def player(mock_reader, mock_writer, test_zone):
p = Player(name="Goku", x=10, y=20, reader=mock_reader, writer=mock_writer)
p.location = test_zone
test_zone._contents.append(p)
players[p.name] = p
return p
@pytest.fixture
def goblin_template():
t = MobTemplate(
name="goblin",
description="a snarling goblin",
pl=50.0,
stamina=40.0,
max_stamina=40.0,
moves=["punch left"],
)
mob_templates["goblin"] = t
return t
@pytest.mark.asyncio
async def test_spawn_valid_mob(player, goblin_template):
"""Spawn creates a mob at the player's position."""
await cmd_spawn(player, "goblin")
assert len(mobs) == 1
mob = mobs[0]
assert mob.name == "goblin"
assert mob.x == player.x
assert mob.y == player.y
messages = [call[0][0] for call in player.writer.write.call_args_list]
assert any("goblin" in msg.lower() and "appears" in msg.lower() for msg in messages)
@pytest.mark.asyncio
async def test_spawn_invalid_type(player, goblin_template):
"""Spawn with unknown type shows available mobs."""
await cmd_spawn(player, "dragon")
assert len(mobs) == 0
messages = [call[0][0] for call in player.writer.write.call_args_list]
assert any("unknown" in msg.lower() for msg in messages)
assert any("goblin" in msg.lower() for msg in messages)
@pytest.mark.asyncio
async def test_spawn_no_args(player, goblin_template):
"""Spawn with no args shows usage."""
await cmd_spawn(player, "")
assert len(mobs) == 0
messages = [call[0][0] for call in player.writer.write.call_args_list]
assert any("usage" in msg.lower() for msg in messages)