| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036 |
- # -*- coding: utf-8 -*-
- """
- Tests für Plugin Extensions (Phase 6).
- Testet Versionierung, Abhängigkeiten, Registry, Hooks,
- Hot-Reload und Testing-Utilities.
- """
- import asyncio
- import json
- import tempfile
- from pathlib import Path
- import pytest
- # ============================================================================
- # Versioning Tests
- # ============================================================================
- class TestSemanticVersion:
- """Tests für SemanticVersion."""
- def test_parse_basic(self):
- """Testet grundlegendes Parsing."""
- from trixy_core.plugins.versioning import parse_version
- v = parse_version("1.2.3")
- assert v.major == 1
- assert v.minor == 2
- assert v.patch == 3
- assert v.prerelease is None
- assert v.build is None
- def test_parse_with_prerelease(self):
- """Testet Parsing mit Prerelease."""
- from trixy_core.plugins.versioning import parse_version
- v = parse_version("1.0.0-alpha.1")
- assert v.major == 1
- assert v.prerelease == "alpha.1"
- def test_parse_with_build(self):
- """Testet Parsing mit Build-Metadaten."""
- from trixy_core.plugins.versioning import parse_version
- v = parse_version("1.0.0+build.123")
- assert v.build == "build.123"
- def test_parse_full(self):
- """Testet vollständiges Parsing."""
- from trixy_core.plugins.versioning import parse_version
- v = parse_version("2.0.0-beta.1+build.456")
- assert v.major == 2
- assert v.minor == 0
- assert v.patch == 0
- assert v.prerelease == "beta.1"
- assert v.build == "build.456"
- def test_comparison(self):
- """Testet Versionsvergleiche."""
- from trixy_core.plugins.versioning import parse_version
- v1 = parse_version("1.0.0")
- v2 = parse_version("2.0.0")
- v3 = parse_version("1.1.0")
- v4 = parse_version("1.0.1")
- assert v1 < v2
- assert v1 < v3
- assert v1 < v4
- assert v3 < v2
- assert v4 < v3
- def test_prerelease_comparison(self):
- """Testet Prerelease-Vergleiche."""
- from trixy_core.plugins.versioning import parse_version
- v1 = parse_version("1.0.0-alpha")
- v2 = parse_version("1.0.0-beta")
- v3 = parse_version("1.0.0")
- # Prerelease < Release
- assert v1 < v3
- assert v2 < v3
- # Alpha < Beta
- assert v1 < v2
- def test_bump_versions(self):
- """Testet Version-Bumping."""
- from trixy_core.plugins.versioning import parse_version
- v = parse_version("1.2.3")
- major = v.bump_major()
- assert str(major) == "2.0.0"
- minor = v.bump_minor()
- assert str(minor) == "1.3.0"
- patch = v.bump_patch()
- assert str(patch) == "1.2.4"
- def test_string_representation(self):
- """Testet String-Darstellung."""
- from trixy_core.plugins.versioning import parse_version
- v = parse_version("1.2.3-alpha+build")
- assert str(v) == "1.2.3-alpha+build"
- class TestVersionRange:
- """Tests für VersionRange."""
- def test_caret_range(self):
- """Testet Caret-Ranges (^)."""
- from trixy_core.plugins.versioning import parse_range, parse_version
- range_ = parse_range("^1.2.3")
- assert range_.satisfies(parse_version("1.2.3"))
- assert range_.satisfies(parse_version("1.2.4"))
- assert range_.satisfies(parse_version("1.3.0"))
- assert range_.satisfies(parse_version("1.9.9"))
- assert not range_.satisfies(parse_version("2.0.0"))
- assert not range_.satisfies(parse_version("1.2.2"))
- def test_tilde_range(self):
- """Testet Tilde-Ranges (~)."""
- from trixy_core.plugins.versioning import parse_range, parse_version
- range_ = parse_range("~1.2.3")
- assert range_.satisfies(parse_version("1.2.3"))
- assert range_.satisfies(parse_version("1.2.4"))
- assert range_.satisfies(parse_version("1.2.99"))
- assert not range_.satisfies(parse_version("1.3.0"))
- assert not range_.satisfies(parse_version("2.0.0"))
- def test_exact_range(self):
- """Testet exakte Versionen."""
- from trixy_core.plugins.versioning import parse_range, parse_version
- range_ = parse_range("1.2.3")
- assert range_.satisfies(parse_version("1.2.3"))
- assert not range_.satisfies(parse_version("1.2.4"))
- def test_comparison_ranges(self):
- """Testet Vergleichs-Ranges."""
- from trixy_core.plugins.versioning import parse_range, parse_version
- # >= 1.0.0
- range1 = parse_range(">=1.0.0")
- assert range1.satisfies(parse_version("1.0.0"))
- assert range1.satisfies(parse_version("2.0.0"))
- assert not range1.satisfies(parse_version("0.9.0"))
- # < 2.0.0
- range2 = parse_range("<2.0.0")
- assert range2.satisfies(parse_version("1.9.9"))
- assert not range2.satisfies(parse_version("2.0.0"))
- def test_wildcard_range(self):
- """Testet Wildcard-Ranges."""
- from trixy_core.plugins.versioning import parse_range, parse_version
- range_ = parse_range("1.2.*")
- assert range_.satisfies(parse_version("1.2.0"))
- assert range_.satisfies(parse_version("1.2.99"))
- assert not range_.satisfies(parse_version("1.3.0"))
- class TestVersionChecker:
- """Tests für VersionChecker."""
- def test_check_compatibility_exact(self):
- """Testet exakte Kompatibilität."""
- from trixy_core.plugins.versioning import VersionChecker, CompatibilityLevel
- checker = VersionChecker()
- result = checker.check("1.0.0", "1.0.0")
- assert result.compatible
- assert result.level == CompatibilityLevel.EXACT
- def test_check_compatibility_patch(self):
- """Testet Patch-Kompatibilität."""
- from trixy_core.plugins.versioning import VersionChecker, CompatibilityLevel
- checker = VersionChecker()
- # Mit Range ^1.0.0 sind Patch-Updates kompatibel
- result = checker.check("^1.0.0", "1.0.1")
- assert result.compatible
- assert result.level == CompatibilityLevel.COMPATIBLE
- def test_check_dependency(self):
- """Testet Abhängigkeitsprüfung."""
- from trixy_core.plugins.versioning import VersionChecker
- checker = VersionChecker()
- # Version erfüllt Range
- result = checker.check("^1.0.0", "1.5.0")
- assert result.compatible
- # Version erfüllt Range nicht
- result = checker.check("^2.0.0", "1.5.0")
- assert not result.compatible
- def test_check_dependencies(self):
- """Testet mehrere Abhängigkeiten."""
- from trixy_core.plugins.versioning import VersionChecker
- checker = VersionChecker()
- required = {"core": "^1.0.0", "utils": "~2.0.0"}
- available = {"core": "1.5.0", "utils": "2.0.5"}
- results = checker.check_dependencies(required, available)
- assert results["core"].compatible
- assert results["utils"].compatible
- # ============================================================================
- # Dependencies Tests
- # ============================================================================
- class TestDependencyGraph:
- """Tests für DependencyGraph."""
- def test_add_node(self):
- """Testet Hinzufügen von Knoten."""
- from trixy_core.plugins.dependencies import DependencyGraph, DependencyNode
- graph = DependencyGraph()
- node = DependencyNode(name="plugin_a", version="1.0.0")
- graph.add_node(node)
- assert "plugin_a" in graph
- assert graph.node_count == 1
- def test_add_edge_via_dependencies(self):
- """Testet Hinzufügen von Kanten via Abhängigkeiten."""
- from trixy_core.plugins.dependencies import DependencyGraph, DependencyNode
- graph = DependencyGraph()
- graph.add_node(DependencyNode(name="plugin_b", version="1.0.0"))
- graph.add_node(DependencyNode(
- name="plugin_a",
- version="1.0.0",
- dependencies={"plugin_b": "^1.0.0"},
- ))
- deps = graph.get_dependencies("plugin_a")
- assert "plugin_b" in deps
- def test_topological_sort(self):
- """Testet topologische Sortierung."""
- from trixy_core.plugins.dependencies import DependencyGraph, DependencyNode
- graph = DependencyGraph()
- # Einfacher Test: Zwei Plugins ohne Abhängigkeiten
- graph.add_node(DependencyNode(name="plugin_a", version="1.0.0"))
- graph.add_node(DependencyNode(name="plugin_b", version="1.0.0"))
- order = graph.get_load_order()
- # Beide sollten in der Ladereihenfolge sein
- assert "plugin_a" in order
- assert "plugin_b" in order
- assert len(order) == 2
- def test_cycle_detection(self):
- """Testet Zykluserkennung."""
- from trixy_core.plugins.dependencies import DependencyGraph, DependencyNode, CycleError
- graph = DependencyGraph()
- graph.add_node(DependencyNode(
- name="plugin_a",
- version="1.0.0",
- dependencies={"plugin_b": "^1.0.0"},
- ))
- graph.add_node(DependencyNode(
- name="plugin_b",
- version="1.0.0",
- dependencies={"plugin_a": "^1.0.0"},
- ))
- with pytest.raises(CycleError):
- graph.get_load_order()
- def test_has_cycle(self):
- """Testet Zyklus-Check ohne Exception."""
- from trixy_core.plugins.dependencies import DependencyGraph, DependencyNode
- graph = DependencyGraph()
- graph.add_node(DependencyNode(name="plugin_a", version="1.0.0"))
- graph.add_node(DependencyNode(
- name="plugin_b",
- version="1.0.0",
- dependencies={"plugin_a": "^1.0.0"},
- ))
- assert not graph.has_cycle()
- # Graph mit Zyklus
- graph2 = DependencyGraph()
- graph2.add_node(DependencyNode(
- name="plugin_a",
- version="1.0.0",
- dependencies={"plugin_b": "^1.0.0"},
- ))
- graph2.add_node(DependencyNode(
- name="plugin_b",
- version="1.0.0",
- dependencies={"plugin_a": "^1.0.0"},
- ))
- assert graph2.has_cycle()
- def test_export_dot(self):
- """Testet DOT-Export."""
- from trixy_core.plugins.dependencies import DependencyGraph, DependencyNode
- graph = DependencyGraph()
- graph.add_node(DependencyNode(name="plugin_b", version="1.0.0"))
- graph.add_node(DependencyNode(
- name="plugin_a",
- version="1.0.0",
- dependencies={"plugin_b": "^1.0.0"},
- ))
- dot = graph.to_dot()
- assert "digraph" in dot
- assert "plugin_a" in dot
- assert "plugin_b" in dot
- class TestDependencyResolver:
- """Tests für DependencyResolver."""
- def test_resolve_simple(self):
- """Testet einfache Auflösung."""
- from trixy_core.plugins.dependencies import DependencyResolver
- resolver = DependencyResolver()
- # Unabhängige Plugins registrieren
- resolver.register_plugin("plugin_a", "1.0.0", {})
- resolver.register_plugin("plugin_b", "1.0.0", {})
- # Alle Plugins auflösen (ohne Abhängigkeiten)
- result = resolver.resolve()
- assert result.success
- assert len(result.load_order) == 2
- def test_resolve_missing_dependency(self):
- """Testet fehlende Abhängigkeit."""
- from trixy_core.plugins.dependencies import DependencyResolver
- resolver = DependencyResolver()
- resolver.register_plugin("plugin_a", "1.0.0", {"plugin_missing": "^1.0.0"})
- result = resolver.resolve(["plugin_a"])
- assert not result.success
- assert len(result.missing) > 0
- # ============================================================================
- # Registry Tests
- # ============================================================================
- class TestPluginManifest:
- """Tests für PluginManifest."""
- def test_create_manifest(self):
- """Testet Manifest-Erstellung."""
- from trixy_core.plugins.registry import PluginManifest, PluginCapability
- manifest = PluginManifest(
- name="test_plugin",
- version="1.0.0",
- description="Test-Plugin",
- author="Test",
- capabilities=[PluginCapability.AUDIO_INPUT],
- )
- assert manifest.name == "test_plugin"
- assert manifest.version == "1.0.0"
- assert PluginCapability.AUDIO_INPUT in manifest.capabilities
- def test_manifest_to_dict(self):
- """Testet Dictionary-Konvertierung."""
- from trixy_core.plugins.registry import PluginManifest
- manifest = PluginManifest(
- name="test_plugin",
- version="1.0.0",
- )
- data = manifest.to_dict()
- assert data["name"] == "test_plugin"
- assert data["version"] == "1.0.0"
- def test_manifest_from_dict(self):
- """Testet Erstellung aus Dictionary."""
- from trixy_core.plugins.registry import PluginManifest
- data = {
- "name": "my_plugin",
- "version": "2.0.0",
- "description": "Mein Plugin",
- "author": "Autor",
- }
- manifest = PluginManifest.from_dict(data)
- assert manifest.name == "my_plugin"
- assert manifest.version == "2.0.0"
- def test_load_save_manifest(self):
- """Testet Laden und Speichern."""
- from trixy_core.plugins.registry import (
- PluginManifest,
- load_manifest,
- save_manifest,
- )
- with tempfile.TemporaryDirectory() as tmpdir:
- manifest = PluginManifest(
- name="test_plugin",
- version="1.0.0",
- )
- path = Path(tmpdir) / "config.json"
- save_manifest(manifest, path)
- loaded = load_manifest(path)
- assert loaded.name == manifest.name
- assert loaded.version == manifest.version
- class TestPluginDiscovery:
- """Tests für PluginDiscovery."""
- def test_discover_plugins(self):
- """Testet Plugin-Entdeckung."""
- from trixy_core.plugins.registry import PluginDiscovery
- from trixy_core.plugins.testing import PluginTestFixture
- with PluginTestFixture() as fixture:
- fixture.create_plugin("plugin_a")
- fixture.create_plugin("plugin_b")
- discovery = PluginDiscovery()
- results = discovery.scan(fixture.base_dir)
- assert len(results) == 2
- names = [r.name for r in results]
- assert "plugin_a" in names
- assert "plugin_b" in names
- class TestPluginRegistry:
- """Tests für PluginRegistry."""
- def test_register_plugin(self):
- """Testet Plugin-Registrierung."""
- from trixy_core.plugins.registry import PluginRegistry, PluginManifest
- registry = PluginRegistry()
- manifest = PluginManifest(
- name="test_plugin",
- version="1.0.0",
- )
- registry.register(manifest)
- assert "test_plugin" in registry
- entry = registry.get("test_plugin")
- assert entry is not None
- assert entry.manifest.name == "test_plugin"
- def test_list_plugins(self):
- """Testet Plugin-Auflistung."""
- from trixy_core.plugins.registry import PluginRegistry, PluginManifest
- registry = PluginRegistry()
- for i in range(3):
- manifest = PluginManifest(
- name=f"plugin_{i}",
- version="1.0.0",
- )
- registry.register(manifest)
- plugins = registry.get_all()
- assert len(plugins) == 3
- # ============================================================================
- # Hooks Tests
- # ============================================================================
- class TestPluginHook:
- """Tests für PluginHook."""
- def test_register_handler(self):
- """Testet Handler-Registrierung."""
- from trixy_core.plugins.hooks import PluginHook
- hook = PluginHook[str]("test_hook")
- @hook.register("test_plugin")
- def handler(value: str) -> str:
- return value.upper()
- assert hook.handler_count == 1
- def test_apply_hook(self):
- """Testet Hook-Anwendung."""
- from trixy_core.plugins.hooks import PluginHook
- hook = PluginHook[str]("test_hook")
- @hook.register("test_plugin")
- def handler(value: str) -> str:
- return value.upper()
- result = hook.apply("hello")
- assert result.value == "HELLO"
- assert result.modified
- def test_apply_multiple_handlers(self):
- """Testet mehrere Handler."""
- from trixy_core.plugins.hooks import PluginHook, HookPriority
- hook = PluginHook[str]("test_hook")
- @hook.register("plugin_a", priority=HookPriority.FIRST)
- def first_handler(value: str) -> str:
- return value + "_a"
- @hook.register("plugin_b", priority=HookPriority.LAST)
- def last_handler(value: str) -> str:
- return value + "_b"
- result = hook.apply("test")
- # Erst A, dann B
- assert result.value == "test_a_b"
- def test_apply_async(self):
- """Testet asynchrone Anwendung."""
- from trixy_core.plugins.hooks import PluginHook
- hook = PluginHook[str]("test_hook")
- @hook.register_async("test_plugin")
- async def async_handler(value: str) -> str:
- await asyncio.sleep(0.01)
- return value.upper()
- async def run_test():
- result = await hook.apply_async("hello")
- assert result.value == "HELLO"
- asyncio.run(run_test())
- def test_once_handler(self):
- """Testet Once-Handler."""
- from trixy_core.plugins.hooks import PluginHook
- hook = PluginHook[int]("test_hook")
- @hook.register("test_plugin", once=True)
- def once_handler(value: int) -> int:
- return value + 1
- # Erster Aufruf
- result1 = hook.apply(0)
- assert result1.value == 1
- assert hook.handler_count == 0 # Handler entfernt
- # Zweiter Aufruf
- result2 = hook.apply(0)
- assert result2.value == 0 # Nicht mehr modifiziert
- def test_trigger(self):
- """Testet Hook als Action."""
- from trixy_core.plugins.hooks import PluginHook
- hook = PluginHook("test_hook")
- called = []
- @hook.register("test_plugin")
- def handler(data):
- called.append(data)
- hook.trigger("test_data")
- assert "test_data" in called
- class TestHookRegistry:
- """Tests für HookRegistry."""
- def test_create_hook(self):
- """Testet Hook-Erstellung."""
- from trixy_core.plugins.hooks import HookRegistry
- registry = HookRegistry()
- hook = registry.create("test_hook", "Test-Beschreibung")
- assert registry.has_hook("test_hook")
- assert hook.name == "test_hook"
- def test_get_or_create(self):
- """Testet get_or_create."""
- from trixy_core.plugins.hooks import HookRegistry
- registry = HookRegistry()
- hook1 = registry.get_or_create("test_hook")
- hook2 = registry.get_or_create("test_hook")
- assert hook1 is hook2
- def test_register_handler(self):
- """Testet Handler-Registrierung."""
- from trixy_core.plugins.hooks import HookRegistry
- registry = HookRegistry()
- registry.register_handler(
- "test_hook",
- "test_plugin",
- lambda x: x.upper(),
- )
- result = registry.apply("test_hook", "hello")
- assert result.value == "HELLO"
- def test_remove_plugin(self):
- """Testet Plugin-Entfernung."""
- from trixy_core.plugins.hooks import HookRegistry
- registry = HookRegistry()
- registry.register_handler("hook_a", "test_plugin", lambda x: x)
- registry.register_handler("hook_b", "test_plugin", lambda x: x)
- removed = registry.remove_plugin("test_plugin")
- assert removed == 2
- # ============================================================================
- # Hot-Reload Tests
- # ============================================================================
- class TestFileWatcher:
- """Tests für FileWatcher."""
- def test_add_directory(self):
- """Testet Verzeichnis-Hinzufügen."""
- from trixy_core.plugins.hotreload import FileWatcher
- with tempfile.TemporaryDirectory() as tmpdir:
- watcher = FileWatcher()
- result = watcher.add_directory(Path(tmpdir))
- assert result
- assert Path(tmpdir) in watcher.watched_directories
- def test_add_invalid_directory(self):
- """Testet ungültiges Verzeichnis."""
- from trixy_core.plugins.hotreload import FileWatcher
- watcher = FileWatcher()
- result = watcher.add_directory(Path("/nonexistent/path"))
- assert not result
- def test_watch_callback(self):
- """Testet Callback-Registrierung."""
- from trixy_core.plugins.hotreload import FileWatcher
- watcher = FileWatcher()
- events = []
- @watcher.on_change
- def handler(event):
- events.append(event)
- assert len(watcher._callbacks) == 1
- class TestWatchEvent:
- """Tests für WatchEvent."""
- def test_event_creation(self):
- """Testet Event-Erstellung."""
- from trixy_core.plugins.hotreload import WatchEvent, WatchEventType
- event = WatchEvent(
- event_type=WatchEventType.MODIFIED,
- path=Path("/test/file.py"),
- )
- assert event.event_type == WatchEventType.MODIFIED
- assert event.path == Path("/test/file.py")
- def test_event_to_dict(self):
- """Testet Event-Serialisierung."""
- from trixy_core.plugins.hotreload import WatchEvent, WatchEventType
- event = WatchEvent(
- event_type=WatchEventType.CREATED,
- path=Path("/test/file.py"),
- )
- data = event.to_dict()
- assert data["event_type"] == "CREATED"
- assert "/test/file.py" in data["path"]
- class TestReloadConfig:
- """Tests für ReloadConfig."""
- def test_default_config(self):
- """Testet Standard-Konfiguration."""
- from trixy_core.plugins.hotreload import ReloadConfig
- config = ReloadConfig()
- assert config.enabled
- assert config.poll_interval == 1.0
- assert ".py" in config.extensions
- def test_custom_config(self):
- """Testet benutzerdefinierte Konfiguration."""
- from trixy_core.plugins.hotreload import ReloadConfig
- config = ReloadConfig(
- enabled=False,
- poll_interval=0.5,
- extensions=[".py"],
- )
- assert not config.enabled
- assert config.poll_interval == 0.5
- # ============================================================================
- # Testing Utilities Tests
- # ============================================================================
- class TestPluginTestHarness:
- """Tests für PluginTestHarness."""
- def test_create_harness(self):
- """Testet Harness-Erstellung."""
- from trixy_core.plugins.testing import PluginTestHarness
- harness = PluginTestHarness()
- assert harness.context is not None
- assert not harness.is_running
- def test_context_events(self):
- """Testet Event-Aufzeichnung."""
- from trixy_core.plugins.testing import PluginTestHarness
- harness = PluginTestHarness()
- context = harness.context
- context.events.append({"name": "test_event", "data": {}})
- assert context.has_event("test_event")
- assert len(context.get_events_by_name("test_event")) == 1
- def test_context_logs(self):
- """Testet Log-Aufzeichnung."""
- from trixy_core.plugins.testing import PluginTestHarness
- harness = PluginTestHarness()
- context = harness.context
- context.logs.append({"level": "error", "message": "Test"})
- context.logs.append({"level": "info", "message": "Info"})
- errors = context.get_logs_by_level("error")
- assert len(errors) == 1
- def test_context_clear(self):
- """Testet Kontext-Bereinigung."""
- from trixy_core.plugins.testing import PluginTestHarness
- harness = PluginTestHarness()
- context = harness.context
- context.events.append({"name": "test"})
- context.logs.append({"level": "info"})
- context.state["key"] = "value"
- context.clear_all()
- assert len(context.events) == 0
- assert len(context.logs) == 0
- assert len(context.state) == 0
- class TestMocks:
- """Tests für Mock-Objekte."""
- def test_mock_event_manager(self):
- """Testet MockEventManager."""
- from trixy_core.plugins.testing import MockEventManager
- manager = MockEventManager()
- event = manager.emit("test_event", {"key": "value"})
- assert event.name == "test_event"
- assert manager.has_event("test_event")
- assert manager.event_count() == 1
- def test_mock_satellite_manager(self):
- """Testet MockSatelliteManager."""
- from trixy_core.plugins.testing import MockSatelliteManager
- manager = MockSatelliteManager()
- manager.add_satellite("room1", {"alias": "Wohnzimmer"})
- assert manager.get("room1") is not None
- assert not manager.is_connected("room1")
- manager.connect("room1")
- assert manager.is_connected("room1")
- def test_mock_application(self):
- """Testet MockApplication."""
- from trixy_core.plugins.testing import MockApplication
- app = MockApplication()
- app.set_config("test_key", "test_value")
- assert app.get_config("test_key") == "test_value"
- event = app.emit("test_event")
- assert event.name == "test_event"
- def test_mock_plugin(self):
- """Testet MockPlugin."""
- from trixy_core.plugins.testing import MockPlugin
- plugin = MockPlugin("test_plugin")
- assert plugin.name == "test_plugin"
- assert plugin.enabled
- plugin.set_state("key", "value")
- state = plugin.get_state()
- assert state["key"] == "value"
- class TestPluginTestFixture:
- """Tests für PluginTestFixture."""
- def test_create_plugin(self):
- """Testet Plugin-Erstellung."""
- from trixy_core.plugins.testing import PluginTestFixture
- with PluginTestFixture() as fixture:
- plugin_dir = fixture.create_plugin("test_plugin")
- assert plugin_dir.exists()
- assert (plugin_dir / "main.py").exists()
- assert (plugin_dir / "config.json").exists()
- def test_multiple_plugins(self):
- """Testet mehrere Plugins."""
- from trixy_core.plugins.testing import PluginTestFixture
- with PluginTestFixture() as fixture:
- fixture.create_plugin("plugin_a")
- fixture.create_plugin("plugin_b")
- assert fixture.plugin_exists("plugin_a")
- assert fixture.plugin_exists("plugin_b")
- def test_add_file(self):
- """Testet Datei-Hinzufügen."""
- from trixy_core.plugins.testing import PluginTestFixture
- with PluginTestFixture() as fixture:
- fixture.create_plugin("test_plugin")
- path = fixture.add_file("test_plugin", "extra.py", "# Extra")
- assert path is not None
- assert path.exists()
- assert path.read_text() == "# Extra"
- def test_update_manifest(self):
- """Testet Manifest-Update."""
- from trixy_core.plugins.testing import PluginTestFixture
- with PluginTestFixture() as fixture:
- fixture.create_plugin("test_plugin")
- fixture.update_manifest("test_plugin", {"version": "2.0.0"})
- manifest = fixture.read_manifest("test_plugin")
- assert manifest["version"] == "2.0.0"
- class TestFixtureFunctions:
- """Tests für Fixture-Hilfsfunktionen."""
- def test_create_test_manifest(self):
- """Testet Manifest-Erstellung."""
- from trixy_core.plugins.testing import create_test_manifest
- manifest = create_test_manifest("my_plugin", version="2.0.0")
- assert manifest["name"] == "my_plugin"
- assert manifest["version"] == "2.0.0"
- def test_create_test_plugin_dir(self):
- """Testet Plugin-Verzeichnis-Erstellung."""
- from trixy_core.plugins.testing import (
- create_test_plugin_dir,
- cleanup_test_dir,
- )
- plugin_dir = create_test_plugin_dir("test_plugin")
- try:
- assert plugin_dir.exists()
- assert (plugin_dir / "main.py").exists()
- assert (plugin_dir / "config.json").exists()
- finally:
- cleanup_test_dir(plugin_dir.parent)
- # ============================================================================
- # Integration Tests
- # ============================================================================
- class TestPluginIntegration:
- """Integrationstests für das Plugin-System."""
- def test_complete_workflow(self):
- """Testet den kompletten Workflow."""
- from trixy_core.plugins.testing import PluginTestFixture
- from trixy_core.plugins.registry import PluginDiscovery, PluginRegistry
- from trixy_core.plugins.dependencies import DependencyResolver
- from trixy_core.plugins.hooks import HookRegistry
- with PluginTestFixture() as fixture:
- # Plugins erstellen
- fixture.create_plugin("core_plugin")
- fixture.create_plugin(
- "feature_plugin",
- manifest_data={
- "dependencies": {"core_plugin": "^1.0.0"},
- },
- )
- # Discovery
- discovery = PluginDiscovery()
- results = discovery.scan(fixture.base_dir)
- assert len(results) == 2
- # Registry
- registry = PluginRegistry()
- for result in results:
- registry.register(result.manifest)
- # Dependency Resolution
- resolver = DependencyResolver()
- resolver.register_plugin("core_plugin", "1.0.0", {})
- resolver.register_plugin("feature_plugin", "1.0.0", {"core_plugin": "^1.0.0"})
- resolution = resolver.resolve(["feature_plugin"])
- assert resolution.success
- # Hooks
- hook_registry = HookRegistry()
- hook_registry.register_handler(
- "plugin_loaded",
- "core_plugin",
- lambda name: f"Plugin {name} geladen",
- )
- result = hook_registry.trigger("plugin_loaded", "feature_plugin")
- assert len(result) == 1
- def test_version_compatibility_check(self):
- """Testet Versionskompatibilitätsprüfung."""
- from trixy_core.plugins.versioning import (
- VersionChecker,
- CompatibilityLevel,
- )
- from trixy_core.plugins.dependencies import DependencyResolver
- checker = VersionChecker()
- resolver = DependencyResolver()
- # Plugin mit Abhängigkeit registrieren
- resolver.register_plugin("base", "1.5.0", {})
- resolver.register_plugin("dependent", "1.0.0", {"base": "^1.0.0"})
- # Auflösung sollte funktionieren
- result = resolver.resolve(["dependent"])
- assert result.success
- # Kompatibilität prüfen
- compat = checker.check("^1.0.0", "1.5.0")
- assert compat.compatible
- if __name__ == "__main__":
- pytest.main([__file__, "-v"])
|