"""Tests for the GMCP parser.""" from __future__ import annotations import json from viandante.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"