Files
Aivanov_scan_ogc/tests/test_zones_config.py
Dom 3a87751444 test: couvrir les modules purs du pipeline (96 nouveaux tests)
Suite de tests unitaires pour tous les modules pipeline qui ne dépendent
pas du VLM — utiles pour garantir la non-régression après refactor et
servir de spec vivante de chaque fonction.

Fichiers :
- tests/test_json_utils.py   (20 tests) : parse_json_output + toutes les
  stratégies de récupération (fences, virgules manquantes, boucles vides,
  fermeture JSON, fallback _raw/_parse_error)
- tests/test_deskew.py       (11 tests) : détection Hough + correction,
  image synthétique + fixtures cache réel
- tests/test_checkboxes.py   (17 tests) : parse_ghs_injustifie,
  dark_ratio, inner_frac, et ground truth visuel sur 17 dossiers
  (mapping hash→OGC résolu au runtime pour éviter les constantes fragiles)
- tests/test_validation.py   (18 tests) : _check_cim10/ccam/ghm/ghs,
  cross-checks GHM↔GHS, annotate sur JSON vide et complet,
  preservation de l'input (copie défensive)
- tests/test_schema.py       (8 tests)  : clean_dossier retire les champs
  debug, préserve les champs métier, compacte la validation, ne modifie
  pas l'input
- tests/test_zones_config.py (8 tests)  : load/save round-trip, merge
  avec defaults, résilience JSON corrompu, get_zone

Total : 107 tests, 5.1 s d'exécution, tous passent. Aucune dépendance
GPU, s'exécutent en CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:29:23 +02:00

86 lines
2.7 KiB
Python

"""Tests unitaires pour pipeline.zones_config."""
from __future__ import annotations
import json
import pytest
from pipeline.zones_config import (
DEFAULTS,
get_zone,
load_config,
save_config,
)
class TestLoadConfig:
def test_fichier_absent_retourne_defaults(self, tmp_path):
cfg = load_config(tmp_path / "inexistant.json")
assert cfg == DEFAULTS
def test_charge_depuis_fichier(self, tmp_path):
path = tmp_path / "zones.json"
custom = {
"recueil": {
"codage_reco": {"x1": 0.5, "y1": 0.1, "x2": 0.9, "y2": 0.4,
"description": "test"},
},
}
path.write_text(json.dumps(custom))
cfg = load_config(path)
assert cfg["recueil"]["codage_reco"]["x1"] == 0.5
def test_merge_avec_defaults(self, tmp_path):
"""Les zones non définies dans le fichier tombent en défaut."""
path = tmp_path / "zones.json"
partial = {
"recueil": {"codage_reco": {"x1": 0.1, "y1": 0.2, "x2": 0.3, "y2": 0.4}},
}
path.write_text(json.dumps(partial))
cfg = load_config(path)
# User override appliqué
assert cfg["recueil"]["codage_reco"]["x1"] == 0.1
# Default gardé pour l'autre zone
assert cfg["recueil"]["accord_checkbox"] == DEFAULTS["recueil"]["accord_checkbox"]
def test_json_corrompu_retombe_sur_defaults(self, tmp_path):
path = tmp_path / "corrupt.json"
path.write_text("{ not valid json [")
cfg = load_config(path)
assert cfg == DEFAULTS
class TestSaveConfig:
def test_save_puis_load_round_trip(self, tmp_path):
path = tmp_path / "zones.json"
original = {
"recueil": {
"codage_reco": {"x1": 0.11, "y1": 0.22, "x2": 0.33, "y2": 0.44,
"description": "abc"},
},
}
save_config(original, path)
reloaded = load_config(path)
assert reloaded["recueil"]["codage_reco"]["x1"] == 0.11
assert reloaded["recueil"]["codage_reco"]["description"] == "abc"
class TestGetZone:
def test_zone_existante(self):
z = get_zone("recueil", "codage_reco")
assert isinstance(z, tuple)
assert len(z) == 4
assert all(isinstance(v, float) for v in z)
def test_zone_inconnue_retourne_none(self):
assert get_zone("recueil", "zone_qui_nexiste_pas") is None
assert get_zone("page_fantaisiste", "whatever") is None
def test_config_explicite(self):
cfg = {
"recueil": {
"my_zone": {"x1": 0.0, "y1": 0.0, "x2": 1.0, "y2": 1.0},
},
}
assert get_zone("recueil", "my_zone", config=cfg) == (0.0, 0.0, 1.0, 1.0)