""" EU-Utility Test Configuration and Shared Fixtures This module provides: - Path configuration for test imports - Shared fixtures for all test types - Mock objects for testing without external dependencies """ import sys import pytest from pathlib import Path from unittest.mock import MagicMock, patch from typing import Generator # Add project root to Python path project_root = Path(__file__).parent.parent if str(project_root) not in sys.path: sys.path.insert(0, str(project_root)) # ==================== Session Fixtures ==================== @pytest.fixture(scope="session") def project_root_path() -> Path: """Return the project root path.""" return Path(__file__).parent.parent @pytest.fixture(scope="session") def test_data_path(project_root_path) -> Path: """Return the test data directory path.""" return project_root_path / "tests" / "fixtures" # ==================== Mock Fixtures ==================== @pytest.fixture def mock_qt_app(): """Create a mock Qt application for testing without GUI.""" mock_app = MagicMock() mock_app.exec = MagicMock(return_value=0) mock_app.quit = MagicMock() return mock_app @pytest.fixture def mock_overlay_window(): """Create a mock overlay window for plugin testing.""" overlay = MagicMock() overlay.show = MagicMock() overlay.hide = MagicMock() overlay.toggle = MagicMock() overlay.add_widget = MagicMock() overlay.remove_widget = MagicMock() overlay.get_position = MagicMock(return_value=(100, 100)) overlay.set_position = MagicMock() return overlay @pytest.fixture def mock_plugin_config(): """Return a sample plugin configuration.""" return { "enabled": True, "hotkey": "ctrl+shift+t", "settings": { "auto_start": False, "update_interval": 5000 } } @pytest.fixture def reset_singletons(): """Reset all singleton instances after test.""" yield # Reset singletons after test from core.event_bus import reset_event_bus from core.plugin_api import PluginAPI from core.nexus_api import NexusAPI from core.data_store import DataStore reset_event_bus() # Reset other singletons NexusAPI._instance = None DataStore._instance = None PluginAPI._instance = None # ==================== Event Bus Fixtures ==================== @pytest.fixture def fresh_event_bus(): """Create a fresh EventBus instance for testing.""" from core.event_bus import EventBus, reset_event_bus # Reset first reset_event_bus() # Create fresh instance bus = EventBus(max_history=100) yield bus # Cleanup bus.shutdown() reset_event_bus() @pytest.fixture def sample_events(): """Return sample events for testing.""" from core.event_bus import ( SkillGainEvent, LootEvent, DamageEvent, GlobalEvent, ChatEvent, EconomyEvent ) from datetime import datetime return { "skill_gain": SkillGainEvent( skill_name="Rifle", skill_value=25.5, gain_amount=0.01, source="test" ), "loot": LootEvent( mob_name="Daikiba", items=[{"name": "Animal Oil", "value": 0.05}], total_tt_value=0.05, source="test" ), "damage": DamageEvent( damage_amount=150.0, damage_type="impact", is_critical=True, target_name="Atrox", attacker_name="Player", is_outgoing=True, source="test" ), "global": GlobalEvent( player_name="Player", achievement_type="hof", value=1000.0, item_name="Uber Item", source="test" ), "chat": ChatEvent( channel="main", sender="OtherPlayer", message="Hello!", source="test" ), "economy": EconomyEvent( transaction_type="sale", amount=100.0, currency="PED", description="Sold item", source="test" ) } # ==================== API Fixtures ==================== @pytest.fixture def mock_nexus_api(): """Create a mock NexusAPI for testing.""" mock_api = MagicMock() mock_api.search_items.return_value = [ MagicMock(id="item1", name="Test Item", type="weapon") ] mock_api.search_mobs.return_value = [ MagicMock(id="mob1", name="Test Mob", type="creature") ] mock_api.get_item_details.return_value = MagicMock( id="item1", name="Test Item", tt_value=10.0 ) mock_api.get_market_data.return_value = MagicMock( item_id="item1", current_markup=110.0 ) mock_api.is_available.return_value = True return mock_api @pytest.fixture def mock_ocr_service(): """Create a mock OCRService for testing.""" mock_ocr = MagicMock() mock_ocr.is_available.return_value = True mock_ocr.recognize.return_value = { "text": "Test OCR Text", "confidence": 0.95, "results": [] } mock_ocr.capture_screen.return_value = MagicMock() return mock_ocr @pytest.fixture def mock_log_reader(): """Create a mock LogReader for testing.""" mock_reader = MagicMock() mock_reader.is_available.return_value = True mock_reader.read_lines.return_value = [ "2024-01-01 12:00:00 [System] Test log line", "2024-01-01 12:00:01 [Combat] You hit for 50 damage" ] mock_reader.get_stats.return_value = { "lines_read": 100, "events_parsed": 10 } return mock_reader # ==================== Data Fixtures ==================== @pytest.fixture def temp_data_dir(tmp_path): """Create a temporary data directory for testing.""" data_dir = tmp_path / "test_data" data_dir.mkdir() return data_dir @pytest.fixture def sample_log_lines(): """Return sample log lines for testing.""" return [ "2024-01-01 12:00:00 [System] You entered the game", "2024-01-01 12:00:05 [Skill] Rifle has improved by 0.01 points", "2024-01-01 12:00:10 [Combat] You hit for 45 damage", "2024-01-01 12:00:15 [Loot] You received Animal Oil x 1", "2024-01-01 12:00:20 [Global] Player received something worth 1000 PED" ] # ==================== Plugin Fixtures ==================== @pytest.fixture def mock_plugin(): """Create a mock plugin for testing.""" plugin = MagicMock() plugin.name = "TestPlugin" plugin.version = "1.0.0" plugin.author = "Test Author" plugin.description = "A test plugin" plugin.enabled = True plugin.initialize = MagicMock() plugin.get_ui = MagicMock(return_value=MagicMock()) plugin.on_show = MagicMock() plugin.on_hide = MagicMock() plugin.shutdown = MagicMock() return plugin @pytest.fixture def plugin_manager_with_mock(): """Create a PluginManager with mocked dependencies.""" from core.plugin_manager import PluginManager with patch('core.plugin_manager.Settings') as MockSettings: mock_settings = MagicMock() mock_settings.get.return_value = [] MockSettings.return_value = mock_settings manager = PluginManager() yield manager # ==================== Pytest Configuration ==================== def pytest_configure(config): """Configure pytest with custom markers.""" config.addinivalue_line("markers", "unit: Unit tests for individual components") config.addinivalue_line("markers", "integration: Integration tests") config.addinivalue_line("markers", "ui: UI automation tests") config.addinivalue_line("markers", "performance: Performance benchmarks") config.addinivalue_line("markers", "slow: Slow tests") config.addinivalue_line("markers", "requires_qt: Tests requiring PyQt6") config.addinivalue_line("markers", "requires_network: Tests requiring network") def pytest_collection_modifyitems(config, items): """Modify test collection to add markers based on test location.""" for item in items: # Add markers based on test file location if "unit" in str(item.fspath): item.add_marker(pytest.mark.unit) elif "integration" in str(item.fspath): item.add_marker(pytest.mark.integration) elif "ui" in str(item.fspath): item.add_marker(pytest.mark.ui) elif "performance" in str(item.fspath): item.add_marker(pytest.mark.performance)