This commit is contained in:
2025-08-12 23:02:52 +07:00
parent a46be309c0
commit 05cb419909
5 changed files with 1456 additions and 1003 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,558 +0,0 @@
#!/usr/bin/env python3
"""
Comprehensive test suite for the Text Texture Generator's enhanced positioning system.
This script validates the positioning calculations and identifies potential issues
without requiring Blender to be installed.
"""
import sys
import traceback
from typing import Dict, Tuple, List, Any
# Mock Blender properties for testing
class MockProps:
"""Mock properties class to simulate Blender addon properties"""
def __init__(self):
# Enhanced positioning properties
self.anchor_point = 'MIDDLE_CENTER'
self.position_mode = 'PRESET'
self.margin_x = 0.0
self.margin_y = 0.0
self.margins_linked = False
self.offset_x = 0
self.offset_y = 0
self.manual_position_x = 50.0
self.manual_position_y = 50.0
self.manual_position_unit = 'PERCENTAGE'
self.constrain_to_canvas = True
# Legacy properties for backward compatibility testing
self.text_align = 'center'
self.padding = 20
# Copy of the enhanced positioning function from the addon
def calculate_text_position(props, canvas_width, canvas_height, text_width, text_height):
"""Calculate text position based on enhanced positioning properties"""
if props.position_mode == 'MANUAL':
# Manual positioning mode
if props.manual_position_unit == 'PERCENTAGE':
x = int((props.manual_position_x / 100.0) * canvas_width)
y = int((props.manual_position_y / 100.0) * canvas_height)
else: # PIXELS
x = int(props.manual_position_x)
y = int(props.manual_position_y)
else:
# Preset anchor-based positioning
margin_x_px = int((props.margin_x / 100.0) * canvas_width)
margin_y_px = int((props.margin_y / 100.0) * canvas_height)
# Calculate base position based on anchor point
if 'LEFT' in props.anchor_point:
base_x = margin_x_px
elif 'RIGHT' in props.anchor_point:
base_x = canvas_width - text_width - margin_x_px
else: # CENTER
base_x = (canvas_width - text_width) // 2
if 'TOP' in props.anchor_point:
base_y = margin_y_px
elif 'BOTTOM' in props.anchor_point:
base_y = canvas_height - text_height - margin_y_px
else: # MIDDLE
base_y = (canvas_height - text_height) // 2
# Apply fine-tuning offsets
x = base_x + props.offset_x
y = base_y + props.offset_y
# Apply canvas constraints if enabled
if props.constrain_to_canvas:
x = max(0, min(x, canvas_width - text_width))
y = max(0, min(y, canvas_height - text_height))
return x, y
def sync_margin_values(props, changed_margin):
"""Synchronize margin values when linked"""
if props.margins_linked:
if changed_margin == 'x':
props.margin_y = props.margin_x
elif changed_margin == 'y':
props.margin_x = props.margin_y
def get_anchor_point_matrix():
"""Return 3x3 matrix of anchor point identifiers for UI layout"""
return [
['TOP_LEFT', 'TOP_CENTER', 'TOP_RIGHT'],
['MIDDLE_LEFT', 'MIDDLE_CENTER', 'MIDDLE_RIGHT'],
['BOTTOM_LEFT', 'BOTTOM_CENTER', 'BOTTOM_RIGHT']
]
class PositioningTestSuite:
"""Comprehensive test suite for positioning system"""
def __init__(self):
self.test_results = []
self.issues_found = []
self.canvas_width = 1024
self.canvas_height = 1024
self.text_width = 200
self.text_height = 50
def log_test(self, test_name: str, passed: bool, details: str = "", expected=None, actual=None):
"""Log test result"""
result = {
'test': test_name,
'passed': passed,
'details': details,
'expected': expected,
'actual': actual
}
self.test_results.append(result)
if not passed:
self.issues_found.append(f"{test_name}: {details}")
if expected is not None and actual is not None:
self.issues_found.append(f" Expected: {expected}, Got: {actual}")
else:
print(f"{test_name}")
def test_anchor_point_calculations(self):
"""Test all 9 anchor point calculations"""
print("\n=== Testing Anchor Point Calculations ===")
anchor_matrix = get_anchor_point_matrix()
expected_positions = {
'TOP_LEFT': (0, 0),
'TOP_CENTER': (412, 0), # (1024-200)/2 = 412
'TOP_RIGHT': (824, 0), # 1024-200 = 824
'MIDDLE_LEFT': (0, 487), # (1024-50)/2 = 487
'MIDDLE_CENTER': (412, 487),
'MIDDLE_RIGHT': (824, 487),
'BOTTOM_LEFT': (0, 974), # 1024-50 = 974
'BOTTOM_CENTER': (412, 974),
'BOTTOM_RIGHT': (824, 974)
}
for row in anchor_matrix:
for anchor in row:
props = MockProps()
props.anchor_point = anchor
props.position_mode = 'PRESET'
props.margin_x = 0.0
props.margin_y = 0.0
props.offset_x = 0
props.offset_y = 0
try:
x, y = calculate_text_position(props, self.canvas_width, self.canvas_height,
self.text_width, self.text_height)
expected = expected_positions[anchor]
if (x, y) == expected:
self.log_test(f"Anchor {anchor}", True, f"Position: ({x}, {y})")
else:
self.log_test(f"Anchor {anchor}", False,
f"Incorrect position calculation", expected, (x, y))
except Exception as e:
self.log_test(f"Anchor {anchor}", False, f"Exception: {str(e)}")
def test_margin_calculations(self):
"""Test margin calculations with various percentages"""
print("\n=== Testing Margin Calculations ===")
test_cases = [
(10.0, 10.0), # 10% margins
(25.0, 25.0), # 25% margins
(50.0, 50.0), # 50% margins (maximum)
(0.0, 0.0), # No margins
]
for margin_x, margin_y in test_cases:
props = MockProps()
props.anchor_point = 'TOP_LEFT'
props.position_mode = 'PRESET'
props.margin_x = margin_x
props.margin_y = margin_y
props.offset_x = 0
props.offset_y = 0
expected_x = int((margin_x / 100.0) * self.canvas_width)
expected_y = int((margin_y / 100.0) * self.canvas_height)
try:
x, y = calculate_text_position(props, self.canvas_width, self.canvas_height,
self.text_width, self.text_height)
if x == expected_x and y == expected_y:
self.log_test(f"Margins {margin_x}%/{margin_y}%", True, f"Position: ({x}, {y})")
else:
self.log_test(f"Margins {margin_x}%/{margin_y}%", False,
f"Incorrect margin calculation", (expected_x, expected_y), (x, y))
except Exception as e:
self.log_test(f"Margins {margin_x}%/{margin_y}%", False, f"Exception: {str(e)}")
def test_manual_positioning(self):
"""Test manual positioning mode with percentage and pixel units"""
print("\n=== Testing Manual Positioning ===")
# Test percentage mode
props = MockProps()
props.position_mode = 'MANUAL'
props.manual_position_unit = 'PERCENTAGE'
props.manual_position_x = 25.0 # 25%
props.manual_position_y = 75.0 # 75%
expected_x = int((25.0 / 100.0) * self.canvas_width) # 256
expected_y = int((75.0 / 100.0) * self.canvas_height) # 768
try:
x, y = calculate_text_position(props, self.canvas_width, self.canvas_height,
self.text_width, self.text_height)
if x == expected_x and y == expected_y:
self.log_test("Manual Percentage Mode", True, f"Position: ({x}, {y})")
else:
self.log_test("Manual Percentage Mode", False,
f"Incorrect calculation", (expected_x, expected_y), (x, y))
except Exception as e:
self.log_test("Manual Percentage Mode", False, f"Exception: {str(e)}")
# Test pixel mode
props.manual_position_unit = 'PIXELS'
props.manual_position_x = 100.0
props.manual_position_y = 200.0
expected_x = 100
expected_y = 200
try:
x, y = calculate_text_position(props, self.canvas_width, self.canvas_height,
self.text_width, self.text_height)
if x == expected_x and y == expected_y:
self.log_test("Manual Pixel Mode", True, f"Position: ({x}, {y})")
else:
self.log_test("Manual Pixel Mode", False,
f"Incorrect calculation", (expected_x, expected_y), (x, y))
except Exception as e:
self.log_test("Manual Pixel Mode", False, f"Exception: {str(e)}")
def test_canvas_constraints(self):
"""Test canvas constraint functionality"""
print("\n=== Testing Canvas Constraints ===")
# Test position that would go out of bounds
props = MockProps()
props.position_mode = 'MANUAL'
props.manual_position_unit = 'PIXELS'
props.manual_position_x = 1000.0 # Would put text partially outside (text_width=200)
props.manual_position_y = 1000.0 # Would put text partially outside (text_height=50)
props.constrain_to_canvas = True
expected_x = self.canvas_width - self.text_width # 824
expected_y = self.canvas_height - self.text_height # 974
try:
x, y = calculate_text_position(props, self.canvas_width, self.canvas_height,
self.text_width, self.text_height)
if x == expected_x and y == expected_y:
self.log_test("Canvas Constraints (constrained)", True, f"Position: ({x}, {y})")
else:
self.log_test("Canvas Constraints (constrained)", False,
f"Constraint failed", (expected_x, expected_y), (x, y))
except Exception as e:
self.log_test("Canvas Constraints (constrained)", False, f"Exception: {str(e)}")
# Test with constraints disabled
props.constrain_to_canvas = False
expected_x = 1000 # Should not be constrained
expected_y = 1000
try:
x, y = calculate_text_position(props, self.canvas_width, self.canvas_height,
self.text_width, self.text_height)
if x == expected_x and y == expected_y:
self.log_test("Canvas Constraints (unconstrained)", True, f"Position: ({x}, {y})")
else:
self.log_test("Canvas Constraints (unconstrained)", False,
f"Should not be constrained", (expected_x, expected_y), (x, y))
except Exception as e:
self.log_test("Canvas Constraints (unconstrained)", False, f"Exception: {str(e)}")
def test_offset_application(self):
"""Test pixel offset fine-tuning"""
print("\n=== Testing Pixel Offset Application ===")
props = MockProps()
props.anchor_point = 'MIDDLE_CENTER'
props.position_mode = 'PRESET'
props.margin_x = 0.0
props.margin_y = 0.0
props.offset_x = 50 # 50px right
props.offset_y = -25 # 25px up
base_x = (self.canvas_width - self.text_width) // 2 # 412
base_y = (self.canvas_height - self.text_height) // 2 # 487
expected_x = base_x + props.offset_x # 462
expected_y = base_y + props.offset_y # 462
try:
x, y = calculate_text_position(props, self.canvas_width, self.canvas_height,
self.text_width, self.text_height)
if x == expected_x and y == expected_y:
self.log_test("Pixel Offset Application", True, f"Position: ({x}, {y})")
else:
self.log_test("Pixel Offset Application", False,
f"Offset not applied correctly", (expected_x, expected_y), (x, y))
except Exception as e:
self.log_test("Pixel Offset Application", False, f"Exception: {str(e)}")
def test_margin_synchronization(self):
"""Test margin link functionality"""
print("\n=== Testing Margin Synchronization ===")
props = MockProps()
props.margins_linked = True
props.margin_x = 15.0
props.margin_y = 10.0
# Test X margin sync
sync_margin_values(props, 'x')
if props.margin_y == props.margin_x:
self.log_test("Margin Sync (X to Y)", True, f"Y margin updated to {props.margin_y}")
else:
self.log_test("Margin Sync (X to Y)", False,
f"Y margin not synced", props.margin_x, props.margin_y)
# Reset and test Y margin sync
props.margin_x = 20.0
props.margin_y = 25.0
sync_margin_values(props, 'y')
if props.margin_x == props.margin_y:
self.log_test("Margin Sync (Y to X)", True, f"X margin updated to {props.margin_x}")
else:
self.log_test("Margin Sync (Y to X)", False,
f"X margin not synced", props.margin_y, props.margin_x)
# Test unlinked margins
props.margins_linked = False
original_x = props.margin_x
original_y = props.margin_y
sync_margin_values(props, 'x')
if props.margin_x == original_x and props.margin_y == original_y:
self.log_test("Margin Sync (Unlinked)", True, "Margins unchanged when unlinked")
else:
self.log_test("Margin Sync (Unlinked)", False,
"Margins changed when they shouldn't")
def test_edge_cases(self):
"""Test edge cases and boundary conditions"""
print("\n=== Testing Edge Cases ===")
# Test zero canvas dimensions
props = MockProps()
try:
x, y = calculate_text_position(props, 0, 0, self.text_width, self.text_height)
self.log_test("Zero Canvas Dimensions", True, f"Handled gracefully: ({x}, {y})")
except Exception as e:
self.log_test("Zero Canvas Dimensions", False, f"Exception: {str(e)}")
# Test text larger than canvas
props = MockProps()
props.anchor_point = 'TOP_LEFT'
props.constrain_to_canvas = True
large_text_width = 2000
large_text_height = 2000
try:
x, y = calculate_text_position(props, self.canvas_width, self.canvas_height,
large_text_width, large_text_height)
if x <= 0 and y <= 0:
self.log_test("Text Larger Than Canvas", True, f"Constrained to: ({x}, {y})")
else:
self.log_test("Text Larger Than Canvas", False,
f"Not properly constrained: ({x}, {y})")
except Exception as e:
self.log_test("Text Larger Than Canvas", False, f"Exception: {str(e)}")
# Test maximum margin values (50%)
props = MockProps()
props.anchor_point = 'TOP_LEFT'
props.margin_x = 50.0
props.margin_y = 50.0
try:
x, y = calculate_text_position(props, self.canvas_width, self.canvas_height,
self.text_width, self.text_height)
expected_x = int(0.5 * self.canvas_width) # 512
expected_y = int(0.5 * self.canvas_height) # 512
if x == expected_x and y == expected_y:
self.log_test("Maximum Margins (50%)", True, f"Position: ({x}, {y})")
else:
self.log_test("Maximum Margins (50%)", False,
f"Incorrect calculation", (expected_x, expected_y), (x, y))
except Exception as e:
self.log_test("Maximum Margins (50%)", False, f"Exception: {str(e)}")
def analyze_ui_integration(self):
"""Analyze UI integration potential issues"""
print("\n=== Analyzing UI Integration ===")
issues = []
# Check anchor point matrix structure
matrix = get_anchor_point_matrix()
if len(matrix) != 3 or any(len(row) != 3 for row in matrix):
issues.append("❌ Anchor point matrix is not 3x3")
else:
print("✅ Anchor point matrix structure is correct")
# Check all anchor points are defined
all_anchors = [anchor for row in matrix for anchor in row]
expected_anchors = [
'TOP_LEFT', 'TOP_CENTER', 'TOP_RIGHT',
'MIDDLE_LEFT', 'MIDDLE_CENTER', 'MIDDLE_RIGHT',
'BOTTOM_LEFT', 'BOTTOM_CENTER', 'BOTTOM_RIGHT'
]
missing_anchors = set(expected_anchors) - set(all_anchors)
if missing_anchors:
issues.append(f"❌ Missing anchor points: {missing_anchors}")
else:
print("✅ All required anchor points are defined")
# Check for property type consistency
props = MockProps()
# Test property ranges
if hasattr(props, 'margin_x') and hasattr(props, 'margin_y'):
print("✅ Margin properties exist")
else:
issues.append("❌ Margin properties missing")
if hasattr(props, 'offset_x') and hasattr(props, 'offset_y'):
print("✅ Offset properties exist")
else:
issues.append("❌ Offset properties missing")
self.issues_found.extend(issues)
def run_all_tests(self):
"""Run all tests and generate comprehensive report"""
print("🔍 ENHANCED POSITIONING SYSTEM TEST SUITE")
print("=" * 50)
try:
self.test_anchor_point_calculations()
self.test_margin_calculations()
self.test_manual_positioning()
self.test_canvas_constraints()
self.test_offset_application()
self.test_margin_synchronization()
self.test_edge_cases()
self.analyze_ui_integration()
except Exception as e:
print(f"❌ Critical error during testing: {e}")
traceback.print_exc()
self.generate_report()
def generate_report(self):
"""Generate comprehensive test report"""
print("\n" + "=" * 60)
print("📊 COMPREHENSIVE TEST REPORT")
print("=" * 60)
total_tests = len(self.test_results)
passed_tests = sum(1 for result in self.test_results if result['passed'])
failed_tests = total_tests - passed_tests
print(f"📈 SUMMARY:")
print(f" Total Tests: {total_tests}")
print(f" ✅ Passed: {passed_tests}")
print(f" ❌ Failed: {failed_tests}")
print(f" Success Rate: {(passed_tests/total_tests*100):.1f}%" if total_tests > 0 else "No tests run")
if self.issues_found:
print(f"\n🐛 ISSUES IDENTIFIED ({len(self.issues_found)}):")
for issue in self.issues_found:
print(f" {issue}")
# Categorize issues by severity
critical_issues = []
major_issues = []
minor_issues = []
for result in self.test_results:
if not result['passed']:
if 'exception' in result['details'].lower():
critical_issues.append(result)
elif 'constraint' in result['test'].lower() or 'calculation' in result['details'].lower():
major_issues.append(result)
else:
minor_issues.append(result)
if critical_issues:
print(f"\n🚨 CRITICAL ISSUES ({len(critical_issues)}):")
for issue in critical_issues:
print(f"{issue['test']}: {issue['details']}")
if major_issues:
print(f"\n⚠️ MAJOR ISSUES ({len(major_issues)}):")
for issue in major_issues:
print(f"{issue['test']}: {issue['details']}")
if minor_issues:
print(f"\n MINOR ISSUES ({len(minor_issues)}):")
for issue in minor_issues:
print(f"{issue['test']}: {issue['details']}")
# Recommendations
print(f"\n🎯 RECOMMENDATIONS:")
if critical_issues:
print(" 1. Fix critical exceptions before deployment")
print(" 2. Add proper error handling for edge cases")
if major_issues:
print(" 3. Review positioning calculation logic")
print(" 4. Test constraint functionality thoroughly")
print(" 5. Add comprehensive unit tests to the addon")
print(" 6. Implement validation for property ranges")
print(" 7. Add user feedback for invalid input combinations")
return {
'total_tests': total_tests,
'passed': passed_tests,
'failed': failed_tests,
'issues': self.issues_found,
'critical_issues': len(critical_issues),
'major_issues': len(major_issues),
'minor_issues': len(minor_issues)
}
if __name__ == "__main__":
print("🚀 Starting Enhanced Positioning System Test Suite...")
test_suite = PositioningTestSuite()
results = test_suite.run_all_tests()
print(f"\n✨ Testing completed!")
print(f"Check the detailed report above for analysis and recommendations.")

