# -*- 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"])