Files
aivanov_CIM/tests/test_rules_manager.py
2026-03-05 01:20:14 +01:00

457 lines
12 KiB
Python

"""
Tests pour le RulesManager.
Ce module teste le chargement, la validation et la gestion des règles de codage.
"""
import json
from pathlib import Path
import pytest
import yaml
from pipeline_mco_pmsi.rules.rules_manager import CodingRule, RuleSet, RulesManager
def test_rules_manager_initialization():
"""Test l'initialisation du RulesManager."""
manager = RulesManager()
assert manager is not None
assert manager.current_ruleset is None
assert manager.rules_hash is None
def test_load_rules_yaml(tmp_path):
"""Test le chargement de règles depuis un fichier YAML."""
# Créer un fichier YAML de test
rules_file = tmp_path / "test_rules.yaml"
rules_data = {
"version": "1.0.0",
"name": "Test Rules",
"description": "Test ruleset",
"mode": "conservateur",
"rules": [
{
"rule_id": "test_001",
"name": "Test Rule",
"description": "A test rule",
"category": "dp",
"condition": {"type": "required"},
"action": "reject_if_missing",
"severity": "bloquant",
"enabled": True,
}
],
}
with open(rules_file, "w") as f:
yaml.dump(rules_data, f)
# Charger les règles
manager = RulesManager()
ruleset = manager.load_rules(rules_file)
# Vérifications
assert ruleset is not None
assert ruleset.version == "1.0.0"
assert ruleset.name == "Test Rules"
assert ruleset.mode == "conservateur"
assert len(ruleset.rules) == 1
assert ruleset.rules[0].rule_id == "test_001"
assert manager.rules_hash is not None
assert len(manager.rules_hash) == 64 # SHA-256
def test_load_rules_json(tmp_path):
"""Test le chargement de règles depuis un fichier JSON."""
# Créer un fichier JSON de test
rules_file = tmp_path / "test_rules.json"
rules_data = {
"version": "1.0.0",
"name": "Test Rules JSON",
"description": "Test ruleset in JSON",
"mode": "agressif",
"rules": [
{
"rule_id": "test_002",
"name": "Test Rule 2",
"description": "Another test rule",
"category": "das",
"condition": {"min_evidence": 1},
"action": "reject_if_insufficient",
"severity": "à_revoir",
"enabled": True,
}
],
}
with open(rules_file, "w") as f:
json.dump(rules_data, f)
# Charger les règles
manager = RulesManager()
ruleset = manager.load_rules(rules_file)
# Vérifications
assert ruleset is not None
assert ruleset.version == "1.0.0"
assert ruleset.mode == "agressif"
assert len(ruleset.rules) == 1
assert ruleset.rules[0].rule_id == "test_002"
def test_load_rules_file_not_found():
"""Test le chargement avec un fichier inexistant."""
manager = RulesManager()
with pytest.raises(FileNotFoundError):
manager.load_rules(Path("nonexistent.yaml"))
def test_load_rules_invalid_format(tmp_path):
"""Test le chargement avec un format invalide."""
# Créer un fichier avec extension non supportée
rules_file = tmp_path / "test_rules.txt"
rules_file.write_text("invalid content")
manager = RulesManager()
with pytest.raises(ValueError, match="Format de fichier non supporté"):
manager.load_rules(rules_file)
def test_generate_hash():
"""Test la génération de hash SHA-256."""
manager = RulesManager()
content1 = "test content"
content2 = "test content"
content3 = "different content"
hash1 = manager._generate_hash(content1)
hash2 = manager._generate_hash(content2)
hash3 = manager._generate_hash(content3)
# Même contenu = même hash
assert hash1 == hash2
# Contenu différent = hash différent
assert hash1 != hash3
# Hash SHA-256 = 64 caractères hex
assert len(hash1) == 64
assert all(c in "0123456789abcdef" for c in hash1)
def test_get_rules_by_category(tmp_path):
"""Test la récupération de règles par catégorie."""
# Créer un fichier avec plusieurs règles
rules_file = tmp_path / "test_rules.yaml"
rules_data = {
"version": "1.0.0",
"name": "Test Rules",
"mode": "conservateur",
"rules": [
{
"rule_id": "dp_001",
"name": "DP Rule",
"description": "DP rule",
"category": "dp",
"condition": {},
"action": "test",
"enabled": True,
},
{
"rule_id": "das_001",
"name": "DAS Rule",
"description": "DAS rule",
"category": "das",
"condition": {},
"action": "test",
"enabled": True,
},
{
"rule_id": "dp_002",
"name": "DP Rule 2",
"description": "Another DP rule",
"category": "dp",
"condition": {},
"action": "test",
"enabled": False, # Désactivée
},
],
}
with open(rules_file, "w") as f:
yaml.dump(rules_data, f)
manager = RulesManager()
manager.load_rules(rules_file)
# Récupérer les règles DP (seulement les activées)
dp_rules = manager.get_rules_by_category("dp")
assert len(dp_rules) == 1
assert dp_rules[0].rule_id == "dp_001"
# Récupérer les règles DAS
das_rules = manager.get_rules_by_category("das")
assert len(das_rules) == 1
assert das_rules[0].rule_id == "das_001"
# Catégorie inexistante
ccam_rules = manager.get_rules_by_category("ccam")
assert len(ccam_rules) == 0
def test_get_rule_by_id(tmp_path):
"""Test la récupération d'une règle par ID."""
rules_file = tmp_path / "test_rules.yaml"
rules_data = {
"version": "1.0.0",
"name": "Test Rules",
"mode": "conservateur",
"rules": [
{
"rule_id": "test_001",
"name": "Test Rule",
"description": "Test",
"category": "dp",
"condition": {},
"action": "test",
}
],
}
with open(rules_file, "w") as f:
yaml.dump(rules_data, f)
manager = RulesManager()
manager.load_rules(rules_file)
# Règle existante
rule = manager.get_rule_by_id("test_001")
assert rule is not None
assert rule.rule_id == "test_001"
# Règle inexistante
rule = manager.get_rule_by_id("nonexistent")
assert rule is None
def test_is_conservative_mode(tmp_path):
"""Test la détection du mode conservateur."""
rules_file = tmp_path / "test_rules.yaml"
rules_data = {
"version": "1.0.0",
"name": "Test Rules",
"mode": "conservateur",
"rules": [],
}
with open(rules_file, "w") as f:
yaml.dump(rules_data, f)
manager = RulesManager()
# Par défaut (pas de ruleset chargé)
assert manager.is_conservative_mode() is True
# Après chargement
manager.load_rules(rules_file)
assert manager.is_conservative_mode() is True
assert manager.is_aggressive_mode() is False
def test_is_aggressive_mode(tmp_path):
"""Test la détection du mode agressif."""
rules_file = tmp_path / "test_rules.yaml"
rules_data = {
"version": "1.0.0",
"name": "Test Rules",
"mode": "agressif",
"rules": [],
}
with open(rules_file, "w") as f:
yaml.dump(rules_data, f)
manager = RulesManager()
manager.load_rules(rules_file)
assert manager.is_aggressive_mode() is True
assert manager.is_conservative_mode() is False
def test_get_version_info(tmp_path):
"""Test la récupération des informations de version."""
rules_file = tmp_path / "test_rules.yaml"
rules_data = {
"version": "2.0.0",
"name": "Test Rules",
"mode": "conservateur",
"rules": [
{
"rule_id": "test_001",
"name": "Test",
"description": "Test",
"category": "dp",
"condition": {},
"action": "test",
"enabled": True,
},
{
"rule_id": "test_002",
"name": "Test 2",
"description": "Test 2",
"category": "das",
"condition": {},
"action": "test",
"enabled": False,
},
],
}
with open(rules_file, "w") as f:
yaml.dump(rules_data, f)
manager = RulesManager()
# Sans ruleset chargé
info = manager.get_version_info()
assert info["version"] == "none"
assert info["rules_count"] == 0
# Avec ruleset chargé
manager.load_rules(rules_file)
info = manager.get_version_info()
assert info["version"] == "2.0.0"
assert info["mode"] == "conservateur"
assert info["rules_count"] == 2
assert info["enabled_rules_count"] == 1
assert "hash" in info
assert len(info["hash"]) == 64
def test_create_default_ruleset():
"""Test la création d'un jeu de règles par défaut."""
manager = RulesManager()
ruleset = manager.create_default_ruleset()
assert ruleset is not None
assert ruleset.version == "1.0.0"
assert ruleset.mode == "conservateur"
assert len(ruleset.rules) > 0
assert manager.rules_hash is not None
# Vérifier quelques règles par défaut
rule_ids = [rule.rule_id for rule in ruleset.rules]
assert "dp_001" in rule_ids
assert "dp_002" in rule_ids
assert "neg_001" in rule_ids
assert "ccam_001" in rule_ids
def test_save_rules_yaml(tmp_path):
"""Test la sauvegarde de règles en YAML."""
manager = RulesManager()
manager.create_default_ruleset()
output_file = tmp_path / "saved_rules.yaml"
manager.save_rules(output_file, format="yaml")
assert output_file.exists()
# Recharger et vérifier
manager2 = RulesManager()
ruleset2 = manager2.load_rules(output_file)
assert ruleset2.version == "1.0.0"
assert len(ruleset2.rules) == len(manager.current_ruleset.rules)
def test_save_rules_json(tmp_path):
"""Test la sauvegarde de règles en JSON."""
manager = RulesManager()
manager.create_default_ruleset()
output_file = tmp_path / "saved_rules.json"
manager.save_rules(output_file, format="json")
assert output_file.exists()
# Recharger et vérifier
manager2 = RulesManager()
ruleset2 = manager2.load_rules(output_file)
assert ruleset2.version == "1.0.0"
assert len(ruleset2.rules) == len(manager.current_ruleset.rules)
def test_save_rules_without_ruleset():
"""Test la sauvegarde sans ruleset chargé."""
manager = RulesManager()
with pytest.raises(ValueError, match="Aucun jeu de règles chargé"):
manager.save_rules(Path("output.yaml"))
def test_coding_rule_validation():
"""Test la validation des règles de codage."""
# Règle valide
rule = CodingRule(
rule_id="test_001",
name="Test",
description="Test rule",
category="dp",
condition={},
action="test",
severity="bloquant",
)
assert rule.severity == "bloquant"
# Sévérité invalide
with pytest.raises(ValueError, match="Sévérité invalide"):
CodingRule(
rule_id="test_002",
name="Test",
description="Test",
category="dp",
condition={},
action="test",
severity="invalid",
)
# Catégorie invalide
with pytest.raises(ValueError, match="Catégorie invalide"):
CodingRule(
rule_id="test_003",
name="Test",
description="Test",
category="invalid",
condition={},
action="test",
)
def test_ruleset_validation():
"""Test la validation des jeux de règles."""
# RuleSet valide
ruleset = RuleSet(
version="1.0.0",
name="Test",
mode="conservateur",
rules=[],
)
assert ruleset.mode == "conservateur"
# Mode invalide
with pytest.raises(ValueError, match="Mode invalide"):
RuleSet(
version="1.0.0",
name="Test",
mode="invalid",
rules=[],
)