"""Tests unitaires pour le module app.fiches.utils.dynamic.indice.ivc. Ces tests verifient les fonctions de traitement Markdown pour l'indice IVC : - _synth_ivc - _ivc_segments - build_ivc_sections """ from app.fiches.utils.dynamic.indice.ivc import ( IVC_RE, _ivc_segments, _synth_ivc, build_ivc_sections, ) # ────────────────────────────────────────────── # Helpers # ────────────────────────────────────────────── def _yaml_ivc_bloc(minerai: dict) -> str: """Construit un bloc YAML markdown pour un minerai IVC.""" lignes = ["```yaml"] lignes.append("minerai:") for k, v in minerai.items(): lignes.append(f" {k}: {v}") lignes.append("```") return "\n".join(lignes) def _sample_minerai(**overrides) -> dict: """Retourne un dictionnaire minerai avec des valeurs par defaut.""" base = { "nom": "Lithium", "ivc": 45, "vulnerabilite": "Moyenne", } base.update(overrides) return base def _make_ivc_md(minerais: list[dict], with_markers: bool = True) -> str: """Construit un markdown complet pour IVC avec des blocs YAML et des templates Jinja2.""" parts = ["# Indice de Vulnerabilite Complete (IVC)\n"] parts.append("Introduction de la fiche.\n") for minerai in minerais: parts.append(_yaml_ivc_bloc(minerai)) parts.append("\n## Analyse de {{ nom }}\n") parts.append("L'IVC de {{ nom }} est de {{ ivc }} avec une vulnerabilite {{ vulnerabilite }}.\n") if with_markers: parts.append("\n## Tableau de synth\u00e8se\n") parts.append("\nancien tableau\n") return "\n".join(parts) # ────────────────────────────────────────────── # IVC_RE (regex) # ────────────────────────────────────────────── class TestIvcRegex: """Tests pour l'expression reguliere IVC_RE.""" def test_match_bloc_ivc_simple(self): """Test la detection d'un bloc yaml IVC simple.""" md = "```yaml\nminerai:\n nom: Lithium\n ivc: 45\n```" matches = list(IVC_RE.finditer(md)) assert len(matches) == 1 def test_match_blocs_ivc_multiples(self): """Test la detection de plusieurs blocs yaml IVC.""" md = ( "```yaml\nminerai:\n nom: Lithium\n ivc: 45\n```\n" "texte\n" "```yaml\nminerai:\n nom: Cobalt\n ivc: 62\n```" ) matches = list(IVC_RE.finditer(md)) assert len(matches) == 2 def test_pas_de_match_sans_minerai(self): """Test qu'un bloc yaml sans 'minerai:' ne matche pas.""" md = "```yaml\nautres:\n x: 1\n```" matches = list(IVC_RE.finditer(md)) assert len(matches) == 0 def test_match_insensible_casse(self): """Test que YAML en majuscules est aussi detecte.""" md = "```YAML\nminerai:\n nom: Test\n```" matches = list(IVC_RE.finditer(md)) assert len(matches) == 1 def test_espaces_entre_yaml_et_minerai(self): """Test avec des espaces entre le tag yaml et minerai.""" md = "```yaml\n minerai:\n nom: Test\n```" matches = list(IVC_RE.finditer(md)) assert len(matches) == 1 # ────────────────────────────────────────────── # _synth_ivc # ────────────────────────────────────────────── class TestSynthIvc: """Tests pour la generation du tableau de synthese IVC.""" def test_un_minerai(self): """Test la synthese avec un seul minerai.""" minerais = [_sample_minerai()] result = _synth_ivc(minerais) assert "| Minerai | IVC | Vuln\u00e9rabilit\u00e9 |" in result assert "| :-- | :-- | :-- |" in result assert "Lithium" in result assert "45" in result assert "Moyenne" in result def test_plusieurs_minerais(self): """Test la synthese avec plusieurs minerais.""" minerais = [ _sample_minerai(nom="Lithium", ivc=45, vulnerabilite="Moyenne"), _sample_minerai(nom="Cobalt", ivc=72, vulnerabilite="Elevee"), _sample_minerai(nom="Cuivre", ivc=18, vulnerabilite="Faible"), ] result = _synth_ivc(minerais) assert "Lithium" in result assert "Cobalt" in result assert "Cuivre" in result def test_nombre_lignes(self): """Test que le nombre de lignes correspond aux donnees.""" minerais = [ _sample_minerai(nom="A", ivc=10, vulnerabilite="X"), _sample_minerai(nom="B", ivc=20, vulnerabilite="Y"), ] result = _synth_ivc(minerais) lignes = result.strip().split("\n") # 2 en-tetes + 2 donnees = 4 assert len(lignes) == 4 def test_en_tetes_tableau(self): """Test que les en-tetes sont corrects.""" minerais = [_sample_minerai()] result = _synth_ivc(minerais) lignes = result.strip().split("\n") assert lignes[0] == "| Minerai | IVC | Vuln\u00e9rabilit\u00e9 |" assert lignes[1] == "| :-- | :-- | :-- |" def test_liste_vide(self): """Test avec une liste vide de minerais.""" result = _synth_ivc([]) lignes = result.strip().split("\n") # Seulement les 2 lignes d'en-tete assert len(lignes) == 2 # ────────────────────────────────────────────── # _ivc_segments # ────────────────────────────────────────────── class TestIvcSegments: """Tests pour l'extraction des segments entre blocs YAML IVC.""" def test_un_segment(self): """Test l'extraction d'un seul segment IVC.""" minerai = _sample_minerai() md = _yaml_ivc_bloc(minerai) + "\nSegment apres le bloc." segments = list(_ivc_segments(md)) # 1 segment + 1 reste eventuel assert len(segments) == 2 data, seg = segments[0] assert data["nom"] == "Lithium" assert "Segment apres le bloc." in seg def test_deux_segments(self): """Test l'extraction de deux segments entre blocs IVC.""" m1 = _sample_minerai(nom="Lithium", ivc=45, vulnerabilite="Moyenne") m2 = _sample_minerai(nom="Cobalt", ivc=72, vulnerabilite="Elevee") md = _yaml_ivc_bloc(m1) + "\nSegment 1\n" + _yaml_ivc_bloc(m2) + "\nSegment 2" segments = list(_ivc_segments(md)) # 2 segments + 1 reste eventuel assert len(segments) == 3 assert segments[0][0]["nom"] == "Lithium" assert "Segment 1" in segments[0][1] assert segments[1][0]["nom"] == "Cobalt" assert "Segment 2" in segments[1][1] def test_reste_final(self): """Test que le reste final (apres le dernier bloc) est capture.""" minerai = _sample_minerai() md = _yaml_ivc_bloc(minerai) + "\nContenu.\nTexte final." segments = list(_ivc_segments(md)) # Le dernier segment doit etre (None, reste) dernier = segments[-1] assert dernier[0] is None def test_pas_de_bloc_yaml(self): """Test avec un markdown sans bloc yaml IVC.""" md = "Texte sans bloc yaml." segments = list(_ivc_segments(md)) # Seulement le reste (None, texte_entier) assert len(segments) == 1 assert segments[0][0] is None assert "Texte sans bloc yaml." in segments[0][1] # ────────────────────────────────────────────── # build_ivc_sections # ────────────────────────────────────────────── class TestBuildIvcSections: """Tests pour la fonction principale de construction des sections dynamiques IVC.""" def test_remplacement_jinja2(self): """Test que les templates Jinja2 sont rendus correctement.""" minerais = [_sample_minerai()] md = _make_ivc_md(minerais) result = build_ivc_sections(md) assert "Lithium" in result assert "45" in result assert "{{ nom }}" not in result def test_tableau_synthese_genere(self): """Test que le tableau de synthese est genere.""" minerais = [_sample_minerai()] md = _make_ivc_md(minerais) result = build_ivc_sections(md) assert "| Minerai | IVC | Vuln\u00e9rabilit\u00e9 |" in result def test_marqueurs_preserves(self): """Test que les marqueurs AUTO-BEGIN/END sont preserves.""" minerais = [_sample_minerai()] md = _make_ivc_md(minerais) result = build_ivc_sections(md) assert "" in result assert "" in result def test_ancien_contenu_remplace(self): """Test que l'ancien contenu entre les marqueurs est remplace.""" minerais = [_sample_minerai()] md = _make_ivc_md(minerais) result = build_ivc_sections(md) assert "ancien tableau" not in result def test_pas_de_bloc_yaml_retourne_original(self): """Test qu'un markdown sans bloc yaml IVC est retourne tel quel.""" md = "# Titre\n\nTexte sans bloc yaml IVC." result = build_ivc_sections(md) assert "Texte sans bloc yaml IVC." in result def test_intro_preservee(self): """Test que l'introduction est preservee dans le resultat.""" minerais = [_sample_minerai()] md = _make_ivc_md(minerais) result = build_ivc_sections(md) assert "# Indice de Vulnerabilite Complete (IVC)" in result assert "Introduction de la fiche." in result def test_plusieurs_minerais(self): """Test avec plusieurs minerais genere un document complet.""" minerais = [ _sample_minerai(nom="Lithium", ivc=45, vulnerabilite="Moyenne"), _sample_minerai(nom="Cobalt", ivc=72, vulnerabilite="Elevee"), ] md = _make_ivc_md(minerais) result = build_ivc_sections(md) assert "Lithium" in result assert "Cobalt" in result assert "45" in result assert "72" in result def test_template_jinja2_avec_toutes_variables(self): """Test que toutes les variables Jinja2 du minerai sont accessibles.""" minerai = _sample_minerai(nom="Indium", ivc=58, vulnerabilite="Haute") md = _make_ivc_md([minerai]) result = build_ivc_sections(md) assert "Indium" in result assert "58" in result assert "Haute" in result def test_md_vide(self): """Test avec un markdown vide.""" result = build_ivc_sections("") assert result == "" def test_bloc_yaml_sans_marqueurs(self): """Test avec un bloc yaml IVC mais sans marqueurs AUTO-BEGIN/END.""" minerais = [_sample_minerai()] md = _make_ivc_md(minerais, with_markers=False) result = build_ivc_sections(md) # Le template doit etre rendu meme sans marqueurs assert "Lithium" in result assert "{{ nom }}" not in result def test_separations_segments(self): """Test que les segments sont separes par des doubles retours a la ligne.""" minerais = [ _sample_minerai(nom="A", ivc=10, vulnerabilite="Faible"), _sample_minerai(nom="B", ivc=20, vulnerabilite="Moyenne"), ] md = _make_ivc_md(minerais) result = build_ivc_sections(md) # Les segments doivent etre joints par "\n\n" assert "\n\n" in result def test_ordre_minerais_preserve(self): """Test que l'ordre des minerais dans le document est preserve.""" minerais = [ _sample_minerai(nom="Premier", ivc=10, vulnerabilite="X"), _sample_minerai(nom="Second", ivc=20, vulnerabilite="Y"), ] md = _make_ivc_md(minerais) result = build_ivc_sections(md) idx_premier = result.find("Premier") idx_second = result.find("Second") assert idx_premier < idx_second def test_synthese_contient_tous_minerais(self): """Test que le tableau de synthese contient tous les minerais.""" minerais = [ _sample_minerai(nom="Lithium", ivc=45, vulnerabilite="Moyenne"), _sample_minerai(nom="Cobalt", ivc=72, vulnerabilite="Elevee"), _sample_minerai(nom="Cuivre", ivc=18, vulnerabilite="Faible"), ] md = _make_ivc_md(minerais) result = build_ivc_sections(md) # Verifier dans la section tableau final assert "Lithium" in result assert "Cobalt" in result assert "Cuivre" in result