feat(gui): câbler les 7 toggles catégories au moteur (P1-2)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
121
tests/unit/test_gui_v6_category_toggles.py
Normal file
121
tests/unit/test_gui_v6_category_toggles.py
Normal file
@@ -0,0 +1,121 @@
|
||||
"""Tests du câblage des 7 toggles « Données à détecter » → moteur (Plan 1b / P1-2).
|
||||
|
||||
Sémantique UI : un toggle ON = « détecter cette catégorie » (= masquer).
|
||||
Un toggle OFF = la catégorie est laissée en clair → elle entre dans
|
||||
``disabled_kinds`` (set des CATÉGORIES désactivées passé au moteur).
|
||||
|
||||
Aucun widget, aucun display : on teste l'état (ConfigState) et le pont
|
||||
(build_engine_kwargs / make_process_fn) en pur Python.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from gui_v6.config_state import (
|
||||
CATEGORY_FIELDS,
|
||||
DETECTION_CATEGORIES,
|
||||
ConfigState,
|
||||
)
|
||||
from gui_v6.engine_bridge import (
|
||||
EngineSettings,
|
||||
NerManagers,
|
||||
build_engine_kwargs,
|
||||
make_process_fn,
|
||||
)
|
||||
|
||||
|
||||
# -- catégories canoniques -------------------------------------------------
|
||||
|
||||
def test_seven_categories_match_engine_set():
|
||||
# Les 7 catégories exposées doivent matcher EXACTEMENT le set moteur.
|
||||
assert set(DETECTION_CATEGORIES) == {
|
||||
"NOM",
|
||||
"DATE_NAISSANCE",
|
||||
"ETAB",
|
||||
"ADRESSE",
|
||||
"NIR",
|
||||
"TEL",
|
||||
"ADHERENT",
|
||||
}
|
||||
# Un champ booléen par catégorie.
|
||||
assert set(CATEGORY_FIELDS.values()) == set(DETECTION_CATEGORIES)
|
||||
|
||||
|
||||
# -- disabled_kinds dérivé -------------------------------------------------
|
||||
|
||||
def test_disabled_kinds_empty_by_default():
|
||||
# Défaut : tous les toggles ON ⇒ aucun désactivé (zéro changement vs aujourd'hui).
|
||||
state = ConfigState()
|
||||
assert state.disabled_kinds() == frozenset()
|
||||
|
||||
|
||||
def test_disabled_kinds_unchecking_nir_and_etab():
|
||||
# Décocher « N° sécurité sociale » (NIR) et « Établissements » (ETAB).
|
||||
state = ConfigState(detect_nir=False, detect_etab=False)
|
||||
assert state.disabled_kinds() == frozenset({"NIR", "ETAB"})
|
||||
|
||||
|
||||
def test_disabled_kinds_all_off():
|
||||
state = ConfigState(
|
||||
detect_nom=False,
|
||||
detect_date_naissance=False,
|
||||
detect_etab=False,
|
||||
detect_adresse=False,
|
||||
detect_nir=False,
|
||||
detect_tel=False,
|
||||
detect_adherent=False,
|
||||
)
|
||||
assert state.disabled_kinds() == frozenset(DETECTION_CATEGORIES)
|
||||
|
||||
|
||||
# -- propagation vers EngineSettings --------------------------------------
|
||||
|
||||
def test_to_engine_settings_propagates_disabled_kinds():
|
||||
state = ConfigState(detect_nir=False, detect_tel=False)
|
||||
settings = state.to_engine_settings()
|
||||
assert settings.disabled_kinds == frozenset({"NIR", "TEL"})
|
||||
|
||||
|
||||
def test_to_engine_settings_default_empty():
|
||||
settings = ConfigState().to_engine_settings()
|
||||
assert settings.disabled_kinds == frozenset()
|
||||
|
||||
|
||||
# -- propagation dans les kwargs moteur -----------------------------------
|
||||
|
||||
def test_build_engine_kwargs_includes_disabled_kinds():
|
||||
settings = EngineSettings(disabled_kinds=frozenset({"NIR", "ETAB"}))
|
||||
kwargs = build_engine_kwargs(settings, managers=None)
|
||||
assert kwargs["disabled_kinds"] == frozenset({"NIR", "ETAB"})
|
||||
|
||||
|
||||
def test_build_engine_kwargs_default_empty_disabled_kinds():
|
||||
# Défaut (set vide) = no-op : la clé est présente mais vide.
|
||||
kwargs = build_engine_kwargs(EngineSettings(), managers=None)
|
||||
assert kwargs["disabled_kinds"] == frozenset()
|
||||
|
||||
|
||||
def test_process_fn_threads_disabled_kinds_to_engine(tmp_path):
|
||||
settings = EngineSettings(
|
||||
use_local_ner=False, disabled_kinds=frozenset({"ADRESSE"})
|
||||
)
|
||||
managers = NerManagers(settings)
|
||||
captured = {}
|
||||
|
||||
def fake_engine(doc_path, out_dir, **kwargs):
|
||||
captured["kwargs"] = kwargs
|
||||
return {"status": "ok"}
|
||||
|
||||
fn = make_process_fn(settings, managers=managers, engine=fake_engine)
|
||||
fn(tmp_path / "doc.pdf", tmp_path / "out")
|
||||
assert captured["kwargs"]["disabled_kinds"] == frozenset({"ADRESSE"})
|
||||
|
||||
|
||||
# -- bout-en-bout : ConfigState → settings → kwargs -----------------------
|
||||
|
||||
def test_end_to_end_state_to_kwargs(tmp_path):
|
||||
state = ConfigState(detect_adherent=False)
|
||||
settings = state.to_engine_settings(config_path=Path("/tmp/c.yml"))
|
||||
kwargs = build_engine_kwargs(settings, managers=None)
|
||||
assert kwargs["disabled_kinds"] == frozenset({"ADHERENT"})
|
||||
@@ -55,10 +55,26 @@ def test_config_interaction_contract_prebuilds_panels_and_mask_editor():
|
||||
]
|
||||
|
||||
|
||||
def test_detection_options_fields_match_category_fields():
|
||||
"""Garde-fou anti-dérive : les champs déclarés dans _DETECTION_OPTIONS doivent
|
||||
rester alignés (mêmes champs ET même ordre) sur CATEGORY_FIELDS, sinon un
|
||||
toggle pointerait vers un attribut ConfigState inexistant (AttributeError au
|
||||
lancement de la GUI au lieu d'un échec de test)."""
|
||||
from gui_v6.config_state import CATEGORY_FIELDS, ConfigState
|
||||
|
||||
fields = [field for _l, _h, field in _DETECTION_OPTIONS]
|
||||
assert fields == list(CATEGORY_FIELDS) # mêmes champs ET même ordre (ordre UI = ordre catégories)
|
||||
for f in fields: # chacun est bien un booléen réel de ConfigState
|
||||
assert isinstance(getattr(ConfigState(), f), bool)
|
||||
|
||||
|
||||
def test_detection_rows_are_readable_in_light_theme():
|
||||
"""Retour Dom : les sous-labels de la colonne détection doivent rester lisibles."""
|
||||
assert ("Noms et prénoms", "Annuaire + IA") in _DETECTION_OPTIONS
|
||||
assert ("Noms et prénoms", "Bases de données + IA") not in _DETECTION_OPTIONS
|
||||
# Chaque ligne est désormais (libellé, aide, champ ConfigState) ; on ne
|
||||
# vérifie ici que le couple (libellé, aide) reste lisible.
|
||||
label_hint = [(label, hint) for label, hint, _field in _DETECTION_OPTIONS]
|
||||
assert ("Noms et prénoms", "Annuaire + IA") in label_hint
|
||||
assert ("Noms et prénoms", "Bases de données + IA") not in label_hint
|
||||
assert MINI_TOGGLE_HEIGHT >= 44
|
||||
assert MINI_TOGGLE_LABEL_FONT_SIZE >= 12
|
||||
assert MINI_TOGGLE_HINT_FONT_SIZE >= 11
|
||||
|
||||
Reference in New Issue
Block a user