""" Unit tests for pyPhotoAlbum models """ import pytest from pyPhotoAlbum.models import ImageData, PlaceholderData, TextBoxData, BaseLayoutElement class TestBaseLayoutElement: """Tests for BaseLayoutElement abstract class""" def test_cannot_instantiate_abstract_class(self): """Test that BaseLayoutElement cannot be instantiated directly""" with pytest.raises(TypeError): BaseLayoutElement() class TestImageData: """Tests for ImageData class""" def test_initialization_default(self): """Test ImageData initialization with default values""" img = ImageData() assert img.image_path == "" assert img.position == (0, 0) assert img.size == (100, 100) assert img.rotation == 0 assert img.z_index == 0 assert img.crop_info == (0, 0, 1, 1) def test_initialization_with_parameters(self, temp_image_file): """Test ImageData initialization with custom parameters""" img = ImageData( image_path=temp_image_file, x=10.0, y=20.0, width=200.0, height=150.0, rotation=45.0, z_index=5 ) assert img.image_path == temp_image_file assert img.position == (10.0, 20.0) assert img.size == (200.0, 150.0) assert img.rotation == 45.0 assert img.z_index == 5 def test_initialization_with_crop_info(self): """Test ImageData initialization with custom crop info""" crop = (0.1, 0.2, 0.8, 0.9) img = ImageData(image_path="test.jpg", crop_info=crop) assert img.crop_info == crop def test_serialization(self, temp_image_file): """Test ImageData serialization to dictionary""" img = ImageData( image_path=temp_image_file, x=15.0, y=25.0, width=180.0, height=120.0, rotation=30.0, z_index=3 ) data = img.serialize() assert data["type"] == "image" assert data["image_path"] == temp_image_file assert data["position"] == (15.0, 25.0) assert data["size"] == (180.0, 120.0) assert data["rotation"] == 30.0 assert data["z_index"] == 3 assert data["crop_info"] == (0, 0, 1, 1) def test_deserialization(self): """Test ImageData deserialization from dictionary""" img = ImageData() data = { "position": (30.0, 40.0), "size": (220.0, 180.0), "rotation": 90.0, "z_index": 7, "image_path": "new_image.jpg", "crop_info": (0.2, 0.3, 0.7, 0.8) } img.deserialize(data) assert img.position == (30.0, 40.0) assert img.size == (220.0, 180.0) assert img.rotation == 90.0 assert img.z_index == 7 assert img.image_path == "new_image.jpg" assert img.crop_info == (0.2, 0.3, 0.7, 0.8) def test_deserialization_with_defaults(self): """Test ImageData deserialization with missing fields uses defaults""" img = ImageData() data = {"image_path": "test.jpg"} img.deserialize(data) assert img.position == (0, 0) assert img.size == (100, 100) assert img.rotation == 0 assert img.z_index == 0 assert img.crop_info == (0, 0, 1, 1) def test_serialize_deserialize_roundtrip(self, temp_image_file): """Test that serialize and deserialize are inverse operations""" original = ImageData( image_path=temp_image_file, x=50.0, y=60.0, width=300.0, height=200.0, rotation=15.0, z_index=2, crop_info=(0.1, 0.1, 0.9, 0.9) ) data = original.serialize() restored = ImageData() restored.deserialize(data) assert restored.image_path == original.image_path assert restored.position == original.position assert restored.size == original.size assert restored.rotation == original.rotation assert restored.z_index == original.z_index assert restored.crop_info == original.crop_info def test_position_modification(self): """Test modifying position after initialization""" img = ImageData() img.position = (100.0, 200.0) assert img.position == (100.0, 200.0) def test_size_modification(self): """Test modifying size after initialization""" img = ImageData() img.size = (400.0, 300.0) assert img.size == (400.0, 300.0) class TestPlaceholderData: """Tests for PlaceholderData class""" def test_initialization_default(self): """Test PlaceholderData initialization with default values""" placeholder = PlaceholderData() assert placeholder.placeholder_type == "image" assert placeholder.default_content == "" assert placeholder.position == (0, 0) assert placeholder.size == (100, 100) assert placeholder.rotation == 0 assert placeholder.z_index == 0 def test_initialization_with_parameters(self): """Test PlaceholderData initialization with custom parameters""" placeholder = PlaceholderData( placeholder_type="text", default_content="Sample", x=20.0, y=30.0, width=150.0, height=100.0, rotation=10.0, z_index=4 ) assert placeholder.placeholder_type == "text" assert placeholder.default_content == "Sample" assert placeholder.position == (20.0, 30.0) assert placeholder.size == (150.0, 100.0) assert placeholder.rotation == 10.0 assert placeholder.z_index == 4 def test_serialization(self): """Test PlaceholderData serialization to dictionary""" placeholder = PlaceholderData( placeholder_type="image", default_content="placeholder.jpg", x=40.0, y=50.0, width=200.0, height=150.0, rotation=20.0, z_index=2 ) data = placeholder.serialize() assert data["type"] == "placeholder" assert data["placeholder_type"] == "image" assert data["default_content"] == "placeholder.jpg" assert data["position"] == (40.0, 50.0) assert data["size"] == (200.0, 150.0) assert data["rotation"] == 20.0 assert data["z_index"] == 2 def test_deserialization(self): """Test PlaceholderData deserialization from dictionary""" placeholder = PlaceholderData() data = { "position": (60.0, 70.0), "size": (250.0, 180.0), "rotation": 45.0, "z_index": 6, "placeholder_type": "text", "default_content": "Default Text" } placeholder.deserialize(data) assert placeholder.position == (60.0, 70.0) assert placeholder.size == (250.0, 180.0) assert placeholder.rotation == 45.0 assert placeholder.z_index == 6 assert placeholder.placeholder_type == "text" assert placeholder.default_content == "Default Text" def test_deserialization_with_defaults(self): """Test PlaceholderData deserialization with missing fields uses defaults""" placeholder = PlaceholderData() data = {"placeholder_type": "image"} placeholder.deserialize(data) assert placeholder.position == (0, 0) assert placeholder.size == (100, 100) assert placeholder.rotation == 0 assert placeholder.z_index == 0 assert placeholder.default_content == "" def test_serialize_deserialize_roundtrip(self): """Test that serialize and deserialize are inverse operations""" original = PlaceholderData( placeholder_type="image", default_content="test.jpg", x=80.0, y=90.0, width=300.0, height=250.0, rotation=60.0, z_index=8 ) data = original.serialize() restored = PlaceholderData() restored.deserialize(data) assert restored.placeholder_type == original.placeholder_type assert restored.default_content == original.default_content assert restored.position == original.position assert restored.size == original.size assert restored.rotation == original.rotation assert restored.z_index == original.z_index class TestTextBoxData: """Tests for TextBoxData class""" def test_initialization_default(self): """Test TextBoxData initialization with default values""" textbox = TextBoxData() assert textbox.text_content == "" assert textbox.font_settings == {"family": "Arial", "size": 12, "color": (0, 0, 0)} assert textbox.alignment == "left" assert textbox.position == (0, 0) assert textbox.size == (100, 100) assert textbox.rotation == 0 assert textbox.z_index == 0 def test_initialization_with_parameters(self): """Test TextBoxData initialization with custom parameters""" font_settings = {"family": "Times", "size": 14, "color": (255, 0, 0)} textbox = TextBoxData( text_content="Hello World", font_settings=font_settings, alignment="center", x=25.0, y=35.0, width=180.0, height=60.0, rotation=5.0, z_index=3 ) assert textbox.text_content == "Hello World" assert textbox.font_settings == font_settings assert textbox.alignment == "center" assert textbox.position == (25.0, 35.0) assert textbox.size == (180.0, 60.0) assert textbox.rotation == 5.0 assert textbox.z_index == 3 def test_serialization(self): """Test TextBoxData serialization to dictionary""" font_settings = {"family": "Helvetica", "size": 16, "color": (0, 0, 255)} textbox = TextBoxData( text_content="Test Text", font_settings=font_settings, alignment="right", x=45.0, y=55.0, width=220.0, height=80.0, rotation=15.0, z_index=5 ) data = textbox.serialize() assert data["type"] == "textbox" assert data["text_content"] == "Test Text" assert data["font_settings"] == font_settings assert data["alignment"] == "right" assert data["position"] == (45.0, 55.0) assert data["size"] == (220.0, 80.0) assert data["rotation"] == 15.0 assert data["z_index"] == 5 def test_deserialization(self): """Test TextBoxData deserialization from dictionary""" textbox = TextBoxData() font_settings = {"family": "Courier", "size": 18, "color": (128, 128, 128)} data = { "position": (65.0, 75.0), "size": (260.0, 100.0), "rotation": 30.0, "z_index": 7, "text_content": "Deserialized Text", "font_settings": font_settings, "alignment": "justify" } textbox.deserialize(data) assert textbox.position == (65.0, 75.0) assert textbox.size == (260.0, 100.0) assert textbox.rotation == 30.0 assert textbox.z_index == 7 assert textbox.text_content == "Deserialized Text" assert textbox.font_settings == font_settings assert textbox.alignment == "justify" def test_deserialization_with_defaults(self): """Test TextBoxData deserialization with missing fields uses defaults""" textbox = TextBoxData() data = {"text_content": "Minimal"} textbox.deserialize(data) assert textbox.position == (0, 0) assert textbox.size == (100, 100) assert textbox.rotation == 0 assert textbox.z_index == 0 assert textbox.font_settings == {"family": "Arial", "size": 12, "color": (0, 0, 0)} assert textbox.alignment == "left" def test_serialize_deserialize_roundtrip(self): """Test that serialize and deserialize are inverse operations""" font_settings = {"family": "Georgia", "size": 20, "color": (255, 255, 0)} original = TextBoxData( text_content="Round Trip Test", font_settings=font_settings, alignment="center", x=85.0, y=95.0, width=320.0, height=120.0, rotation=25.0, z_index=9 ) data = original.serialize() restored = TextBoxData() restored.deserialize(data) assert restored.text_content == original.text_content assert restored.font_settings == original.font_settings assert restored.alignment == original.alignment assert restored.position == original.position assert restored.size == original.size assert restored.rotation == original.rotation assert restored.z_index == original.z_index def test_text_content_modification(self): """Test modifying text content after initialization""" textbox = TextBoxData() textbox.text_content = "Modified Text" assert textbox.text_content == "Modified Text" def test_font_settings_modification(self): """Test modifying font settings after initialization""" textbox = TextBoxData() new_font = {"family": "Verdana", "size": 24, "color": (100, 200, 50)} textbox.font_settings = new_font assert textbox.font_settings == new_font def test_alignment_modification(self): """Test modifying alignment after initialization""" textbox = TextBoxData() textbox.alignment = "right" assert textbox.alignment == "right" class TestElementComparison: """Tests comparing different element types""" def test_different_element_types_serialize_differently(self): """Test that different element types have different serialization""" img = ImageData(x=10, y=10) placeholder = PlaceholderData(x=10, y=10) textbox = TextBoxData(x=10, y=10) img_data = img.serialize() placeholder_data = placeholder.serialize() textbox_data = textbox.serialize() assert img_data["type"] == "image" assert placeholder_data["type"] == "placeholder" assert textbox_data["type"] == "textbox" def test_z_index_comparison(self): """Test that z_index can be used for layering""" img1 = ImageData(z_index=1) img2 = ImageData(z_index=5) img3 = ImageData(z_index=3) elements = [img1, img2, img3] sorted_elements = sorted(elements, key=lambda e: e.z_index) assert sorted_elements[0].z_index == 1 assert sorted_elements[1].z_index == 3 assert sorted_elements[2].z_index == 5