pyPhotoAlbum/tests/test_base_mixin.py
2025-11-11 16:02:02 +00:00

418 lines
11 KiB
Python

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