from collections import Counter from pathlib import Path from mtga_assistant.logparse import ClientDeck, DeckSubmitted, GreMessages, LogParser, MatchRoom FIXTURE = Path(__file__).parent / "fixtures" / "bo3_match.log" def parse_file(path: Path) -> list: p = LogParser() out = [] with open(path, encoding="utf-8") as f: for line in f: out.extend(p.feed(line)) return out def test_fixture_event_kinds(): events = parse_file(FIXTURE) kinds = Counter(type(e).__name__ for e in events) assert kinds["MatchRoom"] == 2 assert kinds["DeckSubmitted"] == 1 assert kinds["ClientDeck"] == 1 assert kinds["GreMessages"] >= 15 rooms = [e for e in events if isinstance(e, MatchRoom)] assert rooms[0].state == "MatchGameRoomStateType_Playing" assert rooms[1].state == "MatchGameRoomStateType_MatchCompleted" assert {p["playerName"] for p in rooms[0].players} == {"Local Player", "Opponent Player"} def test_deck_submitted(): deck = next(e for e in parse_file(FIXTURE) if isinstance(e, DeckSubmitted)) assert deck.name == "Cruel Tutelage" assert sum(deck.main.values()) == 60 assert sum(deck.sideboard.values()) == 15 def test_client_deck_from_pretty_printed_body(): deck = next(e for e in parse_file(FIXTURE) if isinstance(e, ClientDeck)) assert sum(deck.main.values()) == 60 assert sum(deck.sideboard.values()) == 15 def test_single_line_gre_event(): p = LogParser() assert p.feed("[UnityCrossThreadLogger]10/16/2026 12:34:51 AM: Match to X: GreToClientEvent\n") == [] evs = p.feed('{ "greToClientEvent": { "greToClientMessages": [ { "type": "GREMessageType_UIMessage" } ] } }\n') assert len(evs) == 1 and isinstance(evs[0], GreMessages) def test_multiline_body_and_abandoned_fragment(): p = LogParser() assert p.feed("{\n") == [] assert p.feed(' "payload": { "type": "Other" },\n') == [] # A new log entry starts before the body closed: the fragment is dropped. assert p.feed("[UnityCrossThreadLogger]something\n") == [] evs = p.feed('{ "greToClientEvent": { "greToClientMessages": [ { "type": "T" } ] } }\n') assert len(evs) == 1 def test_non_json_lines_ignored(): p = LogParser() for line in ["OnSceneLoaded for DuelScene", "[UnityCrossThreadLogger]STATE CHANGED {\"old\":1}", ""]: assert p.feed(line) == []