micro-rpg-engine / tests /test_parser.py
luizbarbedo's picture
Upload folder using huggingface_hub
7fe39f3 verified
Raw
History Blame Contribute Delete
3.4 kB
"""Parser + engine smoke tests. Run with: python -m tests.test_parser
These use the mock backend, so no model weights or network are required."""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from engine.game_state import GameState, Enemy
from engine import parser
from engine.engine import GameEngine
from engine.llm import build_backend
def check(name, cond):
status = "ok " if cond else "FAIL"
print(f"[{status}] {name}")
if not cond:
raise AssertionError(name)
def test_parse_blocks():
raw = (
"<narrative>You enter a dim hall.</narrative>"
"<state>\nHP: -5\nGOLD: +10\nITEM_ADD: Torch\nLOCATION: Dim Hall\n</state>"
"<choices>\n1. Go north.\n2. Light the torch.\n</choices>"
)
narrative, choices, lines = parser.parse(raw)
check("narrative extracted", narrative == "You enter a dim hall.")
check("choices extracted", choices == ["Go north.", "Light the torch."])
check("state lines count", len(lines) == 4)
def test_apply_changes_clamped():
state = GameState(hp=20, max_hp=20, gold=10)
parser.apply_state_changes(state, ["HP: -5", "GOLD: +10", "ITEM_ADD: Torch"])
check("hp reduced", state.hp == 15)
check("gold added", state.gold == 20)
check("item added", state.has_item("Torch"))
# over-heal is clamped to max_hp
parser.apply_state_changes(state, ["HP: +999"])
check("heal clamped to max", state.hp == 20)
# can't go below zero gold
parser.apply_state_changes(state, ["GOLD: -9999"])
check("gold floored at 0", state.gold == 0)
def test_death():
state = GameState(hp=5)
parser.apply_state_changes(state, ["HP: -50"])
check("hp floored at 0", state.hp == 0)
check("game over on death", state.game_over)
def test_combat_flow():
state = GameState()
parser.apply_state_changes(state, ["ENEMY: Goblin|hp=10|atk=4"])
check("combat started", state.enemy is not None and state.enemy.name == "Goblin")
parser.apply_state_changes(state, ["ENEMY_HP: -6"])
check("enemy damaged", state.enemy.hp == 4)
parser.apply_state_changes(state, ["ENEMY_HP: -10"])
check("combat ended on death", state.enemy is None)
def test_leveling():
state = GameState(level=1, xp=0, max_hp=20)
parser.apply_state_changes(state, ["XP: +10"])
check("leveled up", state.level == 2)
check("max hp grew", state.max_hp == 25)
def test_unparseable_ignored():
state = GameState(hp=20)
before = state.to_dict()
parser.apply_state_changes(state, ["HP: lots", "WUT: 5", "random gibberish"])
check("garbage ignored", state.to_dict() == before)
def test_full_engine_mock():
engine = GameEngine(build_backend("mock"))
opening = engine.start()
check("opening has narrative", len(opening.narrative) > 0)
check("opening has choices", len(opening.choices) == 3)
# force a combat then attack
engine.state.start_combat(Enemy("Wraith", hp=10, max_hp=10, attack=3))
res = engine.act("I attack the wraith with my dagger")
check("attack damaged enemy or ended combat",
engine.state.enemy is None or engine.state.enemy.hp < 10)
def main():
tests = [v for k, v in sorted(globals().items()) if k.startswith("test_")]
for t in tests:
t()
print(f"\nAll {len(tests)} test groups passed.")
if __name__ == "__main__":
main()