""" 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=[], )