- Frontend v4 accessible sur réseau local (192.168.1.40) - Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard) - Ollama GPU fonctionnel - Self-healing interactif - Dashboard confiance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
122 lines
4.3 KiB
Python
122 lines
4.3 KiB
Python
"""
|
|
Test de propriété pour l'absence d'imports circulaires.
|
|
|
|
Propriété 3: Absence d'imports circulaires
|
|
Pour tout module du système, l'importation ne doit pas créer de dépendances cycliques.
|
|
|
|
Auteur: Dom, Alice Kiro
|
|
Date: 20 décembre 2024
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
from hypothesis import given, strategies as st, settings
|
|
import pytest
|
|
|
|
# Ajouter le répertoire racine au path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
|
|
|
from validate_circular_imports import CircularImportDetector
|
|
|
|
|
|
class TestCircularImportsProperty:
|
|
"""Tests de propriété pour l'absence d'imports circulaires"""
|
|
|
|
@settings(max_examples=10, deadline=30000) # 10 exemples, 30s timeout
|
|
@given(st.just("core")) # On teste toujours le répertoire core
|
|
def test_property_no_circular_imports(self, directory_name):
|
|
"""
|
|
Propriété 3: Absence d'imports circulaires
|
|
|
|
Pour tout module du système, l'importation ne doit pas créer
|
|
de dépendances cycliques.
|
|
|
|
Cette propriété garantit que:
|
|
1. Aucun cycle n'existe dans le graphe d'imports
|
|
2. Les imports peuvent être résolus dans un ordre topologique
|
|
3. Le système peut démarrer sans erreurs d'import
|
|
"""
|
|
root_path = Path(__file__).parent.parent.parent
|
|
target_path = root_path / directory_name
|
|
|
|
# Vérifier que le répertoire existe
|
|
assert target_path.exists(), f"Répertoire {directory_name} non trouvé"
|
|
|
|
# Analyser les imports
|
|
detector = CircularImportDetector(root_path)
|
|
detector.analyze_directory(target_path)
|
|
|
|
# Détecter les cycles
|
|
cycles = detector.find_cycles()
|
|
|
|
# Propriété: Aucun cycle ne doit exister
|
|
assert len(cycles) == 0, (
|
|
f"Imports circulaires détectés dans {directory_name}:\n" +
|
|
"\n".join([
|
|
f"Cycle {i+1}: {' → '.join(cycle)}"
|
|
for i, cycle in enumerate(cycles)
|
|
]) +
|
|
"\n\nCeci viole la Propriété 3: Absence d'imports circulaires"
|
|
)
|
|
|
|
# Propriété additionnelle: Le graphe doit être analysable
|
|
assert len(detector.module_paths) > 0, "Aucun module analysé"
|
|
|
|
# Propriété additionnelle: Les dépendances doivent être cohérentes
|
|
total_deps = sum(len(deps) for deps in detector.module_graph.values())
|
|
assert total_deps >= 0, "Nombre de dépendances invalide"
|
|
|
|
def test_property_lazy_imports_work(self):
|
|
"""
|
|
Propriété: Les imports lazy doivent fonctionner correctement
|
|
|
|
Cette propriété garantit que:
|
|
1. Les fonctions de lazy loading retournent les bonnes classes
|
|
2. Les imports conditionnels ne créent pas de cycles
|
|
3. TYPE_CHECKING fonctionne comme attendu
|
|
"""
|
|
from core.models import (
|
|
get_workflow,
|
|
get_workflow_node,
|
|
get_action,
|
|
get_target_spec
|
|
)
|
|
|
|
# Propriété: Les fonctions lazy doivent retourner des classes valides
|
|
classes = [
|
|
get_workflow(),
|
|
get_workflow_node(),
|
|
get_action(),
|
|
get_target_spec()
|
|
]
|
|
|
|
for cls in classes:
|
|
assert hasattr(cls, '__name__'), "Classe sans nom"
|
|
assert callable(cls), "Objet non callable"
|
|
|
|
def test_property_interfaces_are_abstract(self):
|
|
"""
|
|
Propriété: Les interfaces doivent être abstraites
|
|
|
|
Cette propriété garantit que:
|
|
1. Les interfaces ne peuvent pas être instanciées directement
|
|
2. Elles définissent des méthodes abstraites
|
|
3. Elles permettent le découplage
|
|
"""
|
|
from core.interfaces import ITargetResolver, IActionExecutor, IErrorHandler
|
|
|
|
interfaces = [ITargetResolver, IActionExecutor, IErrorHandler]
|
|
|
|
for interface in interfaces:
|
|
# Propriété: Doit avoir des méthodes abstraites
|
|
assert hasattr(interface, '__abstractmethods__'), (
|
|
f"{interface.__name__} n'a pas de méthodes abstraites"
|
|
)
|
|
|
|
# Propriété: Ne peut pas être instanciée directement
|
|
with pytest.raises(TypeError):
|
|
interface()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v"]) |