231 lines
6.2 KiB
Python
231 lines
6.2 KiB
Python
"""Tests for paint mode - terrain editing admin tool."""
|
|
|
|
import pytest
|
|
|
|
from mudlib.player import Player
|
|
from mudlib.zone import Zone
|
|
|
|
|
|
@pytest.fixture
|
|
def player():
|
|
"""Create a test player with a mock writer."""
|
|
mock_writer = MockWriter()
|
|
player = Player(
|
|
name="TestPlayer",
|
|
x=5,
|
|
y=5,
|
|
writer=mock_writer,
|
|
)
|
|
# Create a simple zone for testing
|
|
zone = Zone(
|
|
"test_zone",
|
|
width=20,
|
|
height=20,
|
|
terrain=[["." for _ in range(20)] for _ in range(20)],
|
|
impassable={"^", "~", "#"}, # Add # as impassable
|
|
)
|
|
# Add a wall for passability testing
|
|
zone.terrain[5][6] = "#"
|
|
player.location = zone
|
|
return player
|
|
|
|
|
|
class MockWriter:
|
|
"""Mock writer that captures output."""
|
|
|
|
def __init__(self):
|
|
self.messages = []
|
|
|
|
def write(self, message: str):
|
|
self.messages.append(message)
|
|
|
|
async def drain(self):
|
|
pass
|
|
|
|
def send_gmcp(self, package: str, data: dict):
|
|
"""Mock GMCP send (no-op for paint mode tests)."""
|
|
pass
|
|
|
|
def send_msdp(self, data: dict):
|
|
"""Mock MSDP send (no-op for paint mode tests)."""
|
|
pass
|
|
|
|
def get_output(self) -> str:
|
|
return "".join(self.messages)
|
|
|
|
def clear(self):
|
|
self.messages = []
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_enter_paint_mode(player):
|
|
"""@paint command sets player.paint_mode = True and sends confirmation."""
|
|
from mudlib.commands.paint import cmd_paint
|
|
|
|
await cmd_paint(player, "")
|
|
assert player.paint_mode is True
|
|
output = player.writer.get_output()
|
|
assert "paint mode" in output.lower()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_exit_paint_mode(player):
|
|
"""@paint when already in paint mode exits it."""
|
|
from mudlib.commands.paint import cmd_paint
|
|
|
|
# Enter paint mode first
|
|
await cmd_paint(player, "")
|
|
player.writer.clear()
|
|
|
|
# Exit paint mode
|
|
await cmd_paint(player, "")
|
|
assert player.paint_mode is False
|
|
output = player.writer.get_output()
|
|
assert "exit" in output.lower() or "off" in output.lower()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_paint_mode_default_survey(player):
|
|
"""Entering paint mode starts in survey state (player.painting = False)."""
|
|
from mudlib.commands.paint import cmd_paint
|
|
|
|
await cmd_paint(player, "")
|
|
assert player.paint_mode is True
|
|
assert player.painting is False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_toggle_painting(player):
|
|
"""p command toggles player.painting between True and False."""
|
|
from mudlib.commands.paint import cmd_toggle_painting
|
|
|
|
# Must be in paint mode first
|
|
player.paint_mode = True
|
|
|
|
# Toggle to painting
|
|
await cmd_toggle_painting(player, "")
|
|
assert player.painting is True
|
|
player.writer.clear()
|
|
|
|
# Toggle back to survey
|
|
await cmd_toggle_painting(player, "")
|
|
assert player.painting is False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_toggle_painting_requires_paint_mode(player):
|
|
"""p command only works in paint mode."""
|
|
from mudlib.commands.paint import cmd_toggle_painting
|
|
|
|
player.paint_mode = False
|
|
await cmd_toggle_painting(player, "")
|
|
output = player.writer.get_output()
|
|
assert "paint mode" in output.lower()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_set_brush(player):
|
|
"""Typing a single character while in paint mode sets player.paint_brush."""
|
|
from mudlib.commands.paint import cmd_set_brush
|
|
|
|
player.paint_mode = True
|
|
|
|
await cmd_set_brush(player, "#")
|
|
assert player.paint_brush == "#"
|
|
|
|
await cmd_set_brush(player, "~")
|
|
assert player.paint_brush == "~"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_set_brush_requires_paint_mode(player):
|
|
"""Brush command only works in paint mode."""
|
|
from mudlib.commands.paint import cmd_set_brush
|
|
|
|
player.paint_mode = False
|
|
await cmd_set_brush(player, "#")
|
|
output = player.writer.get_output()
|
|
assert "paint mode" in output.lower()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_set_brush_requires_single_char(player):
|
|
"""Brush must be a single character."""
|
|
from mudlib.commands.paint import cmd_set_brush
|
|
|
|
player.paint_mode = True
|
|
await cmd_set_brush(player, "##")
|
|
output = player.writer.get_output()
|
|
assert "single character" in output.lower()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_paint_mode_movement_ignores_passability(player):
|
|
"""Movement in paint mode doesn't check passability."""
|
|
from mudlib.commands.movement import move_player
|
|
|
|
# There's a wall at (6, 5) - normally can't move there
|
|
player.paint_mode = True
|
|
|
|
# Should be able to move into the wall
|
|
await move_player(player, 1, 0, "east")
|
|
assert player.x == 6
|
|
assert player.y == 5
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_painting_places_tile(player):
|
|
"""Moving while painting sets terrain tile at old position to brush char."""
|
|
from mudlib.commands.movement import move_player
|
|
|
|
player.paint_mode = True
|
|
player.painting = True
|
|
player.paint_brush = "~"
|
|
|
|
# Move from (5,5) to (6,5)
|
|
old_x, old_y = player.x, player.y
|
|
await move_player(player, 1, 0, "east")
|
|
|
|
# Check that the old position now has the brush character
|
|
zone = player.location
|
|
assert isinstance(zone, Zone)
|
|
assert zone.terrain[old_y][old_x] == "~"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_painting_only_in_paint_mode(player):
|
|
"""Painting flag has no effect outside paint mode."""
|
|
from mudlib.commands.movement import move_player
|
|
|
|
player.paint_mode = False
|
|
player.painting = True
|
|
player.paint_brush = "~"
|
|
|
|
# Try to move into wall at (6, 5)
|
|
await move_player(player, 1, 0, "east")
|
|
|
|
# Should have failed - player still at (5, 5)
|
|
assert player.x == 5
|
|
assert player.y == 5
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_survey_mode_does_not_paint(player):
|
|
"""Survey mode (painting=False) allows movement but doesn't paint."""
|
|
from mudlib.commands.movement import move_player
|
|
|
|
player.paint_mode = True
|
|
player.painting = False
|
|
player.paint_brush = "~"
|
|
|
|
old_x, old_y = player.x, player.y
|
|
await move_player(player, 1, 0, "east")
|
|
|
|
# Movement should have happened
|
|
assert player.x == 6
|
|
assert player.y == 5
|
|
|
|
# But no painting should have occurred
|
|
zone = player.location
|
|
assert isinstance(zone, Zone)
|
|
assert zone.terrain[old_y][old_x] == "." # Still the original tile
|