""" Pytest configuration and fixtures for pyPhotoAlbum tests """ import pytest import tempfile import os from pathlib import Path from PIL import Image from pyPhotoAlbum.models import ImageData, PlaceholderData, TextBoxData from pyPhotoAlbum.page_layout import PageLayout, GridLayout from pyPhotoAlbum.project import Project, Page @pytest.fixture def temp_image_file(): """Create a temporary test image file""" with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as f: # Create a simple test image img = Image.new('RGB', (100, 100), color='red') img.save(f.name) yield f.name # Cleanup try: os.unlink(f.name) except: pass @pytest.fixture def temp_dir(): """Create a temporary directory for tests""" with tempfile.TemporaryDirectory() as tmpdir: yield tmpdir @pytest.fixture def sample_image_data(temp_image_file): """Create a sample ImageData instance""" return ImageData( image_path=temp_image_file, x=10.0, y=20.0, width=100.0, height=150.0 ) @pytest.fixture def sample_placeholder_data(): """Create a sample PlaceholderData instance""" return PlaceholderData( placeholder_type="image", x=50.0, y=60.0, width=200.0, height=150.0 ) @pytest.fixture def sample_textbox_data(): """Create a sample TextBoxData instance""" return TextBoxData( text_content="Sample Text", x=30.0, y=40.0, width=150.0, height=50.0 ) @pytest.fixture def sample_page_layout(): """Create a sample PageLayout instance""" layout = PageLayout() return layout @pytest.fixture def sample_grid_layout(): """Create a sample GridLayout instance""" return GridLayout(rows=2, columns=2, spacing=10.0) @pytest.fixture def sample_page(sample_page_layout): """Create a sample Page instance""" return Page(layout=sample_page_layout, page_number=1) @pytest.fixture def sample_project(): """Create a sample Project instance""" return Project(name="Test Project") @pytest.fixture def populated_page_layout(sample_image_data, sample_placeholder_data, sample_textbox_data): """Create a page layout populated with various elements""" layout = PageLayout() layout.add_element(sample_image_data) layout.add_element(sample_placeholder_data) layout.add_element(sample_textbox_data) return layout # GL Widget fixtures (moved from test_gl_widget_fixtures.py) from unittest.mock import Mock, MagicMock from PyQt6.QtCore import Qt, QPointF, QPoint from PyQt6.QtGui import QMouseEvent, QWheelEvent @pytest.fixture def mock_main_window(): """Create a mock main window with a basic project""" window = Mock() window.project = Project(name="Test Project") # Add a test page page = Page( layout=PageLayout(width=210, height=297), # A4 size in mm page_number=1 ) window.project.pages.append(page) window.project.working_dpi = 96 window.project.page_size_mm = (210, 297) window.project.page_spacing_mm = 10 # Mock status bar window.status_bar = Mock() window.status_bar.showMessage = Mock() window.show_status = Mock() return window @pytest.fixture def sample_image_element(): """Create a sample ImageData element for testing""" return ImageData( image_path="test.jpg", x=100, y=100, width=200, height=150, z_index=1 ) @pytest.fixture def sample_placeholder_element(): """Create a sample PlaceholderData element for testing""" return PlaceholderData( x=50, y=50, width=100, height=100, z_index=0 ) @pytest.fixture def sample_textbox_element(): """Create a sample TextBoxData element for testing""" return TextBoxData( x=10, y=10, width=180, height=50, text_content="Test Text", z_index=2 ) @pytest.fixture def mock_page_renderer(): """Create a mock PageRenderer NOTE: This fixture contains simplified coordinate conversion logic for testing. It is NOT a replacement for testing with the real PageRenderer in integration tests. """ renderer = Mock() renderer.screen_x = 50 renderer.screen_y = 50 renderer.zoom = 1.0 renderer.dpi = 96 # Mock coordinate conversion methods def page_to_screen(x, y): return (renderer.screen_x + x * renderer.zoom, renderer.screen_y + y * renderer.zoom) def screen_to_page(x, y): return ((x - renderer.screen_x) / renderer.zoom, (y - renderer.screen_y) / renderer.zoom) def is_point_in_page(x, y): # Simple bounds check (assume 210mm x 297mm page at 96 DPI) page_width_px = 210 * 96 / 25.4 page_height_px = 297 * 96 / 25.4 return (renderer.screen_x <= x <= renderer.screen_x + page_width_px * renderer.zoom and renderer.screen_y <= y <= renderer.screen_y + page_height_px * renderer.zoom) renderer.page_to_screen = page_to_screen renderer.screen_to_page = screen_to_page renderer.is_point_in_page = is_point_in_page return renderer @pytest.fixture def create_mouse_event(): """Factory fixture for creating QMouseEvent objects""" def _create_event(event_type, x, y, button=Qt.MouseButton.LeftButton, modifiers=Qt.KeyboardModifier.NoModifier): """Create a QMouseEvent for testing Args: event_type: QEvent.Type (MouseButtonPress, MouseButtonRelease, MouseMove) x, y: Position coordinates button: Mouse button modifiers: Keyboard modifiers """ pos = QPointF(x, y) return QMouseEvent( event_type, pos, button, button, modifiers ) return _create_event @pytest.fixture def create_wheel_event(): """Factory fixture for creating QWheelEvent objects""" def _create_event(x, y, delta_y=120, modifiers=Qt.KeyboardModifier.NoModifier): """Create a QWheelEvent for testing Args: x, y: Position coordinates delta_y: Wheel delta (positive = scroll up, negative = scroll down) modifiers: Keyboard modifiers (e.g., ControlModifier for zoom) """ pos = QPointF(x, y) global_pos = QPoint(int(x), int(y)) angle_delta = QPoint(0, delta_y) return QWheelEvent( pos, global_pos, QPoint(0, 0), angle_delta, Qt.MouseButton.NoButton, modifiers, Qt.ScrollPhase.NoScrollPhase, False ) return _create_event @pytest.fixture def populated_page(): """Create a page with multiple elements for testing""" page = Page( layout=PageLayout(width=210, height=297), page_number=1 ) # Add various elements page.layout.add_element(ImageData( image_path="img1.jpg", x=10, y=10, width=100, height=75, z_index=0 )) page.layout.add_element(PlaceholderData( x=120, y=10, width=80, height=60, z_index=1 )) page.layout.add_element(TextBoxData( x=10, y=100, width=190, height=40, text_content="Sample Text", z_index=2 )) return page