"""Couche outils IA (voir plan Phase 1, §4 — ai/tools.py) : chaque dispatch doit appeler DIRECTEMENT la fonction screens.*/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 screens 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 = screens.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(screens.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(screens.BACKGROUND_LIBRARY)) result = dispatch_tool(slug, screen_id, admin_id, "add_scene_object", {"kind": "fond", "background_slug": bg_slug}) obj = not_none(screens.get_scene_object(slug, result["object_id"])) assert obj["attributes"]["src"] == screens.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 (screens.add_scene_object, pensé pour un