diff --git a/src/mudlib/if_session.py b/src/mudlib/if_session.py index 7eec8bb..aa06aa6 100644 --- a/src/mudlib/if_session.py +++ b/src/mudlib/if_session.py @@ -109,6 +109,31 @@ class IFSession: confirmation = await self._read_response() return confirmation + async def _do_restore(self) -> str: + """Restore game state from disk. Returns game text or empty string.""" + # Check if save file exists + if not self.save_path.exists(): + return "" + + if not self.process or not self.process.stdin: + return "" + + # Send "restore" command to dfrotz + self.process.stdin.write(b"restore\n") + await self.process.stdin.drain() + + # Read filename prompt + await self._read_response() + + # Send save file path + save_path_str = str(self.save_path) + self.process.stdin.write(f"{save_path_str}\n".encode()) + await self.process.stdin.drain() + + # Read game text response + game_text = await self._read_response() + return game_text + async def _read_response(self) -> str: """Read dfrotz output until the '>' prompt appears.""" if not self.process or not self.process.stdout: diff --git a/tests/test_if_session.py b/tests/test_if_session.py index dc3062e..2ff7c37 100644 --- a/tests/test_if_session.py +++ b/tests/test_if_session.py @@ -410,3 +410,72 @@ async def test_do_save_creates_save_directory(tmp_path): # Now it should exist assert expected_dir.exists() + + +@pytest.mark.asyncio +async def test_do_restore_returns_empty_if_no_save(tmp_path): + """_do_restore() returns empty string if no save file exists.""" + player = MagicMock() + player.name = "tester" + session = IFSession(player, "/path/to/zork.z5", "zork") + session._data_dir = tmp_path + + # Mock process (even though we won't use it) + session.process = MagicMock() + + # No save file exists + assert not session.save_path.exists() + + result = await session._do_restore() + + assert result == "" + + +@pytest.mark.asyncio +async def test_do_restore_sends_restore_command(tmp_path): + """_do_restore() sends restore command and filepath to dfrotz.""" + player = MagicMock() + player.name = "tester" + session = IFSession(player, "/path/to/zork.z5", "zork") + session._data_dir = tmp_path + + # Create a fake save file + session._ensure_save_dir() + session.save_path.write_text("fake save data") + + # Mock process + mock_process = MagicMock() + mock_process.stdin = MagicMock() + mock_process.stdin.write = MagicMock() + mock_process.stdin.drain = AsyncMock() + mock_process.stdout = AsyncMock() + session.process = mock_process + + # Simulate dfrotz responses: filename prompt, then game text + responses = [ + b"Enter saved game to load: \n>", + b"West of House\nYou are standing in an open field.\n>", + ] + response_data = b"".join(responses) + + async def read_side_effect(n): + nonlocal response_data + if response_data: + byte = response_data[:1] + response_data = response_data[1:] + return byte + return b"" + + mock_process.stdout.read = AsyncMock(side_effect=read_side_effect) + + result = await session._do_restore() + + # Should have written "restore\n" then the filepath + calls = mock_process.stdin.write.call_args_list + assert len(calls) == 2 + assert calls[0][0][0] == b"restore\n" + assert str(session.save_path) in calls[1][0][0].decode() + + # Result should contain game text + assert "West of House" in result + assert "open field" in result