Code/tests/unit/test_ihh.py
Stéphan Peccini 8e2556c2b0
test(unit): +381 tests unitaires — couverture 16%→35%
- 9 nouveaux fichiers de tests (persistance, translations, fiches, indices, IHH)
- Enrichissement des tests existants (graph_utils, gitea, widgets, tickets)
- 67→448 tests, tous passent

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:52:21 +01:00

786 lines
31 KiB
Python

"""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"
"<!---- AUTO-BEGIN:TABLEAU-FINAL -->\n"
"ancien contenu\n"
"<!---- AUTO-END:TABLEAU-FINAL -->"
)
resultat = build_ihh_sections(md)
assert "# Tableaux de synth\u00e8se" in resultat
assert "<!---- AUTO-BEGIN:TABLEAU-FINAL -->" in resultat
assert "<!---- AUTO-END:TABLEAU-FINAL -->" 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"
"<!---- AUTO-BEGIN:TABLEAU-FINAL -->\n"
"contenu a remplacer\n"
"<!---- AUTO-END:TABLEAU-FINAL -->"
)
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"
"<!---- AUTO-BEGIN:TABLEAU-FINAL -->\n"
"placeholder\n"
"<!---- AUTO-END:TABLEAU-FINAL -->"
)
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