"""Couche outils IA (voir plan Phase 1, §4 — ai/tools.py) : chaque dispatch doit appeler DIRECTEMENT la fonction game_engine.*/db.* existante (jamais une structure parallèle), et les schémas doivent suivre les constantes SOURCE plutôt qu'une copie littérale (principe validé avec l'utilisateur : une nouvelle valeur d'énum doit suivre automatiquement).""" from collections.abc import Callable from typing import Any import pytest from flask.testing import FlaskClient import ai import auth import db import game_engine from ai.tools import TOOLS, dispatch_tool from tests.conftest import not_none def _tool(name: str) -> Any: return next(t for t in TOOLS if t["name"] == name) def _create_jeu2d_game( client: FlaskClient, tmp_game_slug_cleanup: Callable[[str], str], name: str = "pytest_ai_tools" ) -> Any: resp = client.post("/games/new", data={"name": name}, follow_redirects=False) slug = tmp_game_slug_cleanup(resp.headers["Location"].rstrip("/").split("/")[-1]) screen_id = game_engine.create_screen(slug, "Scène 1", kind="jeu_2d") return slug, screen_id def test_dispatch_add_scene_object_calls_the_real_function( client: FlaskClient, tmp_game_slug_cleanup: Callable[[str], str] ) -> None: slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup) result = dispatch_tool(slug, screen_id, 1, "add_scene_object", {"kind": "decor", "image_url": "/assets/1/x.png"}) obj = not_none(game_engine.get_scene_object(slug, result["object_id"])) assert obj["kind"] == "decor" assert obj["attributes"]["src"] == "/assets/1/x.png" def test_dispatch_add_scene_object_with_background_slug_uses_the_library_image( client: FlaskClient, tmp_game_slug_cleanup: Callable[[str], str] ) -> None: slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup) with client.session_transaction() as sess: admin_id = sess["user_id"] bg_slug = next(iter(game_engine.BACKGROUND_LIBRARY)) result = dispatch_tool(slug, screen_id, admin_id, "add_scene_object", {"kind": "fond", "background_slug": bg_slug}) obj = not_none(game_engine.get_scene_object(slug, result["object_id"])) assert obj["attributes"]["src"] == game_engine.BACKGROUND_LIBRARY[bg_slug]["url"] def test_dispatch_add_scene_object_raises_for_an_unknown_background_slug( client: FlaskClient, tmp_game_slug_cleanup: Callable[[str], str] ) -> None: """Bug corrigé : un slug inventé/mal orthographié par Claude était ignoré en silence (game_engine.add_scene_object, pensé pour un