""" Tests unitaires pour le ReferentielsManager. Ces tests vérifient l'import, le hashing et le chunking des référentiels ATIH. """ import hashlib import tempfile from datetime import datetime from pathlib import Path import pytest from pipeline_mco_pmsi.rag import ReferentielsManager @pytest.fixture def temp_data_dir(): """Crée un répertoire temporaire pour les tests.""" with tempfile.TemporaryDirectory() as tmpdir: yield Path(tmpdir) @pytest.fixture def sample_pdf(): """Crée un PDF de test simple.""" from pypdf import PdfWriter with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp: writer = PdfWriter() writer.add_blank_page(width=200, height=200) writer.write(tmp) tmp_path = Path(tmp.name) yield tmp_path # Cleanup if tmp_path.exists(): tmp_path.unlink() class TestReferentielsManagerInit: """Tests d'initialisation du ReferentielsManager.""" def test_init_creates_data_dir(self, temp_data_dir): """Test que l'initialisation crée le répertoire de données.""" data_dir = temp_data_dir / "referentiels" manager = ReferentielsManager(data_dir=data_dir) assert data_dir.exists() assert manager.data_dir == data_dir assert manager.embedding_model_name == "camembert-bio" def test_init_with_custom_embedding_model(self, temp_data_dir): """Test l'initialisation avec un modèle d'embeddings personnalisé.""" manager = ReferentielsManager( data_dir=temp_data_dir, embedding_model="drbert" ) assert manager.embedding_model_name == "drbert" class TestImportReferentiel: """Tests d'import de référentiels.""" def test_import_referentiel_invalid_type(self, temp_data_dir, sample_pdf): """Test que l'import rejette un type de référentiel invalide.""" manager = ReferentielsManager(data_dir=temp_data_dir) with pytest.raises(ValueError, match="Type de référentiel invalide"): manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="invalid_type", version="2026" ) def test_import_referentiel_file_not_found(self, temp_data_dir): """Test que l'import échoue si le fichier n'existe pas.""" manager = ReferentielsManager(data_dir=temp_data_dir) with pytest.raises(FileNotFoundError): manager.import_referentiel( file_path="/nonexistent/file.pdf", referentiel_type="cim10", version="2026" ) def test_import_referentiel_generates_hash(self, temp_data_dir, sample_pdf): """Test que l'import génère un hash SHA-256.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Calculer le hash attendu with open(sample_pdf, "rb") as f: expected_hash = hashlib.sha256(f.read()).hexdigest() result = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="cim10", version="2026" ) assert result.file_hash == expected_hash assert len(result.file_hash) == 64 # SHA-256 = 64 caractères hex def test_import_referentiel_creates_version(self, temp_data_dir, sample_pdf): """Test que l'import crée une ReferentielVersion correcte.""" manager = ReferentielsManager(data_dir=temp_data_dir) result = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="guide_mco", version="2026" ) assert result.type == "guide_mco" assert result.version == "2026" assert isinstance(result.import_date, datetime) assert result.file_hash is not None assert len(result.file_hash) == 64 def test_import_referentiel_saves_text(self, temp_data_dir, sample_pdf): """Test que l'import sauvegarde le texte extrait.""" manager = ReferentielsManager(data_dir=temp_data_dir) manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="ccam", version="2025" ) text_file = temp_data_dir / "ccam_2025_text.txt" assert text_file.exists() def test_import_referentiel_caches_version(self, temp_data_dir, sample_pdf): """Test que l'import met en cache la version.""" manager = ReferentielsManager(data_dir=temp_data_dir) result = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="cim10", version="2026" ) # Vérifier que la version est dans le cache cached_version = manager.get_version_info("cim10") assert cached_version is not None assert cached_version.type == "cim10" assert cached_version.version == "2026" assert cached_version.file_hash == result.file_hash class TestGetVersionInfo: """Tests de récupération des informations de version.""" def test_get_version_info_not_found(self, temp_data_dir): """Test que get_version_info retourne None si non trouvé.""" manager = ReferentielsManager(data_dir=temp_data_dir) result = manager.get_version_info("cim10") assert result is None def test_get_version_info_returns_cached(self, temp_data_dir, sample_pdf): """Test que get_version_info retourne la version en cache.""" manager = ReferentielsManager(data_dir=temp_data_dir) imported = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="guide_mco", version="2026" ) result = manager.get_version_info("guide_mco") assert result is not None assert result.type == imported.type assert result.version == imported.version assert result.file_hash == imported.file_hash class TestChunkReferentiel: """Tests de chunking des référentiels.""" def test_chunk_referentiel_guide_mco(self, temp_data_dir, sample_pdf): """Test le chunking du Guide MCO.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Import d'abord ref_version = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="guide_mco", version="2026" ) # Chunking chunks = manager.chunk_referentiel(ref_version) assert len(chunks) > 0 for chunk in chunks: assert chunk.referentiel_type == "guide_mco" assert chunk.referentiel_version == "2026" assert chunk.content is not None assert chunk.chunk_id.startswith("guide_mco_2026_") def test_chunk_referentiel_cim10(self, temp_data_dir, sample_pdf): """Test le chunking de la CIM-10.""" manager = ReferentielsManager(data_dir=temp_data_dir) ref_version = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="cim10", version="2026" ) chunks = manager.chunk_referentiel(ref_version) assert len(chunks) > 0 for chunk in chunks: assert chunk.referentiel_type == "cim10" assert chunk.chunk_id.startswith("cim10_2026_") def test_chunk_referentiel_ccam(self, temp_data_dir, sample_pdf): """Test le chunking de la CCAM.""" manager = ReferentielsManager(data_dir=temp_data_dir) ref_version = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="ccam", version="2025" ) chunks = manager.chunk_referentiel(ref_version) assert len(chunks) > 0 for chunk in chunks: assert chunk.referentiel_type == "ccam" assert chunk.chunk_id.startswith("ccam_2025_") def test_chunk_referentiel_file_not_found(self, temp_data_dir): """Test que le chunking échoue si le fichier texte n'existe pas.""" manager = ReferentielsManager(data_dir=temp_data_dir) from pipeline_mco_pmsi.models.metadata import ReferentielVersion # Créer une version sans avoir importé le fichier fake_version = ReferentielVersion( type="cim10", version="2026", import_date=datetime.now(), file_hash="a" * 64, chunk_count=0, index_hash="0" * 64 # Placeholder hash ) with pytest.raises(RuntimeError, match="Fichier texte du référentiel introuvable"): manager.chunk_referentiel(fake_version) class TestChunkGuideMCO: """Tests spécifiques pour le chunking du Guide MCO.""" def test_chunk_guide_mco_preserves_rules(self, temp_data_dir): """Test que le chunking préserve les règles complètes.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Créer un texte de test avec des règles test_text = """CHAPITRE 1 - Le recueil d'information 1.1 Règles générales Règle 1: Le diagnostic principal (DP) est la pathologie ayant motivé l'admission. Critère d'éligibilité: - Le DP doit être documenté dans le dossier médical - Le DP doit être codé selon la CIM-10 Exclusion: Les antécédents ne peuvent pas être DP. 1.2 Règles spécifiques Règle 2: Les diagnostics associés significatifs (DAS) sont les comorbidités. """ # Sauvegarder le texte text_file = temp_data_dir / "guide_mco_2026_text.txt" with open(text_file, "w", encoding="utf-8") as f: f.write(test_text) chunks = manager.chunk_guide_mco(test_text, "2026") # Vérifier qu'on a des chunks assert len(chunks) > 0 # Vérifier que les métadonnées contiennent la section for chunk in chunks: assert "section" in chunk.metadata assert chunk.metadata["chunk_type"] == "section" # Vérifier qu'aucune règle n'est coupée au milieu # (une règle commence par "Règle" et se termine avant la prochaine règle ou section) full_content = "\n".join([c.content for c in chunks]) assert "Règle 1:" in full_content assert "Règle 2:" in full_content assert "Exclusion:" in full_content def test_chunk_guide_mco_respects_size_limits(self, temp_data_dir): """Test que les chunks respectent les limites de taille.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Créer un texte long test_text = "CHAPITRE 1\n\n" + ("Paragraphe de test. " * 500) chunks = manager.chunk_guide_mco(test_text, "2026") # Vérifier que les chunks ne dépassent pas la taille max for chunk in chunks: assert len(chunk.content) <= 4096 # max_chunk_size def test_chunk_guide_mco_creates_overlap(self, temp_data_dir): """Test que le chunking crée un overlap entre chunks.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Créer un texte avec plusieurs sections test_text = """CHAPITRE 1 Section 1.1 """ + ("Contenu de la section 1.1. " * 200) + """ Section 1.2 """ + ("Contenu de la section 1.2. " * 200) chunks = manager.chunk_guide_mco(test_text, "2026") # Si on a plusieurs chunks, vérifier qu'il y a un overlap if len(chunks) > 1: # Le dernier contenu du chunk N devrait apparaître au début du chunk N+1 for i in range(len(chunks) - 1): chunk_n_end = chunks[i].content[-200:] # Derniers 200 caractères chunk_n1_start = chunks[i + 1].content[:400] # Premiers 400 caractères # Vérifier qu'il y a un overlap (au moins quelques mots en commun) # On cherche des mots de plus de 5 caractères words_n = [w for w in chunk_n_end.split() if len(w) > 5] if words_n: # Au moins un mot devrait être dans le chunk suivant assert any(word in chunk_n1_start for word in words_n[:5]) class TestChunkCIM10: """Tests spécifiques pour le chunking de la CIM-10.""" def test_chunk_cim10_preserves_notes(self, temp_data_dir): """Test que le chunking préserve les notes d'inclusion/exclusion.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Créer un texte de test avec des codes et notes test_text = """CHAPITRE I - Maladies infectieuses A00-A09 Maladies intestinales infectieuses A00 Choléra A00.0 Choléra dû à Vibrio cholerae 01, biovar cholerae A00.1 Choléra dû à Vibrio cholerae 01, biovar El Tor A00.9 Choléra, sans précision Inclus: infection à Vibrio cholerae Exclut: intoxication alimentaire (A05.-) A01 Fièvres typhoïde et paratyphoïde A01.0 Fièvre typhoïde Note: La fièvre typhoïde est causée par Salmonella typhi. Comprend: infection à Salmonella typhi """ # Sauvegarder le texte text_file = temp_data_dir / "cim10_2026_text.txt" with open(text_file, "w", encoding="utf-8") as f: f.write(test_text) chunks = manager.chunk_cim10(test_text, "2026") # Vérifier qu'on a des chunks assert len(chunks) > 0 # Vérifier que les métadonnées contiennent le chapitre for chunk in chunks: assert "chapter" in chunk.metadata assert chunk.metadata["chunk_type"] == "code_block" # Vérifier que les notes ne sont pas coupées full_content = "\n".join([c.content for c in chunks]) assert "Inclus:" in full_content assert "Exclut:" in full_content assert "Note:" in full_content def test_chunk_cim10_respects_size_limits(self, temp_data_dir): """Test que les chunks respectent les limites de taille.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Créer un texte long test_text = "CHAPITRE I\n\n" + ("A00 Code de test\n" * 300) chunks = manager.chunk_cim10(test_text, "2026") # Vérifier que les chunks ne dépassent pas la taille max for chunk in chunks: assert len(chunk.content) <= 4096 # max_chunk_size def test_chunk_cim10_does_not_cut_note_blocks(self, temp_data_dir): """Test que les blocs de notes ne sont jamais coupés.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Créer un texte avec un long bloc de notes test_text = """A00 Choléra Inclus: - infection à Vibrio cholerae - choléra classique - choléra El Tor - choléra asiatique - choléra épidémique Exclut: - intoxication alimentaire (A05.-) - gastro-entérite non infectieuse (K52.-) A01 Fièvre typhoïde """ chunks = manager.chunk_cim10(test_text, "2026") # Vérifier que chaque chunk contient soit le bloc complet, soit rien du bloc for chunk in chunks: if "Inclus:" in chunk.content: # Si le chunk contient "Inclus:", il doit contenir toute la liste assert "- infection à Vibrio cholerae" in chunk.content assert "- choléra épidémique" in chunk.content class TestChunkCCAM: """Tests spécifiques pour le chunking de la CCAM.""" def test_chunk_ccam_preserves_extensions(self, temp_data_dir): """Test que le chunking préserve les extensions ATIH.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Créer un texte de test avec des codes CCAM et extensions test_text = """CHAPITRE 1 - Actes diagnostiques SECTION 1.1 - Imagerie YYYY001 Radiographie du thorax Description: Radiographie standard du thorax de face et de profil Extensions ATIH: +ABC Extension pour urgence +DEF Extension pour patient hospitalisé +GHI Extension pour acte itératif Note technique: Cet acte nécessite une prescription médicale. Condition d'application: Patient en position debout ou allongé. YYYY002 Scanner thoracique Description: Tomodensitométrie du thorax avec injection """ # Sauvegarder le texte text_file = temp_data_dir / "ccam_2025_text.txt" with open(text_file, "w", encoding="utf-8") as f: f.write(test_text) chunks = manager.chunk_ccam(test_text, "2025") # Vérifier qu'on a des chunks assert len(chunks) > 0 # Vérifier que les métadonnées contiennent la section for chunk in chunks: assert "section" in chunk.metadata assert chunk.metadata["chunk_type"] == "acte" # Vérifier que les extensions ne sont pas coupées full_content = "\n".join([c.content for c in chunks]) assert "Extensions ATIH:" in full_content assert "+ABC" in full_content assert "+DEF" in full_content assert "+GHI" in full_content def test_chunk_ccam_respects_size_limits(self, temp_data_dir): """Test que les chunks respectent les limites de taille.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Créer un texte long test_text = "CHAPITRE 1\n\n" + ("YYYY001 Acte de test\n" * 300) chunks = manager.chunk_ccam(test_text, "2025") # Vérifier que les chunks ne dépassent pas la taille max for chunk in chunks: assert len(chunk.content) <= 4096 # max_chunk_size def test_chunk_ccam_does_not_cut_technical_notes(self, temp_data_dir): """Test que les notes techniques ne sont jamais coupées.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Créer un texte avec une longue note technique test_text = """YYYY001 Acte chirurgical Note technique: Cet acte nécessite: - Une anesthésie générale - Un plateau technique complet - Une équipe chirurgicale de 3 personnes minimum - Un contrôle radiologique per-opératoire - Une surveillance post-opératoire de 24h Condition d'application: Patient à jeun depuis 6h. YYYY002 Autre acte """ chunks = manager.chunk_ccam(test_text, "2025") # Vérifier que chaque chunk contient soit la note complète, soit rien de la note for chunk in chunks: if "Note technique:" in chunk.content: # Si le chunk contient "Note technique:", il doit contenir toute la note assert "- Une anesthésie générale" in chunk.content assert "- Une surveillance post-opératoire de 24h" in chunk.content class TestBuildIndex: """Tests de construction d'index vectoriel.""" def test_build_index_empty_chunks(self, temp_data_dir): """Test que build_index rejette une liste vide de chunks.""" manager = ReferentielsManager(data_dir=temp_data_dir) with pytest.raises(ValueError, match="La liste de chunks ne peut pas être vide"): manager.build_index([]) def test_build_index_creates_vector_index(self, temp_data_dir, sample_pdf): """Test que build_index crée un index vectoriel.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Import et chunking ref_version = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="cim10", version="2026" ) chunks = manager.chunk_referentiel(ref_version) # Construction de l'index vector_index = manager.build_index(chunks) # Vérifications assert vector_index.index_hash is not None assert len(vector_index.index_hash) == 64 # SHA-256 assert vector_index.dimension > 0 assert vector_index.num_vectors == len(chunks) assert vector_index.index_type == "HNSW" assert isinstance(vector_index.created_at, datetime) def test_build_index_saves_to_disk(self, temp_data_dir, sample_pdf): """Test que build_index sauvegarde l'index sur disque.""" manager = ReferentielsManager(data_dir=temp_data_dir) # Import et chunking ref_version = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="guide_mco", version="2026" ) chunks = manager.chunk_referentiel(ref_version) # Construction de l'index manager.build_index(chunks) # Vérifier que le fichier d'index existe index_file = temp_data_dir / "guide_mco_2026_index.faiss" assert index_file.exists() # Vérifier que le fichier de chunks existe chunks_file = temp_data_dir / "guide_mco_2026_chunks.json" assert chunks_file.exists() class TestRebuildIndex: """Tests de reconstruction d'index après mise à jour.""" def test_rebuild_index_with_code_mapper(self, temp_data_dir, sample_pdf): """Test la reconstruction d'index avec code mapper.""" from pipeline_mco_pmsi.referentiels import CodeMapper from pipeline_mco_pmsi.referentiels.code_mapper import CodeMapping from pipeline_mco_pmsi.models.metadata import ReferentielVersion from datetime import datetime manager = ReferentielsManager(data_dir=temp_data_dir) code_mapper = CodeMapper(mappings_dir=temp_data_dir / "mappings") # Ajouter un mapping de test mapping = CodeMapping( obsolete_code="A00.0", current_code="A00.1", obsolete_label="Ancien code", current_label="Nouveau code", effective_date=datetime.now(), reason="obsolete" ) code_mapper.add_mapping(mapping, "cim10") # Import initial ref_version = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="cim10", version="2026" ) # Chunking et indexation initiale chunks = manager.chunk_referentiel(ref_version) initial_index = manager.build_index(chunks) # Mise à jour du référentiel version dans le cache # Créer une nouvelle instance car ReferentielVersion est frozen updated_ref_version = ReferentielVersion( type=ref_version.type, version=ref_version.version, import_date=ref_version.import_date, file_hash=ref_version.file_hash, chunk_count=len(chunks), index_hash=initial_index.index_hash ) manager._versions_cache[f"cim10_2026"] = updated_ref_version # Reconstruction avec code mapper rebuilt_index = manager.rebuild_index("cim10", "2026", code_mapper=code_mapper) # Vérifications assert rebuilt_index.index_hash is not None assert rebuilt_index.num_vectors > 0 # Le hash devrait être différent car le contenu a changé # (même si dans ce test le PDF est vide, la logique est testée) assert rebuilt_index.index_hash is not None def test_rebuild_index_with_code_mapper(self, temp_data_dir, sample_pdf): """Test la reconstruction d'index avec code mapper.""" from pipeline_mco_pmsi.referentiels import CodeMapper from datetime import datetime manager = ReferentielsManager(data_dir=temp_data_dir) code_mapper = CodeMapper(mappings_dir=temp_data_dir / "mappings") # Ajouter un mapping de test from pipeline_mco_pmsi.referentiels.code_mapper import CodeMapping mapping = CodeMapping( obsolete_code="A00.0", current_code="A00.1", obsolete_label="Ancien code", current_label="Nouveau code", effective_date=datetime.now(), reason="obsolete" ) code_mapper.add_mapping(mapping, "cim10") # Import initial ref_version = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="cim10", version="2026" ) # Chunking et indexation initiale chunks = manager.chunk_referentiel(ref_version) initial_index = manager.build_index(chunks) # Mise à jour du référentiel version dans le cache # Créer une nouvelle instance car ReferentielVersion est frozen from pipeline_mco_pmsi.models.metadata import ReferentielVersion updated_ref_version = ReferentielVersion( type=ref_version.type, version=ref_version.version, import_date=ref_version.import_date, file_hash=ref_version.file_hash, chunk_count=len(chunks), index_hash=initial_index.index_hash ) manager._versions_cache[f"cim10_2026"] = updated_ref_version # Reconstruction avec code mapper rebuilt_index = manager.rebuild_index("cim10", "2026", code_mapper=code_mapper) # Vérifications assert rebuilt_index.index_hash is not None assert rebuilt_index.num_vectors > 0 # Le hash devrait être différent car le contenu a changé # (même si dans ce test le PDF est vide, la logique est testée) assert rebuilt_index.index_hash is not None def test_rebuild_index_referentiel_not_found(self, temp_data_dir): """Test que rebuild_index échoue si le référentiel n'est pas trouvé.""" manager = ReferentielsManager(data_dir=temp_data_dir) with pytest.raises(RuntimeError, match="Version du référentiel .* non trouvée"): manager.rebuild_index("cim10", "2026") def test_rebuild_index_text_file_not_found(self, temp_data_dir): """Test que rebuild_index échoue si le fichier texte n'existe pas.""" from pipeline_mco_pmsi.models.metadata import ReferentielVersion manager = ReferentielsManager(data_dir=temp_data_dir) # Créer une version sans fichier texte fake_version = ReferentielVersion( type="cim10", version="2026", import_date=datetime.now(), file_hash="a" * 64, chunk_count=0, index_hash="0" * 64 ) manager._versions_cache["cim10_2026"] = fake_version with pytest.raises(RuntimeError, match="Fichier texte du référentiel introuvable"): manager.rebuild_index("cim10", "2026") def test_rebuild_index_updates_metadata(self, temp_data_dir, sample_pdf): """Test que rebuild_index met à jour les métadonnées de version.""" from pipeline_mco_pmsi.models.metadata import ReferentielVersion manager = ReferentielsManager(data_dir=temp_data_dir) # Import initial ref_version = manager.import_referentiel( file_path=str(sample_pdf), referentiel_type="ccam", version="2025" ) # Chunking et indexation initiale chunks = manager.chunk_referentiel(ref_version) initial_index = manager.build_index(chunks) # Mise à jour du référentiel version dans le cache # Créer une nouvelle instance car ReferentielVersion est frozen updated_ref_version = ReferentielVersion( type=ref_version.type, version=ref_version.version, import_date=ref_version.import_date, file_hash=ref_version.file_hash, chunk_count=len(chunks), index_hash=initial_index.index_hash ) manager._versions_cache[f"ccam_2025"] = updated_ref_version # Sauvegarder les valeurs initiales initial_hash = updated_ref_version.index_hash initial_count = updated_ref_version.chunk_count # Reconstruction rebuilt_index = manager.rebuild_index("ccam", "2025") # Vérifier que les métadonnées ont été mises à jour updated_version = manager.get_version_info("ccam") assert updated_version.index_hash == rebuilt_index.index_hash assert updated_version.chunk_count == rebuilt_index.num_vectors # Les valeurs devraient être cohérentes assert updated_version.index_hash is not None assert updated_version.chunk_count > 0 class TestApplyCodeMappings: """Tests d'application des mappings de codes.""" def test_apply_code_mappings_cim10(self, temp_data_dir): """Test l'application des mappings pour CIM-10.""" from pipeline_mco_pmsi.referentiels import CodeMapper from pipeline_mco_pmsi.referentiels.code_mapper import CodeMapping from datetime import datetime manager = ReferentielsManager(data_dir=temp_data_dir) code_mapper = CodeMapper() # Ajouter un mapping mapping = CodeMapping( obsolete_code="A00.0", current_code="A00.9", obsolete_label="Ancien", current_label="Nouveau", effective_date=datetime.now(), reason="obsolete" ) code_mapper.add_mapping(mapping, "cim10") # Texte avec code obsolète text = """CHAPITRE I A00.0 Choléra ancien A00.1 Choléra actuel A00.9 Choléra sans précision """ # Appliquer les mappings updated_text = manager._apply_code_mappings(text, "cim10", code_mapper) # Vérifier que le code obsolète a été remplacé assert "A00.9 Choléra ancien" in updated_text assert "A00.1 Choléra actuel" in updated_text # Le code A00.0 ne devrait plus apparaître seul (remplacé par A00.9) import re # Compter les occurrences de A00.0 comme code (pas dans A00.01 par exemple) a00_0_count = len(re.findall(r'\bA00\.0\b', updated_text)) assert a00_0_count == 0 def test_apply_code_mappings_ccam(self, temp_data_dir): """Test l'application des mappings pour CCAM.""" from pipeline_mco_pmsi.referentiels import CodeMapper from pipeline_mco_pmsi.referentiels.code_mapper import CodeMapping from datetime import datetime manager = ReferentielsManager(data_dir=temp_data_dir) code_mapper = CodeMapper() # Ajouter un mapping mapping = CodeMapping( obsolete_code="YYYY001", current_code="YYYY002", obsolete_label="Ancien acte", current_label="Nouvel acte", effective_date=datetime.now(), reason="merged" ) code_mapper.add_mapping(mapping, "ccam") # Texte avec code obsolète text = """CHAPITRE 1 YYYY001 Acte ancien YYYY002 Acte actuel YYYY003 Autre acte """ # Appliquer les mappings updated_text = manager._apply_code_mappings(text, "ccam", code_mapper) # Vérifier que le code obsolète a été remplacé assert "YYYY002 Acte ancien" in updated_text assert "YYYY002 Acte actuel" in updated_text assert "YYYY003 Autre acte" in updated_text # Le code YYYY001 ne devrait plus apparaître assert "YYYY001" not in updated_text def test_apply_code_mappings_with_aliases(self, temp_data_dir): """Test l'application des mappings avec aliases.""" from pipeline_mco_pmsi.referentiels import CodeMapper manager = ReferentielsManager(data_dir=temp_data_dir) code_mapper = CodeMapper() # Ajouter un alias code_mapper.add_alias("A00.X", "A00.9", "cim10") # Texte avec alias text = """A00.X Choléra (alias) A00.9 Choléra sans précision """ # Appliquer les mappings updated_text = manager._apply_code_mappings(text, "cim10", code_mapper) # Vérifier que l'alias a été résolu assert "A00.9 Choléra (alias)" in updated_text assert "A00.X" not in updated_text def test_apply_code_mappings_guide_mco_unchanged(self, temp_data_dir): """Test que les mappings ne modifient pas le guide MCO.""" from pipeline_mco_pmsi.referentiels import CodeMapper manager = ReferentielsManager(data_dir=temp_data_dir) code_mapper = CodeMapper() # Texte du guide text = """CHAPITRE 1 - Le recueil Règle 1: Le DP doit être codé selon la CIM-10. """ # Appliquer les mappings (ne devrait rien changer) updated_text = manager._apply_code_mappings(text, "guide_mco", code_mapper) # Le texte devrait être inchangé assert updated_text == text def test_apply_code_mappings_preserves_unknown_codes(self, temp_data_dir): """Test que les codes inconnus sont préservés.""" from pipeline_mco_pmsi.referentiels import CodeMapper manager = ReferentielsManager(data_dir=temp_data_dir) code_mapper = CodeMapper() # Aucun mapping # Texte avec codes text = """A00.0 Code 1 A00.1 Code 2 A00.2 Code 3 """ # Appliquer les mappings (ne devrait rien changer) updated_text = manager._apply_code_mappings(text, "cim10", code_mapper) # Le texte devrait être inchangé assert updated_text == text