mud/tests/test_persistence.py
Jared Miller 54998c29c5
Add save on logout and disconnect
Player state is now saved when using the quit command or when the connection
is lost unexpectedly. Ensures progress is preserved even without auto-save.
2026-02-07 21:42:16 -05:00

153 lines
3.6 KiB
Python

"""Tests for persistence behavior (save on quit/disconnect)."""
import os
import tempfile
from unittest.mock import AsyncMock, MagicMock
import pytest
from mudlib.commands.quit import cmd_quit
from mudlib.player import Player, players
from mudlib.store import create_account, init_db, load_player_data, save_player
@pytest.fixture
def temp_db():
"""Create a temporary database for testing."""
with tempfile.NamedTemporaryFile(delete=False, suffix=".db") as f:
db_path = f.name
init_db(db_path)
yield db_path
# Cleanup
os.unlink(db_path)
@pytest.fixture
def mock_writer():
writer = MagicMock()
writer.write = MagicMock()
writer.drain = AsyncMock()
writer.close = MagicMock()
writer.is_closing = MagicMock(return_value=False)
return writer
@pytest.fixture
def mock_reader():
return MagicMock()
@pytest.mark.asyncio
async def test_quit_saves_player_state(temp_db, mock_reader, mock_writer):
"""Quit command saves player state before disconnecting."""
# Create an account
create_account("TestPlayer", "password")
# Create player with modified state
player = Player(
name="TestPlayer",
x=42,
y=17,
pl=85.0,
stamina=60.0,
max_stamina=120.0,
flying=True,
reader=mock_reader,
writer=mock_writer,
)
# Add to player registry
players["TestPlayer"] = player
# Execute quit command
await cmd_quit(player, "")
# Verify player was saved
data = load_player_data("TestPlayer")
assert data is not None
assert data["x"] == 42
assert data["y"] == 17
assert data["pl"] == 85.0
assert data["stamina"] == 60.0
assert data["max_stamina"] == 120.0
assert data["flying"] is True
# Verify player was removed from registry
assert "TestPlayer" not in players
@pytest.mark.asyncio
async def test_save_multiple_times(temp_db, mock_reader, mock_writer):
"""Player state can be saved multiple times (updates)."""
create_account("TestPlayer", "password")
player = Player(
name="TestPlayer",
x=10,
y=20,
reader=mock_reader,
writer=mock_writer,
)
# Save initial state
players["TestPlayer"] = player
await cmd_quit(player, "")
# Verify initial save
data = load_player_data("TestPlayer")
assert data is not None
assert data["x"] == 10
assert data["y"] == 20
# Create new player instance with different position
player2 = Player(
name="TestPlayer",
x=50,
y=60,
reader=mock_reader,
writer=mock_writer,
)
# Save again
players["TestPlayer"] = player2
await cmd_quit(player2, "")
# Verify updated state
data = load_player_data("TestPlayer")
assert data is not None
assert data["x"] == 50
assert data["y"] == 60
@pytest.mark.asyncio
async def test_autosave_persists_player_changes(temp_db, mock_reader, mock_writer):
"""Auto-save persists player state changes during gameplay."""
create_account("TestPlayer", "password")
# Create player
player = Player(
name="TestPlayer",
x=10,
y=20,
pl=100.0,
reader=mock_reader,
writer=mock_writer,
)
# Simulate player moving and taking damage
player.x = 25
player.y = 35
player.pl = 75.0
# Manually trigger save (simulating auto-save)
save_player(player)
# Verify state was saved
data = load_player_data("TestPlayer")
assert data is not None
assert data["x"] == 25
assert data["y"] == 35
assert data["pl"] == 75.0