"""Tests unitaires pour le module app.fiches.utils.dynamic.indice.ihh. Ces tests verifient les fonctions de traitement des indices IHH : - _extraire_donnees_operations : extraction et organisation des donnees - _generer_tableau_produits : generation de tableau markdown produits - _generer_tableau_composants : generation de tableau markdown composants - _generer_tableau_minerais : generation de tableau markdown minerais - _synth_ihh : synthese des tableaux IHH - build_ihh_sections : construction des sections dynamiques markdown """ from unittest.mock import patch import pytest from app.fiches.utils.dynamic.indice.ihh import ( IHH_RE, _extraire_donnees_operations, _generer_tableau_composants, _generer_tableau_minerais, _generer_tableau_produits, _synth_ihh, build_ihh_sections, ) # ────────────────────────────────────────────── # Fixtures # ────────────────────────────────────────────── @pytest.fixture def operation_minerai(): """Operation type minerai avec extraction, reserves et traitement.""" return { "minerai": "Lithium", "extraction": {"ihh_pays": 1500, "ihh_acteurs": 2000}, "reserves": {"ihh_pays": 1800}, "traitement": {"ihh_pays": 900, "ihh_acteurs": 1100}, } @pytest.fixture def operation_produit(): """Operation type produit avec assemblage.""" return { "produit": "Batterie", "assemblage": {"ihh_pays": 3000, "ihh_acteurs": 2500}, } @pytest.fixture def operation_composant(): """Operation type composant avec fabrication.""" return { "composant": "Cathode", "fabrication": {"ihh_pays": 1200, "ihh_acteurs": 800}, } @pytest.fixture def mock_pastille(): """Mock la fonction pastille pour retourner une valeur previsible.""" with patch("app.fiches.utils.dynamic.indice.ihh.pastille", side_effect=lambda indice, valeur: f"[{indice}:{valeur}]") as m: yield m # ────────────────────────────────────────────── # IHH_RE (regex) # ────────────────────────────────────────────── class TestIhhRegex: """Tests pour la regex IHH_RE.""" def test_match_bloc_yaml_simple(self): """Test la detection d'un bloc YAML operation basique.""" # Le pattern cherche "opération:" (avec accent) texte = "```yaml\n op\u00e9ration:\n minerai: Lithium\n```" matches = list(IHH_RE.finditer(texte)) assert len(matches) == 1 def test_match_insensible_casse(self): """Test que la regex est insensible a la casse du mot YAML.""" texte = "```YAML\n op\u00e9ration:\n minerai: Cobalt\n```" matches = list(IHH_RE.finditer(texte)) assert len(matches) == 1 def test_pas_de_match_sans_operation(self): """Test qu'un bloc YAML sans 'operation' n'est pas capture.""" texte = "```yaml\n autre_cle: valeur\n```" matches = list(IHH_RE.finditer(texte)) assert len(matches) == 0 def test_match_multiple_blocs(self): """Test la detection de plusieurs blocs YAML operation.""" texte = ( "Intro\n" "```yaml\n op\u00e9ration:\n minerai: Lithium\n```\n" "texte entre\n" "```yaml\n op\u00e9ration:\n produit: Batterie\n```\n" ) matches = list(IHH_RE.finditer(texte)) assert len(matches) == 2 # ────────────────────────────────────────────── # _extraire_donnees_operations # ────────────────────────────────────────────── class TestExtraireDonneesOperations: """Tests pour la fonction _extraire_donnees_operations.""" def test_operation_minerai(self, operation_minerai): """Test l'extraction des donnees pour une operation minerai.""" resultat = _extraire_donnees_operations([operation_minerai]) assert "Lithium" in resultat data = resultat["Lithium"] assert data["type"] == "minerai" assert data["extraction_ihh_pays"] == 1500 assert data["extraction_ihh_acteurs"] == 2000 assert data["reserves_ihh_pays"] == 1800 assert data["traitement_ihh_pays"] == 900 assert data["traitement_ihh_acteurs"] == 1100 def test_operation_produit(self, operation_produit): """Test l'extraction des donnees pour une operation produit.""" resultat = _extraire_donnees_operations([operation_produit]) assert "Batterie" in resultat data = resultat["Batterie"] assert data["type"] == "produit" assert data["assemblage_ihh_pays"] == 3000 assert data["assemblage_ihh_acteurs"] == 2500 def test_operation_composant(self, operation_composant): """Test l'extraction des donnees pour une operation composant.""" resultat = _extraire_donnees_operations([operation_composant]) assert "Cathode" in resultat data = resultat["Cathode"] assert data["type"] == "composant" assert data["fabrication_ihh_pays"] == 1200 assert data["fabrication_ihh_acteurs"] == 800 def test_operations_multiples_types(self, operation_minerai, operation_produit, operation_composant): """Test l'extraction avec des operations de types differents.""" resultat = _extraire_donnees_operations([operation_minerai, operation_produit, operation_composant]) assert len(resultat) == 3 assert resultat["Lithium"]["type"] == "minerai" assert resultat["Batterie"]["type"] == "produit" assert resultat["Cathode"]["type"] == "composant" def test_liste_vide(self): """Test avec une liste d'operations vide.""" resultat = _extraire_donnees_operations([]) assert resultat == {} def test_operation_sans_identifiant(self): """Test qu'une operation sans minerai, produit ou composant est ignoree.""" operation = {"autre_cle": "valeur"} resultat = _extraire_donnees_operations([operation]) assert resultat == {} def test_operation_identifiant_vide(self): """Test qu'une operation avec identifiant vide est ignoree.""" operation = {"minerai": "", "extraction": {"ihh_pays": 100}} resultat = _extraire_donnees_operations([operation]) assert resultat == {} def test_valeurs_par_defaut_minerai(self): """Test que les valeurs par defaut sont '-' pour un nouveau minerai.""" operation = {"minerai": "Cobalt", "extraction": {"ihh_pays": 500, "ihh_acteurs": 600}, "reserves": {"ihh_pays": 700}, "traitement": {"ihh_pays": 400, "ihh_acteurs": 300}} resultat = _extraire_donnees_operations([operation]) data = resultat["Cobalt"] # Les champs non lies a l'extraction doivent rester a '-' assert data["assemblage_ihh_pays"] == "-" assert data["assemblage_ihh_acteurs"] == "-" assert data["fabrication_ihh_pays"] == "-" assert data["fabrication_ihh_acteurs"] == "-" def test_valeurs_par_defaut_produit(self, operation_produit): """Test que les valeurs par defaut sont '-' pour un nouveau produit.""" resultat = _extraire_donnees_operations([operation_produit]) data = resultat["Batterie"] assert data["extraction_ihh_pays"] == "-" assert data["extraction_ihh_acteurs"] == "-" assert data["reserves_ihh_pays"] == "-" assert data["traitement_ihh_pays"] == "-" assert data["traitement_ihh_acteurs"] == "-" def test_valeurs_par_defaut_composant(self, operation_composant): """Test que les valeurs par defaut sont '-' pour un nouveau composant.""" resultat = _extraire_donnees_operations([operation_composant]) data = resultat["Cathode"] assert data["extraction_ihh_pays"] == "-" assert data["assemblage_ihh_pays"] == "-" def test_detection_type_minerai_par_extraction(self): """Test que le type 'minerai' est detecte par la cle 'extraction'.""" operation = {"minerai": "Fer", "extraction": {"ihh_pays": 100}, "reserves": {}, "traitement": {}} resultat = _extraire_donnees_operations([operation]) assert resultat["Fer"]["type"] == "minerai" def test_detection_type_minerai_par_reserves(self): """Test que le type 'minerai' est detecte par la cle 'reserves'.""" operation = {"minerai": "Cuivre", "reserves": {"ihh_pays": 200}} resultat = _extraire_donnees_operations([operation]) assert resultat["Cuivre"]["type"] == "minerai" def test_detection_type_minerai_par_traitement(self): """Test que le type 'minerai' est detecte par la cle 'traitement'.""" operation = {"minerai": "Zinc", "traitement": {"ihh_pays": 300}} resultat = _extraire_donnees_operations([operation]) assert resultat["Zinc"]["type"] == "minerai" def test_detection_type_produit_par_assemblage(self): """Test que le type 'produit' est detecte par la cle 'assemblage'.""" operation = {"produit": "Ecran", "assemblage": {"ihh_pays": 100}} resultat = _extraire_donnees_operations([operation]) assert resultat["Ecran"]["type"] == "produit" def test_detection_type_composant_par_defaut(self): """Test que le type 'composant' est attribue par defaut sans cles specifiques.""" operation = {"composant": "Puce", "fabrication": {"ihh_pays": 500}} resultat = _extraire_donnees_operations([operation]) assert resultat["Puce"]["type"] == "composant" def test_extraction_valeurs_manquantes_dans_sous_dict(self): """Test avec des cles manquantes dans les sous-dictionnaires d'extraction.""" operation = { "minerai": "Titane", "extraction": {}, # Pas de ihh_pays ni ihh_acteurs "reserves": {}, "traitement": {}, } resultat = _extraire_donnees_operations([operation]) data = resultat["Titane"] assert data["extraction_ihh_pays"] == "-" assert data["extraction_ihh_acteurs"] == "-" assert data["reserves_ihh_pays"] == "-" assert data["traitement_ihh_pays"] == "-" assert data["traitement_ihh_acteurs"] == "-" def test_assemblage_valeurs_manquantes(self): """Test avec des cles manquantes dans le sous-dictionnaire assemblage.""" operation = {"produit": "Smartphone", "assemblage": {}} resultat = _extraire_donnees_operations([operation]) data = resultat["Smartphone"] assert data["assemblage_ihh_pays"] == "-" assert data["assemblage_ihh_acteurs"] == "-" def test_fabrication_valeurs_manquantes(self): """Test avec des cles manquantes dans le sous-dictionnaire fabrication.""" operation = {"composant": "Resistance", "fabrication": {}} resultat = _extraire_donnees_operations([operation]) data = resultat["Resistance"] assert data["fabrication_ihh_pays"] == "-" assert data["fabrication_ihh_acteurs"] == "-" def test_meme_minerai_deux_operations(self): """Test que deux operations sur le meme minerai fusionnent les donnees.""" op1 = {"minerai": "Lithium", "extraction": {"ihh_pays": 100, "ihh_acteurs": 200}, "reserves": {"ihh_pays": 300}, "traitement": {"ihh_pays": 400, "ihh_acteurs": 500}} # Deuxieme operation avec fabrication sur le meme identifiant # (cas improbable mais le code le gere) op2 = {"minerai": "Lithium", "fabrication": {"ihh_pays": 600, "ihh_acteurs": 700}} resultat = _extraire_donnees_operations([op1, op2]) assert len(resultat) == 1 data = resultat["Lithium"] # Les donnees extraction de la premiere operation sont conservees assert data["extraction_ihh_pays"] == 100 # Les donnees fabrication de la seconde operation sont ajoutees assert data["fabrication_ihh_pays"] == 600 assert data["fabrication_ihh_acteurs"] == 700 def test_priorite_identifiant_minerai_sur_produit(self): """Test que l'identifiant minerai est prioritaire sur produit et composant.""" operation = {"minerai": "Fer", "produit": "Acier", "composant": "Plaque"} resultat = _extraire_donnees_operations([operation]) # minerai est evalue en premier dans le get chain assert "Fer" in resultat assert "Acier" not in resultat assert "Plaque" not in resultat def test_priorite_identifiant_produit_sur_composant(self): """Test que l'identifiant produit est prioritaire sur composant.""" operation = {"produit": "Acier", "composant": "Plaque"} resultat = _extraire_donnees_operations([operation]) assert "Acier" in resultat assert "Plaque" not in resultat # ────────────────────────────────────────────── # _generer_tableau_produits # ────────────────────────────────────────────── class TestGenererTableauProduits: """Tests pour la fonction _generer_tableau_produits.""" def test_dict_vide(self): """Test qu'un dictionnaire vide retourne une chaine vide.""" assert _generer_tableau_produits({}) == "" def test_un_produit(self, mock_pastille): """Test la generation d'un tableau avec un seul produit.""" produits = { "Batterie": { "type": "produit", "assemblage_ihh_pays": 3000, "assemblage_ihh_acteurs": 2500, } } resultat = _generer_tableau_produits(produits) assert "## Assemblage des produits" in resultat assert "| Batterie |" in resultat assert "| Produit | Assemblage IHH Pays | Assemblage IHH Acteurs |" in resultat assert "| :-- | :--: | :--: |" in resultat assert "[IHH:3000]" in resultat assert "[IHH:2500]" in resultat def test_plusieurs_produits_tries(self, mock_pastille): """Test que les produits sont tries par ordre alphabetique.""" produits = { "Smartphone": {"type": "produit", "assemblage_ihh_pays": 100, "assemblage_ihh_acteurs": 200}, "Batterie": {"type": "produit", "assemblage_ihh_pays": 300, "assemblage_ihh_acteurs": 400}, "Ecran": {"type": "produit", "assemblage_ihh_pays": 500, "assemblage_ihh_acteurs": 600}, } resultat = _generer_tableau_produits(produits) # Verifier l'ordre : Batterie < Ecran < Smartphone idx_batterie = resultat.index("Batterie") idx_ecran = resultat.index("Ecran") idx_smartphone = resultat.index("Smartphone") assert idx_batterie < idx_ecran < idx_smartphone def test_valeur_tiret(self, mock_pastille): """Test avec des valeurs '-' (donnees manquantes).""" produits = { "Produit": {"type": "produit", "assemblage_ihh_pays": "-", "assemblage_ihh_acteurs": "-"}, } resultat = _generer_tableau_produits(produits) assert "[IHH:-]" in resultat # ────────────────────────────────────────────── # _generer_tableau_composants # ────────────────────────────────────────────── class TestGenererTableauComposants: """Tests pour la fonction _generer_tableau_composants.""" def test_dict_vide(self): """Test qu'un dictionnaire vide retourne une chaine vide.""" assert _generer_tableau_composants({}) == "" def test_un_composant(self, mock_pastille): """Test la generation d'un tableau avec un seul composant.""" composants = { "Cathode": { "type": "composant", "fabrication_ihh_pays": 1200, "fabrication_ihh_acteurs": 800, } } resultat = _generer_tableau_composants(composants) assert "## Fabrication des composants" in resultat assert "| Cathode |" in resultat assert "| Composant | Fabrication IHH Pays | Fabrication IHH Acteurs |" in resultat assert "| :-- | :--: | :--: |" in resultat assert "[IHH:1200]" in resultat assert "[IHH:800]" in resultat def test_plusieurs_composants_tries(self, mock_pastille): """Test que les composants sont tries par ordre alphabetique.""" composants = { "Puce": {"type": "composant", "fabrication_ihh_pays": 100, "fabrication_ihh_acteurs": 200}, "Anode": {"type": "composant", "fabrication_ihh_pays": 300, "fabrication_ihh_acteurs": 400}, "Cathode": {"type": "composant", "fabrication_ihh_pays": 500, "fabrication_ihh_acteurs": 600}, } resultat = _generer_tableau_composants(composants) idx_anode = resultat.index("Anode") idx_cathode = resultat.index("Cathode") idx_puce = resultat.index("Puce") assert idx_anode < idx_cathode < idx_puce # ────────────────────────────────────────────── # _generer_tableau_minerais # ────────────────────────────────────────────── class TestGenererTableauMinerais: """Tests pour la fonction _generer_tableau_minerais.""" def test_dict_vide(self): """Test qu'un dictionnaire vide retourne une chaine vide.""" assert _generer_tableau_minerais({}) == "" def test_un_minerai(self, mock_pastille): """Test la generation d'un tableau avec un seul minerai.""" minerais = { "Lithium": { "type": "minerai", "extraction_ihh_pays": 1500, "extraction_ihh_acteurs": 2000, "reserves_ihh_pays": 1800, "traitement_ihh_pays": 900, "traitement_ihh_acteurs": 1100, } } resultat = _generer_tableau_minerais(minerais) assert "## Op\u00e9rations sur les minerais" in resultat assert "| Lithium |" in resultat assert "| Minerai | Extraction IHH Pays | Extraction IHH Acteurs | R\u00e9serves IHH Pays | Traitement IHH Pays | Traitement IHH Acteurs |" in resultat assert "| :-- | :--: | :--: | :--: | :--: | :--: |" in resultat assert "[IHH:1500]" in resultat assert "[IHH:2000]" in resultat assert "[IHH:1800]" in resultat assert "[IHH:900]" in resultat assert "[IHH:1100]" in resultat def test_plusieurs_minerais_tries(self, mock_pastille): """Test que les minerais sont tries par ordre alphabetique.""" minerais = { "Zinc": {"type": "minerai", "extraction_ihh_pays": 1, "extraction_ihh_acteurs": 2, "reserves_ihh_pays": 3, "traitement_ihh_pays": 4, "traitement_ihh_acteurs": 5}, "Cobalt": {"type": "minerai", "extraction_ihh_pays": 6, "extraction_ihh_acteurs": 7, "reserves_ihh_pays": 8, "traitement_ihh_pays": 9, "traitement_ihh_acteurs": 10}, "Lithium": {"type": "minerai", "extraction_ihh_pays": 11, "extraction_ihh_acteurs": 12, "reserves_ihh_pays": 13, "traitement_ihh_pays": 14, "traitement_ihh_acteurs": 15}, } resultat = _generer_tableau_minerais(minerais) idx_cobalt = resultat.index("Cobalt") idx_lithium = resultat.index("Lithium") idx_zinc = resultat.index("Zinc") assert idx_cobalt < idx_lithium < idx_zinc def test_minerai_avec_tirets(self, mock_pastille): """Test avec des valeurs '-' (donnees manquantes).""" minerais = { "Fer": { "type": "minerai", "extraction_ihh_pays": "-", "extraction_ihh_acteurs": "-", "reserves_ihh_pays": "-", "traitement_ihh_pays": "-", "traitement_ihh_acteurs": "-", } } resultat = _generer_tableau_minerais(minerais) assert "| Fer |" in resultat # 5 pastilles avec valeur "-" assert resultat.count("[IHH:-]") == 5 # ────────────────────────────────────────────── # _synth_ihh # ────────────────────────────────────────────── class TestSynthIhh: """Tests pour la fonction _synth_ihh.""" def test_liste_vide(self, mock_pastille): """Test avec une liste d'operations vide.""" resultat = _synth_ihh([]) assert resultat == "" def test_une_operation_minerai(self, operation_minerai, mock_pastille): """Test avec une seule operation minerai.""" resultat = _synth_ihh([operation_minerai]) assert "## Op\u00e9rations sur les minerais" in resultat assert "Lithium" in resultat # Pas de tableau produits ni composants assert "## Assemblage des produits" not in resultat assert "## Fabrication des composants" not in resultat def test_une_operation_produit(self, operation_produit, mock_pastille): """Test avec une seule operation produit.""" resultat = _synth_ihh([operation_produit]) assert "## Assemblage des produits" in resultat assert "Batterie" in resultat assert "## Op\u00e9rations sur les minerais" not in resultat def test_une_operation_composant(self, operation_composant, mock_pastille): """Test avec une seule operation composant.""" resultat = _synth_ihh([operation_composant]) assert "## Fabrication des composants" in resultat assert "Cathode" in resultat def test_toutes_categories(self, operation_minerai, operation_produit, operation_composant, mock_pastille): """Test avec les trois categories d'operations.""" resultat = _synth_ihh([operation_minerai, operation_produit, operation_composant]) assert "## Assemblage des produits" in resultat assert "## Fabrication des composants" in resultat assert "## Op\u00e9rations sur les minerais" in resultat def test_operations_sans_identifiant(self, mock_pastille): """Test que les operations sans identifiant sont ignorees.""" operations = [{"autre_cle": "valeur"}] resultat = _synth_ihh(operations) assert resultat == "" # ────────────────────────────────────────────── # build_ihh_sections # ────────────────────────────────────────────── class TestBuildIhhSections: """Tests pour la fonction build_ihh_sections.""" def test_markdown_sans_bloc_yaml(self): """Test qu'un markdown sans bloc YAML est retourne tel quel.""" md = "# Titre\n\nContenu normal sans bloc YAML." resultat = build_ihh_sections(md) assert resultat == md def test_markdown_vide(self): """Test avec un markdown vide.""" resultat = build_ihh_sections("") assert resultat == "" def test_un_bloc_yaml_simple(self, mock_pastille): """Test avec un seul bloc YAML operation.""" md = ( "Introduction\n\n" "```yaml\n" "op\u00e9ration:\n" " minerai: Lithium\n" " extraction:\n" " ihh_pays: 1500\n" " ihh_acteurs: 2000\n" " reserves:\n" " ihh_pays: 1800\n" " traitement:\n" " ihh_pays: 900\n" " ihh_acteurs: 1100\n" "```\n" "Section apres le bloc." ) resultat = build_ihh_sections(md) assert "Introduction" in resultat assert "Section apres le bloc." in resultat # Le bloc YAML brut ne doit plus etre present assert "```yaml" not in resultat def test_jinja_template_dans_section(self, mock_pastille): """Test que les templates Jinja2 sont rendus avec les donnees de l'operation.""" md = ( "Intro\n\n" "```yaml\n" "op\u00e9ration:\n" " minerai: Lithium\n" " extraction:\n" " ihh_pays: 1500\n" " reserves:\n" " ihh_pays: 1800\n" " traitement:\n" " ihh_pays: 900\n" "```\n" "Le minerai est {{ minerai }}." ) resultat = build_ihh_sections(md) assert "Le minerai est Lithium." in resultat def test_plusieurs_blocs_yaml(self, mock_pastille): """Test avec plusieurs blocs YAML operations.""" md = ( "Introduction generale\n\n" "```yaml\n" "op\u00e9ration:\n" " minerai: Lithium\n" " extraction:\n" " ihh_pays: 1500\n" " reserves:\n" " ihh_pays: 1800\n" " traitement:\n" " ihh_pays: 900\n" "```\n" "Section Lithium : {{ minerai }}\n\n" "```yaml\n" "op\u00e9ration:\n" " produit: Batterie\n" " assemblage:\n" " ihh_pays: 3000\n" "```\n" "Section Batterie : {{ produit }}" ) resultat = build_ihh_sections(md) assert "Introduction generale" in resultat assert "Section Lithium : Lithium" in resultat assert "Section Batterie : Batterie" in resultat def test_avec_tableau_synthese(self, mock_pastille): """Test la generation du tableau de synthese quand le marqueur est present.""" md = ( "Introduction\n\n" "```yaml\n" "op\u00e9ration:\n" " minerai: Lithium\n" " extraction:\n" " ihh_pays: 1500\n" " reserves:\n" " ihh_pays: 1800\n" " traitement:\n" " ihh_pays: 900\n" "```\n" "Texte apres\n\n" "# Tableaux de synth\u00e8se\n" "\n" "ancien contenu\n" "" ) resultat = build_ihh_sections(md) assert "# Tableaux de synth\u00e8se" in resultat assert "" in resultat assert "" in resultat # L'ancien contenu doit etre remplace assert "ancien contenu" not in resultat # Le tableau minerais doit etre genere assert "Lithium" in resultat def test_sans_tableau_synthese(self, mock_pastille): """Test sans marqueur de tableau de synthese.""" md = ( "Introduction\n\n" "```yaml\n" "op\u00e9ration:\n" " produit: Batterie\n" " assemblage:\n" " ihh_pays: 3000\n" "```\n" "Fin du document." ) resultat = build_ihh_sections(md) assert "# Tableaux de synth\u00e8se" not in resultat assert "Introduction" in resultat assert "Fin du document." in resultat def test_intro_vide_avant_bloc(self, mock_pastille): """Test quand le bloc YAML est au tout debut du markdown.""" md = ( "```yaml\n" "op\u00e9ration:\n" " produit: Batterie\n" " assemblage:\n" " ihh_pays: 3000\n" "```\n" "Section apres." ) resultat = build_ihh_sections(md) assert "Section apres." in resultat def test_synthese_remplace_marqueurs_differents_niveaux_titre(self, mock_pastille): """Test que la regex de remplacement gere differents niveaux de titre (#, ##, ###).""" md = ( "Introduction\n\n" "```yaml\n" "op\u00e9ration:\n" " minerai: Cobalt\n" " extraction:\n" " ihh_pays: 800\n" " reserves:\n" " ihh_pays: 600\n" " traitement:\n" " ihh_pays: 500\n" "```\n" "Texte\n\n" "## Tableaux de synth\u00e8se\n" "\n" "contenu a remplacer\n" "" ) resultat = build_ihh_sections(md) # Le titre doit etre normalise en h1 assert "# Tableaux de synth\u00e8se" in resultat assert "contenu a remplacer" not in resultat def test_retour_type_str(self): """Test que la fonction retourne toujours une chaine.""" assert isinstance(build_ihh_sections(""), str) assert isinstance(build_ihh_sections("Texte simple"), str) def test_integration_complete(self, mock_pastille): """Test d'integration avec minerai, produit, composant et synthese.""" md = ( "# Analyse IHH\n\n" "```yaml\n" "op\u00e9ration:\n" " minerai: Lithium\n" " extraction:\n" " ihh_pays: 1500\n" " ihh_acteurs: 2000\n" " reserves:\n" " ihh_pays: 1800\n" " traitement:\n" " ihh_pays: 900\n" " ihh_acteurs: 1100\n" "```\n" "Extraction de {{ minerai }}\n\n" "```yaml\n" "op\u00e9ration:\n" " produit: Batterie\n" " assemblage:\n" " ihh_pays: 3000\n" " ihh_acteurs: 2500\n" "```\n" "Assemblage de {{ produit }}\n\n" "```yaml\n" "op\u00e9ration:\n" " composant: Cathode\n" " fabrication:\n" " ihh_pays: 1200\n" " ihh_acteurs: 800\n" "```\n" "Fabrication de {{ composant }}\n\n" "# Tableaux de synth\u00e8se\n" "\n" "placeholder\n" "" ) resultat = build_ihh_sections(md) # Introduction preservee assert "# Analyse IHH" in resultat # Templates Jinja rendus assert "Extraction de Lithium" in resultat assert "Assemblage de Batterie" in resultat assert "Fabrication de Cathode" in resultat # Tableau de synthese genere assert "## Assemblage des produits" in resultat assert "## Fabrication des composants" in resultat assert "## Op\u00e9rations sur les minerais" in resultat # Placeholder remplace assert "placeholder" not in resultat