- 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>
578 lines
22 KiB
Python
578 lines
22 KiB
Python
"""Tests unitaires pour le module app.fiches.utils.dynamic.indice.ics.
|
|
|
|
Ces tests verifient les fonctions de traitement Markdown pour l'indice ICS :
|
|
- _normalize_unicode
|
|
- _pairs_dataframe
|
|
- _fill
|
|
- _segments
|
|
- _pivot
|
|
- _synth
|
|
- build_dynamic_sections
|
|
"""
|
|
|
|
import textwrap
|
|
|
|
import pandas as pd
|
|
import pytest
|
|
|
|
from app.fiches.utils.dynamic.indice.ics import (
|
|
PAIR_RE,
|
|
_fill,
|
|
_normalize_unicode,
|
|
_pairs_dataframe,
|
|
_pivot,
|
|
_segments,
|
|
_synth,
|
|
build_dynamic_sections,
|
|
)
|
|
|
|
# ──────────────────────────────────────────────
|
|
# Helpers
|
|
# ──────────────────────────────────────────────
|
|
|
|
def _yaml_bloc(pair_dict: dict) -> str:
|
|
"""Construit un bloc YAML markdown a partir d'un dictionnaire pair."""
|
|
lignes = ["```yaml", "pair:"]
|
|
for k, v in pair_dict.items():
|
|
lignes.append(f" {k}: {v}")
|
|
lignes.append("```")
|
|
return "\n".join(lignes)
|
|
|
|
|
|
def _sample_pair(**overrides) -> dict:
|
|
"""Retourne un dictionnaire pair avec des valeurs par defaut."""
|
|
base = {
|
|
"composant": "Batterie",
|
|
"minerai": "Lithium",
|
|
"f_tech": 0.80,
|
|
"delai": 0.50,
|
|
"cout": 0.70,
|
|
"ics": 0.65,
|
|
}
|
|
base.update(overrides)
|
|
return base
|
|
|
|
|
|
# ──────────────────────────────────────────────
|
|
# _normalize_unicode
|
|
# ──────────────────────────────────────────────
|
|
class TestNormalizeUnicode:
|
|
"""Tests pour la normalisation Unicode NFKC."""
|
|
|
|
def test_texte_ascii_inchange(self):
|
|
"""Test qu'un texte ASCII pur n'est pas modifie."""
|
|
texte = "Hello world 123"
|
|
assert _normalize_unicode(texte) == texte
|
|
|
|
def test_ligatures_decomposees(self):
|
|
"""Test que les ligatures Unicode sont decomposees (NFKC)."""
|
|
# U+FB01 = fi ligature -> "fi" en NFKC
|
|
assert _normalize_unicode("\ufb01") == "fi"
|
|
|
|
def test_exposants_normalises(self):
|
|
"""Test que les caracteres exposants sont normalises."""
|
|
# U+00B2 = superscript 2 -> "2" en NFKC
|
|
assert _normalize_unicode("\u00b2") == "2"
|
|
|
|
def test_indices_normalises(self):
|
|
"""Test que les caracteres indices sont normalises."""
|
|
# U+2082 = subscript 2 -> "2" en NFKC
|
|
assert _normalize_unicode("\u2082") == "2"
|
|
|
|
def test_texte_vide(self):
|
|
"""Test avec un texte vide."""
|
|
assert _normalize_unicode("") == ""
|
|
|
|
def test_accents_francais_preserves(self):
|
|
"""Test que les accents francais courants sont preserves."""
|
|
texte = "Criticite par couple Composant"
|
|
resultat = _normalize_unicode(texte)
|
|
assert "Criticite" in resultat
|
|
|
|
|
|
# ──────────────────────────────────────────────
|
|
# PAIR_RE (regex)
|
|
# ──────────────────────────────────────────────
|
|
class TestPairRegex:
|
|
"""Tests pour l'expression reguliere PAIR_RE."""
|
|
|
|
def test_match_bloc_yaml_simple(self):
|
|
"""Test la detection d'un bloc yaml simple."""
|
|
md = "texte\n```yaml\npair:\n ics: 0.5\n```\ntexte"
|
|
matches = PAIR_RE.findall(md)
|
|
assert len(matches) == 1
|
|
|
|
def test_match_blocs_yaml_multiples(self):
|
|
"""Test la detection de plusieurs blocs yaml."""
|
|
md = "```yaml\na: 1\n```\ntexte\n```yaml\nb: 2\n```"
|
|
matches = PAIR_RE.findall(md)
|
|
assert len(matches) == 2
|
|
|
|
def test_pas_de_match_sans_yaml(self):
|
|
"""Test qu'un texte sans bloc yaml ne matche pas."""
|
|
md = "Du texte simple sans bloc."
|
|
matches = PAIR_RE.findall(md)
|
|
assert len(matches) == 0
|
|
|
|
def test_match_insensible_casse(self):
|
|
"""Test que YAML en majuscules est aussi detecte."""
|
|
md = "```YAML\ndata: 1\n```"
|
|
matches = PAIR_RE.findall(md)
|
|
assert len(matches) == 1
|
|
|
|
def test_yaml_avec_annotation(self):
|
|
"""Test un bloc yaml avec annotation apres le tag."""
|
|
md = "```yaml pair-data\npair:\n ics: 0.3\n```"
|
|
matches = PAIR_RE.findall(md)
|
|
assert len(matches) == 1
|
|
|
|
|
|
# ──────────────────────────────────────────────
|
|
# _pairs_dataframe
|
|
# ──────────────────────────────────────────────
|
|
class TestPairsDataframe:
|
|
"""Tests pour l'extraction des paires en DataFrame."""
|
|
|
|
def test_une_paire(self):
|
|
"""Test l'extraction d'une seule paire YAML."""
|
|
pair = _sample_pair()
|
|
md = _yaml_bloc(pair)
|
|
df = _pairs_dataframe(md)
|
|
|
|
assert isinstance(df, pd.DataFrame)
|
|
assert len(df) == 1
|
|
assert df.iloc[0]["composant"] == "Batterie"
|
|
assert df.iloc[0]["minerai"] == "Lithium"
|
|
assert df.iloc[0]["ics"] == pytest.approx(0.65)
|
|
|
|
def test_plusieurs_paires(self):
|
|
"""Test l'extraction de plusieurs paires YAML."""
|
|
pair1 = _sample_pair(composant="Batterie", minerai="Lithium", ics=0.65)
|
|
pair2 = _sample_pair(composant="Ecran", minerai="Indium", ics=0.80)
|
|
md = _yaml_bloc(pair1) + "\ntexte\n" + _yaml_bloc(pair2)
|
|
df = _pairs_dataframe(md)
|
|
|
|
assert len(df) == 2
|
|
assert set(df["composant"]) == {"Batterie", "Ecran"}
|
|
|
|
def test_pas_de_bloc_yaml(self):
|
|
"""Test avec un markdown sans bloc yaml."""
|
|
df = _pairs_dataframe("Texte sans bloc yaml.")
|
|
assert df.empty
|
|
|
|
def test_bloc_yaml_sans_cle_pair(self):
|
|
"""Test avec un bloc yaml qui n'a pas la cle 'pair'."""
|
|
md = "```yaml\nautres_donnees:\n x: 1\n```"
|
|
df = _pairs_dataframe(md)
|
|
assert df.empty
|
|
|
|
def test_bloc_yaml_liste_pas_dict(self):
|
|
"""Test avec un bloc yaml contenant une liste au lieu d'un dict."""
|
|
md = "```yaml\n- item1\n- item2\n```"
|
|
df = _pairs_dataframe(md)
|
|
assert df.empty
|
|
|
|
def test_texte_vide(self):
|
|
"""Test avec un texte vide."""
|
|
df = _pairs_dataframe("")
|
|
assert df.empty
|
|
|
|
def test_melange_blocs_valides_invalides(self):
|
|
"""Test avec un melange de blocs valides et invalides."""
|
|
pair_valide = _sample_pair(composant="GPU", minerai="Gallium", ics=0.40)
|
|
md = (
|
|
"```yaml\ninfos: test\n```\n"
|
|
+ _yaml_bloc(pair_valide) + "\n"
|
|
+ "```yaml\n- liste\n```"
|
|
)
|
|
df = _pairs_dataframe(md)
|
|
assert len(df) == 1
|
|
assert df.iloc[0]["composant"] == "GPU"
|
|
|
|
|
|
# ──────────────────────────────────────────────
|
|
# _fill
|
|
# ──────────────────────────────────────────────
|
|
class TestFill:
|
|
"""Tests pour le remplissage de placeholders dans un segment."""
|
|
|
|
def test_remplacement_simple(self):
|
|
"""Test le remplacement d'un placeholder simple."""
|
|
segment = "Le composant {{ composant }} utilise {{ minerai }}."
|
|
pair = {"composant": "Batterie", "minerai": "Lithium", "ics": 0.65}
|
|
result = _fill(segment, pair)
|
|
|
|
assert "Batterie" in result
|
|
assert "Lithium" in result
|
|
assert "{{ composant }}" not in result
|
|
|
|
def test_remplacement_valeur_numerique(self):
|
|
"""Test le remplacement avec des valeurs numeriques formatees."""
|
|
segment = "ICS = {{ ics }} et f_tech = {{ f_tech }}."
|
|
pair = {"ics": 0.65, "f_tech": 0.80}
|
|
result = _fill(segment, pair)
|
|
|
|
assert "0.65" in result
|
|
assert "0.80" in result
|
|
|
|
def test_remplacement_ics_dans_formule(self):
|
|
"""Test le remplacement de la valeur ICS dans une expression ICS = X."""
|
|
segment = "Le resultat est ICS = 0.00 pour ce couple."
|
|
pair = {"ics": 0.75}
|
|
result = _fill(segment, pair)
|
|
|
|
assert "ICS = 0.75" in result
|
|
|
|
def test_remplacement_ics_valeur_existante(self):
|
|
"""Test que ICS = ancien est remplace par la nouvelle valeur."""
|
|
segment = "Calcul : ICS = 0.99 fin."
|
|
pair = {"ics": 0.42}
|
|
result = _fill(segment, pair)
|
|
|
|
assert "ICS = 0.42" in result
|
|
assert "ICS = 0.99" not in result
|
|
|
|
def test_placeholder_insensible_casse(self):
|
|
"""Test que les placeholders sont insensibles a la casse."""
|
|
segment = "{{ COMPOSANT }} et {{ Minerai }}."
|
|
pair = {"composant": "RAM", "minerai": "Silicium", "ics": 0.50}
|
|
result = _fill(segment, pair)
|
|
|
|
assert "RAM" in result
|
|
assert "Silicium" in result
|
|
|
|
def test_placeholder_espaces_variables(self):
|
|
"""Test les placeholders avec des espacements differents."""
|
|
segment = "{{composant}} et {{ minerai }}."
|
|
pair = {"composant": "PCB", "minerai": "Cuivre", "ics": 0.30}
|
|
result = _fill(segment, pair)
|
|
|
|
assert "PCB" in result
|
|
assert "Cuivre" in result
|
|
|
|
def test_valeur_entiere(self):
|
|
"""Test le formatage d'une valeur entiere en .2f."""
|
|
segment = "Valeur: {{ ics }}."
|
|
pair = {"ics": 1}
|
|
result = _fill(segment, pair)
|
|
|
|
assert "1.00" in result
|
|
|
|
def test_unicode_normalise(self):
|
|
"""Test que le segment est normalise Unicode avant remplacement."""
|
|
# U+00B2 (superscript 2) normalise en "2"
|
|
segment = "ICS\u00b2 {{ composant }}"
|
|
pair = {"composant": "X", "ics": 0.5}
|
|
result = _fill(segment, pair)
|
|
|
|
assert "X" in result
|
|
|
|
|
|
# ──────────────────────────────────────────────
|
|
# _segments
|
|
# ──────────────────────────────────────────────
|
|
class TestSegments:
|
|
"""Tests pour l'extraction des segments entre blocs YAML."""
|
|
|
|
def test_un_segment(self):
|
|
"""Test l'extraction d'un seul segment."""
|
|
pair = _sample_pair()
|
|
md = _yaml_bloc(pair) + "\nSegment apres le bloc."
|
|
segments = list(_segments(md))
|
|
|
|
assert len(segments) == 1
|
|
pair_result, seg = segments[0]
|
|
assert pair_result["composant"] == "Batterie"
|
|
assert "Segment apres le bloc." in seg
|
|
|
|
def test_deux_segments(self):
|
|
"""Test l'extraction de deux segments entre trois blocs."""
|
|
pair1 = _sample_pair(composant="A", minerai="X", ics=0.1,
|
|
f_tech=0.2, delai=0.3, cout=0.4)
|
|
pair2 = _sample_pair(composant="B", minerai="Y", ics=0.5,
|
|
f_tech=0.6, delai=0.7, cout=0.8)
|
|
md = _yaml_bloc(pair1) + "\nSegment 1\n" + _yaml_bloc(pair2) + "\nSegment 2"
|
|
segments = list(_segments(md))
|
|
|
|
assert len(segments) == 2
|
|
assert segments[0][0]["composant"] == "A"
|
|
assert "Segment 1" in segments[0][1]
|
|
assert segments[1][0]["composant"] == "B"
|
|
assert "Segment 2" in segments[1][1]
|
|
|
|
def test_segment_vide_entre_blocs(self):
|
|
"""Test que les segments entre blocs consecutifs sont captures."""
|
|
pair1 = _sample_pair(composant="C", minerai="Z", ics=0.2,
|
|
f_tech=0.3, delai=0.4, cout=0.5)
|
|
pair2 = _sample_pair(composant="D", minerai="W", ics=0.6,
|
|
f_tech=0.7, delai=0.8, cout=0.9)
|
|
md = _yaml_bloc(pair1) + "\n" + _yaml_bloc(pair2)
|
|
segments = list(_segments(md))
|
|
|
|
assert len(segments) == 2
|
|
|
|
def test_pas_de_bloc_yaml(self):
|
|
"""Test avec un markdown sans bloc yaml."""
|
|
md = "Texte sans bloc yaml."
|
|
segments = list(_segments(md))
|
|
assert len(segments) == 0
|
|
|
|
|
|
# ──────────────────────────────────────────────
|
|
# _pivot
|
|
# ──────────────────────────────────────────────
|
|
class TestPivot:
|
|
"""Tests pour la generation du tableau pivot par minerai."""
|
|
|
|
@pytest.fixture
|
|
def df_simple(self):
|
|
"""DataFrame simple avec deux paires."""
|
|
return pd.DataFrame([
|
|
{"composant": "Batterie", "minerai": "Lithium", "ics": 0.65,
|
|
"f_tech": 0.80, "delai": 0.50, "cout": 0.70},
|
|
{"composant": "Ecran", "minerai": "Lithium", "ics": 0.45,
|
|
"f_tech": 0.60, "delai": 0.30, "cout": 0.40},
|
|
])
|
|
|
|
@pytest.fixture
|
|
def df_multi_minerai(self):
|
|
"""DataFrame avec plusieurs minerais."""
|
|
return pd.DataFrame([
|
|
{"composant": "Batterie", "minerai": "Lithium", "ics": 0.65,
|
|
"f_tech": 0.80, "delai": 0.50, "cout": 0.70},
|
|
{"composant": "Ecran", "minerai": "Indium", "ics": 0.80,
|
|
"f_tech": 0.90, "delai": 0.60, "cout": 0.85},
|
|
])
|
|
|
|
def test_en_tetes_tableau(self, df_simple):
|
|
"""Test que les en-tetes du tableau sont presents."""
|
|
result = _pivot(df_simple)
|
|
assert "| Composant | ICS | Faisabilit\u00e9 technique | D\u00e9lai d'impl\u00e9mentation | Impact \u00e9conomique |" in result
|
|
|
|
def test_titre_minerai(self, df_simple):
|
|
"""Test que le titre du minerai est un h2."""
|
|
result = _pivot(df_simple)
|
|
assert "## Lithium" in result
|
|
|
|
def test_tri_ics_descendant(self, df_simple):
|
|
"""Test que les lignes sont triees par ICS descendant."""
|
|
result = _pivot(df_simple)
|
|
lignes = result.strip().split("\n")
|
|
# Trouver les lignes de donnees (apres les en-tetes)
|
|
data_lignes = [line for line in lignes if line.startswith(("| Batterie", "| Ecran"))]
|
|
assert len(data_lignes) == 2
|
|
# Batterie (0.65) doit apparaitre avant Ecran (0.45)
|
|
idx_batterie = result.find("Batterie")
|
|
idx_ecran = result.find("Ecran")
|
|
assert idx_batterie < idx_ecran
|
|
|
|
def test_formatage_valeurs(self, df_simple):
|
|
"""Test le formatage des valeurs en .2f."""
|
|
result = _pivot(df_simple)
|
|
assert "0.65" in result
|
|
assert "0.80" in result
|
|
|
|
def test_plusieurs_minerais(self, df_multi_minerai):
|
|
"""Test avec plusieurs minerais genere plusieurs sections."""
|
|
result = _pivot(df_multi_minerai)
|
|
assert "## Lithium" in result or "## Indium" in result
|
|
# Les deux minerais doivent etre presents
|
|
assert "Lithium" in result
|
|
assert "Indium" in result
|
|
|
|
def test_dataframe_vide(self):
|
|
"""Test avec un DataFrame vide."""
|
|
df = pd.DataFrame(columns=["composant", "minerai", "ics", "f_tech", "delai", "cout"])
|
|
result = _pivot(df)
|
|
assert result == ""
|
|
|
|
|
|
# ──────────────────────────────────────────────
|
|
# _synth
|
|
# ──────────────────────────────────────────────
|
|
class TestSynth:
|
|
"""Tests pour la generation du tableau de synthese ICS."""
|
|
|
|
@pytest.fixture
|
|
def df_synth(self):
|
|
"""DataFrame pour la synthese."""
|
|
return pd.DataFrame([
|
|
{"composant": "Batterie", "minerai": "Lithium", "ics": 0.65},
|
|
{"composant": "Ecran", "minerai": "Indium", "ics": 0.80},
|
|
{"composant": "PCB", "minerai": "Cuivre", "ics": 0.30},
|
|
])
|
|
|
|
def test_en_tetes_synthese(self, df_synth):
|
|
"""Test que les en-tetes du tableau de synthese sont presents."""
|
|
result = _synth(df_synth)
|
|
assert "| Composant | Minerai | ICS |" in result
|
|
assert "| :-- | :-- | :--: |" in result
|
|
|
|
def test_tri_ics_descendant(self, df_synth):
|
|
"""Test que la synthese est triee par ICS descendant."""
|
|
result = _synth(df_synth)
|
|
idx_ecran = result.find("Ecran") # ics=0.80
|
|
idx_batterie = result.find("Batterie") # ics=0.65
|
|
idx_pcb = result.find("PCB") # ics=0.30
|
|
|
|
assert idx_ecran < idx_batterie < idx_pcb
|
|
|
|
def test_formatage_ics(self, df_synth):
|
|
"""Test le formatage des valeurs ICS en .2f."""
|
|
result = _synth(df_synth)
|
|
assert "0.80" in result
|
|
assert "0.65" in result
|
|
assert "0.30" in result
|
|
|
|
def test_toutes_lignes_presentes(self, df_synth):
|
|
"""Test que toutes les lignes de donnees sont presentes."""
|
|
result = _synth(df_synth)
|
|
lignes = result.strip().split("\n")
|
|
# 2 en-tetes + 3 donnees = 5
|
|
assert len(lignes) == 5
|
|
|
|
def test_une_seule_paire(self):
|
|
"""Test la synthese avec une seule paire."""
|
|
df = pd.DataFrame([{"composant": "GPU", "minerai": "Gallium", "ics": 0.50}])
|
|
result = _synth(df)
|
|
assert "GPU" in result
|
|
assert "Gallium" in result
|
|
assert "0.50" in result
|
|
|
|
|
|
# ──────────────────────────────────────────────
|
|
# build_dynamic_sections
|
|
# ──────────────────────────────────────────────
|
|
class TestBuildDynamicSections:
|
|
"""Tests pour la fonction principale de construction des sections dynamiques ICS."""
|
|
|
|
def _make_full_md(self, pairs: list[dict], with_markers: bool = True) -> str:
|
|
"""Construit un markdown complet avec entete, blocs YAML et marqueurs."""
|
|
parts = ["# Pr\u00e9sentation\n\nIntro du document.\n"]
|
|
parts.append("# Criticit\u00e9 par couple Composant -> Minerai\n")
|
|
for pair in pairs:
|
|
parts.append(_yaml_bloc(pair))
|
|
parts.append("\nAnalyse de {{ composant }} avec {{ minerai }}.")
|
|
parts.append("ICS = 0.00\n")
|
|
if with_markers:
|
|
parts.append("\n<!---- AUTO-BEGIN:PIVOT -->\nancien pivot\n<!---- AUTO-END:PIVOT -->\n")
|
|
parts.append("\n<!---- AUTO-BEGIN:TABLEAU-FINAL -->\nancien tableau\n<!---- AUTO-END:TABLEAU-FINAL -->\n")
|
|
return "\n".join(parts)
|
|
|
|
def test_remplacement_complet(self):
|
|
"""Test que build_dynamic_sections remplace les sections dynamiques."""
|
|
pair = _sample_pair()
|
|
md = self._make_full_md([pair])
|
|
result = build_dynamic_sections(md)
|
|
|
|
# Le pivot et la synthese doivent etre generes
|
|
assert "## Lithium" in result # pivot
|
|
assert "| Composant | Minerai | ICS |" in result # synthese
|
|
|
|
def test_placeholders_remplaces(self):
|
|
"""Test que les placeholders sont remplaces dans les segments."""
|
|
pair = _sample_pair()
|
|
md = self._make_full_md([pair])
|
|
result = build_dynamic_sections(md)
|
|
|
|
assert "Batterie" in result
|
|
assert "Lithium" in result
|
|
assert "{{ composant }}" not in result
|
|
|
|
def test_ics_remplace_dans_segment(self):
|
|
"""Test que la valeur ICS est mise a jour dans le segment."""
|
|
pair = _sample_pair(ics=0.72)
|
|
md = self._make_full_md([pair])
|
|
result = build_dynamic_sections(md)
|
|
|
|
assert "ICS = 0.72" in result
|
|
assert "ICS = 0.00" not in result
|
|
|
|
def test_marqueurs_pivot_preserves(self):
|
|
"""Test que les marqueurs AUTO-BEGIN/END:PIVOT sont preserves."""
|
|
pair = _sample_pair()
|
|
md = self._make_full_md([pair])
|
|
result = build_dynamic_sections(md)
|
|
|
|
assert "<!---- AUTO-BEGIN:PIVOT -->" in result
|
|
assert "<!---- AUTO-END:PIVOT -->" in result
|
|
|
|
def test_marqueurs_tableau_final_preserves(self):
|
|
"""Test que les marqueurs AUTO-BEGIN/END:TABLEAU-FINAL sont preserves."""
|
|
pair = _sample_pair()
|
|
md = self._make_full_md([pair])
|
|
result = build_dynamic_sections(md)
|
|
|
|
assert "<!---- AUTO-BEGIN:TABLEAU-FINAL -->" in result
|
|
assert "<!---- AUTO-END:TABLEAU-FINAL -->" in result
|
|
|
|
def test_pas_de_bloc_yaml_retourne_original(self):
|
|
"""Test qu'un markdown sans bloc yaml est retourne tel quel."""
|
|
md = "# Titre\n\nTexte sans bloc yaml."
|
|
result = build_dynamic_sections(md)
|
|
assert "Texte sans bloc yaml." in result
|
|
|
|
def test_texte_vide(self):
|
|
"""Test avec un texte vide."""
|
|
result = build_dynamic_sections("")
|
|
assert result == ""
|
|
|
|
def test_plusieurs_paires(self):
|
|
"""Test avec plusieurs paires genere un tableau complet."""
|
|
pair1 = _sample_pair(composant="Batterie", minerai="Lithium", ics=0.65,
|
|
f_tech=0.80, delai=0.50, cout=0.70)
|
|
pair2 = _sample_pair(composant="Ecran", minerai="Indium", ics=0.80,
|
|
f_tech=0.90, delai=0.60, cout=0.85)
|
|
md = self._make_full_md([pair1, pair2])
|
|
result = build_dynamic_sections(md)
|
|
|
|
assert "Batterie" in result
|
|
assert "Ecran" in result
|
|
assert "Lithium" in result
|
|
assert "Indium" in result
|
|
|
|
def test_unicode_normalise(self):
|
|
"""Test que les caracteres Unicode sont normalises dans le resultat."""
|
|
pair = _sample_pair()
|
|
md = self._make_full_md([pair])
|
|
# Injecter un caractere Unicode non-normalise
|
|
md = md.replace("Batterie", "Batterie\u00b2")
|
|
result = build_dynamic_sections(md)
|
|
|
|
# Le resultat doit etre normalise (superscript 2 -> "2")
|
|
assert isinstance(result, str)
|
|
|
|
def test_ancien_contenu_pivot_remplace(self):
|
|
"""Test que l'ancien contenu entre les marqueurs PIVOT est remplace."""
|
|
pair = _sample_pair()
|
|
md = self._make_full_md([pair])
|
|
result = build_dynamic_sections(md)
|
|
|
|
assert "ancien pivot" not in result
|
|
|
|
def test_ancien_contenu_tableau_final_remplace(self):
|
|
"""Test que l'ancien contenu entre les marqueurs TABLEAU-FINAL est remplace."""
|
|
pair = _sample_pair()
|
|
md = self._make_full_md([pair])
|
|
result = build_dynamic_sections(md)
|
|
|
|
assert "ancien tableau" not in result
|
|
|
|
def test_bloc_yaml_sans_pair_ignore(self):
|
|
"""Test qu'un bloc yaml sans la cle 'pair' ne casse pas le traitement."""
|
|
md = textwrap.dedent("""\
|
|
# Presentation
|
|
|
|
# Criticite par couple Composant -> Minerai
|
|
|
|
```yaml
|
|
metadata:
|
|
version: 1
|
|
```
|
|
|
|
Texte d'analyse.
|
|
""")
|
|
result = build_dynamic_sections(md)
|
|
# Aucune paire trouvee, le texte original est retourne
|
|
assert "Texte d'analyse." in result
|