from mtga_assistant.history import HistoryRecorder, HistoryStore, decode, encode, import_log, replay_game from mtga_assistant.logparse import LogParser from test_gamestate import FIXTURE, ME def parse(path): p = LogParser() with open(path, encoding="utf-8") as f: return [ev for line in f for ev in p.feed(line)] def test_events_round_trip(): for ev in parse(FIXTURE): enc = encode(ev) if enc is None: continue back = decode(enc) assert type(back) is type(ev) def test_import_records_each_game_once(tmp_path): store = HistoryStore(tmp_path / "h.db") assert import_log(FIXTURE, store, None) == 1 assert import_log(FIXTURE, store, None) == 0 # already recorded games = store.games() assert [g.game_number for g in games] == [2, 1] # newest first g1 = games[1] assert g1.opponent == "Opponent Player" assert g1.result == "Won" and games[0].result == "Won" assert g1.best_of == 3 assert g1.on_play == "me" assert g1.deck_name == "Cruel Tutelage" assert g1.replayable def test_replay_stops_at_the_requested_game(tmp_path): store = HistoryStore(tmp_path / "h.db") import_log(FIXTURE, store, None) events = store.events(store.games()[0].match_id) t1 = replay_game(events, 1, None) assert t1.game.game_number == 1 assert t1.game.on_play == ME assert t1.game_results == ["Won"] t2 = replay_game(events, 2, None) assert t2.game.game_number == 2 assert t2.game_results == ["Won", "Won"] assert t2.games_on_draw() == {2: 1} def test_events_pruned_beyond_cap_but_summaries_kept(tmp_path): store = HistoryStore(tmp_path / "h.db", max_events_mb=0) import_log(FIXTURE, store, None) games = store.games() assert len(games) == 2 and not any(g.replayable for g in games) assert store.events(games[0].match_id) == [] def test_recorder_ignores_unfinished_match(tmp_path): from mtga_assistant.gamestate import MatchTracker store = HistoryStore(tmp_path / "h.db") rec, t = HistoryRecorder(store), MatchTracker() events = parse(FIXTURE) for ev in events[:-3]: # stop before the match completes t.handle(ev) rec.observe(ev, t) assert store.games() == [] def test_old_database_is_upgraded_and_backfilled(tmp_path): import sqlite3 path = tmp_path / "old.db" store = HistoryStore(path) import_log(FIXTURE, store, None) # Simulate a database from before commanders were stored. conn = sqlite3.connect(path) conn.execute("UPDATE games SET my_commander = NULL, opp_commander = NULL") conn.commit() conn.close() store = HistoryStore(path) assert all(g.my_commander is None for g in store.games()) assert store.backfill_commanders(None) == 2 assert all(g.my_commander == "" and g.opp_commander == "" for g in store.games()) # not a Brawl match assert store.backfill_commanders(None) == 0 def test_schema_without_commander_columns_gets_them(tmp_path): import sqlite3 path = tmp_path / "v1.db" conn = sqlite3.connect(path) conn.executescript("""CREATE TABLE games (match_id TEXT NOT NULL, game_number INTEGER NOT NULL, started_ms INTEGER, ended_ms INTEGER, event_id TEXT, opponent TEXT, deck_name TEXT, on_play TEXT, result TEXT, my_colors TEXT, opp_colors TEXT, turns INTEGER, best_of INTEGER, PRIMARY KEY (match_id, game_number)); INSERT INTO games VALUES ('m1', 1, 1, 2, 'Ladder', 'Opp', 'Deck', 'me', 'Won', 'U', 'R', 5, 1);""") conn.commit() conn.close() games = HistoryStore(path).games() assert len(games) == 1 and games[0].deck_name == "Deck" and games[0].my_commander is None