Spaces:
Sleeping
Sleeping
Claude
test: rΓ©organiser les 110 fichiers tests/test_*.py par cercle architectural
d109222 unverified | """Tests du chantier 5 (post-Sprint 97) β dΓ©coupage des monolithes. | |
| Couvre : | |
| - 5.A : :mod:`picarones.measurements.narrative.detectors` est dΓ©sormais un | |
| package thΓ©matique de 6 sous-modules (1229 lignes β 6 fichiers). | |
| Tous les imports historiques restent accessibles. | |
| - 5.B : :mod:`picarones.cli` est dΓ©sormais un package avec 6 | |
| sous-modules + ``__init__.py`` (1519 lignes β 7 fichiers). | |
| Le groupe ``cli`` reste exportΓ© pour l'entry-point ``pyproject.toml``. | |
| """ | |
| from __future__ import annotations | |
| import pytest | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 5.A β narrative/detectors dΓ©composΓ© en 6 familles | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class TestDetectorsPackage: | |
| def test_detectors_is_now_a_package(self): | |
| """``detectors.py`` est devenu ``detectors/`` (package).""" | |
| from picarones.measurements.narrative import detectors | |
| # Un package a __path__, un module simple ne l'a pas | |
| assert hasattr(detectors, "__path__"), ( | |
| "detectors devrait Γͺtre un package depuis le chantier 5" | |
| ) | |
| def test_all_18_detectors_importable_from_root(self, name): | |
| """RΓ©trocompat : les 18 dΓ©tecteurs s'importent depuis le package | |
| comme avant le chantier 5 (tests Sprints 20, 23, 29, 36, 44, 46, 73).""" | |
| from picarones.measurements.narrative import detectors | |
| assert hasattr(detectors, name), f"{name} disparu après chantier 5" | |
| assert callable(getattr(detectors, name)) | |
| def test_DETECTORS_BY_TYPE_still_exposed(self): | |
| from picarones.measurements.narrative.detectors import DETECTORS_BY_TYPE | |
| assert isinstance(DETECTORS_BY_TYPE, dict) | |
| assert len(DETECTORS_BY_TYPE) == 18, ( | |
| f"DETECTORS_BY_TYPE doit contenir 18 entrΓ©es, en a {len(DETECTORS_BY_TYPE)}" | |
| ) | |
| def test_register_default_detectors_still_callable(self): | |
| from picarones.measurements.narrative.detectors import register_default_detectors | |
| assert callable(register_default_detectors) | |
| def test_submodules_have_expected_detector_count(self, submodule, detector_count): | |
| """Chaque sous-module thΓ©matique a le bon nombre de dΓ©tecteurs.""" | |
| import importlib | |
| mod = importlib.import_module( | |
| f"picarones.measurements.narrative.detectors.{submodule}" | |
| ) | |
| detectors_in_sub = [ | |
| n for n in dir(mod) | |
| if n.startswith("detect_") and callable(getattr(mod, n)) | |
| ] | |
| assert len(detectors_in_sub) == detector_count, ( | |
| f"{submodule} : {len(detectors_in_sub)} dΓ©tecteurs trouvΓ©s, " | |
| f"{detector_count} attendus β {detectors_in_sub}" | |
| ) | |
| def test_identity_through_submodule_and_root(self): | |
| """Le dΓ©tecteur exposΓ© depuis __init__.py et depuis son sous-module | |
| est la mΓͺme fonction (pas de redΓ©finition).""" | |
| from picarones.measurements.narrative.detectors import detect_global_leader_cer | |
| from picarones.measurements.narrative.detectors.ranking import ( | |
| detect_global_leader_cer as via_submodule, | |
| ) | |
| assert detect_global_leader_cer is via_submodule | |
| def test_detector_smoke_via_root(self): | |
| """Smoke test : un dΓ©tecteur fonctionne via l'import root.""" | |
| from picarones.measurements.narrative.detectors import detect_global_leader_cer | |
| result = detect_global_leader_cer({ | |
| "ranking": [ | |
| {"engine": "tess", "mean_cer": 0.05}, | |
| {"engine": "pero", "mean_cer": 0.07}, | |
| ], | |
| }) | |
| assert len(result) == 1 | |
| assert result[0].payload["engine"] == "tess" | |
| def test_helpers_are_in_dedicated_module(self): | |
| """Les helpers internes (_engines_summary, etc.) vivent dans | |
| ``_helpers.py`` (pattern modulaire propre).""" | |
| from picarones.measurements.narrative.detectors import _helpers | |
| assert hasattr(_helpers, "_engines_summary") | |
| assert hasattr(_helpers, "_engine_by_name") | |
| assert hasattr(_helpers, "_n_docs") | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 5.B β cli.py dΓ©composΓ© en package | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class TestCliPackage: | |
| def test_cli_is_now_a_package(self): | |
| try: | |
| import picarones.cli as cli_pkg | |
| except ImportError as exc: | |
| if "click" in str(exc): | |
| pytest.skip("click non installΓ©") | |
| raise | |
| assert hasattr(cli_pkg, "__path__"), ( | |
| "picarones.cli devrait Γͺtre un package depuis le chantier 5" | |
| ) | |
| def test_cli_group_still_exported(self): | |
| """L'entry-point ``picarones.cli:cli`` (pyproject.toml) doit | |
| rester valide après le chantier 5.""" | |
| try: | |
| from picarones.cli import cli | |
| except ImportError as exc: | |
| if "click" in str(exc): | |
| pytest.skip("click non installΓ©") | |
| raise | |
| assert cli is not None | |
| def test_helpers_still_exported(self): | |
| """``_setup_logging`` et ``_engine_from_name`` restent accessibles | |
| depuis ``picarones.cli`` (les sous-modules les utilisent).""" | |
| try: | |
| import picarones.cli as cli_pkg | |
| except ImportError as exc: | |
| if "click" in str(exc): | |
| pytest.skip("click non installΓ©") | |
| raise | |
| assert callable(cli_pkg._setup_logging) | |
| assert callable(cli_pkg._engine_from_name) | |
| def test_submodule_loaded(self, submodule): | |
| try: | |
| import picarones.cli as cli_pkg | |
| except ImportError as exc: | |
| if "click" in str(exc): | |
| pytest.skip("click non installΓ©") | |
| raise | |
| assert hasattr(cli_pkg, submodule), ( | |
| f"{submodule} non chargΓ© en cascade β les commandes de cette " | |
| "famille ne seraient pas enregistrΓ©es" | |
| ) | |
| def test_all_15_commands_registered(self, cmd_name): | |
| """Les 15 commandes/groupes historiques doivent Γͺtre enregistrΓ©s | |
| sur le groupe ``cli`` après l'import en cascade.""" | |
| try: | |
| from picarones.cli import cli | |
| except ImportError as exc: | |
| if "click" in str(exc): | |
| pytest.skip("click non installΓ©") | |
| raise | |
| assert hasattr(cli, "commands"), ( | |
| "le groupe cli devrait avoir un attribut commands (Click Group)" | |
| ) | |
| assert cmd_name in cli.commands, ( | |
| f"commande '{cmd_name}' manquante aprΓ¨s le chantier 5 β " | |
| f"commandes prΓ©sentes : {sorted(cli.commands.keys())}" | |
| ) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 5.C β runner.py reste tel quel (dΓ©jΓ allΓ©gΓ© au chantier 2) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class TestRunnerStillReachable: | |
| """Le chantier 2 a dΓ©jΓ allΓ©gΓ© ``runner.py`` de 303 lignes (1322 β 1019). | |
| Le chantier 5 ne le dΓ©coupe pas davantage β vΓ©rification que les | |
| fonctions historiques restent accessibles.""" | |
| def test_function_still_in_runner(self, name): | |
| try: | |
| from picarones.measurements import runner | |
| except ImportError as exc: | |
| if "tqdm" in str(exc): | |
| pytest.skip("tqdm non installΓ©") | |
| raise | |
| assert hasattr(runner, name), ( | |
| f"runner.{name} a disparu" | |
| ) | |
| assert callable(getattr(runner, name)) | |