v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution
- 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>
This commit is contained in:
122
tests/property/test_circular_imports_property.py
Normal file
122
tests/property/test_circular_imports_property.py
Normal file
@@ -0,0 +1,122 @@
|
||||
"""
|
||||
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"])
|
||||
Reference in New Issue
Block a user