Files
Text-Texture-Generator-for-…/tests/unit/ui/test_panel_layout_overhaul.py
2025-10-13 13:35:52 +02:00

206 lines
6.4 KiB
Python

"""Tests for the overhauled Positioning & Layout UI."""
from types import SimpleNamespace
import importlib
import pytest
panels = importlib.import_module("src.ui.panels")
class FakeLayout:
"""Minimal substitute for Blender layout that records UI calls."""
def __init__(self, kind="layout"):
self.kind = kind
self.calls = []
self.children = []
self.enabled = True
self.alignment = None
self.scale_x = 1.0
self.scale_y = 1.0
self.use_property_split = False
self.use_property_decorate = True
def _child(self, kind, kwargs):
child = FakeLayout(kind)
self.calls.append((kind, kwargs, child))
self.children.append(child)
return child
def label(self, text="", **kwargs):
self.calls.append(("label", {"text": text, **kwargs}))
return None
def prop(self, props, prop_name, **kwargs):
# Access attribute to mirror Blender's behaviour of raising AttributeError
getattr(props, prop_name)
data = {"name": prop_name}
data.update(kwargs)
self.calls.append(("prop", data))
return None
def separator(self, **kwargs):
self.calls.append(("separator", kwargs))
return None
def row(self, **kwargs):
return self._child("row", kwargs)
def column(self, **kwargs):
return self._child("column", kwargs)
def box(self):
return self._child("box", {})
def operator(self, operator_id, **kwargs):
self.calls.append(("operator", {"id": operator_id, **kwargs}))
return SimpleNamespace()
def collect_calls(layout):
"""Flatten recorded calls from layout tree."""
flattened = []
for entry in layout.calls:
if len(entry) == 3:
kind, kwargs, child = entry
flattened.append((kind, kwargs))
flattened.extend(collect_calls(child))
else:
flattened.append(entry)
return flattened
def make_default_props(**overrides):
"""Helper to build a props namespace with defaults for positioning tests."""
defaults = dict(
text="Main",
texture_width=1024,
texture_height=1024,
prepend_text="",
append_text="",
prepend_margin=10.0,
append_margin=10.0,
prepend_append_layout="HORIZONTAL",
position_mode="PRESET",
anchor_point="MIDDLE_CENTER",
margins_linked=False,
margin_x=0.0,
margin_y=0.0,
offset_x=0,
offset_y=0,
manual_position_unit="PERCENTAGE",
manual_position_x=50.0,
manual_position_y=50.0,
constrain_to_canvas=True,
image_overlays=[],
active_overlay_index=0,
)
defaults.update(overrides)
return SimpleNamespace(**defaults)
def test_text_input_section_exposes_dimensions():
"""Dimensions should appear alongside the main text control."""
layout = FakeLayout()
props = make_default_props()
panels.draw_text_input_section(layout, props)
calls = collect_calls(layout)
prop_names = [data["name"] for kind, data in calls if kind == "prop"]
assert "texture_width" in prop_names
assert "texture_height" in prop_names
def test_positioning_section_drops_additional_text(monkeypatch):
"""Positioning panel should no longer render prepend/append controls."""
layout = FakeLayout()
props = make_default_props()
monkeypatch.setattr("src.utils.system.get_anchor_point_matrix", lambda: [["CENTER"]])
monkeypatch.setattr(panels, "safe_operator_call", lambda *args, **kwargs: SimpleNamespace())
panels.draw_positioning_section(layout, props)
calls = collect_calls(layout)
labels = [data["text"] for kind, data in calls if kind == "label"]
prop_names = [data["name"] for kind, data in calls if kind == "prop"]
assert "Additional Text:" not in labels
assert "prepend_text" not in prop_names
assert "append_text" not in prop_names
def test_composition_section_renders_text_component(monkeypatch):
"""Composition panel should show text component controls within the proper section."""
layout = FakeLayout()
text_component = SimpleNamespace(
enabled=True,
name="Intro Text",
component_type="TEXT",
placement_mode="PREPEND",
text_content="Intro",
text_spacing=10.0,
image_spacing=5.0,
x_position=0.5,
y_position=0.5,
scale=1.0,
rotation=0.0,
z_index=0,
)
props = make_default_props(image_overlays=[text_component])
monkeypatch.setattr(panels, "safe_operator_call", lambda *args, **kwargs: SimpleNamespace())
monkeypatch.setattr(panels, "has_image_overlays", lambda: True)
panels.draw_composition_section(layout, props)
calls = collect_calls(layout)
prop_names = [data["name"] for kind, data in calls if kind == "prop"]
labels = [data["text"] for kind, data in calls if kind == "label"]
sections = [text for text in labels if "Components" in text]
assert "component_type" in prop_names
assert "text_content" in prop_names
assert "placement_mode" in prop_names
assert "text_spacing" in prop_names
assert "Prepended Components" in sections
def test_composition_section_renders_image_component(monkeypatch):
"""Composition panel should show image component controls within the proper section."""
layout = FakeLayout()
image_component = SimpleNamespace(
enabled=True,
name="Logo",
component_type="IMAGE",
placement_mode="ABSOLUTE",
image_path="/tmp/logo.png",
x_position=0.5,
y_position=0.5,
text_spacing=10.0,
image_spacing=5.0,
scale=1.0,
rotation=0.0,
z_index=1,
)
props = make_default_props(image_overlays=[image_component])
monkeypatch.setattr(panels, "safe_operator_call", lambda *args, **kwargs: SimpleNamespace())
monkeypatch.setattr(panels, "has_image_overlays", lambda: True)
panels.draw_composition_section(layout, props)
calls = collect_calls(layout)
prop_names = [data["name"] for kind, data in calls if kind == "prop"]
labels = [data["text"] for kind, data in calls if kind == "label"]
sections = [text for text in labels if "Components" in text]
assert "component_type" in prop_names
assert "image_path" in prop_names
assert "placement_mode" in prop_names
assert "x_position" in prop_names
assert "Absolute Components" in sections