Add restore functionality to IF sessions
This commit is contained in:
parent
e2bd260538
commit
5f0fec14ef
2 changed files with 94 additions and 0 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue