This commit is contained in:
2025-10-10 11:28:22 +02:00
parent 205aa7c421
commit d02cdc1463
157 changed files with 639 additions and 33540 deletions

View File

@@ -0,0 +1,156 @@
"""Unit tests for texture generation engine control flow."""
import pytest
from unittest.mock import Mock, patch, MagicMock
import sys
from pathlib import Path
# Add src to path for imports
src_path = Path(__file__).parent.parent.parent.parent / "src"
sys.path.insert(0, str(src_path))
from core.generation_engine import generate_texture_image
class TestGenerateTextureImageControlFlow:
"""Tests for generate_texture_image() control flow and error handling."""
def test_generate_texture_image_returns_none_when_pack_fails(self):
"""
Test that verifies the control flow bug: when texture generation succeeds
but pack() fails, the function incorrectly returns (None, None) instead
of returning the successfully generated image.
This test MUST fail initially because of the missing return statement
after line 244 in generation_engine.py.
"""
# Arrange: Create mock Blender image
mock_blender_img = Mock()
mock_blender_img.name = "TestTexture_512x512"
mock_blender_img.filepath_raw = ""
mock_blender_img.pack = Mock(side_effect=RuntimeError("Pack failed"))
mock_blender_img.pixels = MagicMock()
# Mock props with valid generation settings
mock_props = Mock()
mock_props.text = "Test"
mock_props.font_size = 64
mock_props.text_color = (1.0, 1.0, 1.0, 1.0)
mock_props.background_transparent = False
mock_props.background_color = (0.0, 0.0, 0.0, 1.0)
mock_props.font_path = "default"
mock_props.use_custom_font = False
mock_props.custom_font_path = ""
mock_props.prepend_text = ""
mock_props.append_text = ""
mock_props.prepend_append_layout = 'HORIZONTAL'
mock_props.prepend_margin = 10
mock_props.append_margin = 10
mock_props.enable_text_fitting = False
mock_props.generate_normal_map = False
# Patch bpy at module level with proper structure
with patch('core.generation_engine.bpy') as mock_bpy:
# Properly structure the bpy mock
mock_images = Mock()
mock_images.new = Mock(return_value=mock_blender_img)
mock_images.__contains__ = Mock(return_value=False)
mock_bpy.data.images = mock_images
# Patch PIL at the import level (inside the function)
with patch('PIL.Image') as mock_pil:
mock_pil_img = Mock()
mock_pil_img.size = (512, 512)
mock_pil_img.transpose = Mock(return_value=mock_pil_img)
mock_pil_img.getdata = Mock(return_value=[(255, 255, 255, 255)] * (512 * 512))
mock_pil.new.return_value = mock_pil_img
mock_pil.FLIP_TOP_BOTTOM = 0
with patch('PIL.ImageDraw') as mock_draw:
mock_draw_instance = Mock()
mock_draw_instance.textbbox = Mock(return_value=(0, 0, 100, 50))
mock_draw_instance.text = Mock()
mock_draw.Draw.return_value = mock_draw_instance
with patch('PIL.ImageFont') as mock_font:
mock_font.load_default.return_value = Mock()
# Act: Call generate_texture_image
result_img, result_normal = generate_texture_image(mock_props, 512, 512)
# Assert: Function should return the successfully generated image,
# not (None, None) even if pack() fails
# This assertion WILL FAIL due to the control flow bug
assert result_img is not None, (
"Expected function to return the generated image despite pack() failure, "
"but got None. This indicates a control flow bug where the function "
"falls through to exception handler after successful generation."
)
assert result_img == mock_blender_img, (
"Expected the function to return the mock Blender image"
)
def test_generate_texture_image_returns_image_on_success(self):
"""
Test that when both generation and pack succeed, the function returns
the generated image (not None).
This test should also fail initially for the same control flow reason.
"""
# Arrange: Create mock Blender image with successful pack
mock_blender_img = Mock()
mock_blender_img.name = "TestTexture_512x512"
mock_blender_img.filepath_raw = ""
mock_blender_img.pack = Mock() # Succeeds (no exception)
mock_blender_img.pixels = MagicMock()
mock_props = Mock()
mock_props.text = "Test"
mock_props.font_size = 64
mock_props.text_color = (1.0, 1.0, 1.0, 1.0)
mock_props.background_transparent = False
mock_props.background_color = (0.0, 0.0, 0.0, 1.0)
mock_props.font_path = "default"
mock_props.use_custom_font = False
mock_props.custom_font_path = ""
mock_props.prepend_text = ""
mock_props.append_text = ""
mock_props.prepend_append_layout = 'HORIZONTAL'
mock_props.prepend_margin = 10
mock_props.append_margin = 10
mock_props.enable_text_fitting = False
mock_props.generate_normal_map = False
with patch('core.generation_engine.bpy') as mock_bpy:
# Properly structure the bpy mock
mock_images = Mock()
mock_images.new = Mock(return_value=mock_blender_img)
mock_images.__contains__ = Mock(return_value=False)
mock_bpy.data.images = mock_images
with patch('PIL.Image') as mock_pil:
mock_pil_img = Mock()
mock_pil_img.size = (512, 512)
mock_pil_img.transpose = Mock(return_value=mock_pil_img)
mock_pil_img.getdata = Mock(return_value=[(255, 255, 255, 255)] * (512 * 512))
mock_pil.new.return_value = mock_pil_img
mock_pil.FLIP_TOP_BOTTOM = 0
with patch('PIL.ImageDraw') as mock_draw:
mock_draw_instance = Mock()
mock_draw_instance.textbbox = Mock(return_value=(0, 0, 100, 50))
mock_draw_instance.text = Mock()
mock_draw.Draw.return_value = mock_draw_instance
with patch('PIL.ImageFont') as mock_font:
mock_font.load_default.return_value = Mock()
# Act
result_img, result_normal = generate_texture_image(mock_props, 512, 512)
# Assert: Should return the generated image
assert result_img is not None, (
"Expected function to return generated image on success, got None"
)
assert result_img == mock_blender_img
assert result_normal is None # No normal map requested