View File

@@ -1,150 +0,0 @@
#!/usr/bin/env python3
"""
Test script to verify that preset names with Unicode characters like 'ö' work correctly.
This script tests the validation logic outside of Blender.
"""
import re
import json
import os
import tempfile
def test_preset_name_validation():
"""Test the new preset name validation regex"""
# Test cases with expected results
test_cases = [
# Valid names (should pass)
("Test Preset", True),
("Mein schönes Preset", True), # German with ö
("Préférence française", True), # French with accents
("Configuración español", True), # Spanish with ñ
("Test_123", True),
("Hello-World", True),
("Тест", True), # Cyrillic
("テスト", True), # Japanese
("测试", True), # Chinese
# Invalid names (should fail)
("Test<Preset", False), # Contains <
("Test>Preset", False), # Contains >
("Test:Preset", False), # Contains :
("Test\"Preset", False), # Contains "
("Test|Preset", False), # Contains |
("Test?Preset", False), # Contains ?
("Test*Preset", False), # Contains *
("Test/Preset", False), # Contains /
("Test\\Preset", False), # Contains \
("", False), # Empty string
]
print("Testing preset name validation...")
for preset_name, should_pass in test_cases:
# Test the Unicode regex pattern
unicode_pattern_match = bool(re.match(r'^[\w\s\-]+$', preset_name, re.UNICODE))
# Test filesystem-unsafe characters
invalid_chars = ['<', '>', ':', '"', '|', '?', '*', '/', '\\']
has_invalid_chars = any(char in preset_name for char in invalid_chars)
# Combined validation (same as in the actual code)
validation_passes = unicode_pattern_match and not has_invalid_chars and preset_name.strip()
status = "✅ PASS" if validation_passes == should_pass else "❌ FAIL"
print(f"{status}: '{preset_name}' -> Expected: {should_pass}, Got: {validation_passes}")
if validation_passes != should_pass:
print(f" Unicode match: {unicode_pattern_match}, Has invalid chars: {has_invalid_chars}")
def test_json_serialization():
"""Test that Unicode characters work correctly with JSON serialization/deserialization"""
print("\nTesting JSON serialization with Unicode characters...")
test_data = {
'name': 'Schönes Preset',
'text': 'Höllö Wörld',
'texture_width': 1024,
'texture_height': 1024,
'font_size': 96
}
try:
# Test JSON encoding/decoding
json_str = json.dumps(test_data, indent=2, ensure_ascii=False)
decoded_data = json.loads(json_str)
print("✅ JSON serialization successful")
print(f"Original name: {test_data['name']}")
print(f"Decoded name: {decoded_data['name']}")
print(f"Names match: {test_data['name'] == decoded_data['name']}")
# Test file I/O
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
json.dump(test_data, f, indent=2, ensure_ascii=False)
temp_file = f.name
with open(temp_file, 'r', encoding='utf-8') as f:
file_data = json.load(f)
os.unlink(temp_file)
print("✅ File I/O successful")
print(f"File data name: {file_data['name']}")
print(f"File names match: {test_data['name'] == file_data['name']}")
except Exception as e:
print(f"❌ JSON serialization failed: {e}")
def test_filesystem_compatibility():
"""Test creating files with Unicode names"""
print("\nTesting filesystem compatibility...")
test_names = [
"schönes_preset",
"café_preset",
"naïve_preset",
"test_ñ_preset"
]
temp_dir = tempfile.mkdtemp()
print(f"Testing in directory: {temp_dir}")
for name in test_names:
try:
filename = f"{name}.json"
filepath = os.path.join(temp_dir, filename)
# Create file
with open(filepath, 'w', encoding='utf-8') as f:
json.dump({'name': name}, f, ensure_ascii=False)
# Read file back
with open(filepath, 'r', encoding='utf-8') as f:
data = json.load(f)
# Clean up
os.unlink(filepath)
print(f"{name}: File created and read successfully")
except Exception as e:
print(f"{name}: Failed - {e}")
# Clean up temp directory
os.rmdir(temp_dir)
if __name__ == "__main__":
print("=" * 60)
print("Testing Text Texture Generator Preset Unicode Support")
print("=" * 60)
test_preset_name_validation()
test_json_serialization()
test_filesystem_compatibility()
print("\n" + "=" * 60)
print("Test completed! Check results above.")
print("=" * 60)

