"""Tests unitaires pour pipeline.validation.""" from __future__ import annotations import pytest from pipeline.validation import ( _check_ccam, _check_cim10, _check_ghm, _check_ghs, _cross_check_ghm_ghs, annotate, validate_recueil, ) # ============================================================ # Vérifications par type de code # ============================================================ class TestCheckCim10: def test_code_valide(self): r = _check_cim10("K650") assert r["valid"] is True assert "libelle_ref" in r def test_code_vide(self): assert _check_cim10("")["valid"] is None assert _check_cim10(None)["valid"] is None def test_code_avec_suffixe_pmsi(self): # Les suffixes * et +N sont gérés par la normalisation r = _check_cim10("C795 *") assert r["valid"] is True def test_code_invalide_avec_suggestion(self): # K65O (O au lieu de 0) n'existe pas, mais K650 oui r = _check_cim10("K65O") assert r["valid"] is False assert r.get("suggestion") == "K650" def test_code_invalide_sans_suggestion(self): # Code farfelu sans voisin proche r = _check_cim10("ZZZZ9999") assert r["valid"] is False # suggestion peut être absente assert r.get("suggestion") is None or r.get("suggestion") != "ZZZZ9999" class TestCheckGhm: def test_ghm_valide(self): r = _check_ghm("11M122") assert r["valid"] is True assert isinstance(r.get("ghs_possibles"), list) assert len(r["ghs_possibles"]) > 0 def test_ghm_invalide(self): r = _check_ghm("99Z999") assert r["valid"] is False class TestCheckGhs: def test_ghs_valide(self): assert _check_ghs("4323")["valid"] is True def test_ghs_invalide(self): assert _check_ghs("99999")["valid"] is False class TestCheckCcam: def test_ccam_valide(self): assert _check_ccam("EBFA012")["valid"] is True def test_ccam_invalide(self): assert _check_ccam("XXXX000")["valid"] is False # ============================================================ # Cross-checks GHM ↔ GHS # ============================================================ class TestCrossCheckGhmGhs: def test_couple_coherent(self): # 11M122 a bien 4323 dans ses GHS possibles r = _cross_check_ghm_ghs("11M122", "4323") assert r["checked"] is True assert r["coherent"] is True def test_couple_incoherent(self): # 11M122 ne correspond pas à n'importe quel GHS r = _cross_check_ghm_ghs("11M122", "9999") assert r["checked"] is True assert r["coherent"] is False def test_ghm_manquant(self): r = _cross_check_ghm_ghs("", "4323") assert r["checked"] is False def test_ghm_invalide(self): r = _cross_check_ghm_ghs("99Z999", "4323") assert r["checked"] is False assert "invalide" in r["reason"].lower() # ============================================================ # annotate (intégration) # ============================================================ class TestAnnotate: def test_annotate_json_vide(self): out = annotate({"fichier": "TEST", "extraction": {}}) assert "fichier" in out assert out["extraction"] == {} def test_annotate_recueil_complet(self): raw = { "fichier": "TEST", "extraction": { "recueil": { "codage_etab": {"dp": "K650", "dr": "", "das": [ {"code": "T814", "position": "2"}, ]}, "codage_reco": {"dp": "", "dr": "", "das": []}, "ghm_etab": "11M122", "ghs_etab": "4323", "ghm_reco": "", "ghs_reco": "", }, }, } out = annotate(raw) v = out["extraction"]["recueil"]["_validation"] assert v["codage_etab"]["dp"]["valid"] is True assert v["ghm_etab"]["valid"] is True assert v["cross_checks"]["etab"]["coherent"] is True assert v["summary"]["valid"] >= 3 def test_annotate_preserve_source(self): """L'annotation ne doit pas modifier l'input (copie défensive).""" raw = { "fichier": "T", "extraction": {"recueil": {"codage_etab": {"dp": "K650"}}}, } out = annotate(raw) assert "_validation" not in raw["extraction"]["recueil"] assert "_validation" in out["extraction"]["recueil"]