pyPhotoAlbum/tests/test_interaction_command_factory.py
Duncan Tourolle f6ed11b0bc
All checks were successful
Python CI / test (push) Successful in 1m20s
Lint / lint (push) Successful in 1m4s
Tests / test (3.11) (push) Successful in 1m27s
Tests / test (3.12) (push) Successful in 2m25s
Tests / test (3.13) (push) Successful in 2m52s
Tests / test (3.14) (push) Successful in 1m9s
black formatting
2025-11-27 23:07:16 +01:00

234 lines
7.4 KiB
Python

"""
Unit tests for interaction command factory.
"""
import pytest
from unittest.mock import Mock
from pyPhotoAlbum.mixins.interaction_command_factory import InteractionCommandFactory, InteractionState
from pyPhotoAlbum.mixins.interaction_command_builders import CommandBuilder
class TestInteractionState:
"""Tests for InteractionState value object."""
def test_initialization(self):
"""Test that InteractionState initializes correctly."""
element = Mock()
state = InteractionState(
element=element, interaction_type="move", position=(0.0, 0.0), size=(100.0, 100.0), rotation=0.0
)
assert state.element == element
assert state.interaction_type == "move"
assert state.position == (0.0, 0.0)
assert state.size == (100.0, 100.0)
assert state.rotation == 0.0
def test_to_dict(self):
"""Test that to_dict returns correct dictionary."""
state = InteractionState(position=(0.0, 0.0), size=(100.0, 100.0))
result = state.to_dict()
assert result == {"position": (0.0, 0.0), "size": (100.0, 100.0)}
def test_to_dict_excludes_none(self):
"""Test that to_dict excludes None values."""
state = InteractionState(position=(0.0, 0.0), size=None)
result = state.to_dict()
assert "position" in result
assert "size" not in result
def test_is_valid_with_required_fields(self):
"""Test that is_valid returns True when required fields are present."""
element = Mock()
state = InteractionState(element=element, interaction_type="move")
assert state.is_valid()
def test_is_valid_without_element(self):
"""Test that is_valid returns False without element."""
state = InteractionState(element=None, interaction_type="move")
assert not state.is_valid()
def test_is_valid_without_interaction_type(self):
"""Test that is_valid returns False without interaction_type."""
element = Mock()
state = InteractionState(element=element, interaction_type=None)
assert not state.is_valid()
def test_clear(self):
"""Test that clear resets all fields."""
element = Mock()
state = InteractionState(
element=element, interaction_type="move", position=(0.0, 0.0), size=(100.0, 100.0), rotation=0.0
)
state.clear()
assert state.element is None
assert state.interaction_type is None
assert state.position is None
assert state.size is None
assert state.rotation is None
class TestInteractionCommandFactory:
"""Tests for InteractionCommandFactory."""
def test_initialization_registers_default_builders(self):
"""Test that factory initializes with default builders."""
factory = InteractionCommandFactory()
assert factory.has_builder("move")
assert factory.has_builder("resize")
assert factory.has_builder("rotate")
assert factory.has_builder("image_pan")
def test_register_builder(self):
"""Test registering a custom builder."""
factory = InteractionCommandFactory()
custom_builder = Mock(spec=CommandBuilder)
factory.register_builder("custom", custom_builder)
assert factory.has_builder("custom")
def test_get_supported_types(self):
"""Test getting list of supported types."""
factory = InteractionCommandFactory()
types = factory.get_supported_types()
assert "move" in types
assert "resize" in types
assert "rotate" in types
assert "image_pan" in types
def test_create_command_move(self):
"""Test creating a move command."""
factory = InteractionCommandFactory()
element = Mock()
element.position = (10.0, 10.0)
start_state = {"position": (0.0, 0.0)}
command = factory.create_command("move", element, start_state)
assert command is not None
def test_create_command_resize(self):
"""Test creating a resize command."""
factory = InteractionCommandFactory()
element = Mock()
element.position = (10.0, 10.0)
element.size = (200.0, 200.0)
start_state = {"position": (0.0, 0.0), "size": (100.0, 100.0)}
command = factory.create_command("resize", element, start_state)
assert command is not None
def test_create_command_rotate(self):
"""Test creating a rotate command."""
factory = InteractionCommandFactory()
element = Mock()
element.rotation = 45.0
start_state = {"rotation": 0.0}
command = factory.create_command("rotate", element, start_state)
assert command is not None
def test_create_command_unknown_type(self, capsys):
"""Test creating command with unknown type."""
factory = InteractionCommandFactory()
element = Mock()
command = factory.create_command("unknown", element, {})
assert command is None
captured = capsys.readouterr()
assert "No builder registered for interaction type 'unknown'" in captured.out
def test_create_command_no_significant_change(self):
"""Test that no command is created for insignificant changes."""
factory = InteractionCommandFactory()
element = Mock()
element.position = (0.05, 0.05)
start_state = {"position": (0.0, 0.0)}
command = factory.create_command("move", element, start_state)
assert command is None
def test_create_command_with_custom_builder(self):
"""Test using a custom builder."""
factory = InteractionCommandFactory()
# Create a mock builder that always returns a mock command
custom_builder = Mock(spec=CommandBuilder)
mock_command = Mock()
custom_builder.can_build.return_value = True
custom_builder.build.return_value = mock_command
factory.register_builder("custom", custom_builder)
element = Mock()
start_state = {"position": (0.0, 0.0)}
command = factory.create_command("custom", element, start_state)
assert command == mock_command
custom_builder.can_build.assert_called_once()
custom_builder.build.assert_called_once()
class TestInteractionStateIntegration:
"""Integration tests for InteractionState with factory."""
def test_state_to_dict_with_factory(self):
"""Test that state.to_dict() works with factory."""
factory = InteractionCommandFactory()
element = Mock()
element.position = (10.0, 10.0)
state = InteractionState(element=element, interaction_type="move", position=(0.0, 0.0))
command = factory.create_command(state.interaction_type, state.element, state.to_dict())
assert command is not None
def test_state_lifecycle(self):
"""Test complete lifecycle of interaction state."""
element = Mock()
element.position = (0.0, 0.0)
# Begin interaction
state = InteractionState()
state.element = element
state.interaction_type = "move"
state.position = element.position
assert state.is_valid()
# Simulate movement
element.position = (10.0, 10.0)
# Create command
factory = InteractionCommandFactory()
command = factory.create_command(state.interaction_type, state.element, state.to_dict())
assert command is not None
# Clear state
state.clear()
assert not state.is_valid()