""" 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()