Inventory saved as JSON list of thing template names in an inventory column. Migration adds column to existing databases. load_player_data returns inventory list, save_player serializes Thing names from contents.
152 lines
3.5 KiB
Python
152 lines
3.5 KiB
Python
"""Tests for inventory persistence."""
|
|
|
|
import json
|
|
|
|
import pytest
|
|
|
|
from mudlib.player import Player
|
|
from mudlib.store import (
|
|
create_account,
|
|
init_db,
|
|
load_player_data,
|
|
save_player,
|
|
)
|
|
from mudlib.thing import Thing
|
|
from mudlib.things import ThingTemplate, thing_templates
|
|
from mudlib.zone import Zone
|
|
|
|
|
|
@pytest.fixture
|
|
def db(tmp_path):
|
|
"""Initialize a temporary database."""
|
|
db_path = tmp_path / "test.db"
|
|
init_db(db_path)
|
|
return db_path
|
|
|
|
|
|
@pytest.fixture
|
|
def test_zone():
|
|
terrain = [["." for _ in range(10)] for _ in range(10)]
|
|
return Zone(
|
|
name="testzone",
|
|
width=10,
|
|
height=10,
|
|
terrain=terrain,
|
|
)
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def register_templates():
|
|
"""Register test templates."""
|
|
thing_templates.clear()
|
|
thing_templates["rock"] = ThingTemplate(
|
|
name="rock",
|
|
description="a rock",
|
|
aliases=["stone"],
|
|
)
|
|
thing_templates["sword"] = ThingTemplate(
|
|
name="sword",
|
|
description="a sword",
|
|
)
|
|
yield
|
|
thing_templates.clear()
|
|
|
|
|
|
# --- save ---
|
|
|
|
|
|
def test_save_player_with_inventory(db, test_zone):
|
|
"""save_player persists inventory as JSON list of template names."""
|
|
import sqlite3
|
|
|
|
create_account("Alice", "pass123")
|
|
player = Player(
|
|
name="Alice",
|
|
x=5,
|
|
y=5,
|
|
location=test_zone,
|
|
)
|
|
Thing(name="rock", location=player)
|
|
Thing(name="sword", location=player)
|
|
|
|
save_player(player)
|
|
|
|
# Check raw DB value
|
|
conn = sqlite3.connect(str(db))
|
|
cursor = conn.cursor()
|
|
cursor.execute("SELECT inventory FROM accounts WHERE name = ?", ("Alice",))
|
|
row = cursor.fetchone()
|
|
conn.close()
|
|
|
|
assert row is not None
|
|
inventory = json.loads(row[0])
|
|
assert sorted(inventory) == ["rock", "sword"]
|
|
|
|
|
|
def test_save_player_empty_inventory(db, test_zone):
|
|
"""save_player stores empty list when no inventory."""
|
|
import sqlite3
|
|
|
|
create_account("Bob", "pass123")
|
|
player = Player(
|
|
name="Bob",
|
|
x=5,
|
|
y=5,
|
|
location=test_zone,
|
|
)
|
|
|
|
save_player(player)
|
|
|
|
conn = sqlite3.connect(str(db))
|
|
cursor = conn.cursor()
|
|
cursor.execute("SELECT inventory FROM accounts WHERE name = ?", ("Bob",))
|
|
row = cursor.fetchone()
|
|
conn.close()
|
|
|
|
assert row is not None
|
|
assert json.loads(row[0]) == []
|
|
|
|
|
|
# --- load ---
|
|
|
|
|
|
def test_load_player_data_includes_inventory(db):
|
|
"""load_player_data returns inventory list."""
|
|
import sqlite3
|
|
|
|
create_account("Alice", "pass123")
|
|
|
|
# Manually set inventory in DB
|
|
conn = sqlite3.connect(str(db))
|
|
cursor = conn.cursor()
|
|
cursor.execute(
|
|
"UPDATE accounts SET inventory = ? WHERE name = ?",
|
|
(json.dumps(["rock", "sword"]), "Alice"),
|
|
)
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
data = load_player_data("Alice")
|
|
assert data is not None
|
|
assert sorted(data["inventory"]) == ["rock", "sword"]
|
|
|
|
|
|
def test_load_player_data_empty_inventory(db):
|
|
"""load_player_data returns empty list for no inventory."""
|
|
create_account("Bob", "pass123")
|
|
data = load_player_data("Bob")
|
|
assert data is not None
|
|
assert data["inventory"] == []
|
|
|
|
|
|
def test_load_player_data_migration_no_column(db):
|
|
"""Old DB without inventory column returns empty list."""
|
|
|
|
create_account("Charlie", "pass123")
|
|
|
|
# init_db already ran the migration adding the inventory column,
|
|
# so this just verifies a fresh account gets empty inventory
|
|
|
|
data = load_player_data("Charlie")
|
|
assert data is not None
|
|
assert data["inventory"] == []
|