Initial commit
This commit is contained in:
456
tests/test_rules_manager.py
Normal file
456
tests/test_rules_manager.py
Normal file
@@ -0,0 +1,456 @@
|
||||
"""
|
||||
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=[],
|
||||
)
|
||||
Reference in New Issue
Block a user