"""Tests for M15 per-diagnostic storage + Report bundles + app logging.""" import json import tempfile import unittest import zipfile from dataclasses import dataclass, field from pathlib import Path from unittest import mock from rigdoctor.core import applog, diagstore @dataclass class FakeSummary: start: float = 1.0 end: float = 2.0 samples: int = 3 events: list = field(default_factory=list) @dataclass class FakeFinding: severity: str = "ok" category: str = "GPU" title: str = "Looks fine" detail: str = "no issues" @dataclass class FakeResult: game: str = "Path of Exile 2" summary: FakeSummary = field(default_factory=FakeSummary) findings: list = field(default_factory=lambda: [FakeFinding()]) dir: str | None = None class StoreTests(unittest.TestCase): def setUp(self): self.tmp = Path(tempfile.mkdtemp()) def test_disabled_returns_none(self): with mock.patch.object(diagstore, "enabled", return_value=False): self.assertIsNone(diagstore.store(FakeResult())) def test_store_writes_artifacts(self): with mock.patch.object(diagstore, "enabled", return_value=True), \ mock.patch("rigdoctor.render.render_summary", return_value="SUMMARY-TEXT"), \ mock.patch("rigdoctor.core.gamelogs.collect", return_value="LOG-TEXT"), \ mock.patch.object(diagstore.config, "DIAGNOSTICS_DIR", self.tmp / "diagnostics"): directory = diagstore.store(FakeResult()) self.assertTrue((directory / "result.json").exists()) self.assertTrue((directory / "report.txt").exists()) self.assertEqual((directory / "gamelogs.txt").read_text(), "LOG-TEXT") data = json.loads((directory / "result.json").read_text()) self.assertEqual(data["game"], "Path of Exile 2") self.assertEqual(len(data["findings"]), 1) def test_record_ai_then_report_includes_ai_and_applog(self): diag = self.tmp / "20260522-poe2" diag.mkdir() diagstore.record_ai(diag, provider="claude", model="claude-opus-4-7", system="SYS", prompt="EXACT DATA SENT", response="THE REPLY") ai_files = list((diag / "ai").glob("explain-*.json")) self.assertTrue(ai_files) record = json.loads(ai_files[0].read_text()) self.assertEqual(record["model"], "claude-opus-4-7") self.assertEqual(record["data_sent_to_model"], "EXACT DATA SENT") self.assertEqual(record["model_reply"], "THE REPLY") app_log = self.tmp / "app.log" app_log.write_text("app log line") with mock.patch.object(diagstore.config, "REPORTS_DIR", self.tmp / "reports"), \ mock.patch.object(diagstore.config, "APP_LOG", app_log): out = diagstore.make_report(diag) self.assertTrue(out.exists()) with zipfile.ZipFile(out) as zf: names = zf.namelist() self.assertTrue(any(n.endswith("app.log") for n in names)) self.assertTrue(any("/ai/explain-" in n for n in names)) class AppLogTests(unittest.TestCase): def test_disabled_is_noop(self): with mock.patch.object(applog.config, "load_config", return_value={"logging_enabled": False}): self.assertFalse(applog.setup(force=True)) def test_enabled_writes_file(self): tmp = Path(tempfile.mkdtemp()) with mock.patch.object(applog.config, "load_config", return_value={"logging_enabled": True}), \ mock.patch.object(applog.config, "STATE_DIR", tmp), \ mock.patch.object(applog.config, "APP_LOG", tmp / "app.log"): self.assertTrue(applog.setup(force=True)) applog.get_logger("test").info("hello world") applog.setup(force=True) # cleanup path: re-run detaches/reattaches cleanly self.assertTrue((tmp / "app.log").exists()) if __name__ == "__main__": unittest.main()