"""Tests for auto-triggering portals on movement.""" import pytest from mudlib.player import Player from mudlib.portal import Portal from mudlib.zone import Zone from mudlib.zones import register_zone, zone_registry @pytest.fixture def test_zone(): terrain = [["." for _ in range(10)] for _ in range(10)] return Zone( name="testzone", width=10, height=10, toroidal=True, terrain=terrain, ) @pytest.fixture def target_zone(): terrain = [["." for _ in range(10)] for _ in range(10)] return Zone( name="targetzone", width=10, height=10, toroidal=True, terrain=terrain, ) @pytest.fixture def player(mock_reader, mock_writer, test_zone): p = Player( name="TestPlayer", x=5, y=5, reader=mock_reader, writer=mock_writer, location=test_zone, ) return p @pytest.fixture(autouse=True) def clear_zones(): """Clear zone registry before and after each test.""" zone_registry.clear() yield zone_registry.clear() @pytest.mark.asyncio async def test_move_onto_portal_triggers_zone_transition( player, test_zone, target_zone ): """Walking onto a portal tile auto-triggers zone transition.""" from mudlib.commands.movement import move_player register_zone("targetzone", target_zone) # Place portal at (6, 5), one tile east of player Portal( name="shimmering doorway", location=test_zone, x=6, y=5, target_zone="targetzone", target_x=3, target_y=7, ) # Move east onto the portal await move_player(player, 1, 0, "east") # Player should end up in target zone at portal's target coords assert player.location is target_zone assert player.x == 3 assert player.y == 7 assert player in target_zone.contents assert player not in test_zone.contents @pytest.mark.asyncio async def test_move_onto_portal_sends_transition_message( player, test_zone, target_zone, mock_writer ): """Auto-triggered portal shows transition message to player.""" from mudlib.commands.movement import move_player register_zone("targetzone", target_zone) Portal( name="mystic portal", location=test_zone, x=6, y=5, target_zone="targetzone", target_x=2, target_y=3, ) await move_player(player, 1, 0, "east") # Check that player got a transition message output = "".join([call[0][0] for call in mock_writer.write.call_args_list]) assert "enter" in output.lower() or "portal" in output.lower() @pytest.mark.asyncio async def test_move_onto_tile_without_portal_normal_movement( player, test_zone, mock_writer ): """Normal movement still works when no portal present.""" from mudlib.commands.movement import move_player initial_x = player.x initial_y = player.y # Move east to empty tile await move_player(player, 1, 0, "east") # Player should still be in test zone with updated position assert player.location is test_zone assert player.x == initial_x + 1 assert player.y == initial_y assert player in test_zone.contents # Should see look output (viewport with @ symbol) output = "".join([call[0][0] for call in mock_writer.write.call_args_list]) assert "@" in output # Player's position marker in viewport @pytest.mark.asyncio async def test_portal_autotrigger_target_zone_not_found(player, test_zone, mock_writer): """If target zone not registered, player stays and gets error.""" from mudlib.commands.movement import move_player # Create portal with invalid target zone (not registered) Portal( name="broken portal", location=test_zone, x=6, y=5, target_zone="nonexistent", target_x=3, target_y=7, ) await move_player(player, 1, 0, "east") # Player should stay in original zone at portal tile assert player.location is test_zone assert player.x == 6 assert player.y == 5 # Should see error message output = "".join([call[0][0] for call in mock_writer.write.call_args_list]) assert "doesn't lead anywhere" in output.lower() or "nowhere" in output.lower()