EU-Utility/tests/unit/test_plugin_manager.py

301 lines
9.7 KiB
Python

"""
Unit Tests - Plugin Manager
============================
Tests for plugin discovery, loading, enable/disable functionality.
"""
import pytest
import json
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
class TestPluginManager:
"""Test PluginManager functionality."""
def test_plugin_manager_initialization(self, mock_overlay):
"""Test plugin manager initializes correctly."""
from core.plugin_manager import PluginManager
pm = PluginManager(mock_overlay)
assert pm.overlay == mock_overlay
assert pm.plugins == {}
assert pm.plugin_classes == {}
assert "enabled" in pm.config
def test_load_config_existing_file(self, mock_overlay, temp_dir):
"""Test loading config from existing file."""
from core.plugin_manager import PluginManager
# Create config file
config_dir = temp_dir / "config"
config_dir.mkdir()
config_file = config_dir / "plugins.json"
test_config = {"enabled": ["test.plugin"], "settings": {}}
config_file.write_text(json.dumps(test_config))
with patch.object(Path, 'exists', return_value=True):
with patch.object(Path, 'read_text', return_value=json.dumps(test_config)):
pm = PluginManager(mock_overlay)
assert pm.config == test_config
def test_load_config_default(self, mock_overlay):
"""Test default config when file doesn't exist."""
from core.plugin_manager import PluginManager
pm = PluginManager(mock_overlay)
assert pm.config["enabled"] == []
assert pm.config["settings"] == {}
def test_is_plugin_enabled(self, mock_overlay):
"""Test plugin enabled check."""
from core.plugin_manager import PluginManager
pm = PluginManager(mock_overlay)
pm.config["enabled"] = ["plugin1", "plugin2"]
assert pm.is_plugin_enabled("plugin1") is True
assert pm.is_plugin_enabled("plugin2") is True
assert pm.is_plugin_enabled("plugin3") is False
def test_enable_plugin(self, mock_overlay):
"""Test enabling a plugin."""
from core.plugin_manager import PluginManager
pm = PluginManager(mock_overlay)
# Mock save_config to avoid file operations
pm.save_config = Mock()
result = pm.enable_plugin("test.plugin")
assert "test.plugin" in pm.config["enabled"]
assert result is True
def test_disable_plugin(self, mock_overlay):
"""Test disabling a plugin."""
from core.plugin_manager import PluginManager
pm = PluginManager(mock_overlay)
pm.config["enabled"] = ["test.plugin", "other.plugin"]
pm.save_config = Mock()
result = pm.disable_plugin("test.plugin")
assert "test.plugin" not in pm.config["enabled"]
assert "other.plugin" in pm.config["enabled"]
assert result is True
def test_disable_plugin_not_loaded(self, mock_overlay):
"""Test disabling a plugin that's not loaded."""
from core.plugin_manager import PluginManager
pm = PluginManager(mock_overlay)
pm.save_config = Mock()
result = pm.disable_plugin("nonexistent.plugin")
assert result is False
def test_discover_plugins_empty(self, mock_overlay, temp_dir):
"""Test plugin discovery with no plugins."""
from core.plugin_manager import PluginManager
with patch.object(Path, 'exists', return_value=False):
pm = PluginManager(mock_overlay)
plugins = pm.discover_plugins()
assert plugins == []
def test_get_plugin_not_loaded(self, mock_overlay):
"""Test getting a plugin that's not loaded."""
from core.plugin_manager import PluginManager
pm = PluginManager(mock_overlay)
result = pm.get_plugin("nonexistent")
assert result is None
def test_trigger_hotkey_no_match(self, mock_overlay):
"""Test hotkey trigger with no matching plugin."""
from core.plugin_manager import PluginManager
pm = PluginManager(mock_overlay)
pm.plugins = {}
result = pm.trigger_hotkey("ctrl+shift+x")
assert result is False
def test_shutdown_all(self, mock_overlay):
"""Test shutting down all plugins."""
from core.plugin_manager import PluginManager
pm = PluginManager(mock_overlay)
# Mock plugins
mock_plugin1 = Mock()
mock_plugin2 = Mock()
pm.plugins = {
"plugin1": mock_plugin1,
"plugin2": mock_plugin2
}
pm.shutdown_all()
mock_plugin1.shutdown.assert_called_once()
mock_plugin2.shutdown.assert_called_once()
assert pm.plugins == {}
class TestBasePlugin:
"""Test BasePlugin functionality."""
def test_base_plugin_initialization(self, mock_overlay):
"""Test base plugin initialization."""
from plugins.base_plugin import BasePlugin
class TestPlugin(BasePlugin):
name = "Test Plugin"
version = "1.0.0"
author = "Test Author"
description = "Test description"
config = {"test_setting": True}
plugin = TestPlugin(mock_overlay, config)
assert plugin.name == "Test Plugin"
assert plugin.version == "1.0.0"
assert plugin.author == "Test Author"
assert plugin.description == "Test description"
assert plugin.overlay == mock_overlay
assert plugin.config == config
assert plugin.enabled is True
def test_base_plugin_default_methods(self, mock_overlay):
"""Test base plugin default method implementations."""
from plugins.base_plugin import BasePlugin
class TestPlugin(BasePlugin):
name = "Test"
plugin = TestPlugin(mock_overlay, {})
# These should not raise exceptions
plugin.initialize()
plugin.shutdown()
plugin.on_hotkey()
ui = plugin.get_ui()
assert ui is None
def test_base_plugin_logging(self, mock_overlay):
"""Test plugin logging methods."""
from plugins.base_plugin import BasePlugin
class TestPlugin(BasePlugin):
name = "Test"
plugin = TestPlugin(mock_overlay, {})
# These should not raise exceptions
plugin.log_info("Info message")
plugin.log_debug("Debug message")
plugin.log_warning("Warning message")
plugin.log_error("Error message")
class TestPluginStore:
"""Test Plugin Store functionality."""
def test_plugin_store_initialization(self, mock_plugin_manager):
"""Test plugin store initializes correctly."""
from core.plugin_store import PluginStore
store = PluginStore(mock_plugin_manager)
assert store.plugin_manager == mock_plugin_manager
assert store.available_plugins == []
def test_plugin_store_fetch_plugins(self, mock_plugin_manager, mock_http_client):
"""Test fetching plugins from store."""
from core.plugin_store import PluginStore
store = PluginStore(mock_plugin_manager)
store.http = mock_http_client
mock_response = {
"success": True,
"data": [
{
"id": "test-plugin",
"name": "Test Plugin",
"version": "1.0.0",
"author": "Test",
"description": "A test plugin"
}
]
}
mock_http_client.get.return_value = mock_response
plugins = store.fetch_available_plugins()
assert len(plugins) == 1
assert plugins[0]["name"] == "Test Plugin"
class TestPluginDependencyManager:
"""Test Plugin Dependency Manager."""
def test_check_python_dependency_installed(self):
"""Test checking installed Python dependency."""
from core.plugin_dependency_manager import DependencyManager
dm = DependencyManager()
# Check for a standard library module that always exists
result = dm.check_python_dependency("sys")
assert result is True
def test_check_python_dependency_not_installed(self):
"""Test checking non-existent Python dependency."""
from core.plugin_dependency_manager import DependencyManager
dm = DependencyManager()
# Check for a fake module
result = dm.check_python_dependency("nonexistent_module_xyz")
assert result is False
def test_parse_requirements(self):
"""Test parsing requirements from plugin class."""
from core.plugin_dependency_manager import DependencyManager
dm = DependencyManager()
class MockPlugin:
requirements = ["requests>=2.0.0", "numpy"]
reqs = dm.parse_requirements(MockPlugin)
assert reqs == ["requests>=2.0.0", "numpy"]
def test_get_install_command(self):
"""Test getting pip install command."""
from core.plugin_dependency_manager import DependencyManager
dm = DependencyManager()
packages = ["requests", "numpy>=1.0.0"]
cmd = dm.get_install_command(packages)
assert "pip" in cmd
assert "install" in cmd
assert "requests" in cmd
assert "numpy>=1.0.0" in cmd