237 lines
6.5 KiB
Python
237 lines
6.5 KiB
Python
"""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)
|
|
|