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

204 lines
6.4 KiB
Python

"""
Tests for ViewportMixin
"""
import pytest
from unittest.mock import Mock, MagicMock, patch
from PyQt6.QtWidgets import QApplication
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from pyPhotoAlbum.mixins.viewport import ViewportMixin
from pyPhotoAlbum.project import Project, Page
from pyPhotoAlbum.page_layout import PageLayout
# Create a minimal test widget class
class TestViewportWidget(ViewportMixin, QOpenGLWidget):
"""Test widget combining ViewportMixin with QOpenGLWidget"""
pass
class TestViewportMixinInitialization:
"""Test ViewportMixin initialization"""
def test_initialization_sets_defaults(self, qtbot):
"""Test that mixin initializes with correct defaults"""
widget = TestViewportWidget()
qtbot.addWidget(widget)
assert widget.zoom_level == 1.0
assert widget.pan_offset == [0, 0]
assert widget.initial_zoom_set is False
def test_zoom_level_is_mutable(self, qtbot):
"""Test that zoom level can be changed"""
widget = TestViewportWidget()
qtbot.addWidget(widget)
widget.zoom_level = 1.5
assert widget.zoom_level == 1.5
def test_pan_offset_is_mutable(self, qtbot):
"""Test that pan offset can be changed"""
widget = TestViewportWidget()
qtbot.addWidget(widget)
widget.pan_offset = [100, 50]
assert widget.pan_offset == [100, 50]
class TestViewportCalculations:
"""Test viewport zoom calculations"""
def test_calculate_fit_to_screen_no_project(self, qtbot):
"""Test fit-to-screen with no project returns 1.0"""
widget = TestViewportWidget()
qtbot.addWidget(widget)
widget.resize(800, 600)
# Mock window() to return a window without project
mock_window = Mock()
mock_window.project = None
widget.window = Mock(return_value=mock_window)
zoom = widget._calculate_fit_to_screen_zoom()
assert zoom == 1.0
def test_calculate_fit_to_screen_empty_project(self, qtbot):
"""Test fit-to-screen with empty project returns 1.0"""
widget = TestViewportWidget()
qtbot.addWidget(widget)
widget.resize(800, 600)
# Mock window() to return a window with empty project
mock_window = Mock()
mock_window.project = Project(name="Empty")
mock_window.project.pages = []
widget.window = Mock(return_value=mock_window)
zoom = widget._calculate_fit_to_screen_zoom()
assert zoom == 1.0
def test_calculate_fit_to_screen_with_page(self, qtbot):
"""Test fit-to-screen calculates correct zoom for A4 page"""
widget = TestViewportWidget()
qtbot.addWidget(widget)
widget.resize(1000, 800)
# Mock window with project and A4 page
mock_window = Mock()
mock_window.project = Project(name="Test")
mock_window.project.working_dpi = 96
# A4 page: 210mm x 297mm
page = Page(
layout=PageLayout(width=210, height=297),
page_number=1
)
mock_window.project.pages = [page]
widget.window = Mock(return_value=mock_window)
zoom = widget._calculate_fit_to_screen_zoom()
# Calculate expected zoom
# A4 at 96 DPI: width=794px, height=1123px
# Window: 1000x800, margins: 100px each side
# Available: 800x600
# zoom_w = 800/794 ≈ 1.007, zoom_h = 600/1123 ≈ 0.534
# Should use min(zoom_w, zoom_h, 1.0) = 0.534
assert 0.5 < zoom < 0.6 # Approximately 0.534
assert zoom <= 1.0 # Never zoom beyond 100%
def test_calculate_fit_to_screen_small_window(self, qtbot):
"""Test fit-to-screen with small window returns small zoom"""
widget = TestViewportWidget()
qtbot.addWidget(widget)
widget.resize(400, 300) # Small window
mock_window = Mock()
mock_window.project = Project(name="Test")
mock_window.project.working_dpi = 96
page = Page(
layout=PageLayout(width=210, height=297),
page_number=1
)
mock_window.project.pages = [page]
widget.window = Mock(return_value=mock_window)
zoom = widget._calculate_fit_to_screen_zoom()
# With 400x300 window and 200px margins, available space is 200x100
# This should produce a very small zoom
assert zoom < 0.3
def test_calculate_fit_to_screen_large_window(self, qtbot):
"""Test fit-to-screen with large window caps at 1.0"""
widget = TestViewportWidget()
qtbot.addWidget(widget)
widget.resize(3000, 2000) # Very large window
mock_window = Mock()
mock_window.project = Project(name="Test")
mock_window.project.working_dpi = 96
page = Page(
layout=PageLayout(width=210, height=297),
page_number=1
)
mock_window.project.pages = [page]
widget.window = Mock(return_value=mock_window)
zoom = widget._calculate_fit_to_screen_zoom()
# Even with huge window, zoom should not exceed 1.0
assert zoom == 1.0
def test_calculate_fit_to_screen_different_dpi(self, qtbot):
"""Test fit-to-screen respects different DPI values"""
widget = TestViewportWidget()
qtbot.addWidget(widget)
widget.resize(1000, 800)
mock_window = Mock()
mock_window.project = Project(name="Test")
mock_window.project.working_dpi = 300 # High DPI
page = Page(
layout=PageLayout(width=210, height=297),
page_number=1
)
mock_window.project.pages = [page]
widget.window = Mock(return_value=mock_window)
zoom = widget._calculate_fit_to_screen_zoom()
# At 300 DPI, page is much larger in pixels
# So zoom should be smaller
assert zoom < 0.3
class TestViewportOpenGL:
"""Test OpenGL-related viewport methods"""
def test_initializeGL_sets_clear_color(self, qtbot):
"""Test that initializeGL is callable (actual GL testing is integration)"""
widget = TestViewportWidget()
qtbot.addWidget(widget)
# Just verify the method exists and is callable
assert hasattr(widget, 'initializeGL')
assert callable(widget.initializeGL)
def test_resizeGL_is_callable(self, qtbot):
"""Test that resizeGL is callable"""
widget = TestViewportWidget()
qtbot.addWidget(widget)
assert hasattr(widget, 'resizeGL')
assert callable(widget.resizeGL)