"""Tests for image transformation validation.""" import pytest from pydantic import ValidationError from app.images.schemas import BoardImageUpdate def test_valid_transformations(): """Test that valid transformations are accepted.""" data = BoardImageUpdate( transformations={ "scale": 1.5, "rotation": 45, "opacity": 0.8, "flipped_h": True, "flipped_v": False, "greyscale": False, } ) assert data.transformations is not None assert data.transformations["scale"] == 1.5 assert data.transformations["rotation"] == 45 assert data.transformations["opacity"] == 0.8 assert data.transformations["flipped_h"] is True assert data.transformations["greyscale"] is False def test_minimal_transformations(): """Test that minimal transformation data is accepted.""" data = BoardImageUpdate( transformations={ "scale": 1.0, "rotation": 0, "opacity": 1.0, } ) assert data.transformations is not None def test_transformation_scale_bounds(): """Test scale bounds validation.""" # Valid scales valid_scales = [0.01, 0.5, 1.0, 5.0, 10.0] for scale in valid_scales: data = BoardImageUpdate(transformations={"scale": scale}) assert data.transformations["scale"] == scale def test_transformation_rotation_bounds(): """Test rotation bounds (any value allowed, normalized client-side).""" # Various rotation values rotations = [0, 45, 90, 180, 270, 360, 450, -90] for rotation in rotations: data = BoardImageUpdate(transformations={"rotation": rotation}) assert data.transformations["rotation"] == rotation def test_transformation_opacity_bounds(): """Test opacity bounds.""" # Valid opacity values valid_opacities = [0.0, 0.25, 0.5, 0.75, 1.0] for opacity in valid_opacities: data = BoardImageUpdate(transformations={"opacity": opacity}) assert data.transformations["opacity"] == opacity def test_transformation_boolean_flags(): """Test boolean transformation flags.""" data = BoardImageUpdate( transformations={ "flipped_h": True, "flipped_v": True, "greyscale": True, } ) assert data.transformations["flipped_h"] is True assert data.transformations["flipped_v"] is True assert data.transformations["greyscale"] is True def test_transformation_crop_data(): """Test crop transformation data.""" data = BoardImageUpdate( transformations={ "crop": { "x": 10, "y": 10, "width": 100, "height": 100, } } ) assert data.transformations["crop"] is not None assert data.transformations["crop"]["x"] == 10 assert data.transformations["crop"]["width"] == 100 def test_transformation_null_crop(): """Test that crop can be null (no crop).""" data = BoardImageUpdate( transformations={ "crop": None, } ) assert data.transformations["crop"] is None def test_partial_transformation_update(): """Test updating only some transformation fields.""" # Only update scale data = BoardImageUpdate(transformations={"scale": 2.0}) assert data.transformations["scale"] == 2.0 # Only update rotation data = BoardImageUpdate(transformations={"rotation": 90}) assert data.transformations["rotation"] == 90 # Only update opacity data = BoardImageUpdate(transformations={"opacity": 0.5}) assert data.transformations["opacity"] == 0.5 def test_complete_transformation_update(): """Test updating all transformation fields.""" data = BoardImageUpdate( transformations={ "scale": 1.5, "rotation": 45, "opacity": 0.8, "flipped_h": True, "flipped_v": False, "greyscale": True, "crop": { "x": 20, "y": 20, "width": 150, "height": 150, }, } ) assert data.transformations is not None assert len(data.transformations) == 7 def test_position_validation_with_transformations(): """Test that position and transformations can be updated together.""" data = BoardImageUpdate( position={"x": 100, "y": 200}, transformations={"scale": 1.5, "rotation": 45}, ) assert data.position == {"x": 100, "y": 200} assert data.transformations["scale"] == 1.5 assert data.transformations["rotation"] == 45 def test_invalid_position_missing_x(): """Test that position without x coordinate is rejected.""" with pytest.raises(ValidationError) as exc_info: BoardImageUpdate(position={"y": 100}) assert "must contain 'x' and 'y'" in str(exc_info.value) def test_invalid_position_missing_y(): """Test that position without y coordinate is rejected.""" with pytest.raises(ValidationError) as exc_info: BoardImageUpdate(position={"x": 100}) assert "must contain 'x' and 'y'" in str(exc_info.value) def test_z_order_update(): """Test Z-order update.""" data = BoardImageUpdate(z_order=5) assert data.z_order == 5 # Negative Z-order allowed (layering) data = BoardImageUpdate(z_order=-1) assert data.z_order == -1 # Large Z-order allowed data = BoardImageUpdate(z_order=999999) assert data.z_order == 999999 def test_group_id_update(): """Test group ID update.""" from uuid import uuid4 group_id = uuid4() data = BoardImageUpdate(group_id=group_id) assert data.group_id == group_id # Null group ID (remove from group) data = BoardImageUpdate(group_id=None) assert data.group_id is None def test_empty_update(): """Test that empty update (no fields) is valid.""" data = BoardImageUpdate() assert data.position is None assert data.transformations is None assert data.z_order is None assert data.group_id is None def test_transformation_data_types(): """Test that transformation data types are validated.""" # Valid types data = BoardImageUpdate( transformations={ "scale": 1.5, # float "rotation": 45, # int (converted to float) "opacity": 0.8, # float "flipped_h": True, # bool "flipped_v": False, # bool "greyscale": True, # bool } ) assert isinstance(data.transformations["scale"], (int, float)) assert isinstance(data.transformations["flipped_h"], bool)