View File

@@ -1,231 +0,0 @@
#!/usr/bin/env python3
"""
Advanced UI Integration and Backward Compatibility Test Suite
for the Text Texture Generator's enhanced positioning system.
This focuses on potential issues that the basic positioning tests might miss.
"""
import sys
import re
class UICompatibilityTestSuite:
"""Test suite focused on UI integration and compatibility issues"""
def __init__(self):
self.issues_found = []
self.warnings = []
def analyze_ui_layout_structure(self):
"""Analyze the UI layout structure from the addon code"""
print("\n=== Analyzing UI Layout Structure ===")
# Read the addon code to analyze UI structure
try:
with open('__init__.py', 'r') as f:
addon_code = f.read()
except FileNotFoundError:
self.issues_found.append("❌ Cannot read __init__.py for UI analysis")
return
# Check for Positioning & Alignment section
if "Positioning & Alignment" in addon_code:
print("'Positioning & Alignment' section found in UI")
else:
self.issues_found.append("'Positioning & Alignment' section not found in UI")
# Check for position mode toggle
if 'position_mode' in addon_code and 'PRESET' in addon_code and 'MANUAL' in addon_code:
print("✅ Position mode toggle implementation found")
else:
self.issues_found.append("❌ Position mode toggle not properly implemented")
# Check for 3x3 anchor grid implementation
anchor_grid_patterns = [
r'get_anchor_point_matrix\(\)',
r'for.*anchor.*in.*matrix',
r'grid_row.*=.*position_col\.row'
]
grid_found = all(re.search(pattern, addon_code, re.DOTALL) for pattern in anchor_grid_patterns)
if grid_found:
print("✅ 3x3 anchor grid UI implementation found")
else:
self.issues_found.append("❌ 3x3 anchor grid UI implementation incomplete")
# Check for margin controls with link functionality
if 'margins_linked' in addon_code and 'LINKED' in addon_code and 'UNLINKED' in addon_code:
print("✅ Margin link/unlink controls found")
else:
self.issues_found.append("❌ Margin link/unlink controls not properly implemented")
# Check for conditional UI visibility
if 'position_mode == ' in addon_code:
print("✅ Conditional UI visibility based on position mode found")
else:
self.warnings.append("⚠️ No conditional UI visibility found - controls might always be visible")
def test_backward_compatibility_integration(self):
"""Test how the new system integrates with existing text_align property"""
print("\n=== Testing Backward Compatibility Integration ===")
try:
with open('__init__.py', 'r') as f:
addon_code = f.read()
except FileNotFoundError:
self.issues_found.append("❌ Cannot read addon code for compatibility analysis")
return
# Find the backward compatibility section in generate_texture_image
compat_section = re.search(
r'# Apply legacy text_align.*?props\.anchor_point == \'MIDDLE_CENTER\'.*?# Apply offsets even in legacy mode',
addon_code, re.DOTALL
)
if compat_section:
print("✅ Backward compatibility section found in texture generation")
# Check if all text_align values are handled
compat_code = compat_section.group(0)
align_values = ['left', 'center', 'right']
missing_aligns = []
for align in align_values:
if f"text_align == '{align}'" not in compat_code:
missing_aligns.append(align)
if missing_aligns:
self.issues_found.append(f"❌ Missing text_align compatibility for: {missing_aligns}")
else:
print("✅ All text_align values have compatibility handling")
# Check if legacy mode only applies to MIDDLE_CENTER
if "anchor_point == 'MIDDLE_CENTER'" in compat_code:
print("✅ Legacy compatibility properly scoped to MIDDLE_CENTER anchor")
else:
self.issues_found.append("❌ Legacy compatibility scope issue - should only apply to MIDDLE_CENTER")
else:
self.issues_found.append("❌ Backward compatibility section not found in texture generation")
# Check if text_align property is still defined
if re.search(r'text_align.*EnumProperty', addon_code):
print("✅ Legacy text_align property still defined")
else:
self.issues_found.append("❌ Legacy text_align property not found - breaking change!")
def analyze_property_update_chains(self):
"""Analyze property update chains for consistency"""
print("\n=== Analyzing Property Update Chains ===")
try:
with open('__init__.py', 'r') as f:
addon_code = f.read()
except FileNotFoundError:
self.issues_found.append("❌ Cannot read addon code for update chain analysis")
return
# Find all properties with update=update_live_preview
update_properties = re.findall(r'(\w+):\s*\w+Property.*?update=update_live_preview', addon_code, re.DOTALL)
expected_positioning_props = [
'anchor_point', 'position_mode', 'margin_x', 'margin_y',
'margins_linked', 'offset_x', 'offset_y', 'manual_position_x',
'manual_position_y', 'manual_position_unit', 'constrain_to_canvas'
]
missing_updates = []
for prop in expected_positioning_props:
if prop not in update_properties:
missing_updates.append(prop)
if missing_updates:
self.issues_found.append(f"❌ Properties missing live preview updates: {missing_updates}")
else:
print("✅ All positioning properties have live preview updates")
# Check for visual feedback properties
visual_props = ['show_position_guides', 'show_text_bounds', 'show_canvas_grid']
missing_visual_updates = []
for prop in visual_props:
if prop not in update_properties:
missing_visual_updates.append(prop)
if missing_visual_updates:
self.issues_found.append(f"❌ Visual feedback properties missing updates: {missing_visual_updates}")
else:
print("✅ All visual feedback properties have live preview updates")
def run_compatibility_tests(self):
"""Run all compatibility and UI integration tests"""
print("🔍 UI INTEGRATION & COMPATIBILITY TEST SUITE")
print("=" * 55)
try:
self.analyze_ui_layout_structure()
self.test_backward_compatibility_integration()
self.analyze_property_update_chains()
except Exception as e:
print(f"❌ Critical error during compatibility testing: {e}")
import traceback
traceback.print_exc()
self.generate_compatibility_report()
def generate_compatibility_report(self):
"""Generate compatibility and UI integration report"""
print("\n" + "=" * 60)
print("📊 UI INTEGRATION & COMPATIBILITY REPORT")
print("=" * 60)
total_issues = len(self.issues_found)
total_warnings = len(self.warnings)
print(f"📈 SUMMARY:")
print(f" 🚨 Critical Issues: {total_issues}")
print(f" ⚠️ Warnings: {total_warnings}")
if self.issues_found:
print(f"\n🚨 CRITICAL ISSUES FOUND ({total_issues}):")
for issue in self.issues_found:
print(f" {issue}")
if self.warnings:
print(f"\n⚠️ WARNINGS ({total_warnings}):")
for warning in self.warnings:
print(f" {warning}")
if not self.issues_found and not self.warnings:
print("\n🎉 NO CRITICAL ISSUES OR WARNINGS FOUND!")
print(" The UI integration and compatibility appear to be well implemented.")
# Recommendations based on findings
print(f"\n🎯 RECOMMENDATIONS:")
if total_issues > 0:
print(" 1. 🚨 Address all critical issues before deployment")
print(" 2. Test UI elements thoroughly in actual Blender environment")
if total_warnings > 0:
print(" 3. ⚠️ Review and address warnings for robustness")
print(" 4. Add explicit error handling for edge cases")
print(" 5. ✅ Add automated UI tests to prevent regressions")
print(" 6. ✅ Test backward compatibility with existing presets")
print(" 7. ✅ Validate all property ranges in actual use cases")
return {
'critical_issues': total_issues,
'warnings': total_warnings,
'issues_list': self.issues_found,
'warnings_list': self.warnings
}
if __name__ == "__main__":
print("🚀 Starting UI Integration & Compatibility Test Suite...")
test_suite = UICompatibilityTestSuite()
results = test_suite.run_compatibility_tests()
print(f"\n✨ UI & Compatibility testing completed!")