This commit is contained in:
2025-10-14 12:23:58 +02:00
parent cf4f3ce564
commit f8dc03caf9
21 changed files with 384 additions and 43 deletions

View File

@@ -3,10 +3,16 @@
from unittest.mock import Mock, patch, MagicMock, call
import pytest
from types import SimpleNamespace
from src.operators.generation_ops import (
TEXT_TEXTURE_OT_generate,
TEXT_TEXTURE_OT_preview,
TEXT_TEXTURE_OT_generate_shader
TEXT_TEXTURE_OT_generate_shader,
TEXT_TEXTURE_OT_generate_plane,
TEXT_TEXTURE_OT_reset_settings,
_sanitize_text_for_name,
_resolve_material_name,
)
@@ -41,6 +47,35 @@ def create_mock_props(text="test", width=512, height=512, **kwargs):
return props
class DummyModifiers:
"""Simple stand-in for Blender's modifier collection."""
def __init__(self):
self.created = []
def new(self, name, mod_type=None, **kwargs):
mod_type = mod_type or kwargs.get('type')
modifier = SimpleNamespace(
name=name,
type=mod_type,
subdivision_type='CATMULL_CLARK',
levels=0,
render_levels=0,
)
self.created.append(modifier)
return modifier
class DummyCollection:
"""Simple collection helper with clear tracking."""
def __init__(self):
self.cleared = False
def clear(self):
self.cleared = True
def create_mock_context(props=None, **kwargs):
"""Create mock Blender context with scene properties.
@@ -533,4 +568,115 @@ class TestGenerateShaderOperator:
invalid_context.scene = None
assert TEXT_TEXTURE_OT_generate_shader.poll(invalid_context) is False
else:
pytest.skip("Operator does not implement poll method")
pytest.skip("Operator does not implement poll method")
class TestGenerationHelpers:
"""Unit tests for helper utilities in generation_ops."""
def test_sanitize_text_removes_invalid_characters(self):
assert _sanitize_text_for_name("Hello @World!!!") == "Hello_World"
def test_sanitize_text_truncates_and_defaults(self):
assert _sanitize_text_for_name(" " * 5 + "--") == "Texture"
assert len(_sanitize_text_for_name("A" * 50)) == 20
def test_resolve_material_uses_custom_name(self):
props = create_mock_props()
props.custom_material_name = " Custom Mat "
assert _resolve_material_name(props, "Ignored") == "Custom Mat"
def test_resolve_material_defaults_to_sanitized(self):
props = create_mock_props()
props.custom_material_name = ""
assert _resolve_material_name(props, "Sample") == "TextTexture_Mat_Sample"
class TestGeneratePlaneOperator:
"""Tests for the Create Plane operator."""
def test_generate_plane_success(self):
op = TEXT_TEXTURE_OT_generate_plane()
op.report = Mock()
props = create_mock_props(text="Plane Test", width=800, height=400)
context = create_mock_context(props)
plane = SimpleNamespace(
type='MESH',
name='Plane',
scale=SimpleNamespace(x=1.0, y=1.0, z=1.0),
modifiers=DummyModifiers(),
data=SimpleNamespace(materials=[]),
)
context.active_object = plane
mat = SimpleNamespace(name="TextTexture_Mat_Plane_Test")
with patch('src.operators.generation_ops.bpy') as mock_bpy:
mock_bpy.ops.text_texture.generate_shader.return_value = {'FINISHED'}
mock_bpy.ops.mesh.primitive_plane_add.return_value = None
mock_bpy.data.materials.get.return_value = mat
result = op.execute(context)
assert result == {'FINISHED'}
assert pytest.approx(plane.scale.x, rel=1e-6) == 2.0
assert pytest.approx(plane.scale.y, rel=1e-6) == 1.0
assert plane.modifiers.created[0].subdivision_type == 'SIMPLE'
assert plane.modifiers.created[0].levels == 1
assert plane.data.materials[0] is mat
def test_generate_plane_handles_shader_failure(self):
op = TEXT_TEXTURE_OT_generate_plane()
op.report = Mock()
props = create_mock_props()
context = create_mock_context(props)
with patch('src.operators.generation_ops.bpy') as mock_bpy:
mock_bpy.ops.text_texture.generate_shader.return_value = {'CANCELLED'}
result = op.execute(context)
assert result == {'CANCELLED'}
op.report.assert_called()
class TestResetSettingsOperator:
"""Tests for the reset settings operator."""
class DummyProps:
__annotations__ = {
'text': None,
'image_overlays': None,
'preset_search_query': None,
}
def __init__(self):
self.text = "Custom"
self.image_overlays = DummyCollection()
self.preset_search_query = "search"
self.unset_called = []
self.bl_rna = SimpleNamespace(properties=[
SimpleNamespace(identifier='text'),
SimpleNamespace(identifier='image_overlays'),
SimpleNamespace(identifier='preset_search_query'),
])
def property_unset(self, name):
self.unset_called.append(name)
def test_reset_settings_unsets_all_known_properties(self):
op = TEXT_TEXTURE_OT_reset_settings()
op.report = Mock()
props = self.DummyProps()
context = create_mock_context(props)
result = op.execute(context)
assert result == {'FINISHED'}
assert set(props.unset_called) >= {'text', 'image_overlays', 'preset_search_query'}
assert props.image_overlays.cleared is True
op.report.assert_called()