""" 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