remove multiline

This commit is contained in:
2025-10-13 00:10:24 +02:00
parent 97950f44c1
commit ad55572aa8
21 changed files with 112 additions and 943 deletions

View File

@@ -114,13 +114,6 @@ def addon_package(tmp_path, request):
content = content.replace('VERSION_TYPE = "free"', f'VERSION_TYPE = "{version_type}"')
constants_file.write_text(content)
# For FREE version, exclude PRO-only files
if version_type == "free":
# Remove text_editor_ops.py (multiline editor is PRO-only)
text_editor_ops = temp_src / "operators" / "text_editor_ops.py"
if text_editor_ops.exists():
text_editor_ops.unlink()
# Create zip from patched source
addon_zip = tmp_path / "text_texture_generator.zip"
with zipfile.ZipFile(addon_zip, 'w', zipfile.ZIP_DEFLATED) as zf:
@@ -129,4 +122,4 @@ def addon_package(tmp_path, request):
arc_name = f"text_texture_generator/{file_path.relative_to(temp_src)}"
zf.write(file_path, arc_name)
return addon_zip
return addon_zip

View File

@@ -800,56 +800,33 @@ print("SUCCESS: Single-line text remains unchanged")
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):
def test_free_version_no_multiline_artifacts(blender_container, addon_package):
"""
SPECIFICATION: FREE version must block multiline editor operator via poll().
SPECIFICATION: Multiline feature must be absent from the addon.
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)
This verification runs inside Blender to ensure that stale helpers or
operators are not exposed through the package API.
"""
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")
def fail(msg):
print(f"FAIL: {msg}")
sys.exit(1)
# Verify operator is a MockOperator (text_editor_ops.py should be excluded)
# has_multiline_text helper must be gone
try:
import text_texture_generator.operators.text_editor_ops as text_editor_ops
print(f"FAIL: text_editor_ops module should not exist in FREE version")
sys.exit(1)
except (ImportError, ModuleNotFoundError):
pass # Expected - module excluded from FREE build
from text_texture_generator.utils.constants import has_multiline_text
fail("has_multiline_text() helper is still importable")
except ImportError:
print("SUCCESS: has_multiline_text helper removed")
# Import operator from main module (should be MockOperator)
import text_texture_generator
op_class = text_texture_generator.TEXT_TEXTURE_OT_edit_multiline_text
# Verify it's a MockOperator (no bl_rna, empty bl_idname)
if hasattr(op_class, 'bl_rna'):
print(f"FAIL: Operator should be MockOperator (has bl_rna)")
sys.exit(1)
if not hasattr(op_class, 'bl_idname') or op_class.bl_idname != "":
print(f"FAIL: MockOperator should have empty bl_idname, got: {getattr(op_class, 'bl_idname', 'MISSING')}")
sys.exit(1)
print("SUCCESS: Multiline editor operator correctly blocked via poll()")
# Legacy multiline operator must also be absent
try:
from text_texture_generator import TEXT_TEXTURE_OT_edit_multiline_text
fail("TEXT_TEXTURE_OT_edit_multiline_text is still exposed")
except ImportError:
print("SUCCESS: Multiline editor operator removed")
"""
tar_stream = io.BytesIO()
@@ -873,61 +850,6 @@ print("SUCCESS: Multiline editor operator correctly blocked via poll()")
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
assert "SUCCESS: has_multiline_text helper removed" in output
assert "SUCCESS: Multiline editor operator removed" 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 import the operator - in FREE version, this module should not exist
try:
from text_texture_generator.operators.text_editor_ops import TEXT_TEXTURE_OT_edit_multiline_text
# If we get here in FREE version, something is wrong
print("ERROR: text_editor_ops should not exist in FREE version")
sys.exit(1)
except ImportError:
# Expected in FREE version - module should not exist
print("SUCCESS: Multiline editor module correctly absent in FREE version")
sys.exit(0)
"""
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: Multiline editor module correctly absent in FREE version" in output

View File

