Files
rpa_vision_v3/tests/unit/test_fusion_engine.py
Dom a27b74cf22 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>
2026-01-29 11:23:51 +01:00

188 lines
6.1 KiB
Python

"""
Tests unitaires pour FusionEngine avec property-based testing.
Property 17: State Embedding Component Weights Sum
- Les poids de fusion doivent toujours sommer à 1.0
- Validates: Requirements 4.5
"""
import sys
from pathlib import Path
# Ajouter le répertoire parent au path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
import pytest
import numpy as np
from core.embedding.fusion_engine import FusionEngine, FusionConfig
class TestFusionEngine:
"""Tests pour FusionEngine."""
def setup_method(self):
"""Setup avant chaque test."""
self.engine = FusionEngine()
def test_default_weights_sum_to_one(self):
"""Property 17: Les poids par défaut doivent sommer à 1.0."""
weights = self.engine.config.weights
total = sum(weights.values())
assert abs(total - 1.0) < 1e-6, f"Weights sum to {total}, expected 1.0"
def test_custom_weights_sum_to_one(self):
"""Property 17: Les poids personnalisés doivent sommer à 1.0."""
custom_weights = {
'image': 0.4,
'text': 0.3,
'title': 0.2,
'ui': 0.1
}
config = FusionConfig(weights=custom_weights)
engine = FusionEngine(config=config)
total = sum(engine.config.weights.values())
assert abs(total - 1.0) < 1e-6, f"Custom weights sum to {total}, expected 1.0"
def test_fusion_with_all_components(self):
"""Test fusion avec tous les composants présents."""
dim = 512
embeddings = {
'image': np.random.randn(dim),
'text': np.random.randn(dim),
'title': np.random.randn(dim),
'ui': np.random.randn(dim)
}
fused = self.engine.fuse(embeddings)
# Vérifier dimensions
assert fused.shape == (dim,), f"Expected shape ({dim},), got {fused.shape}"
# Vérifier normalisation
norm = np.linalg.norm(fused)
assert abs(norm - 1.0) < 1e-5, f"Fused vector norm is {norm}, expected 1.0"
def test_fusion_with_missing_components(self):
"""Test fusion avec composants manquants."""
dim = 512
embeddings = {
'image': np.random.randn(dim),
'text': np.random.randn(dim)
# title et ui manquants
}
fused = self.engine.fuse(embeddings)
# Doit quand même fonctionner
assert fused.shape == (dim,)
norm = np.linalg.norm(fused)
assert abs(norm - 1.0) < 1e-5
def test_fusion_normalization(self):
"""Test que la fusion normalise toujours le résultat."""
dim = 512
# Créer des vecteurs non normalisés
embeddings = {
'image': np.random.randn(dim) * 10, # Grande magnitude
'text': np.random.randn(dim) * 0.1, # Petite magnitude
}
fused = self.engine.fuse(embeddings)
norm = np.linalg.norm(fused)
assert abs(norm - 1.0) < 1e-5, "Fusion should normalize result"
def test_fusion_weighted_combination(self):
"""Test que la fusion applique bien les poids."""
dim = 512
# Créer des vecteurs orthogonaux pour faciliter la vérification
image_vec = np.zeros(dim)
image_vec[0] = 1.0
text_vec = np.zeros(dim)
text_vec[1] = 1.0
embeddings = {
'image': image_vec,
'text': text_vec
}
fused = self.engine.fuse(embeddings)
# Le vecteur fusionné devrait avoir des composantes non nulles
# aux positions 0 et 1
assert fused[0] != 0, "Image component should contribute"
assert fused[1] != 0, "Text component should contribute"
# Vérifier normalisation
norm = np.linalg.norm(fused)
assert abs(norm - 1.0) < 1e-5
def test_fusion_empty_embeddings(self):
"""Test fusion avec dictionnaire vide."""
with pytest.raises((ValueError, KeyError)):
self.engine.fuse({})
def test_fusion_single_component(self):
"""Test fusion avec un seul composant."""
dim = 512
embeddings = {
'image': np.random.randn(dim)
}
fused = self.engine.fuse(embeddings)
# Doit fonctionner et normaliser
assert fused.shape == (dim,)
norm = np.linalg.norm(fused)
assert abs(norm - 1.0) < 1e-5
def test_weights_validation(self):
"""Test validation des poids."""
# Poids ne sommant pas à 1.0
with pytest.raises(ValueError):
config = FusionConfig(weights={'image': 0.5, 'text': 0.3}) # Sum = 0.8
FusionEngine(config=config)
if __name__ == '__main__':
# Exécuter les tests manuellement
test = TestFusionEngine()
print("="*70)
print("TESTS UNITAIRES - FusionEngine")
print("Property 17: State Embedding Component Weights Sum")
print("="*70)
tests = [
('test_default_weights_sum_to_one', test.test_default_weights_sum_to_one),
('test_custom_weights_sum_to_one', test.test_custom_weights_sum_to_one),
('test_fusion_with_all_components', test.test_fusion_with_all_components),
('test_fusion_with_missing_components', test.test_fusion_with_missing_components),
('test_fusion_normalization', test.test_fusion_normalization),
('test_fusion_weighted_combination', test.test_fusion_weighted_combination),
('test_fusion_empty_embeddings', test.test_fusion_empty_embeddings),
('test_fusion_single_component', test.test_fusion_single_component),
('test_weights_validation', test.test_weights_validation),
]
passed = 0
failed = 0
for test_name, test_func in tests:
try:
test.setup_method()
test_func()
print(f"{test_name}")
passed += 1
except Exception as e:
print(f"{test_name}: {e}")
failed += 1
print("\n" + "="*70)
print(f"RÉSULTATS: {passed} passés, {failed} échoués")
print("="*70)
sys.exit(0 if failed == 0 else 1)