301 lines
9.7 KiB
Python
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
|