@@ -516,286 +516,13 @@ except Exception as e:
assert "Can set 4096px: True" in output
def test_pro_version_multiline_editor_operator_poll_allows_access(
def test_pro_version_text_normalization_matches_free_version(
blender_container,
addon_package,
tmp_path
):
"""
Verify multiline editor operator poll() returns True in PRO version.
Expected behavior (VERSION_TYPE="full"):
- TEXT_TEXTURE_OT_edit_multiline_text.poll() returns True
- Operator button should be enabled in UI
- has_multiline_text() returns True
"""
script_content = """
import bpy
import sys
# Enable addon
try:
bpy.ops.preferences.addon_enable(module='text_texture_generator')
except Exception as e:
print(f"ERROR enabling addon: {e}")
sys.exit(1)
# Verify multiline text feature is enabled
try:
from text_texture_generator.utils.constants import has_multiline_text, VERSION_TYPE
print(f"VERSION_TYPE: {VERSION_TYPE}")
if not has_multiline_text():
print(f"FAIL: has_multiline_text() should return True in PRO version")
sys.exit(1)
# Verify operator poll returns True
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 not poll_result:
print(f"FAIL: Operator poll() should return True in PRO version")
sys.exit(1)
print("SUCCESS: Multiline editor operator poll() returns True")
except Exception as e:
print(f"ERROR: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
"""
# Copy test script
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)
# Copy addon package
addon_tar_stream = io.BytesIO()
with tarfile.open(fileobj=addon_tar_stream, mode='w') as tar:
addon_info = tarfile.TarInfo(name='text_texture_generator.zip')
addon_info.size = addon_package.stat().st_size
with open(addon_package, 'rb') as f:
tar.addfile(addon_info, f)
addon_tar_stream.seek(0)
blender_container.put_archive('/addon-test', addon_tar_stream)
container_script_path = "/addon-test/test_editor_poll.py"
container_addon_path = "/addon-test/text_texture_generator.zip"
# Install addon
install_cmd = [
"/usr/local/bin/run_blender.sh",
"--background",
"--python-expr",
(
"import bpy; "
f"bpy.ops.preferences.addon_install(filepath='{container_addon_path}'); "
"bpy.ops.preferences.addon_enable(module='text_texture_generator'); "
"bpy.ops.wm.save_userpref()"
)
]
install_result = blender_container.exec_run(
install_cmd,
workdir="/addon-test"
)
assert install_result.exit_code == 0
# Run poll verification test
test_cmd = [
"/usr/local/bin/run_blender.sh",
"--background",
"--python",
container_script_path
]
test_result = blender_container.exec_run(
test_cmd,
workdir="/addon-test"
)
output = test_result.output.decode('utf-8', errors='replace')
print("\n=== Multiline Editor Poll Output ===")
print(output)
print("=== End Output ===\n")
assert test_result.exit_code == 0, (
f"Poll verification failed with exit code {test_result.exit_code}\n{output}"
)
assert "VERSION_TYPE: full" in output
assert "SUCCESS: Multiline editor operator poll() returns True" in output
def test_pro_version_multiline_editor_can_be_invoked(
blender_container,
addon_package,
tmp_path
):
"""
Verify multiline editor operator can be successfully invoked in PRO version.
Expected behavior (VERSION_TYPE="full"):
- Operator can be invoked without errors
- Dialog is opened (invoke_props_dialog called)
- temp_text is initialized from current text property
"""
script_content = """
import bpy
import sys
# Enable addon
try:
bpy.ops.preferences.addon_enable(module='text_texture_generator')
except Exception as e:
print(f"ERROR enabling addon: {e}")
sys.exit(1)
# Test operator invocation
try:
from text_texture_generator.operators.text_editor_ops import TEXT_TEXTURE_OT_edit_multiline_text
# Create scene and properties
bpy.ops.mesh.primitive_cube_add()
context = bpy.context
# Verify operator is registered and accessible
# We can't directly instantiate Blender operators, but we can verify registration
if not hasattr(TEXT_TEXTURE_OT_edit_multiline_text, 'bl_idname'):
print("ERROR: Operator missing bl_idname")
sys.exit(1)
# Verify it's a real Blender operator (has bl_rna)
if not hasattr(TEXT_TEXTURE_OT_edit_multiline_text, 'bl_rna'):
print("ERROR: Operator is not a proper Blender operator (missing bl_rna)")
sys.exit(1)
# Verify temp_text property is defined (check annotations or __annotations__)
has_temp_text = (
hasattr(TEXT_TEXTURE_OT_edit_multiline_text, 'temp_text') or
(hasattr(TEXT_TEXTURE_OT_edit_multiline_text, '__annotations__') and
'temp_text' in TEXT_TEXTURE_OT_edit_multiline_text.__annotations__)
)
if not has_temp_text:
print("ERROR: Operator missing temp_text property")
print(f"Available attributes: {dir(TEXT_TEXTURE_OT_edit_multiline_text)}")
sys.exit(1)
print("Operator registered successfully")
print("temp_text property exists: True")
print("SUCCESS: Multiline editor operator can be invoked")
except Exception as e:
print(f"ERROR: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
"""
# Copy test script
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)
# Copy addon package
addon_tar_stream = io.BytesIO()
with tarfile.open(fileobj=addon_tar_stream, mode='w') as tar:
addon_info = tarfile.TarInfo(name='text_texture_generator.zip')
addon_info.size = addon_package.stat().st_size
with open(addon_package, 'rb') as f:
tar.addfile(addon_info, f)
addon_tar_stream.seek(0)
blender_container.put_archive('/addon-test', addon_tar_stream)
container_script_path = "/addon-test/test_editor_invoke.py"
container_addon_path = "/addon-test/text_texture_generator.zip"
# Install addon
install_cmd = [
"/usr/local/bin/run_blender.sh",
"--background",
"--python-expr",
(
"import bpy; "
f"bpy.ops.preferences.addon_install(filepath='{container_addon_path}'); "
"bpy.ops.preferences.addon_enable(module='text_texture_generator'); "
"bpy.ops.wm.save_userpref()"
)
]
install_result = blender_container.exec_run(
install_cmd,
workdir="/addon-test"
)
assert install_result.exit_code == 0
# Run invoke test
test_cmd = [
"/usr/local/bin/run_blender.sh",
"--background",
"--python",
container_script_path
]
test_result = blender_container.exec_run(
test_cmd,
workdir="/addon-test"
)
output = test_result.output.decode('utf-8', errors='replace')
print("\n=== Multiline Editor Invoke Output ===")
print(output)
print("=== End Output ===\n")
assert test_result.exit_code == 0, (
f"Invoke test failed with exit code {test_result.exit_code}\n{output}"
)
assert "Operator registered successfully" in output
assert "temp_text property exists: True" in output
assert "SUCCESS: Multiline editor operator can be invoked" in output
def test_pro_version_multiline_text_preserved_during_processing(
blender_container,
addon_package,
tmp_path
):
"""
Verify multiline text with newlines is preserved in PRO version.
Expected behavior (VERSION_TYPE="full"):
- Text processor preserves \\n characters in PRO version
- "Line 1\\nLine 2\\nLine 3" remains unchanged
- No newline stripping in PRO mode
Verify newline handling matches the single-line specification in PRO builds.
"""
script_content = """
import bpy
@@ -822,18 +549,15 @@ try:
print(f"Input: {repr(input_text)}")
print(f"Output: {repr(result)}")
# In PRO version, newlines should be preserved
if VERSION_TYPE == "full" or VERSION_TYPE == "pro":
if "\\n" not in result:
print(f"FAIL: Newlines should be preserved in PRO version")
sys.exit(1)
newline_count = result.count("\\n")
if newline_count != 2:
print(f"FAIL: Expected 2 newlines, got {newline_count}")
sys.exit(1)
if "\\n" in result:
print("FAIL: Result should not contain newline characters")
sys.exit(1)
print("SUCCESS: Multiline text preserved in PRO version")
if result != "Line 1 Line 2 Line 3":
print(f"FAIL: Expected normalized output, got {repr(result)}")
sys.exit(1)
print("SUCCESS: Text content normalized in PRO version")
except Exception as e:
print(f"ERROR: {e}")
@@ -845,7 +569,7 @@ except Exception as e:
# Copy test script
tar_stream = io.BytesIO()
with tarfile.open(fileobj=tar_stream, mode='w') as tar:
script_info = tarfile.TarInfo(name='test_multiline_preserve.py')
script_info = tarfile.TarInfo(name='test_text_normalization.py')
script_bytes = script_content.encode('utf-8')
script_info.size = len(script_bytes)
tar.addfile(script_info, io.BytesIO(script_bytes))
@@ -864,7 +588,7 @@ except Exception as e:
addon_tar_stream.seek(0)
blender_container.put_archive('/addon-test', addon_tar_stream)
container_script_path = "/addon-test/test_multiline_preserve.py"
container_script_path = "/addon-test/test_text_normalization.py"
container_addon_path = "/addon-test/text_texture_generator.zip"
# Install addon
@@ -887,7 +611,7 @@ except Exception as e:
assert install_result.exit_code == 0
# Run multiline preservation test
# Run text normalization test
test_cmd = [
"/usr/local/bin/run_blender.sh",
"--background",
@@ -902,13 +626,13 @@ except Exception as e:
output = test_result.output.decode('utf-8', errors='replace')
print("\n=== Multiline Preservation Output ===")
print("\n=== Text Normalization Output ===")
print(output)
print("=== End Output ===\n")
assert test_result.exit_code == 0, (
f"Multiline preservation test failed with exit code {test_result.exit_code}\n{output}"
f"Text normalization test failed with exit code {test_result.exit_code}\n{output}"
)
assert "VERSION_TYPE: full" in output
assert "SUCCESS: Multiline text preserved in PRO version" in output
assert "SUCCESS: Text content normalized in PRO version" in output