diff --git a/tests/test_gui_integration.py b/tests/test_gui_integration.py new file mode 100644 index 0000000..8b03a36 --- /dev/null +++ b/tests/test_gui_integration.py @@ -0,0 +1,131 @@ +""" +Tests for GUI integration with core modules. +Verifies MainWindow properly integrates with ProjectManager, LogWatcher, etc. +""" + +import pytest +import sys +from pathlib import Path +from unittest.mock import Mock, MagicMock, patch + +# Add project to path +sys.path.insert(0, str(Path(__file__).parent.parent)) + + +class TestProjectDataCompatibility: + """Test that GUI uses correct ProjectData attributes.""" + + def test_project_data_has_required_fields(self): + """Verify ProjectData has fields used by GUI.""" + from core.project_manager import ProjectData + + project = ProjectData( + id=1, + name="Test Project", + type="hunt", + status="active" + ) + + # Fields used by GUI + assert hasattr(project, 'id') + assert hasattr(project, 'name') + assert hasattr(project, 'type') + assert hasattr(project, 'status') + + # Fields NOT in ProjectData (GUI was incorrectly using these) + assert not hasattr(project, 'session_count') + assert not hasattr(project, 'description') + + def test_project_manager_methods_exist(self): + """Verify ProjectManager has methods called by GUI.""" + from core.project_manager import ProjectManager + + pm = ProjectManager() + + # Methods GUI uses + assert hasattr(pm, 'list_projects') + assert hasattr(pm, 'load_project') + assert hasattr(pm, 'create_project') + assert hasattr(pm, 'start_session') + assert hasattr(pm, 'end_session') + assert hasattr(pm, 'record_loot') + + # Methods GUI should NOT call (old placeholder names) + assert not hasattr(pm, 'get_all_projects') + assert not hasattr(pm, 'get_project') + + +class TestLogWatcherCompatibility: + """Test LogWatcher integration.""" + + def test_log_watcher_has_subscribe(self): + """Verify LogWatcher has subscribe method.""" + from core.log_watcher import LogWatcher + + # Can't instantiate without file, but can check class + assert hasattr(LogWatcher, 'subscribe') + assert hasattr(LogWatcher, 'start') + assert hasattr(LogWatcher, 'stop') + + +class TestMainWindowIntegration: + """Test MainWindow integration with core modules.""" + + @pytest.fixture + def mock_qapp(self): + """Create mock QApplication.""" + with patch('PyQt6.QtWidgets.QApplication') as mock_app: + mock_instance = Mock() + mock_app.instance.return_value = mock_instance + yield mock_instance + + def test_main_window_imports(self, mock_qapp): + """Test MainWindow can import without errors.""" + with patch('ui.main_window.DatabaseManager') as mock_db, \ + patch('ui.main_window.ProjectManager') as mock_pm, \ + patch('ui.main_window.HUDOverlay'), \ + patch('ui.main_window.QMainWindow'): + + mock_db_instance = Mock() + mock_db_instance.initialize.return_value = True + mock_db.return_value = mock_db_instance + + mock_pm_instance = Mock() + mock_pm_instance.list_projects.return_value = [] + mock_pm.return_value = mock_pm_instance + + from ui.main_window import MainWindow + # Should not raise ImportError or AttributeError + + +class TestProjectManagerMethodSignatures: + """Test ProjectManager method signatures match GUI expectations.""" + + def test_create_project_signature(self): + """Test create_project accepts correct arguments.""" + from core.project_manager import ProjectManager + import inspect + + sig = inspect.signature(ProjectManager.create_project) + params = list(sig.parameters.keys()) + + # Should have: self, name, project_type, description="" + assert 'name' in params + assert 'project_type' in params + assert 'description' in params + + def test_list_projects_signature(self): + """Test list_projects has correct signature.""" + from core.project_manager import ProjectManager + import inspect + + sig = inspect.signature(ProjectManager.list_projects) + params = list(sig.parameters.keys()) + + # Should have optional filters + assert 'project_type' in params + assert 'status' in params + + +if __name__ == "__main__": + pytest.main([__file__, "-v"]) \ No newline at end of file diff --git a/tests/test_gui_simple.py b/tests/test_gui_simple.py new file mode 100644 index 0000000..3f41720 --- /dev/null +++ b/tests/test_gui_simple.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +""" +Simple test runner for GUI integration - no pytest required. +Run: python tests/test_gui_simple.py +""" + +import sys +from pathlib import Path + +# Add project to path +sys.path.insert(0, str(Path(__file__).parent.parent)) + +def test_project_data_fields(): + """Test ProjectData has fields GUI uses.""" + from core.project_manager import ProjectData + + project = ProjectData( + id=1, + name="Test Project", + type="hunt", + status="active" + ) + + # Required fields + assert hasattr(project, 'id'), "Missing: id" + assert hasattr(project, 'name'), "Missing: name" + assert hasattr(project, 'type'), "Missing: type" + assert hasattr(project, 'status'), "Missing: status" + + # These fields caused AttributeErrors + assert not hasattr(project, 'session_count'), "Unexpected: session_count" + assert not hasattr(project, 'description'), "Unexpected: description" + + print("✅ ProjectData fields correct") + return True + +def test_project_manager_methods(): + """Test ProjectManager has methods GUI calls.""" + from core.project_manager import ProjectManager + + pm = ProjectManager() + + # Required methods + assert hasattr(pm, 'list_projects'), "Missing: list_projects" + assert hasattr(pm, 'load_project'), "Missing: load_project" + assert hasattr(pm, 'create_project'), "Missing: create_project" + assert hasattr(pm, 'start_session'), "Missing: start_session" + assert hasattr(pm, 'end_session'), "Missing: end_session" + assert hasattr(pm, 'record_loot'), "Missing: record_loot" + + # These were wrong method names + assert not hasattr(pm, 'get_all_projects'), "Should not have: get_all_projects" + assert not hasattr(pm, 'get_project'), "Should not have: get_project" + + print("✅ ProjectManager methods correct") + return True + +def test_create_project_signature(): + """Test create_project has correct signature.""" + from core.project_manager import ProjectManager + import inspect + + sig = inspect.signature(ProjectManager.create_project) + params = list(sig.parameters.keys()) + + # Correct signature: create_project(name, project_type, metadata=None) + assert 'name' in params, "Missing: name" + assert 'project_type' in params, "Missing: project_type" + assert 'metadata' in params, "Missing: metadata" + + print("✅ create_project signature correct") + return True + +def test_list_projects_signature(): + """Test list_projects returns list.""" + from core.project_manager import ProjectManager + + pm = ProjectManager() + projects = pm.list_projects() + + assert isinstance(projects, list), "list_projects should return list" + + print(f"✅ list_projects works (found {len(projects)} projects)") + return True + +def test_log_watcher_methods(): + """Test LogWatcher has required methods.""" + from core.log_watcher import LogWatcher + + assert hasattr(LogWatcher, 'subscribe'), "Missing: subscribe" + assert hasattr(LogWatcher, 'start'), "Missing: start" + assert hasattr(LogWatcher, 'stop'), "Missing: stop" + + print("✅ LogWatcher methods correct") + return True + +def run_all_tests(): + """Run all tests.""" + print("="*60) + print("GUI INTEGRATION TESTS") + print("="*60) + print() + + tests = [ + test_project_data_fields, + test_project_manager_methods, + test_create_project_signature, + test_list_projects_signature, + test_log_watcher_methods, + ] + + passed = 0 + failed = 0 + + for test in tests: + try: + if test(): + passed += 1 + except Exception as e: + print(f"❌ {test.__name__} FAILED: {e}") + failed += 1 + + print() + print("="*60) + print(f"RESULTS: {passed} passed, {failed} failed") + print("="*60) + + return failed == 0 + +if __name__ == "__main__": + success = run_all_tests() + sys.exit(0 if success else 1) \ No newline at end of file diff --git a/ui/main_window.py b/ui/main_window.py index 95f0b1d..d107609 100644 --- a/ui/main_window.py +++ b/ui/main_window.py @@ -797,7 +797,8 @@ class MainWindow(QMainWindow): dialog = NewProjectDialog(self) if dialog.exec() == QDialog.DialogCode.Accepted: name, description = dialog.get_project_data() - project = self.project_manager.create_project(name, 'hunt', description) + metadata = {"description": description} if description else None + project = self.project_manager.create_project(name, 'hunt', metadata) self.refresh_project_list() self.log_info("ProjectManager", f"Created project: {project.name}") self.status_bar.showMessage(f"Project '{name}' created", 3000)