# -*- coding: utf-8 -*- """ Unit-Tests für trixy_core.plugins. """ import json import pytest from pathlib import Path from unittest.mock import MagicMock, AsyncMock from trixy_core.plugins.trixy_plugin import TrixyPlugin from trixy_core.plugins.plugin_manager import PluginManager class ConcretePlugin(TrixyPlugin): """Konkrete Plugin-Implementierung für Tests.""" NAME = "TestPlugin" VERSION = "1.0.0" DESCRIPTION = "Ein Test-Plugin" AUTHOR = "Test Author" def __init__(self, application, plugin_path, config=None): super().__init__(application, plugin_path, config) self.loaded = False self.unloaded = False async def on_load(self): self.loaded = True async def on_unload(self): self.unloaded = True class TestTrixyPlugin: """Tests für TrixyPlugin-Basisklasse.""" @pytest.fixture def mock_application(self): """Erstellt eine Mock-Anwendung.""" return MagicMock() @pytest.fixture def plugin_path(self, temp_dir): """Erstellt einen Plugin-Pfad.""" plugin_dir = temp_dir / "test_plugin" plugin_dir.mkdir() return plugin_dir @pytest.fixture def plugin(self, mock_application, plugin_path): """Erstellt ein Test-Plugin.""" config = {"setting1": "value1", "nested": {"key": "value"}} return ConcretePlugin(mock_application, plugin_path, config) def test_plugin_initialization(self, plugin, mock_application, plugin_path): """Testet die Plugin-Initialisierung.""" assert plugin.application == mock_application assert plugin.plugin_path == plugin_path assert plugin.enabled is True def test_plugin_name(self, plugin): """Testet den Plugin-Namen.""" assert plugin.name == "TestPlugin" def test_plugin_version(self, plugin): """Testet die Plugin-Version.""" assert plugin.VERSION == "1.0.0" def test_plugin_config(self, plugin): """Testet die Plugin-Konfiguration.""" assert plugin.config["setting1"] == "value1" def test_plugin_enabled(self, plugin): """Testet enabled-Eigenschaft.""" assert plugin.enabled is True assert plugin.is_enabled() is True plugin.enabled = False assert plugin.enabled is False assert plugin.is_enabled() is False def test_get_config_value(self, plugin): """Testet get_config_value.""" assert plugin.get_config_value("setting1") == "value1" assert plugin.get_config_value("nested.key") == "value" assert plugin.get_config_value("nonexistent", "default") == "default" def test_set_config_value(self, plugin): """Testet set_config_value.""" plugin.set_config_value("new_setting", "new_value") assert plugin.config["new_setting"] == "new_value" plugin.set_config_value("nested.new_key", "nested_value") assert plugin.config["nested"]["new_key"] == "nested_value" def test_reload_config(self, plugin, plugin_path): """Testet reload_config.""" # Erstelle config.json config_file = plugin_path / "config.json" config_file.write_text(json.dumps({"reloaded": True})) result = plugin.reload_config() assert result is True assert plugin.config["reloaded"] is True def test_reload_config_no_file(self, plugin): """Testet reload_config ohne Datei.""" result = plugin.reload_config() assert result is False def test_save_config(self, plugin, plugin_path): """Testet save_config.""" plugin.config["saved_setting"] = "saved_value" result = plugin.save_config() assert result is True config_file = plugin_path / "config.json" assert config_file.exists() data = json.loads(config_file.read_text()) assert data["saved_setting"] == "saved_value" @pytest.mark.asyncio async def test_on_load(self, plugin): """Testet on_load.""" await plugin.on_load() assert plugin.loaded is True @pytest.mark.asyncio async def test_on_unload(self, plugin): """Testet on_unload.""" await plugin.on_unload() assert plugin.unloaded is True @pytest.mark.asyncio async def test_lifecycle_hooks(self, plugin): """Testet Lifecycle-Hooks.""" # Diese sollten ohne Fehler durchlaufen await plugin.on_enable() await plugin.on_disable() await plugin.on_config_change({}) def test_repr(self, plugin): """Testet __repr__.""" repr_str = repr(plugin) assert "Plugin" in repr_str assert "TestPlugin" in repr_str assert "1.0.0" in repr_str class TestPluginManager: """Tests für PluginManager.""" @pytest.fixture def mock_application(self): """Erstellt eine Mock-Anwendung mit EventManager.""" app = MagicMock() app.events = MagicMock() app.events.register_object = MagicMock() app.events.unregister_object = MagicMock() return app @pytest.fixture def plugins_dir(self, temp_dir): """Erstellt ein Plugin-Verzeichnis.""" plugins = temp_dir / "plugins" plugins.mkdir() return plugins @pytest.fixture def manager(self, mock_application, plugins_dir): """Erstellt einen PluginManager.""" return PluginManager(mock_application, directory=plugins_dir) @pytest.fixture def test_plugin_dir(self, plugins_dir): """Erstellt ein Test-Plugin-Verzeichnis.""" plugin_dir = plugins_dir / "test_plugin" plugin_dir.mkdir() # main.py erstellen main_py = plugin_dir / "main.py" main_py.write_text(''' from trixy_core.plugins.trixy_plugin import TrixyPlugin class TestPlugin(TrixyPlugin): NAME = "TestPlugin" VERSION = "1.0.0" async def on_load(self): pass async def on_unload(self): pass ''') # config.json erstellen config_json = plugin_dir / "config.json" config_json.write_text('{"enabled": true}') return plugin_dir def test_manager_initialization(self, manager): """Testet die Manager-Initialisierung.""" assert manager.count == 0 assert manager.enabled_count == 0 @pytest.mark.asyncio async def test_load_plugin(self, manager, test_plugin_dir): """Testet das Laden eines Plugins.""" result = await manager.load("test_plugin") assert result is True assert manager.count == 1 assert "TestPlugin" in manager @pytest.mark.asyncio async def test_load_nonexistent_plugin(self, manager): """Testet das Laden eines nicht existierenden Plugins.""" result = await manager.load("nonexistent") assert result is False assert "nonexistent" in manager.get_failed() @pytest.mark.asyncio async def test_unload_plugin(self, manager, test_plugin_dir): """Testet das Entladen eines Plugins.""" await manager.load("test_plugin") result = await manager.unload("TestPlugin") assert result is True assert manager.count == 0 @pytest.mark.asyncio async def test_reload_plugin(self, manager, test_plugin_dir): """Testet das Neuladen eines Plugins.""" await manager.load("test_plugin") result = await manager.reload("test_plugin") assert result is True assert manager.count == 1 @pytest.mark.asyncio async def test_get_plugin(self, manager, test_plugin_dir): """Testet get.""" await manager.load("test_plugin") plugin = manager.get("TestPlugin") assert plugin is not None assert plugin.name == "TestPlugin" @pytest.mark.asyncio async def test_get_all(self, manager, test_plugin_dir): """Testet get_all.""" await manager.load("test_plugin") plugins = manager.get_all() assert len(plugins) == 1 @pytest.mark.asyncio async def test_enable_plugin(self, manager, test_plugin_dir): """Testet enable.""" await manager.load("test_plugin") plugin = manager.get("TestPlugin") plugin.enabled = False result = await manager.enable("TestPlugin") assert result is True assert plugin.enabled is True @pytest.mark.asyncio async def test_disable_plugin(self, manager, test_plugin_dir): """Testet disable.""" await manager.load("test_plugin") result = await manager.disable("TestPlugin") plugin = manager.get("TestPlugin") assert result is True assert plugin.enabled is False @pytest.mark.asyncio async def test_load_all(self, manager, test_plugin_dir): """Testet load_all.""" count = await manager.load_all() assert count == 1 assert manager.count == 1 @pytest.mark.asyncio async def test_unload_all(self, manager, test_plugin_dir): """Testet unload_all.""" await manager.load("test_plugin") count = await manager.unload_all() assert count == 1 assert manager.count == 0 @pytest.mark.asyncio async def test_contains(self, manager, test_plugin_dir): """Testet __contains__.""" await manager.load("test_plugin") assert "TestPlugin" in manager assert "NonExistent" not in manager @pytest.mark.asyncio async def test_getitem(self, manager, test_plugin_dir): """Testet __getitem__.""" await manager.load("test_plugin") plugin = manager["TestPlugin"] assert plugin.name == "TestPlugin" @pytest.mark.asyncio async def test_getitem_raises_keyerror(self, manager): """Testet, dass __getitem__ KeyError wirft.""" with pytest.raises(KeyError): _ = manager["NonExistent"] @pytest.mark.asyncio async def test_iter(self, manager, test_plugin_dir): """Testet __iter__.""" await manager.load("test_plugin") plugins = list(manager) assert len(plugins) == 1 @pytest.mark.asyncio async def test_len(self, manager, test_plugin_dir): """Testet __len__.""" assert len(manager) == 0 await manager.load("test_plugin") assert len(manager) == 1 @pytest.mark.asyncio async def test_get_enabled(self, manager, test_plugin_dir): """Testet get_enabled.""" await manager.load("test_plugin") enabled = manager.get_enabled() assert len(enabled) == 1 assert manager.enabled_count == 1 def test_skip_hidden_directories(self, manager, plugins_dir): """Testet, dass versteckte Verzeichnisse übersprungen werden.""" # Erstelle verstecktes Verzeichnis hidden = plugins_dir / "_hidden" hidden.mkdir() # Sollte nicht versuchen zu laden # (load_all würde es überspringen) @pytest.mark.asyncio async def test_plugin_without_main_py(self, manager, plugins_dir): """Testet Plugin ohne main.py.""" # Erstelle Verzeichnis ohne main.py empty = plugins_dir / "empty_plugin" empty.mkdir() result = await manager.load("empty_plugin") assert result is False assert "empty_plugin" in manager.get_failed()