240 lines
8.0 KiB
Python
240 lines
8.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
test_skill_kanten_generator.py
|
|
|
|
Unit-Tests für skill-kanten-generator.py
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
# Füge das aktuelle Verzeichnis zum Python-Pfad hinzu
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
|
|
from skill_kanten_generator import (
|
|
Edge,
|
|
SkillInfo,
|
|
deduplicate_edges,
|
|
generate_metadata_edges,
|
|
build_skill_index,
|
|
generate_journey_graph,
|
|
)
|
|
|
|
|
|
class TestEdge(unittest.TestCase):
|
|
"""Tests für die Edge-Datenklasse."""
|
|
|
|
def test_key_ungereicht(self):
|
|
"""Die key()-Methode sollte ungerichtet sein."""
|
|
edge1 = Edge("a", "b", 0.5, "category", "test")
|
|
edge2 = Edge("b", "a", 0.5, "category", "test")
|
|
self.assertEqual(edge1.key(), edge2.key())
|
|
|
|
def test_to_dict(self):
|
|
"""to_dict() sollte das richtige Format liefern."""
|
|
edge = Edge("a", "b", 0.9, "declared", "manual")
|
|
result = edge.to_dict()
|
|
self.assertEqual(result["skill_a"], "a")
|
|
self.assertEqual(result["skill_b"], "b")
|
|
self.assertEqual(result["weight"], 0.9)
|
|
self.assertEqual(result["type"], "declared")
|
|
self.assertEqual(result["source"], "manual")
|
|
|
|
|
|
class TestDeduplicateEdges(unittest.TestCase):
|
|
"""Tests für die Deduplizierung."""
|
|
|
|
def test_keine_doppelt(self):
|
|
"""Keine Doppelte: gleiche Anzahl zurück."""
|
|
edges = [
|
|
Edge("a", "b", 0.5, "category", "test"),
|
|
Edge("c", "d", 0.7, "manual", "test"),
|
|
]
|
|
result = deduplicate_edges(edges)
|
|
self.assertEqual(len(result), 2)
|
|
|
|
def test_doppelt_hoehere_prioritaet(self):
|
|
"""Bei Doppelt mit gleichen Skills: höhere Priorität gewinnt."""
|
|
edges = [
|
|
Edge("a", "b", 0.5, "category", "test"), # category
|
|
Edge("a", "b", 0.9, "declared", "test"), # declared (höher)
|
|
]
|
|
result = deduplicate_edges(edges)
|
|
self.assertEqual(len(result), 1)
|
|
self.assertEqual(result[0].edge_type, "declared")
|
|
|
|
def test_doppelt_hoeheres_gewicht(self):
|
|
"""Bei gleicher Priorität: höheres Gewicht gewinnt."""
|
|
edges = [
|
|
Edge("a", "b", 0.5, "category", "test"),
|
|
Edge("a", "b", 0.7, "category", "test"),
|
|
]
|
|
result = deduplicate_edges(edges)
|
|
self.assertEqual(len(result), 1)
|
|
self.assertEqual(result[0].weight, 0.7)
|
|
|
|
|
|
class TestBuildSkillIndex(unittest.TestCase):
|
|
"""Tests für build_skill_index()."""
|
|
|
|
def test_leere_index(self):
|
|
"""Mit leerem usage.json: leerer Index."""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
skills_dir = Path(tmpdir) / "skills"
|
|
skills_dir.mkdir()
|
|
(skills_dir / ".usage.json").write_text("{}")
|
|
|
|
# Mock-Path
|
|
import skill_kanten_generator as sg
|
|
original = sg.SKILLS_DIR
|
|
sg.SKILLS_DIR = skills_dir
|
|
sg.USAGE_FILE = skills_dir / ".usage.json"
|
|
|
|
try:
|
|
index = build_skill_index()
|
|
self.assertEqual(len(index), 0)
|
|
finally:
|
|
sg.SKILLS_DIR = original
|
|
sg.USAGE_FILE = original / ".usage.json"
|
|
|
|
def test_index_erstellt(self):
|
|
"""Ein Skill aus .usage.json sollte im Index erscheinen."""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
skills_dir = Path(tmpdir) / "skills"
|
|
skills_dir.mkdir()
|
|
|
|
usage = {
|
|
"my-skill": {
|
|
"use_count": 10,
|
|
"state": "active",
|
|
}
|
|
}
|
|
(skills_dir / ".usage.json").write_text(json.dumps(usage))
|
|
|
|
import skill_kanten_generator as sg
|
|
original = sg.SKILLS_DIR
|
|
sg.SKILLS_DIR = skills_dir
|
|
sg.USAGE_FILE = skills_dir / ".usage.json"
|
|
|
|
try:
|
|
index = build_skill_index()
|
|
self.assertIn("my-skill", index)
|
|
self.assertEqual(index["my-skill"].use_count, 10)
|
|
finally:
|
|
sg.SKILLS_DIR = original
|
|
sg.USAGE_FILE = original / ".usage.json"
|
|
|
|
|
|
class TestGenerateMetadataEdges(unittest.TestCase):
|
|
"""Tests für generate_metadata_edges()."""
|
|
|
|
def test_gleiche_kategorie(self):
|
|
"""Skills mit gleicher Kategorie erhalten eine Kante."""
|
|
skills = {
|
|
"skill-a": SkillInfo(name="skill-a", category="test"),
|
|
"skill-b": SkillInfo(name="skill-b", category="test"),
|
|
}
|
|
edges = generate_metadata_edges(skills)
|
|
|
|
self.assertEqual(len(edges), 1)
|
|
self.assertEqual(edges[0].edge_type, "category")
|
|
self.assertEqual(edges[0].weight, 0.7)
|
|
|
|
def test_different_categories_no_edge(self):
|
|
"""Skills mit verschiedenen Kategorien: keine Kante."""
|
|
skills = {
|
|
"skill-a": SkillInfo(name="skill-a", category="cat-a"),
|
|
"skill-b": SkillInfo(name="skill-b", category="cat-b"),
|
|
}
|
|
edges = generate_metadata_edges(skills)
|
|
self.assertEqual(len(edges), 0)
|
|
|
|
def test_related_skills(self):
|
|
"""Skills mit related_skills-Verbindung erhalten eine Kante."""
|
|
skills = {
|
|
"skill-a": SkillInfo(
|
|
name="skill-a",
|
|
related_skills=["skill-b"],
|
|
),
|
|
"skill-b": SkillInfo(name="skill-b"),
|
|
}
|
|
edges = generate_metadata_edges(skills)
|
|
|
|
self.assertEqual(len(edges), 1)
|
|
self.assertEqual(edges[0].edge_type, "declared")
|
|
self.assertEqual(edges[0].skill_a, "skill-a")
|
|
self.assertEqual(edges[0].skill_b, "skill-b")
|
|
|
|
|
|
class TestFullWorkflow(unittest.TestCase):
|
|
"""Integrationstest für den kompletten Workflow."""
|
|
|
|
def test_journey_graph_generated(self):
|
|
"""Der komplette Workflow sollte einen Graphen erzeugen."""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
hermes_dir = Path(tmpdir) / "hermes" / "profiles" / "werkstatt"
|
|
skills_dir = hermes_dir / "skills"
|
|
skills_dir.mkdir(parents=True)
|
|
|
|
# .usage.json
|
|
usage = {
|
|
"orchestrator": {
|
|
"use_count": 10,
|
|
"state": "active",
|
|
},
|
|
"wartung": {
|
|
"use_count": 7,
|
|
"state": "active",
|
|
},
|
|
}
|
|
(skills_dir / ".usage.json").write_text(json.dumps(usage))
|
|
|
|
# SKILL.md mit gleicher Kategorie
|
|
(skills_dir / "orchestrator").mkdir()
|
|
(skills_dir / "orchestrator" / "SKILL.md").write_text(
|
|
"---\n"
|
|
"name: orchestrator\n"
|
|
"category: devops\n"
|
|
"---\n"
|
|
"# Orchestrator\n"
|
|
)
|
|
(skills_dir / "wartung").mkdir()
|
|
(skills_dir / "wartung" / "SKILL.md").write_text(
|
|
"---\n"
|
|
"name: wartung\n"
|
|
"category: devops\n"
|
|
"---\n"
|
|
"# Wartung\n"
|
|
)
|
|
|
|
import skill_kanten_generator as sg
|
|
original = sg.SKILLS_DIR
|
|
sg.SKILLS_DIR = skills_dir
|
|
sg.USAGE_FILE = skills_dir / ".usage.json"
|
|
|
|
try:
|
|
graph = generate_journey_graph()
|
|
|
|
# Prüfe Struktur
|
|
self.assertIn("nodes", graph)
|
|
self.assertIn("edges", graph)
|
|
self.assertIn("generated_at", graph)
|
|
|
|
# Prüfe Knotenanzahl
|
|
self.assertEqual(len(graph["nodes"]), 2)
|
|
|
|
# Prüfe Kante (beide in gleicher Kategorie)
|
|
edge_types = [e["type"] for e in graph["edges"]]
|
|
self.assertIn("category", edge_types)
|
|
|
|
finally:
|
|
sg.SKILLS_DIR = original
|
|
sg.USAGE_FILE = original / ".usage.json"
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|