""" Tests pour le gestionnaire d'apprentissage. """ import pytest import numpy as np import tempfile import shutil from pathlib import Path from datetime import datetime from unittest.mock import Mock, MagicMock from geniusia2.core.learning_manager import LearningManager from geniusia2.core.models import Action, TaskProfile from geniusia2.core.embeddings_manager import EmbeddingsManager from geniusia2.core.logger import Logger @pytest.fixture def temp_dirs(): """Crée des répertoires temporaires pour les tests.""" temp_dir = tempfile.mkdtemp() profiles_dir = Path(temp_dir) / "profiles" logs_dir = Path(temp_dir) / "logs" index_dir = Path(temp_dir) / "index" keys_dir = Path(temp_dir) / "keys" profiles_dir.mkdir(parents=True, exist_ok=True) logs_dir.mkdir(parents=True, exist_ok=True) index_dir.mkdir(parents=True, exist_ok=True) keys_dir.mkdir(parents=True, exist_ok=True) yield { "profiles": str(profiles_dir), "logs": str(logs_dir), "index": str(index_dir), "keys": str(keys_dir) } shutil.rmtree(temp_dir) @pytest.fixture def mock_embeddings_manager(temp_dirs): """Crée un gestionnaire d'embeddings mocké.""" return EmbeddingsManager( model_name="ViT-B-32", index_path=temp_dirs["index"], device="cpu" ) @pytest.fixture def mock_logger(temp_dirs): """Crée un logger mocké.""" return Logger( log_dir=temp_dirs["logs"], key_path=temp_dirs["keys"] ) @pytest.fixture def learning_manager(mock_embeddings_manager, mock_logger, temp_dirs): """Crée une instance du gestionnaire d'apprentissage pour les tests.""" config = { "thresholds": { "autopilot_observations": 20, "autopilot_concordance": 0.95, "confidence_min": 0.90, "rollback_confidence": 0.85 } } return LearningManager( embeddings_manager=mock_embeddings_manager, logger=mock_logger, config=config, profiles_path=temp_dirs["profiles"] ) def test_initialization(learning_manager): """Test l'initialisation du gestionnaire.""" assert learning_manager.mode == "shadow" assert len(learning_manager.tasks) == 0 assert learning_manager.current_task_id is None def test_observe_action(learning_manager): """Test l'enregistrement d'une observation.""" action = Action( action_type="click", target_element="valider_button", bbox=(100, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title="Test Window" ) learning_manager.observe(action) # Vérifier qu'une tâche a été créée assert len(learning_manager.tasks) == 1 # Vérifier les propriétés de la tâche task_id = list(learning_manager.tasks.keys())[0] task = learning_manager.tasks[task_id] assert task.observation_count == 1 assert task.mode == "shadow" assert len(task.action_sequence) == 1 assert task.window_whitelist == ["Test Window"] def test_mode_transition_shadow_to_assist(learning_manager): """Test la transition de Shadow vers Assisté.""" action = Action( action_type="click", target_element="button", bbox=(100, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title="Test" ) # Observer 5 fois pour déclencher la transition for _ in range(5): learning_manager.observe(action) task_id = list(learning_manager.tasks.keys())[0] task = learning_manager.tasks[task_id] # Devrait être passé en mode Assisté assert task.mode == "assist" assert task.observation_count == 5 def test_calculate_confidence(learning_manager): """Test le calcul du score de confiance.""" # Créer une tâche de test action = Action( action_type="click", target_element="button", bbox=(100, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title="Test" ) learning_manager.observe(action) task_id = list(learning_manager.tasks.keys())[0] # Calculer la confiance confidence = learning_manager.calculate_confidence( vision_conf=0.9, llm_score=0.8, task_id=task_id ) # Vérifier la formule : 0.6 * 0.9 + 0.3 * 0.8 + 0.1 * 0.0 = 0.78 assert 0.77 <= confidence <= 0.79 def test_confirm_action_accept(learning_manager): """Test la confirmation d'une action acceptée.""" action = Action( action_type="click", target_element="button", bbox=(100, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title="Test" ) learning_manager.observe(action) task_id = list(learning_manager.tasks.keys())[0] # Accepter l'action learning_manager.confirm_action({ "type": "accept", "task_id": task_id }) task = learning_manager.tasks[task_id] assert task.concordance_rate == 1.0 def test_confirm_action_reject(learning_manager): """Test la confirmation d'une action rejetée.""" action = Action( action_type="click", target_element="button", bbox=(100, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title="Test" ) learning_manager.observe(action) task_id = list(learning_manager.tasks.keys())[0] # Rejeter l'action learning_manager.confirm_action({ "type": "reject", "task_id": task_id }) task = learning_manager.tasks[task_id] assert task.concordance_rate == 0.0 def test_confirm_action_correct(learning_manager): """Test la correction d'une action.""" action = Action( action_type="click", target_element="wrong_button", bbox=(100, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title="Test" ) learning_manager.observe(action) task_id = list(learning_manager.tasks.keys())[0] # Corriger l'action corrected_action = Action( action_type="click", target_element="correct_button", bbox=(200, 100, 50, 30), confidence=0.95, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title="Test" ) learning_manager.confirm_action({ "type": "correct", "task_id": task_id, "corrected_action": corrected_action }) task = learning_manager.tasks[task_id] assert task.correction_count == 1 assert len(task.action_sequence) == 2 def test_should_transition_to_auto(learning_manager): """Test la vérification des critères pour passer en Autopilot.""" action = Action( action_type="click", target_element="button", bbox=(100, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title="Test" ) # Observer 20 fois for _ in range(20): learning_manager.observe(action) task_id = list(learning_manager.tasks.keys())[0] task = learning_manager.tasks[task_id] # Définir une concordance élevée task.concordance_rate = 0.96 # Devrait être éligible pour Autopilot assert learning_manager.should_transition_to_auto(task_id) def test_rollback_if_low_confidence(learning_manager): """Test la rétrogradation en cas de confiance faible.""" action = Action( action_type="click", target_element="button", bbox=(100, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title="Test" ) learning_manager.observe(action) task_id = list(learning_manager.tasks.keys())[0] task = learning_manager.tasks[task_id] # Forcer le mode Auto avec confiance faible task.mode = "auto" task.confidence_score = 0.85 # En dessous du seuil de 0.90 learning_manager.rollback_if_low_confidence(task_id) # Devrait être rétrogradé en Assisté assert task.mode == "assist" def test_evaluate_task(learning_manager): """Test l'évaluation d'une tâche.""" action = Action( action_type="click", target_element="button", bbox=(100, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title="Test" ) learning_manager.observe(action) task_id = list(learning_manager.tasks.keys())[0] metrics = learning_manager.evaluate_task(task_id) assert "task_id" in metrics assert "task_name" in metrics assert "mode" in metrics assert "observation_count" in metrics assert "concordance_rate" in metrics assert "confidence_score" in metrics assert "correction_count" in metrics assert metrics["observation_count"] == 1 def test_get_all_tasks(learning_manager): """Test la récupération de toutes les tâches.""" # Créer plusieurs tâches for i in range(3): action = Action( action_type="click", target_element=f"button_{i}", bbox=(100 + i*50, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title=f"Test_{i}" ) learning_manager.observe(action) all_tasks = learning_manager.get_all_tasks() assert len(all_tasks) == 3 assert all(isinstance(task, dict) for task in all_tasks) def test_get_task_stats(learning_manager): """Test les statistiques globales.""" # Créer des tâches dans différents modes for i in range(3): action = Action( action_type="click", target_element=f"button_{i}", bbox=(100, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title=f"Test_{i}" ) learning_manager.observe(action) stats = learning_manager.get_task_stats() assert "total_tasks" in stats assert "shadow_tasks" in stats assert "assist_tasks" in stats assert "auto_tasks" in stats assert stats["total_tasks"] == 3 def test_record_execution(learning_manager): """Test l'enregistrement d'une exécution.""" action = Action( action_type="click", target_element="button", bbox=(100, 100, 50, 30), confidence=0.9, embedding=np.random.rand(512).astype(np.float32), timestamp=datetime.now(), window_title="Test" ) learning_manager.observe(action) task_id = list(learning_manager.tasks.keys())[0] # Enregistrer une exécution learning_manager.record_execution({ "task_id": task_id, "confidence": 0.92 }) task = learning_manager.tasks[task_id] assert task.confidence_score == 0.92 assert task.last_execution is not None if __name__ == "__main__": pytest.main([__file__, "-v"])