120 lines
3.2 KiB
Python
120 lines
3.2 KiB
Python
"""Tests for the GMCP parser."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
from progetto2.gmcp import (
|
|
GmcpEvent,
|
|
extract_room_info,
|
|
extract_vitals,
|
|
parse_gmcp,
|
|
)
|
|
|
|
|
|
def test_parse_module_only() -> None:
|
|
ev = parse_gmcp(b"Char.Login")
|
|
assert ev == GmcpEvent("Char.Login", None)
|
|
|
|
|
|
def test_parse_with_json_object() -> None:
|
|
raw = b'Char.Vitals {"hp":100,"max_hp":100,"sp":50,"mv":80}'
|
|
ev = parse_gmcp(raw)
|
|
assert ev is not None
|
|
assert ev.module == "Char.Vitals"
|
|
assert ev.data == {"hp": 100, "max_hp": 100, "sp": 50, "mv": 80}
|
|
|
|
|
|
def test_parse_with_json_array() -> None:
|
|
raw = b"Room.Info " + json.dumps(
|
|
[{"name": "Foo"}, {"name": "Bar"}]
|
|
).encode()
|
|
ev = parse_gmcp(raw)
|
|
assert ev is not None
|
|
assert ev.module == "Room.Info"
|
|
assert isinstance(ev.data, list)
|
|
assert len(ev.data) == 2
|
|
|
|
|
|
def test_parse_garbage_returns_none_or_partial() -> None:
|
|
# Empty payload
|
|
assert parse_gmcp(b"") is None
|
|
# Whitespace only
|
|
assert parse_gmcp(b" \n") is None
|
|
# Bad module
|
|
assert parse_gmcp(b" .bad") is None
|
|
|
|
|
|
def test_parse_invalid_json_keeps_module() -> None:
|
|
ev = parse_gmcp(b"Char.Vitals {not valid")
|
|
assert ev is not None
|
|
assert ev.module == "Char.Vitals"
|
|
assert ev.data is None # JSON parse failure tolerated
|
|
|
|
|
|
def test_extract_vitals_basic() -> None:
|
|
v = extract_vitals(
|
|
{"hp": 100, "max_hp": 100, "sp": 50, "max_sp": 50, "mv": 80, "max_mv": 80}
|
|
)
|
|
assert v == {
|
|
"hp": 100, "max_hp": 100,
|
|
"sp": 50, "max_sp": 50,
|
|
"mv": 80, "max_mv": 80,
|
|
}
|
|
|
|
|
|
def test_extract_vitals_synonyms() -> None:
|
|
v = extract_vitals({"health": 50, "max_health": 100, "mana": 30, "move": 80})
|
|
assert v["hp"] == 50
|
|
assert v["max_hp"] == 100
|
|
assert v["sp"] == 30
|
|
assert v["mv"] == 80
|
|
|
|
|
|
def test_extract_vitals_partial() -> None:
|
|
v = extract_vitals({"hp": 100})
|
|
assert v == {"hp": 100}
|
|
|
|
|
|
def test_extract_vitals_empty_or_non_dict() -> None:
|
|
assert extract_vitals({}) == {}
|
|
assert extract_vitals(None) == {}
|
|
assert extract_vitals([1, 2, 3]) == {}
|
|
|
|
|
|
def test_extract_room_info_with_vnum() -> None:
|
|
info = extract_room_info(
|
|
{"name": "Outer Courtyard", "num": 1234, "exits": {"north": "vnum99"}}
|
|
)
|
|
assert info is not None
|
|
rid, name, body, num_id = info
|
|
assert name == "Outer Courtyard"
|
|
assert rid == "vnum1234"
|
|
assert num_id == "vnum1234"
|
|
|
|
|
|
def test_extract_room_info_without_vnum() -> None:
|
|
info = extract_room_info(
|
|
{"title": "Dungeon Entry", "description": "Stairs lead down.", "exits": ["n", "s"]}
|
|
)
|
|
assert info is not None
|
|
rid, name, _, num_id = info
|
|
assert name == "Dungeon Entry"
|
|
assert rid == "dungeon entry"
|
|
assert num_id is None
|
|
|
|
|
|
def test_extract_room_info_no_name_returns_none() -> None:
|
|
assert extract_room_info({"num": 1}) is None
|
|
assert extract_room_info({"exits": ["n"]}) is None
|
|
assert extract_room_info(None) is None
|
|
|
|
|
|
def test_extract_room_info_exits_canonicalised() -> None:
|
|
info = extract_room_info(
|
|
{"name": "X", "exits": ["north", "east", "up"]}
|
|
)
|
|
assert info is not None
|
|
# We didn't pull exits here — that happens in cli. Check that direct parsing
|
|
# still identifies room name + body.
|
|
assert info[1] == "X"
|