457 lines
12 KiB
Python
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=[],
|
|
)
|