This commit is contained in:
2025-10-10 18:42:13 +02:00
parent 596f640912
commit 6253de27e2
20 changed files with 1327 additions and 12 deletions

View File

@@ -150,8 +150,8 @@ bpy.ops.mesh.primitive_cube_add()
obj = bpy.context.active_object
# Try basic generation
props = bpy.context.scene.ttg_props
props.text_input = "Free Version Test"
props = bpy.context.scene.text_texture_props
props.text = "Free Version Test"
props.texture_size = 512 # Within free limit
try:
@@ -602,4 +602,347 @@ print(f"SUCCESS: max_concurrent_operations correctly limited to {max_concurrent}
# This test WILL FAIL because get_version_limits() has the bug
assert test_result.exit_code == 0, f"Concurrent limit test failed:\n{output}"
assert "SUCCESS: max_concurrent_operations correctly limited to 1" in output
assert "SUCCESS: max_concurrent_operations correctly limited to 1" in output
def test_free_version_strips_newlines_from_multiline_text(blender_container, addon_package):
"""
SPECIFICATION: FREE version must strip newlines during text processing.
Expected behavior (VERSION_TYPE="free"):
- process_text_content() strips \\n from input text
- "Line 1\\nLine 2\\nLine 3" becomes "Line 1 Line 2 Line 3"
- Newlines replaced with spaces, consecutive spaces normalized
Current state:
- process_text_content() exists and works correctly (unit tested)
- BUT: Not yet called in generation pipeline
- Test WILL FAIL until integration is complete
"""
version_type, enabled_features = get_version_type(blender_container, addon_package)
if version_type == "full":
pytest.skip("Test requires VERSION_TYPE='free' - currently 'full' (specification test)")
script_content = """
import bpy
import sys
# Test text processing directly
from text_texture_generator.core.text_processor import process_text_content
input_text = "Line 1\\nLine 2\\nLine 3"
expected = "Line 1 Line 2 Line 3"
result = process_text_content(input_text)
if result != expected:
print(f"FAIL: Expected '{expected}', got '{result}'")
sys.exit(1)
if "\\n" in result:
print(f"FAIL: Result should not contain newlines, got: {result}")
sys.exit(1)
print("SUCCESS: Multiline text correctly stripped to single line")
"""
tar_stream = io.BytesIO()
with tarfile.open(fileobj=tar_stream, mode='w') as tar:
script_info = tarfile.TarInfo(name='test_newline_strip.py')
script_bytes = script_content.encode('utf-8')
script_info.size = len(script_bytes)
tar.addfile(script_info, io.BytesIO(script_bytes))
tar_stream.seek(0)
blender_container.put_archive('/addon-test', tar_stream)
test_cmd = [
"/usr/local/bin/run_blender.sh",
"--background",
"--python",
"/addon-test/test_newline_strip.py"
]
test_result = blender_container.exec_run(test_cmd, workdir="/addon-test")
output = test_result.output.decode('utf-8', errors='replace')
assert test_result.exit_code == 0, f"Newline strip test failed:\n{output}"
assert "SUCCESS: Multiline text correctly stripped" in output
def test_free_version_handles_multiple_consecutive_newlines(blender_container, addon_package):
"""
SPECIFICATION: FREE version must collapse multiple consecutive newlines.
Expected behavior (VERSION_TYPE="free"):
- process_text_content() collapses multiple newlines
- "Hello\\n\\n\\nWorld" becomes "Hello World"
- Consecutive spaces normalized to single space
Current state:
- process_text_content() exists and works correctly (unit tested)
- Test verifies the function behavior directly
"""
version_type, enabled_features = get_version_type(blender_container, addon_package)
if version_type == "full":
pytest.skip("Test requires VERSION_TYPE='free' - currently 'full' (specification test)")
script_content = """
import bpy
import sys
from text_texture_generator.core.text_processor import process_text_content
input_text = "Hello\\n\\n\\nWorld"
expected = "Hello World"
result = process_text_content(input_text)
if result != expected:
print(f"FAIL: Expected '{expected}', got '{result}'")
sys.exit(1)
if "\\n" in result:
print(f"FAIL: Result should not contain newlines, got: {result}")
sys.exit(1)
print("SUCCESS: Multiple newlines correctly collapsed")
"""
tar_stream = io.BytesIO()
with tarfile.open(fileobj=tar_stream, mode='w') as tar:
script_info = tarfile.TarInfo(name='test_multi_newline.py')
script_bytes = script_content.encode('utf-8')
script_info.size = len(script_bytes)
tar.addfile(script_info, io.BytesIO(script_bytes))
tar_stream.seek(0)
blender_container.put_archive('/addon-test', tar_stream)
test_cmd = [
"/usr/local/bin/run_blender.sh",
"--background",
"--python",
"/addon-test/test_multi_newline.py"
]
test_result = blender_container.exec_run(test_cmd, workdir="/addon-test")
output = test_result.output.decode('utf-8', errors='replace')
assert test_result.exit_code == 0, f"Multiple newline test failed:\n{output}"
assert "SUCCESS: Multiple newlines correctly collapsed" in output
def test_free_version_preserves_single_line_text(blender_container, addon_package):
"""
SPECIFICATION: FREE version should leave single-line text unchanged.
Expected behavior (VERSION_TYPE="free"):
- process_text_content() preserves text without newlines
- "No newlines here" remains "No newlines here"
- No modification when input is already single-line
Current state:
- process_text_content() exists and works correctly (unit tested)
- Test verifies the function behavior directly
"""
version_type, enabled_features = get_version_type(blender_container, addon_package)
if version_type == "full":
pytest.skip("Test requires VERSION_TYPE='free' - currently 'full' (specification test)")
script_content = """
import bpy
import sys
from text_texture_generator.core.text_processor import process_text_content
input_text = "No newlines here"
expected = "No newlines here"
result = process_text_content(input_text)
if result != expected:
print(f"FAIL: Expected '{expected}', got '{result}'")
sys.exit(1)
if "\\n" in result:
print(f"FAIL: Result should not contain newlines")
sys.exit(1)
print("SUCCESS: Single-line text remains unchanged")
"""
tar_stream = io.BytesIO()
with tarfile.open(fileobj=tar_stream, mode='w') as tar:
script_info = tarfile.TarInfo(name='test_single_line.py')
script_bytes = script_content.encode('utf-8')
script_info.size = len(script_bytes)
tar.addfile(script_info, io.BytesIO(script_bytes))
tar_stream.seek(0)
blender_container.put_archive('/addon-test', tar_stream)
test_cmd = [
"/usr/local/bin/run_blender.sh",
"--background",
"--python",
"/addon-test/test_single_line.py"
]
test_result = blender_container.exec_run(test_cmd, workdir="/addon-test")
output = test_result.output.decode('utf-8', errors='replace')
assert test_result.exit_code == 0, f"Single-line test failed:\n{output}"
def test_free_version_multiline_editor_operator_poll_blocks_access(blender_container, addon_package):
"""
SPECIFICATION: FREE version must block multiline editor operator via poll().
Expected behavior (VERSION_TYPE="free"):
- TEXT_TEXTURE_OT_edit_multiline_text.poll() returns False
- Operator button should be disabled/grayed out in UI
- has_multiline_text() returns False
Current state (VERSION_TYPE="full"):
- Test SKIPS (multiline editor is available)
"""
version_type, enabled_features = get_version_type(blender_container, addon_package)
if version_type == "full":
pytest.skip("Test requires VERSION_TYPE='free' - currently 'full' (specification test)")
script_content = """
import bpy
import sys
# Verify multiline text feature is disabled
from text_texture_generator.utils.constants import has_multiline_text
if has_multiline_text():
print(f"FAIL: has_multiline_text() should return False in FREE version")
sys.exit(1)
# Verify operator poll returns False
from text_texture_generator.operators.text_editor_ops import TEXT_TEXTURE_OT_edit_multiline_text
# Create a minimal mock context
class MockContext:
pass
context = MockContext()
poll_result = TEXT_TEXTURE_OT_edit_multiline_text.poll(context)
if poll_result:
print(f"FAIL: Operator poll() should return False in FREE version")
sys.exit(1)
print("SUCCESS: Multiline editor operator correctly blocked via poll()")
"""
tar_stream = io.BytesIO()
with tarfile.open(fileobj=tar_stream, mode='w') as tar:
script_info = tarfile.TarInfo(name='test_editor_poll.py')
script_bytes = script_content.encode('utf-8')
script_info.size = len(script_bytes)
tar.addfile(script_info, io.BytesIO(script_bytes))
tar_stream.seek(0)
blender_container.put_archive('/addon-test', tar_stream)
test_cmd = [
"/usr/local/bin/run_blender.sh",
"--background",
"--python",
"/addon-test/test_editor_poll.py"
]
test_result = blender_container.exec_run(test_cmd, workdir="/addon-test")
output = test_result.output.decode('utf-8', errors='replace')
assert test_result.exit_code == 0, f"Operator poll test failed:\n{output}"
assert "SUCCESS: Multiline editor operator correctly blocked" in output
def test_free_version_multiline_editor_invoke_fails_gracefully(blender_container, addon_package):
"""
SPECIFICATION: FREE version must fail gracefully if operator is invoked.
Expected behavior (VERSION_TYPE="free"):
- Even if poll() is bypassed, invoke should fail gracefully
- No crashes or exceptions
- Returns appropriate error status
Current state (VERSION_TYPE="full"):
- Test SKIPS (operator works normally)
"""
version_type, enabled_features = get_version_type(blender_container, addon_package)
if version_type == "full":
pytest.skip("Test requires VERSION_TYPE='free' - currently 'full' (specification test)")
script_content = """
import bpy
import sys
# Attempt to invoke operator directly (bypassing poll)
from text_texture_generator.operators.text_editor_ops import TEXT_TEXTURE_OT_edit_multiline_text
# Create minimal context
bpy.ops.mesh.primitive_cube_add()
context = bpy.context
# Create operator instance
op = TEXT_TEXTURE_OT_edit_multiline_text()
# Mock event
class MockEvent:
pass
event = MockEvent()
# Try to invoke (should fail gracefully, not crash)
try:
# Since poll() returns False, we expect this to be blocked at operator level
# or return gracefully if somehow invoked
result = op.invoke(context, event)
# If it returns, it should be CANCELLED or FINISHED (not crash)
if result not in [{'CANCELLED'}, {'FINISHED'}]:
print(f"FAIL: Expected CANCELLED or FINISHED, got {result}")
sys.exit(1)
print("SUCCESS: Operator invoke failed gracefully")
except Exception as e:
# Should not crash - fail gracefully
print(f"FAIL: Operator should fail gracefully, not crash: {e}")
sys.exit(1)
"""
tar_stream = io.BytesIO()
with tarfile.open(fileobj=tar_stream, mode='w') as tar:
script_info = tarfile.TarInfo(name='test_editor_invoke.py')
script_bytes = script_content.encode('utf-8')
script_info.size = len(script_bytes)
tar.addfile(script_info, io.BytesIO(script_bytes))
tar_stream.seek(0)
blender_container.put_archive('/addon-test', tar_stream)
test_cmd = [
"/usr/local/bin/run_blender.sh",
"--background",
"--python",
"/addon-test/test_editor_invoke.py"
]
test_result = blender_container.exec_run(test_cmd, workdir="/addon-test")
output = test_result.output.decode('utf-8', errors='replace')
assert test_result.exit_code == 0, f"Operator invoke test failed:\n{output}"
assert "SUCCESS: Operator invoke failed gracefully" in output
assert "SUCCESS: Single-line text remains unchanged" in output