mud/tests/test_look_targeting.py

207 lines
5.3 KiB
Python

"""Tests for look command target resolution."""
import pytest
from mudlib.commands.look import cmd_look
from mudlib.entity import Mob
from mudlib.player import Player
from mudlib.thing import Thing
from mudlib.zone import Zone
@pytest.fixture
def zone():
"""Create a test zone."""
terrain = [["." for _ in range(100)] for _ in range(100)]
return Zone(
name="test",
description="Test Zone",
width=100,
height=100,
toroidal=False,
terrain=terrain,
)
@pytest.fixture
def mock_writer():
"""Create a mock writer that captures output."""
from unittest.mock import MagicMock
class MockWriter:
def __init__(self):
self.output = []
# Mock telnet options
self.local_option = MagicMock()
self.remote_option = MagicMock()
self.local_option.enabled = MagicMock(return_value=False)
self.remote_option.enabled = MagicMock(return_value=False)
def write(self, data):
self.output.append(data)
async def drain(self):
pass
def get_output(self):
return "".join(self.output)
return MockWriter()
@pytest.fixture
def player(zone, mock_writer):
"""Create a test player."""
p = Player(
name="TestPlayer",
location=zone,
x=50,
y=50,
writer=mock_writer,
)
return p
@pytest.mark.asyncio
async def test_look_finds_mob_by_exact_name(player, zone, mock_writer):
"""look goblin finds mob with exact name."""
_mob = Mob(name="goblin", location=zone, x=50, y=50)
await cmd_look(player, "goblin")
output = mock_writer.get_output()
assert "goblin" in output.lower()
@pytest.mark.asyncio
async def test_look_finds_mob_by_prefix(player, zone, mock_writer):
"""look gob prefix matches goblin."""
_mob = Mob(name="goblin", location=zone, x=50, y=50)
await cmd_look(player, "gob")
output = mock_writer.get_output()
assert "goblin" in output.lower()
@pytest.mark.asyncio
async def test_look_finds_second_mob_with_ordinal(player, zone, mock_writer):
"""look 2.goblin finds second goblin."""
_mob1 = Mob(name="goblin", location=zone, x=50, y=50)
_mob2 = Mob(name="goblin", location=zone, x=50, y=50)
await cmd_look(player, "2.goblin")
output = mock_writer.get_output()
# Should find the second goblin
assert "goblin" in output.lower()
@pytest.mark.asyncio
async def test_look_finds_thing_on_ground(player, zone, mock_writer):
"""look sword finds thing on ground and shows description."""
_sword = Thing(
name="sword",
description="A sharp blade.",
location=zone,
x=50,
y=50,
)
await cmd_look(player, "sword")
output = mock_writer.get_output()
assert "A sharp blade." in output
@pytest.mark.asyncio
async def test_look_shows_error_for_nonexistent(player, zone, mock_writer):
"""look nonexistent shows 'You don't see that here.'"""
await cmd_look(player, "nonexistent")
output = mock_writer.get_output()
assert "You don't see that here." in output
@pytest.mark.asyncio
async def test_look_prioritizes_entity_over_thing(player, zone, mock_writer):
"""look target finds entity before thing with same name."""
_mob = Mob(name="target", location=zone, x=50, y=50)
_thing = Thing(
name="target",
description="A thing.",
location=zone,
x=50,
y=50,
)
await cmd_look(player, "target")
output = mock_writer.get_output()
# Should show entity info (name/posture), not thing description
assert "target" in output.lower()
# Should not show thing description
assert "A thing." not in output
@pytest.mark.asyncio
async def test_look_skips_dead_mobs(player, zone, mock_writer):
"""look goblin skips dead mobs."""
_mob = Mob(name="goblin", location=zone, x=50, y=50)
_mob.alive = False
await cmd_look(player, "goblin")
output = mock_writer.get_output()
assert "You don't see that here." in output
@pytest.mark.asyncio
async def test_look_skips_self(player, zone, mock_writer):
"""look TestPlayer doesn't target the player themselves."""
await cmd_look(player, "TestPlayer")
output = mock_writer.get_output()
assert "You don't see that here." in output
@pytest.mark.asyncio
async def test_look_finds_thing_in_inventory(player, zone, mock_writer):
"""look sword finds thing in inventory when not on ground."""
_sword = Thing(
name="sword",
description="A sharp blade.",
location=player,
)
await cmd_look(player, "sword")
output = mock_writer.get_output()
assert "A sharp blade." in output
@pytest.mark.asyncio
async def test_look_finds_second_thing_with_ordinal(player, zone, mock_writer):
"""look 2.sword finds second sword on ground."""
_sword1 = Thing(
name="sword",
description="A rusty blade.",
location=zone,
x=50,
y=50,
)
_sword2 = Thing(
name="sword",
description="A sharp blade.",
location=zone,
x=50,
y=50,
)
await cmd_look(player, "2.sword")
output = mock_writer.get_output()
# Should show the second sword's description
assert "A sharp blade." in output
# Should not show the first sword's description
assert "A rusty blade." not in output