418 lines
11 KiB
Python
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()
|