1.1.0
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user