Files
anonymisation/tests/unit/test_engine_capabilities.py

86 lines
3.4 KiB
Python

"""Couche 'capabilities moteurs' : vérité testable sur les moteurs disponibles.
Un moteur n'est *disponible* que si ses dépendances (et son modèle, pour
CamemBERT) chargent réellement dans l'environnement courant. Cette couche est
consommée par la GUI (afficher/désactiver) et le CLI (`--engines`) pour que
l'application ne promette jamais un moteur qu'elle n'embarque pas.
Sondes injectables → aucun modèle, aucun réseau dans les tests.
"""
from __future__ import annotations
import engine_capabilities as ec
def _probes(camembert=True, eds=False, gliner=False):
return {
"camembert": lambda: (camembert, "ok" if camembert else "modèle absent"),
"eds": lambda: (eds, "ok" if eds else "edsnlp non embarqué"),
"gliner": lambda: (gliner, "ok" if gliner else "gliner non embarqué"),
}
def test_capabilities_map_reads_injected_probes():
caps = ec.capabilities_map(probes=_probes(camembert=True, eds=False, gliner=False))
assert set(caps) == {"camembert", "eds", "gliner"}
assert caps["camembert"].available is True
assert caps["eds"].available is False
assert caps["gliner"].available is False
def test_camembert_required_others_optional():
caps = ec.capabilities_map(probes=_probes())
assert caps["camembert"].required is True
assert caps["eds"].required is False
assert caps["gliner"].required is False
def test_reason_surfaced_when_unavailable():
caps = ec.capabilities_map(probes=_probes(eds=False))
assert "edsnlp" in caps["eds"].reason # explication présentable à l'utilisateur
# un moteur disponible expose aussi une raison non vide
assert caps["camembert"].reason
def test_available_engines_filters_unavailable():
avail = ec.available_engines(probes=_probes(camembert=True, eds=True, gliner=False))
keys = {c.key for c in avail}
assert keys == {"camembert", "eds"}
def test_labels_are_human_readable():
caps = ec.capabilities_map(probes=_probes())
assert "CamemBERT" in caps["camembert"].label
assert "EDS" in caps["eds"].label
assert "GLiNER" in caps["gliner"].label
def test_default_probes_run_without_crash_and_are_consistent():
"""Les sondes par défaut (find_spec + fichier modèle) ne crashent pas et
renvoient un booléen + une raison non vide pour chaque moteur."""
caps = ec.capabilities_map() # sondes réelles de l'environnement
assert set(caps) == {"camembert", "eds", "gliner"}
for cap in caps.values():
assert isinstance(cap.available, bool)
assert isinstance(cap.reason, str) and cap.reason
def test_optional_engines_require_bundled_models(monkeypatch, tmp_path):
monkeypatch.setattr(ec, "_has_module", lambda name: name in {"onnxruntime", "edsnlp", "spacy", "gliner"})
monkeypatch.setattr(ec, "_app_dir", lambda: tmp_path)
(tmp_path / "models" / "camembert-bio-deid" / "onnx").mkdir(parents=True)
(tmp_path / "models" / "camembert-bio-deid" / "onnx" / "model.onnx").write_bytes(b"fake")
caps = ec.capabilities_map()
assert caps["eds"].available is False
assert "modèle" in caps["eds"].reason
assert caps["gliner"].available is False
assert "modèle" in caps["gliner"].reason
(tmp_path / "models" / "eds-pseudo-public").mkdir()
(tmp_path / "models" / "gliner_multi_pii-v1").mkdir()
caps = ec.capabilities_map()
assert caps["eds"].available is True
assert caps["gliner"].available is True