test_json_simplifier.py
1 """ 2 Tests pour le post-processeur JSONSimplifier 3 ------------------------------------------- 4 Ce module teste les fonctionnalités du post-processeur JSONSimplifier, 5 y compris l'activation/désactivation et différents scénarios de traitement. 6 """ 7 8 import pytest 9 import json 10 import os 11 from unittest.mock import MagicMock, patch 12 from typing import Dict, Any 13 14 from postprocessors.json_simplifier import JSONSimplifier 15 from postprocessors import get_postprocessor 16 17 # Données de test 18 SAMPLE_JSON_RESULT = { 19 "result": { 20 "analysis": { 21 "sentiment": "positive", 22 "tone": "formal", 23 "key_points": [ 24 "Point 1: Le sujet est bien expliqué", 25 "Point 2: Arguments clairs et cohérents", 26 "Point 3: Conclusion logique" 27 ], 28 "complexity_score": 0.75, 29 "readability_metrics": { 30 "flesch_kincaid": 65.2, 31 "smog_index": 8.1, 32 "coleman_liau_index": 10.3 33 } 34 }, 35 "language": "fr", 36 "processing_time": 1.23 37 } 38 } 39 40 EXPECTED_PLAIN_TEXT = "Le texte a un sentiment positif avec un ton formel. Il comprend 3 points clés: le sujet est bien expliqué, les arguments sont clairs et cohérents, et la conclusion est logique. Le texte a un score de complexité de 0,75 et présente une bonne lisibilité avec un indice Flesch-Kincaid de 65,2." 41 42 class MockModel: 43 """Classe simulant un modèle de langage pour les tests""" 44 45 def __init__(self, return_value=None): 46 self.return_value = return_value or EXPECTED_PLAIN_TEXT 47 48 def generate(self, prompt, **kwargs): 49 return self.return_value 50 51 class TestJSONSimplifier: 52 53 @pytest.fixture 54 def basic_config(self): 55 """Configuration de base pour le post-processeur""" 56 return { 57 "enabled": True, 58 "model": "test-model", 59 "system_prompt": "Translate this json {text} in plain french", 60 "max_tokens": 500, 61 "temperature": 0.3, 62 "apply_to": ["inference", "video", "transcription"] 63 } 64 65 @pytest.fixture 66 def disabled_config(self): 67 """Configuration avec le post-processeur désactivé""" 68 return { 69 "enabled": False, 70 "model": "test-model", 71 "system_prompt": "Translate this json {text} in plain french", 72 "max_tokens": 500, 73 "temperature": 0.3, 74 "apply_to": ["inference", "video", "transcription"] 75 } 76 77 @pytest.fixture 78 def limited_tasks_config(self): 79 """Configuration avec un ensemble limité de types de tâches""" 80 return { 81 "enabled": True, 82 "model": "test-model", 83 "system_prompt": "Translate this json {text} in plain french", 84 "max_tokens": 500, 85 "temperature": 0.3, 86 "apply_to": ["inference", "video"] # Sans "transcription" 87 } 88 89 def test_initialization(self, basic_config): 90 """Teste l'initialisation correcte du post-processeur""" 91 simplifier = JSONSimplifier(basic_config) 92 93 assert simplifier.enabled == basic_config["enabled"] 94 assert simplifier.model_name == basic_config["model"] 95 assert simplifier.system_prompt == basic_config["system_prompt"] 96 assert simplifier.max_tokens == basic_config["max_tokens"] 97 assert simplifier.temperature == basic_config["temperature"] 98 assert simplifier.apply_to == basic_config["apply_to"] 99 assert simplifier.model is None # Le modèle n'est pas chargé à l'initialisation 100 101 def test_should_process_enabled(self, basic_config): 102 """Teste la méthode should_process quand le post-processeur est activé""" 103 simplifier = JSONSimplifier(basic_config) 104 105 # Les types de tâches listés dans apply_to devraient retourner True 106 assert simplifier.should_process("inference") is True 107 assert simplifier.should_process("video") is True 108 assert simplifier.should_process("transcription") is True 109 110 # Les autres types de tâches devraient retourner False 111 assert simplifier.should_process("other_task") is False 112 113 def test_should_process_disabled(self, disabled_config): 114 """Teste la méthode should_process quand le post-processeur est désactivé""" 115 simplifier = JSONSimplifier(disabled_config) 116 117 # Tous les types de tâches devraient retourner False 118 assert simplifier.should_process("inference") is False 119 assert simplifier.should_process("video") is False 120 assert simplifier.should_process("transcription") is False 121 assert simplifier.should_process("other_task") is False 122 123 def test_should_process_limited_tasks(self, limited_tasks_config): 124 """Teste la méthode should_process avec un ensemble limité de types de tâches""" 125 simplifier = JSONSimplifier(limited_tasks_config) 126 127 # Les types de tâches listés dans apply_to devraient retourner True 128 assert simplifier.should_process("inference") is True 129 assert simplifier.should_process("video") is True 130 131 # Les types de tâches non listés devraient retourner False 132 assert simplifier.should_process("transcription") is False 133 assert simplifier.should_process("other_task") is False 134 135 @patch('postprocessors.json_simplifier.ModelManager') 136 def test_process_success(self, mock_model_manager, basic_config): 137 """Teste le traitement réussi d'un résultat JSON""" 138 # Configurer le mock pour ModelManager 139 mock_manager_instance = MagicMock() 140 mock_model_manager.get_instance.return_value = mock_manager_instance 141 142 # Configurer le mock pour le modèle 143 mock_model = MockModel() 144 mock_manager_instance.get_model.return_value = mock_model 145 146 # Créer l'instance du simplifier 147 simplifier = JSONSimplifier(basic_config) 148 149 # Traiter le résultat JSON 150 result = SAMPLE_JSON_RESULT.copy() 151 processed = simplifier.process(result, "inference") 152 153 # Vérifier les résultats 154 assert "plain_explanation" in processed 155 assert processed["plain_explanation"] == EXPECTED_PLAIN_TEXT 156 157 # Vérifier que le résultat original a été préservé 158 assert processed["result"] == SAMPLE_JSON_RESULT["result"] 159 160 # Vérifier que le modèle a été correctement appelé 161 mock_manager_instance.get_model.assert_called_once_with("llm", basic_config["model"]) 162 163 @patch('postprocessors.json_simplifier.ModelManager') 164 def test_process_model_error(self, mock_model_manager, basic_config): 165 """Teste le comportement quand le modèle rencontre une erreur""" 166 # Configurer le mock pour déclencher une exception lors de l'appel de generate 167 mock_manager_instance = MagicMock() 168 mock_model_manager.get_instance.return_value = mock_manager_instance 169 170 mock_model = MagicMock() 171 mock_model.generate.side_effect = Exception("Erreur de modèle simulée") 172 mock_manager_instance.get_model.return_value = mock_model 173 174 # Créer l'instance du simplifier 175 simplifier = JSONSimplifier(basic_config) 176 177 # Traiter le résultat JSON 178 result = SAMPLE_JSON_RESULT.copy() 179 processed = simplifier.process(result, "inference") 180 181 # Vérifier que les résultats originaux sont retournés sans modification 182 assert "plain_explanation" not in processed 183 assert processed == result 184 185 @patch('postprocessors.json_simplifier.ModelManager') 186 def test_process_model_not_available(self, mock_model_manager, basic_config): 187 """Teste le comportement quand le modèle n'est pas disponible""" 188 # Configurer le mock pour retourner None (modèle non disponible) 189 mock_manager_instance = MagicMock() 190 mock_model_manager.get_instance.return_value = mock_manager_instance 191 mock_manager_instance.get_model.return_value = None 192 193 # Créer l'instance du simplifier 194 simplifier = JSONSimplifier(basic_config) 195 196 # Traiter le résultat JSON 197 result = SAMPLE_JSON_RESULT.copy() 198 processed = simplifier.process(result, "inference") 199 200 # Vérifier que les résultats originaux sont retournés sans modification 201 assert "plain_explanation" not in processed 202 assert processed == result 203 204 def test_process_disabled(self, disabled_config): 205 """Teste le traitement quand le post-processeur est désactivé""" 206 # Créer l'instance du simplifier désactivé 207 simplifier = JSONSimplifier(disabled_config) 208 209 # Traiter le résultat JSON 210 result = SAMPLE_JSON_RESULT.copy() 211 processed = simplifier.process(result, "inference") 212 213 # Vérifier que les résultats originaux sont retournés sans modification 214 assert "plain_explanation" not in processed 215 assert processed == result 216 217 def test_process_task_not_in_apply_to(self, limited_tasks_config): 218 """Teste le traitement quand le type de tâche n'est pas dans apply_to""" 219 # Créer l'instance du simplifier avec types de tâches limités 220 simplifier = JSONSimplifier(limited_tasks_config) 221 222 # Traiter le résultat JSON pour un type de tâche non inclus 223 result = SAMPLE_JSON_RESULT.copy() 224 processed = simplifier.process(result, "transcription") # transcription n'est pas dans apply_to 225 226 # Vérifier que les résultats originaux sont retournés sans modification 227 assert "plain_explanation" not in processed 228 assert processed == result 229 230 @patch('postprocessors.json_simplifier.ModelManager') 231 def test_process_json_serialization(self, mock_model_manager, basic_config): 232 """Teste la sérialisation JSON lors du traitement""" 233 # Configurer le mock 234 mock_manager_instance = MagicMock() 235 mock_model_manager.get_instance.return_value = mock_manager_instance 236 mock_model = MockModel() 237 mock_manager_instance.get_model.return_value = mock_model 238 239 # Créer l'instance du simplifier 240 simplifier = JSONSimplifier(basic_config) 241 242 # Définir un objet JSON avec des types non-sérialisables 243 complex_result = { 244 "result": { 245 "data": set([1, 2, 3]), # un ensemble n'est pas JSON-sérialisable 246 "function": lambda x: x # une fonction n'est pas JSON-sérialisable 247 } 248 } 249 250 # Traiter le résultat JSON 251 try: 252 processed = simplifier.process(complex_result, "inference") 253 # Le test devrait échouer ici, car la sérialisation devrait échouer 254 assert False, "La sérialisation aurait dû échouer avec des types non-sérialisables" 255 except: 256 # Vérifier que l'exception est bien gérée et que le résultat original est retourné 257 pass 258 259 def test_get_postprocessor_function(self, basic_config): 260 """Teste la fonction get_postprocessor du module postprocessors""" 261 with patch('postprocessors.available_postprocessors', {"json_simplifier": JSONSimplifier}): 262 # Obtenir une instance du post-processeur via la fonction get_postprocessor 263 processor = get_postprocessor("json_simplifier", basic_config) 264 265 # Vérifier que l'instance est bien du type JSONSimplifier 266 assert isinstance(processor, JSONSimplifier) 267 268 # Vérifier qu'un nom de post-processeur invalide retourne None 269 assert get_postprocessor("invalid_processor", {}) is None 270 271 @patch('postprocessors.json_simplifier.ModelManager') 272 def test_prompt_formatting(self, mock_model_manager, basic_config): 273 """Teste le formatage du prompt avec le JSON""" 274 # Configurer le mock 275 mock_manager_instance = MagicMock() 276 mock_model_manager.get_instance.return_value = mock_manager_instance 277 mock_model = MagicMock() 278 mock_manager_instance.get_model.return_value = mock_model 279 mock_model.generate.return_value = EXPECTED_PLAIN_TEXT 280 281 # Créer l'instance du simplifier 282 simplifier = JSONSimplifier(basic_config) 283 284 # Traiter le résultat JSON 285 result = SAMPLE_JSON_RESULT.copy() 286 simplifier.process(result, "inference") 287 288 # Vérifier que le prompt formaté a été passé au modèle 289 # Récupérer les arguments de l'appel à generate 290 args, kwargs = mock_model.generate.call_args 291 prompt = args[0] 292 293 # Vérifier que le prompt contient le JSON et respecte le template 294 assert "{text}" not in prompt # Le placeholder doit être remplacé 295 assert "Translate this json" in prompt # Le début du prompt doit être présent 296 assert json.dumps(result["result"]) in prompt # Le JSON doit être sérialisé et inclus 297 298 def test_integration_with_env_variables(self): 299 """Teste l'intégration avec les variables d'environnement""" 300 # Sauvegarder les variables d'environnement actuelles 301 original_enabled = os.environ.get("JSON_SIMPLIFIER_ENABLED") 302 original_model = os.environ.get("JSON_SIMPLIFIER_MODEL") 303 original_apply_to = os.environ.get("JSON_SIMPLIFIER_APPLY_TO") 304 305 try: 306 # Configurer les variables d'environnement pour le test 307 os.environ["JSON_SIMPLIFIER_ENABLED"] = "true" 308 os.environ["JSON_SIMPLIFIER_MODEL"] = "test-env-model" 309 os.environ["JSON_SIMPLIFIER_APPLY_TO"] = "inference,video" 310 311 # Charger la configuration depuis l'environnement 312 from config import load_config 313 config = load_config() 314 315 # Vérifier que la configuration a été correctement chargée 316 assert config["postprocessing"]["json_simplifier"]["enabled"] is True 317 assert config["postprocessing"]["json_simplifier"]["model"] == "test-env-model" 318 assert config["postprocessing"]["json_simplifier"]["apply_to"] == ["inference", "video"] 319 320 finally: 321 # Restaurer les variables d'environnement originales 322 if original_enabled is not None: 323 os.environ["JSON_SIMPLIFIER_ENABLED"] = original_enabled 324 else: 325 os.environ.pop("JSON_SIMPLIFIER_ENABLED", None) 326 327 if original_model is not None: 328 os.environ["JSON_SIMPLIFIER_MODEL"] = original_model 329 else: 330 os.environ.pop("JSON_SIMPLIFIER_MODEL", None) 331 332 if original_apply_to is not None: 333 os.environ["JSON_SIMPLIFIER_APPLY_TO"] = original_apply_to 334 else: 335 os.environ.pop("JSON_SIMPLIFIER_APPLY_TO", None) 336 337 338 if __name__ == "__main__": 339 print("Exécution des tests du post-processeur JSONSimplifier...") 340 pytest.main(["-xvs", __file__])