"""Integration test: dm_cycle con LLM mockato.""" import json import sys sys.path.insert(0, "src") from unittest.mock import patch from src.engine import db, dm MOCK_TOOL_RESP = json.dumps({ "tool": "roll_dice", "params": {"die": "d20", "count": 1}, "narration": "Tendi l'orecchio nel buio...", }) MOCK_COMBAT_RESP = json.dumps({ "tool": "combat", "params": { "character_id": 1, "target_ac": 12, "attack_bonus": 2, "damage_die": "d8", }, "narration": "Affronti il guardiano con la spada sguainata!", }) def _setup_campaign(): conn = db.init_db() camp_id = db.create_campaign("Test Integrazione", "Avventura") char_id = db.create_character(camp_id, "Eroe", "guerriero", "soldato") db.update_character( char_id, level=1, str=15, agi=11, sta=14, per=9, int=8, lck=10, hp_current=12, hp_max=12, ac=15, armor_type="light", ) db.seed_adventure_state(camp_id) return camp_id, char_id @patch("src.engine.dm.llm_ask", return_value=MOCK_TOOL_RESP) def test_dm_cycle_returns_tool_params_narration(mock_ask): camp_id, _ = _setup_campaign() out = dm.dm_cycle(camp_id, "Provo a sentire rumori") assert "tool" in out assert "params" in out assert "narration" in out assert out["tool"] == "roll_dice" assert out["params"]["die"] == "d20" assert "Tendi l'orecchio" in out["narration"] @patch("src.engine.dm.llm_ask", return_value=MOCK_TOOL_RESP) def test_dm_cycle_advances_turn(mock_ask): camp_id, _ = _setup_campaign() turn_before = db.get_campaign(camp_id)["turn"] out = dm.dm_cycle(camp_id, "Provo a sentire rumori") assert out["turn"] == turn_before + 1 assert db.get_campaign(camp_id)["turn"] == turn_before + 1 @patch("src.engine.dm.llm_ask", return_value=MOCK_TOOL_RESP) def test_dm_cycle_writes_log(mock_ask): camp_id, _ = _setup_campaign() out = dm.dm_cycle(camp_id, "Provo a sentire rumori") log = db.get_log(camp_id, limit=1) assert len(log) >= 1 assert log[0]["action"] == "Provo a sentire rumori" assert "Tendi l'orecchio" in log[0]["result"] @patch("src.engine.dm.llm_ask", return_value=MOCK_COMBAT_RESP) def test_dm_cycle_combat_injects_campaign_id(mock_ask): camp_id, char_id = _setup_campaign() # Replace character_id placeholder in mock with real ID resp = json.loads(MOCK_COMBAT_RESP) resp["params"]["character_id"] = char_id with patch("src.engine.dm.llm_ask", return_value=json.dumps(resp)): out = dm.dm_cycle(camp_id, "Attacco il guardiano") assert out["tool"] == "combat" assert out["params"].get("campaign_id") == camp_id @patch("src.engine.dm.llm_ask", return_value="{}") def test_dm_cycle_fallback_on_empty_json(mock_ask): camp_id, _ = _setup_campaign() out = dm.dm_cycle(camp_id, "saluto il guardiano") # Fallback heuristic: should produce dm_override narrate assert out["tool"] in ("combat", "dm_override") assert out["full_output"]