"""Tests for IF mode integration with player model and server shell.""" from unittest.mock import AsyncMock, MagicMock import pytest from mudlib.if_session import IFResponse, IFSession from mudlib.player import Player @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 player(mock_reader, mock_writer): return Player(name="TestPlayer", x=5, y=5, reader=mock_reader, writer=mock_writer) def test_player_has_if_session_attribute(player): """Player has if_session attribute that defaults to None.""" assert hasattr(player, "if_session") assert player.if_session is None def test_player_if_session_can_be_set(player): """Player.if_session can be set to an IFSession instance.""" session = IFSession(player, "/path/to/story.z5", "story") player.if_session = session assert player.if_session == session @pytest.mark.asyncio async def test_if_mode_routes_input_to_if_session(player): """Input routes to if_session.handle_input in IF mode.""" # Create a mock IF session mock_session = MagicMock() mock_session.handle_input = AsyncMock( return_value=IFResponse(output="You see a room.\r\n", done=False) ) player.if_session = mock_session player.mode_stack.append("if") # Simulate input routing (what shell loop should do) if player.mode == "if" and player.if_session: response = await player.if_session.handle_input("look") assert response.output == "You see a room.\r\n" assert response.done is False mock_session.handle_input.assert_called_once_with("look") @pytest.mark.asyncio async def test_if_mode_done_clears_session_and_pops_mode(player): """When handle_input returns done=True, mode pops and if_session is cleared.""" # Create a mock IF session that returns done=True mock_session = MagicMock() mock_session.handle_input = AsyncMock( return_value=IFResponse(output="Goodbye.\r\n", done=True) ) mock_session.stop = AsyncMock() player.if_session = mock_session player.mode_stack.append("if") # Simulate shell loop handling done response if player.mode == "if" and player.if_session: response = await player.if_session.handle_input("::quit") if response.done: await player.if_session.stop() player.if_session = None player.mode_stack.pop() assert player.mode == "normal" assert player.if_session is None mock_session.stop.assert_called_once() @pytest.mark.asyncio async def test_mode_stack_push_and_pop_for_if(player): """Test mode stack mechanics for IF mode.""" assert player.mode_stack == ["normal"] assert player.mode == "normal" # Enter IF mode player.mode_stack.append("if") assert player.mode == "if" assert player.mode_stack == ["normal", "if"] # Exit IF mode player.mode_stack.pop() assert player.mode == "normal" assert player.mode_stack == ["normal"] @pytest.mark.asyncio async def test_empty_input_allowed_in_if_mode(player): """Empty input is allowed in IF mode.""" # Create a mock IF session mock_session = MagicMock() mock_session.handle_input = AsyncMock( return_value=IFResponse(output="Time passes.\r\n", done=False) ) player.if_session = mock_session player.mode_stack.append("if") # Empty input should still be passed to IF session response = await player.if_session.handle_input("") assert response.output == "Time passes.\r\n" mock_session.handle_input.assert_called_once_with("")