""" Tests for SizeOperationsMixin """ import pytest from unittest.mock import Mock, patch from PyQt6.QtWidgets import QMainWindow from pyPhotoAlbum.mixins.operations.size_ops import SizeOperationsMixin from pyPhotoAlbum.models import ImageData from pyPhotoAlbum.commands import CommandHistory from pyPhotoAlbum.page_layout import PageLayout class TestSizeWindow(SizeOperationsMixin, QMainWindow): """Test window with size operations mixin""" def __init__(self): super().__init__() self.gl_widget = Mock() self.gl_widget.selected_elements = set() self.project = Mock() self.project.history = CommandHistory() self._update_view_called = False self._status_message = None self._warning_message = None self._require_selection_count = None def require_selection(self, min_count=1): self._require_selection_count = min_count return len(self.gl_widget.selected_elements) >= min_count def get_current_page(self): if hasattr(self, '_current_page'): return self._current_page return None def update_view(self): self._update_view_called = True def show_status(self, message, timeout=0): self._status_message = message def show_warning(self, title, message): self._warning_message = message class TestMakeSameSize: """Test make_same_size method""" @patch('pyPhotoAlbum.mixins.operations.size_ops.AlignmentManager') def test_make_same_size_success(self, mock_manager, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element1 = ImageData(image_path="/test1.jpg", x=0, y=0, width=100, height=100) element2 = ImageData(image_path="/test2.jpg", x=150, y=0, width=200, height=150) window.gl_widget.selected_elements = {element1, element2} mock_manager.make_same_size.return_value = [ (element1, (0, 0), (100, 100)), (element2, (150, 0), (200, 150)) ] window.make_same_size() assert mock_manager.make_same_size.called assert window._update_view_called assert "same size" in window._status_message.lower() def test_make_same_size_insufficient_selection(self, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element1 = ImageData(image_path="/test1.jpg", x=0, y=0, width=100, height=100) window.gl_widget.selected_elements = {element1} window.make_same_size() assert window._require_selection_count == 2 assert not window._update_view_called class TestMakeSameWidth: """Test make_same_width method""" @patch('pyPhotoAlbum.mixins.operations.size_ops.AlignmentManager') def test_make_same_width_success(self, mock_manager, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element1 = ImageData(image_path="/test1.jpg", x=0, y=0, width=100, height=100) element2 = ImageData(image_path="/test2.jpg", x=150, y=0, width=200, height=150) window.gl_widget.selected_elements = {element1, element2} mock_manager.make_same_width.return_value = [ (element1, (0, 0), (100, 100)), (element2, (150, 0), (200, 150)) ] window.make_same_width() assert mock_manager.make_same_width.called assert window._update_view_called assert "same width" in window._status_message.lower() class TestMakeSameHeight: """Test make_same_height method""" @patch('pyPhotoAlbum.mixins.operations.size_ops.AlignmentManager') def test_make_same_height_success(self, mock_manager, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element1 = ImageData(image_path="/test1.jpg", x=0, y=0, width=100, height=100) element2 = ImageData(image_path="/test2.jpg", x=150, y=0, width=200, height=150) window.gl_widget.selected_elements = {element1, element2} mock_manager.make_same_height.return_value = [ (element1, (0, 0), (100, 100)), (element2, (150, 0), (200, 150)) ] window.make_same_height() assert mock_manager.make_same_height.called assert window._update_view_called assert "same height" in window._status_message.lower() class TestFitToWidth: """Test fit_to_width method""" @patch('pyPhotoAlbum.mixins.operations.size_ops.AlignmentManager') def test_fit_to_width_success(self, mock_manager, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element = ImageData(image_path="/test.jpg", x=50, y=50, width=100, height=100) window.gl_widget.selected_elements = {element} # Setup page page = Mock() page.layout = Mock() page.layout.size = (210, 297) # A4 window._current_page = page mock_manager.fit_to_page_width.return_value = (element, (50, 50), (100, 100)) window.fit_to_width() assert mock_manager.fit_to_page_width.called assert window._update_view_called assert "width" in window._status_message.lower() def test_fit_to_width_no_page(self, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element = ImageData(image_path="/test.jpg", x=50, y=50, width=100, height=100) window.gl_widget.selected_elements = {element} window._current_page = None window.fit_to_width() assert "page" in window._warning_message.lower() assert not window._update_view_called class TestFitToHeight: """Test fit_to_height method""" @patch('pyPhotoAlbum.mixins.operations.size_ops.AlignmentManager') def test_fit_to_height_success(self, mock_manager, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element = ImageData(image_path="/test.jpg", x=50, y=50, width=100, height=100) window.gl_widget.selected_elements = {element} page = Mock() page.layout = Mock() page.layout.size = (210, 297) window._current_page = page mock_manager.fit_to_page_height.return_value = (element, (50, 50), (100, 100)) window.fit_to_height() assert mock_manager.fit_to_page_height.called assert window._update_view_called assert "height" in window._status_message.lower() class TestFitToPage: """Test fit_to_page method""" @patch('pyPhotoAlbum.mixins.operations.size_ops.AlignmentManager') def test_fit_to_page_success(self, mock_manager, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element = ImageData(image_path="/test.jpg", x=50, y=50, width=100, height=100) window.gl_widget.selected_elements = {element} page = Mock() page.layout = Mock() page.layout.size = (210, 297) window._current_page = page mock_manager.fit_to_page.return_value = (element, (50, 50), (100, 100)) window.fit_to_page() assert mock_manager.fit_to_page.called assert window._update_view_called assert "fitted element to page" in window._status_message.lower() def test_fit_to_page_no_page(self, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element = ImageData(image_path="/test.jpg", x=50, y=50, width=100, height=100) window.gl_widget.selected_elements = {element} window._current_page = None window.fit_to_page() assert "page" in window._warning_message.lower() assert not window._update_view_called class TestSizeCommandPattern: """Test size operations with command pattern""" @patch('pyPhotoAlbum.mixins.operations.size_ops.AlignmentManager') def test_size_operation_creates_command(self, mock_manager, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element1 = ImageData(image_path="/test1.jpg", x=0, y=0, width=100, height=100) element2 = ImageData(image_path="/test2.jpg", x=150, y=0, width=200, height=150) window.gl_widget.selected_elements = {element1, element2} mock_manager.make_same_size.return_value = [ (element1, (0, 0), (100, 100)), (element2, (150, 0), (200, 150)) ] assert not window.project.history.can_undo() window.make_same_size() assert window.project.history.can_undo() @patch('pyPhotoAlbum.mixins.operations.size_ops.AlignmentManager') def test_fit_operation_creates_command(self, mock_manager, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element = ImageData(image_path="/test.jpg", x=50, y=50, width=100, height=100) window.gl_widget.selected_elements = {element} page = Mock() page.layout = Mock() page.layout.size = (210, 297) window._current_page = page mock_manager.fit_to_page.return_value = (element, (50, 50), (100, 100)) assert not window.project.history.can_undo() window.fit_to_page() assert window.project.history.can_undo() class TestExpandImage: """Test expand_image method""" @patch('pyPhotoAlbum.mixins.operations.size_ops.AlignmentManager') def test_expand_image_success(self, mock_manager, qtbot): window = TestSizeWindow() qtbot.addWidget(window) # Create an element to expand element = ImageData(image_path="/test.jpg", x=50, y=50, width=50, height=50) window.gl_widget.selected_elements = {element} # Create a mock page with other elements page = Mock() page.layout = Mock() page.layout.size = (210, 297) page.layout.snapping_system = Mock() page.layout.snapping_system.grid_spacing = 10.0 # Mock other elements on the page other_element = ImageData(image_path="/other.jpg", x=150, y=50, width=50, height=50) page.layout.elements = [element, other_element] window._current_page = page # Mock the expand_to_bounds return value mock_manager.expand_to_bounds.return_value = (element, (50, 50), (50, 50)) window.expand_image() # Verify that expand_to_bounds was called with correct parameters assert mock_manager.expand_to_bounds.called call_args = mock_manager.expand_to_bounds.call_args assert call_args[0][0] == element # First arg is the element assert call_args[0][1] == (210, 297) # Second arg is page size assert other_element in call_args[0][2] # Third arg includes other elements assert element not in call_args[0][2] # But not the selected element itself assert call_args[0][3] == 10.0 # Fourth arg is min_gap assert window._update_view_called assert "expanded image" in window._status_message.lower() assert "10" in window._status_message # Gap size mentioned def test_expand_image_no_page(self, qtbot): window = TestSizeWindow() qtbot.addWidget(window) element = ImageData(image_path="/test.jpg", x=50, y=50, width=50, height=50) window.gl_widget.selected_elements = {element} window._current_page = None window.expand_image() assert "page" in window._warning_message.lower() assert not window._update_view_called def test_expand_image_insufficient_selection(self, qtbot): window = TestSizeWindow() qtbot.addWidget(window) window.gl_widget.selected_elements = set() window.expand_image() assert window._require_selection_count == 1 assert not window._update_view_called