| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- # -*- 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()
|