""" Tests for ApplicationStateMixin (base mixin) """ import pytest from unittest.mock import Mock, MagicMock from PyQt6.QtWidgets import QMainWindow, QStatusBar, QMessageBox from pyPhotoAlbum.mixins.base import ApplicationStateMixin from pyPhotoAlbum.project import Project, Page from pyPhotoAlbum.page_layout import PageLayout class TestAppStateWindow(ApplicationStateMixin, QMainWindow): """Test window with application state mixin""" def __init__(self): super().__init__() class TestPropertyAccess: """Test property access methods""" def test_project_property_get(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) project = Mock(spec=Project) window._project = project assert window.project == project def test_project_property_set(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) project = Mock(spec=Project) window.project = project assert window._project == project def test_project_property_missing_raises_error(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) with pytest.raises(AttributeError): _ = window.project def test_gl_widget_property_get(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) gl_widget = Mock() window._gl_widget = gl_widget assert window.gl_widget == gl_widget def test_gl_widget_property_missing_raises_error(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) with pytest.raises(AttributeError): _ = window.gl_widget def test_status_bar_property_get(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) status_bar = QStatusBar() window._status_bar = status_bar assert window.status_bar == status_bar def test_status_bar_property_missing_raises_error(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) with pytest.raises(AttributeError): _ = window.status_bar def test_template_manager_property_get(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) template_manager = Mock() window._template_manager = template_manager assert window.template_manager == template_manager def test_template_manager_property_missing_raises_error(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) with pytest.raises(AttributeError): _ = window.template_manager class TestGetCurrentPage: """Test get_current_page method""" def test_get_current_page_success(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) # Setup project with pages project = Mock(spec=Project) page1 = Mock(spec=Page) page2 = Mock(spec=Page) project.pages = [page1, page2] gl_widget = Mock() gl_widget.current_page_index = 0 window._project = project window._gl_widget = gl_widget assert window.get_current_page() == page1 def test_get_current_page_second_page(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) project = Mock(spec=Project) page1 = Mock(spec=Page) page2 = Mock(spec=Page) project.pages = [page1, page2] gl_widget = Mock() gl_widget.current_page_index = 1 window._project = project window._gl_widget = gl_widget assert window.get_current_page() == page2 def test_get_current_page_no_project(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) window._project = None window._gl_widget = Mock() assert window.get_current_page() is None def test_get_current_page_no_pages(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) project = Mock(spec=Project) project.pages = [] window._project = project window._gl_widget = Mock() assert window.get_current_page() is None def test_get_current_page_invalid_index(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) project = Mock(spec=Project) project.pages = [Mock(spec=Page)] gl_widget = Mock() gl_widget.current_page_index = 5 # Out of range window._project = project window._gl_widget = gl_widget assert window.get_current_page() is None class TestGetCurrentPageIndex: """Test get_current_page_index method""" def test_get_current_page_index_success(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) project = Mock(spec=Project) project.pages = [Mock(), Mock()] gl_widget = Mock() gl_widget.current_page_index = 1 window._project = project window._gl_widget = gl_widget assert window.get_current_page_index() == 1 def test_get_current_page_index_no_project(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) window._project = None window._gl_widget = Mock() assert window.get_current_page_index() == -1 def test_get_current_page_index_no_pages(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) project = Mock(spec=Project) project.pages = [] window._project = project window._gl_widget = Mock() assert window.get_current_page_index() == -1 class TestShowStatus: """Test show_status method""" def test_show_status_with_status_bar(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) status_bar = Mock(spec=QStatusBar) window._status_bar = status_bar window.show_status("Test message", 3000) status_bar.showMessage.assert_called_once_with("Test message", 3000) def test_show_status_default_timeout(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) status_bar = Mock(spec=QStatusBar) window._status_bar = status_bar window.show_status("Test message") status_bar.showMessage.assert_called_once_with("Test message", 2000) class TestDialogMethods: """Test dialog methods (error, warning, info)""" def test_show_error(self, qtbot, monkeypatch): window = TestAppStateWindow() qtbot.addWidget(window) mock_critical = Mock() monkeypatch.setattr(QMessageBox, 'critical', mock_critical) window.show_error("Error Title", "Error message") mock_critical.assert_called_once_with(window, "Error Title", "Error message") def test_show_warning(self, qtbot, monkeypatch): window = TestAppStateWindow() qtbot.addWidget(window) mock_warning = Mock() monkeypatch.setattr(QMessageBox, 'warning', mock_warning) window.show_warning("Warning Title", "Warning message") mock_warning.assert_called_once_with(window, "Warning Title", "Warning message") def test_show_info(self, qtbot, monkeypatch): window = TestAppStateWindow() qtbot.addWidget(window) mock_info = Mock() monkeypatch.setattr(QMessageBox, 'information', mock_info) window.show_info("Info Title", "Info message") mock_info.assert_called_once_with(window, "Info Title", "Info message") class TestRequirePage: """Test require_page method""" def test_require_page_with_page(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) project = Mock(spec=Project) project.pages = [Mock(spec=Page)] gl_widget = Mock() gl_widget.current_page_index = 0 window._project = project window._gl_widget = gl_widget assert window.require_page() is True def test_require_page_no_page_with_warning(self, qtbot, monkeypatch): window = TestAppStateWindow() qtbot.addWidget(window) project = Mock(spec=Project) project.pages = [] window._project = project window._gl_widget = Mock() mock_warning = Mock() monkeypatch.setattr(QMessageBox, 'warning', mock_warning) result = window.require_page(show_warning=True) assert result is False mock_warning.assert_called_once() def test_require_page_no_page_without_warning(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) project = Mock(spec=Project) project.pages = [] window._project = project window._gl_widget = Mock() result = window.require_page(show_warning=False) assert result is False class TestRequireSelection: """Test require_selection method""" def test_require_selection_one_element(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) gl_widget = Mock() gl_widget.selected_elements = {Mock()} window._gl_widget = gl_widget assert window.require_selection(min_count=1) is True def test_require_selection_multiple_elements(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) gl_widget = Mock() gl_widget.selected_elements = {Mock(), Mock(), Mock()} window._gl_widget = gl_widget assert window.require_selection(min_count=3) is True def test_require_selection_insufficient_with_warning(self, qtbot, monkeypatch): window = TestAppStateWindow() qtbot.addWidget(window) gl_widget = Mock() gl_widget.selected_elements = set() window._gl_widget = gl_widget mock_info = Mock() monkeypatch.setattr(QMessageBox, 'information', mock_info) result = window.require_selection(min_count=1, show_warning=True) assert result is False mock_info.assert_called_once() # Check it shows "No Selection" message call_args = mock_info.call_args[0] assert "No Selection" in call_args def test_require_selection_insufficient_multiple_with_warning(self, qtbot, monkeypatch): window = TestAppStateWindow() qtbot.addWidget(window) gl_widget = Mock() gl_widget.selected_elements = {Mock()} window._gl_widget = gl_widget mock_info = Mock() monkeypatch.setattr(QMessageBox, 'information', mock_info) result = window.require_selection(min_count=3, show_warning=True) assert result is False mock_info.assert_called_once() # Check it shows "at least N elements" message call_args = mock_info.call_args[0] assert "at least 3" in call_args[2] def test_require_selection_insufficient_without_warning(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) gl_widget = Mock() gl_widget.selected_elements = set() window._gl_widget = gl_widget result = window.require_selection(min_count=1, show_warning=False) assert result is False class TestUpdateView: """Test update_view method""" def test_update_view(self, qtbot): window = TestAppStateWindow() qtbot.addWidget(window) gl_widget = Mock() window._gl_widget = gl_widget window.update_view() gl_widget.update.assert_called_once()