"""Tests unitaires pour le module app.fiches.utils.dynamic.indice.isg. Ces tests verifient les fonctions de traitement Markdown pour l'indice ISG : - _synth_isg - build_isg_sections """ import textwrap from unittest.mock import patch import pytest from app.fiches.utils.dynamic.indice.isg import ( _synth_isg, build_isg_sections, ) # ────────────────────────────────────────────── # Helpers # ────────────────────────────────────────────── def _yaml_pays_bloc(pays: list[dict]) -> str: """Construit un bloc YAML markdown avec des donnees de pays ISG.""" lignes = ["```yaml"] for p in pays: lignes.append(f"{p['id']}:") lignes.append(f" pays: {p['pays']}") lignes.append(f" wgi_ps: {p['wgi_ps']}") lignes.append(f" fsi: {p['fsi']}") lignes.append(f" ndgain: {p['ndgain']}") lignes.append(f" isg: {p['isg']}") lignes.append("```") return "\n".join(lignes) def _sample_pays(**overrides) -> dict: """Retourne un dictionnaire pays avec des valeurs par defaut.""" base = { "id": "chine", "pays": "Chine", "wgi_ps": 35, "fsi": 72, "ndgain": 48, "isg": 54, } base.update(overrides) return base def _make_isg_md(pays: list[dict], with_front_matter: bool = True, indice_court: str = "ISG") -> str: """Construit un markdown complet pour ISG.""" parts = [] if with_front_matter: parts.append( f"---\nindice: Indice de Stabilit\u00e9 G\u00e9opolitique\n" f"indice_court: {indice_court}\n---\n" ) parts.append("# Indice de Stabilit\u00e9 G\u00e9opolitique (ISG)\n") parts.append("Introduction de la fiche.\n") parts.append("# Criticit\u00e9 par pays\n") parts.append(_yaml_pays_bloc(pays)) parts.append("\n## Tableau de synth\u00e8se\n") parts.append("\nancien tableau\n") return "\n".join(parts) @pytest.fixture(autouse=True) def _mock_pastille(): """Mock la fonction pastille pour retourner une valeur previsible.""" with patch( "app.fiches.utils.dynamic.indice.isg.pastille", side_effect=lambda indice, valeur: f"[{indice}:{valeur}]", ): yield # ────────────────────────────────────────────── # _synth_isg # ────────────────────────────────────────────── class TestSynthIsg: """Tests pour la generation du tableau de synthese ISG.""" def test_un_pays(self): """Test la synthese avec un seul pays.""" pays = [_sample_pays()] md = _yaml_pays_bloc(pays) result = _synth_isg(md) assert "| Pays | WGI | FSI | NDGAIN | ISG |" in result assert "| :-- | :-- | :-- | :-- | :-- |" in result assert "Chine" in result assert "54" in result def test_plusieurs_pays_tries_alpha(self): """Test que les pays sont tries alphabetiquement par nom.""" pays = [ _sample_pays(id="chine", pays="Chine", isg=54), _sample_pays(id="australie", pays="Australie", isg=25), _sample_pays(id="rdc", pays="RDC", isg=82), ] md = _yaml_pays_bloc(pays) result = _synth_isg(md) idx_australie = result.find("Australie") idx_chine = result.find("Chine") idx_rdc = result.find("RDC") assert idx_australie < idx_chine < idx_rdc def test_toutes_colonnes_presentes(self): """Test que toutes les colonnes de donnees sont presentes.""" pays = [_sample_pays(wgi_ps=35, fsi=72, ndgain=48, isg=54)] md = _yaml_pays_bloc(pays) result = _synth_isg(md) assert "35" in result assert "72" in result assert "48" in result assert "54" in result def test_pas_de_bloc_yaml(self): """Test avec un texte sans bloc yaml retourne un message par defaut.""" result = _synth_isg("Texte sans donnees YAML.") assert "aucune donnee de pays trouvee" in result.lower() or "aucune donn" in result def test_texte_vide(self): """Test avec un texte vide.""" result = _synth_isg("") assert "aucune donn" in result def test_nombre_lignes(self): """Test que le nombre de lignes correspond aux donnees.""" pays = [ _sample_pays(id="a", pays="Alpha", isg=10), _sample_pays(id="b", pays="Beta", isg=20), _sample_pays(id="c", pays="Gamma", isg=30), ] md = _yaml_pays_bloc(pays) result = _synth_isg(md) lignes = result.strip().split("\n") # 2 en-tetes + 3 donnees = 5 assert len(lignes) == 5 def test_pastille_incluse(self): """Test que la pastille est incluse dans la colonne ISG.""" pays = [_sample_pays(isg=25)] md = _yaml_pays_bloc(pays) result = _synth_isg(md) # La pastille mockee retourne [ISG:valeur] avant la valeur assert "[ISG:25]" in result assert "25" in result # ────────────────────────────────────────────── # build_isg_sections # ────────────────────────────────────────────── class TestBuildIsgSections: """Tests pour la fonction principale de construction des sections dynamiques ISG.""" def test_remplacement_tableau_final(self): """Test que le tableau final est remplace entre les marqueurs.""" pays = [_sample_pays()] md = _make_isg_md(pays) result = build_isg_sections(md) assert "" in result assert "" in result assert "ancien tableau" not in result def test_tableau_synthese_genere(self): """Test que le tableau de synthese est genere correctement.""" pays = [_sample_pays()] md = _make_isg_md(pays) result = build_isg_sections(md) assert "| Pays | WGI | FSI | NDGAIN | ISG |" in result assert "Chine" in result def test_bloc_yaml_pays_supprime(self): """Test que le bloc YAML des pays est supprime de la section Criticite.""" pays = [_sample_pays()] md = _make_isg_md(pays) result = build_isg_sections(md) assert "# Criticit\u00e9 par pays" in result # Le bloc YAML doit etre supprime assert "```yaml" not in result def test_front_matter_isg_valide(self): """Test que la fiche est traitee quand indice_court est ISG.""" pays = [_sample_pays()] md = _make_isg_md(pays, indice_court="ISG") result = build_isg_sections(md) # La fiche doit etre traitee assert "| Pays | WGI | FSI | NDGAIN | ISG |" in result def test_front_matter_non_isg_retourne_original(self): """Test que la fiche n'est pas traitee si indice_court != ISG.""" pays = [_sample_pays()] md = _make_isg_md(pays, indice_court="ICS") result = build_isg_sections(md) # Le markdown original doit etre retourne sans modification assert "ancien tableau" in result def test_sans_front_matter(self): """Test le traitement sans front-matter YAML.""" pays = [_sample_pays()] md = _make_isg_md(pays, with_front_matter=False) result = build_isg_sections(md) # Sans front-matter, la fiche est quand meme traitee (pas de filtre) assert "| Pays | WGI | FSI | NDGAIN | ISG |" in result def test_plusieurs_pays(self): """Test avec plusieurs pays dans le bloc YAML.""" pays = [ _sample_pays(id="australie", pays="Australie", wgi_ps=85, fsi=28, ndgain=72, isg=25), _sample_pays(id="chine", pays="Chine", wgi_ps=35, fsi=72, ndgain=48, isg=54), _sample_pays(id="rdc", pays="RDC", wgi_ps=15, fsi=102, ndgain=33, isg=82), ] md = _make_isg_md(pays) result = build_isg_sections(md) assert "Australie" in result assert "Chine" in result assert "RDC" in result def test_texte_sans_marqueurs(self): """Test avec un markdown sans marqueurs AUTO-BEGIN/END.""" md = textwrap.dedent("""\ --- indice_court: ISG --- # ISG # Criticit\u00e9 par pays ```yaml fr: pays: France wgi_ps: 80 fsi: 30 ndgain: 65 isg: 28 ``` ## Tableau de synth\u00e8se Pas de marqueurs ici. """) result = build_isg_sections(md) # Sans marqueurs, le sub ne match pas, le tableau n'est pas remplace assert isinstance(result, str) def test_md_vide_avec_front_matter_isg(self): """Test avec un markdown minimal contenant seulement le front-matter ISG.""" md = "---\nindice_court: ISG\n---\n\nContenu minimal." result = build_isg_sections(md) # Pas de bloc YAML de pays, pas de marqueurs, retourne le texte en l'etat assert "Contenu minimal." in result def test_preservation_contenu_hors_sections(self): """Test que le contenu hors des sections dynamiques est preserve.""" pays = [_sample_pays()] md = _make_isg_md(pays) result = build_isg_sections(md) assert "# Indice de Stabilit\u00e9 G\u00e9opolitique (ISG)" in result assert "Introduction de la fiche." in result def test_tri_alphabetique_dans_resultat(self): """Test que les pays sont tries alphabetiquement dans le resultat final.""" pays = [ _sample_pays(id="z", pays="Zambie", isg=60), _sample_pays(id="a", pays="Albanie", isg=30), ] md = _make_isg_md(pays) result = build_isg_sections(md) idx_albanie = result.find("Albanie") idx_zambie = result.find("Zambie") assert idx_albanie < idx_zambie