"""Tests pour la validation batch des justifications (QC post-codage).""" from unittest.mock import patch, MagicMock import pytest from src.config import ( Diagnostic, DossierMedical, PreuveClinique, Sejour, BiologieCle, ) class TestPreuveClinique: def test_create(self): p = PreuveClinique(type="biologie", element="CRP 180 mg/L", interpretation="syndrome inflammatoire majeur") assert p.type == "biologie" assert p.element == "CRP 180 mg/L" assert p.interpretation == "syndrome inflammatoire majeur" def test_diagnostic_with_preuves(self): d = Diagnostic( texte="Pancréatite aiguë", cim10_suggestion="K85.9", preuves_cliniques=[ PreuveClinique(type="biologie", element="Lipasémie 450 UI/L", interpretation="pancréatite biologique"), PreuveClinique(type="imagerie", element="TDM: pancréatite stade D", interpretation="confirmation"), ], ) assert len(d.preuves_cliniques) == 2 assert d.preuves_cliniques[0].type == "biologie" def test_diagnostic_default_empty_preuves(self): d = Diagnostic(texte="Test") assert d.preuves_cliniques == [] def test_serialization_round_trip(self): d = Diagnostic( texte="Test", preuves_cliniques=[ PreuveClinique(type="clinique", element="fièvre 39°C", interpretation="syndrome infectieux"), ], ) data = d.model_dump() assert data["preuves_cliniques"][0]["type"] == "clinique" d2 = Diagnostic(**data) assert d2.preuves_cliniques[0].element == "fièvre 39°C" class TestApplyLlmResultPreuves: """Teste le stockage des preuves cliniques dans _apply_llm_result_diagnostic.""" def test_preuves_stored(self): from src.medical.rag_search import _apply_llm_result_diagnostic diag = Diagnostic(texte="Pneumopathie") llm_result = { "code": "J18.9", "confidence": "high", "justification": "Pneumopathie confirmée", "preuves_cliniques": [ {"type": "biologie", "element": "CRP 120 mg/L", "interpretation": "syndrome inflammatoire"}, {"type": "imagerie", "element": "Radio thorax: opacité", "interpretation": "foyer pulmonaire"}, ], } _apply_llm_result_diagnostic(diag, llm_result) assert len(diag.preuves_cliniques) == 2 assert diag.preuves_cliniques[0].type == "biologie" assert diag.preuves_cliniques[1].element == "Radio thorax: opacité" def test_preuves_empty_list(self): from src.medical.rag_search import _apply_llm_result_diagnostic diag = Diagnostic(texte="Test") llm_result = {"code": "K85.9", "confidence": "medium", "preuves_cliniques": []} _apply_llm_result_diagnostic(diag, llm_result) assert diag.preuves_cliniques == [] def test_preuves_missing(self): from src.medical.rag_search import _apply_llm_result_diagnostic diag = Diagnostic(texte="Test") llm_result = {"code": "K85.9", "confidence": "medium"} _apply_llm_result_diagnostic(diag, llm_result) assert diag.preuves_cliniques == [] def test_preuves_malformed_skipped(self): from src.medical.rag_search import _apply_llm_result_diagnostic diag = Diagnostic(texte="Test") llm_result = { "code": "K85.9", "confidence": "high", "preuves_cliniques": [ {"type": "bio"}, # manque 'element' → ignoré {"type": "imagerie", "element": "TDM ok", "interpretation": "normal"}, "not a dict", # ignoré ], } _apply_llm_result_diagnostic(diag, llm_result) assert len(diag.preuves_cliniques) == 1 assert diag.preuves_cliniques[0].element == "TDM ok" class TestValidateJustifications: """Teste la fonction _validate_justifications.""" @patch("src.medical.ollama_client.call_ollama") def test_confidence_adjusted(self, mock_ollama): from src.medical.cim10_extractor import _validate_justifications mock_ollama.return_value = { "validations": [ { "numero": 1, "code": "K85.9", "verdict": "maintenir", "confidence_recommandee": "high", "commentaire": "bien justifié", }, { "numero": 2, "code": "I10", "verdict": "maintenir", "confidence_recommandee": "low", "commentaire": "pas de preuve tensionnelle", }, ], "alertes_globales": [], } dossier = DossierMedical( sejour=Sejour(sexe="M", age=60), diagnostic_principal=Diagnostic( texte="Pancréatite aiguë", cim10_suggestion="K85.9", cim10_confidence="medium", ), diagnostics_associes=[ Diagnostic( texte="HTA", cim10_suggestion="I10", cim10_confidence="high", ), ], ) _validate_justifications(dossier) # DP: medium → high assert dossier.diagnostic_principal.cim10_confidence == "high" # DAS: high → low assert dossier.diagnostics_associes[0].cim10_confidence == "low" # Alertes de confiance assert any("QC:" in a and "I10" in a for a in dossier.alertes_codage) @patch("src.medical.ollama_client.call_ollama") def test_das_supprimer_alerte(self, mock_ollama): from src.medical.cim10_extractor import _validate_justifications mock_ollama.return_value = { "validations": [ { "numero": 1, "code": "K85.9", "verdict": "maintenir", "confidence_recommandee": "high", "commentaire": "ok", }, { "numero": 2, "code": "R10.4", "verdict": "supprimer", "confidence_recommandee": "low", "commentaire": "symptôme couvert par le DP", }, ], "alertes_globales": ["Vérifier la spécificité du DP"], } dossier = DossierMedical( diagnostic_principal=Diagnostic( texte="Pancréatite aiguë", cim10_suggestion="K85.9", cim10_confidence="high", ), diagnostics_associes=[ Diagnostic( texte="Douleur abdominale", cim10_suggestion="R10.4", cim10_confidence="medium", ), ], ) _validate_justifications(dossier) # Le DAS n'est pas supprimé automatiquement, mais une alerte est ajoutée assert any("à reconsidérer" in a for a in dossier.alertes_codage) assert any("Vérifier la spécificité" in a for a in dossier.alertes_codage) @patch("src.medical.ollama_client.call_ollama") def test_ollama_returns_none(self, mock_ollama): from src.medical.cim10_extractor import _validate_justifications mock_ollama.return_value = None dossier = DossierMedical( diagnostic_principal=Diagnostic( texte="Test", cim10_suggestion="K85.9", cim10_confidence="high", ), ) _validate_justifications(dossier) assert dossier.alertes_codage == [] def test_no_diags(self): from src.medical.cim10_extractor import _validate_justifications dossier = DossierMedical() _validate_justifications(dossier) assert dossier.alertes_codage == [] @patch("src.medical.ollama_client.call_ollama") def test_invalid_validation_nums_skipped(self, mock_ollama): from src.medical.cim10_extractor import _validate_justifications mock_ollama.return_value = { "validations": [ {"numero": 0, "code": "X", "verdict": "supprimer", "confidence_recommandee": "low", "commentaire": "oob"}, {"numero": 99, "code": "Y", "verdict": "supprimer", "confidence_recommandee": "low", "commentaire": "oob"}, {"numero": "abc", "code": "Z", "verdict": "supprimer", "confidence_recommandee": "low", "commentaire": "type"}, ], "alertes_globales": [], } dossier = DossierMedical( diagnostic_principal=Diagnostic(texte="T", cim10_suggestion="A00", cim10_confidence="high"), ) _validate_justifications(dossier) # Aucune modification, tous les numéros sont invalides assert dossier.diagnostic_principal.cim10_confidence == "high" assert dossier.alertes_codage == []