This commit is contained in:
2025-09-13 10:38:28 +03:00
parent 7c40714d48
commit 7c041e2a26
45 changed files with 1936 additions and 2 deletions

View File

@@ -0,0 +1,3 @@
"""
Integration tests for Text Texture Generator.
"""

Binary file not shown.

View File

@@ -0,0 +1,204 @@
"""
Integration tests for the complete text generation pipeline.
Tests how the core modules work together.
"""
import pytest
from unittest.mock import Mock, patch, MagicMock
import sys
import os
# Add src to path for importing modules
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../src'))
from fixtures.sample_data import *
class TestTextGenerationPipeline:
"""Integration tests for the complete text generation workflow"""
@pytest.mark.integration
@patch('src.core.text_processor.process_multiline_text')
@patch('src.core.text_fitting.find_optimal_font_size')
@patch('src.core.text_fitting.calculate_text_position')
def test_basic_text_generation_workflow(self, mock_calc_position, mock_find_size, mock_process_text):
"""Test the basic workflow from text input to positioned output"""
# Setup mocks
mock_process_text.return_value = {
'lines': ['Hello', 'World'],
'total_height': 40,
'line_count': 2
}
mock_find_size.return_value = 24
mock_calc_position.return_value = {
'x': 50, 'y': 50,
'text_width': 100, 'text_height': 40
}
# Simulate a basic workflow
text = "Hello\nWorld"
font = Mock()
canvas_width, canvas_height = 300, 200
# Step 1: Process multiline text
from src.core.text_processor import process_multiline_text
processed = process_multiline_text(text, font, canvas_width, canvas_height)
# Step 2: Find optimal font size
from src.core.text_fitting import find_optimal_font_size
optimal_size = find_optimal_font_size(text, "/fake/font.ttf", 200, 100)
# Step 3: Calculate position
from src.core.text_fitting import calculate_text_position
available_area = {'x': 0, 'y': 0, 'width': canvas_width, 'height': canvas_height}
position = calculate_text_position(text, font, available_area, 'center')
# Verify workflow completed
assert processed['line_count'] == 2
assert optimal_size == 24
assert position['x'] == 50 and position['y'] == 50
# Verify functions were called in sequence
mock_process_text.assert_called_once()
mock_find_size.assert_called_once()
mock_calc_position.assert_called_once()
@pytest.mark.integration
@patch('src.core.text_fitting.check_text_overlap')
@patch('src.core.text_fitting.resolve_text_conflicts')
def test_overlap_detection_and_resolution_workflow(self, mock_resolve, mock_check):
"""Test the workflow for detecting and resolving text overlaps"""
# Setup mocks
mock_check.return_value = [(0, 1)] # Positions 0 and 1 overlap
mock_resolve.return_value = [
{'x': 0, 'y': 0, 'width': 100, 'height': 50},
{'x': 0, 'y': 60, 'width': 100, 'height': 50} # Moved down
]
# Initial overlapping positions
positions = [
{'x': 0, 'y': 0, 'width': 100, 'height': 50},
{'x': 50, 'y': 25, 'width': 100, 'height': 50} # Overlaps
]
# Step 1: Check for overlaps
from src.core.text_fitting import check_text_overlap
overlaps = check_text_overlap(positions)
# Step 2: Resolve conflicts
from src.core.text_fitting import resolve_text_conflicts
resolved = resolve_text_conflicts(positions, 500, 400)
# Verify workflow
assert len(overlaps) == 1
assert len(resolved) == 2
assert resolved[1]['y'] == 60 # Second position moved down
mock_check.assert_called_once_with(positions)
mock_resolve.assert_called_once()
@pytest.mark.integration
def test_text_metrics_and_fitting_integration(self):
"""Test integration between text metrics calculation and fitting"""
with patch('src.core.text_processor.calculate_text_metrics') as mock_metrics, \
patch('src.core.text_fitting.calculate_text_scaling') as mock_scaling:
# Setup mocks
mock_metrics.return_value = {
'width': 200, 'height': 50,
'ascent': 40, 'descent': 10
}
mock_scaling.return_value = (1.5, 2.0, 1.5) # width_scale, height_scale, uniform_scale
# Test workflow
font = Mock()
text = "Sample Text"
from src.core.text_processor import calculate_text_metrics
from src.core.text_fitting import calculate_text_scaling
# Get text metrics
metrics = calculate_text_metrics(text, font)
# Calculate scaling based on metrics
scaling = calculate_text_scaling(text, font, 300, 100)
# Verify integration
assert metrics['width'] == 200
assert metrics['height'] == 50
assert scaling[2] == 1.5 # uniform_scale
mock_metrics.assert_called_once_with(text, font)
mock_scaling.assert_called_once()
@pytest.mark.integration
@patch('src.core.text_fitting.calculate_available_text_area')
@patch('src.core.text_processor.optimize_text_layout')
def test_area_calculation_and_layout_optimization(self, mock_optimize, mock_calc_area):
"""Test integration between area calculation and layout optimization"""
# Setup mocks
mock_calc_area.return_value = {
'x': 10, 'y': 10, 'width': 300, 'height': 200, 'area': 60000
}
mock_optimize.return_value = [
{'x': 10, 'y': 10, 'width': 100, 'height': 50, 'text': 'Block 1'},
{'x': 150, 'y': 10, 'width': 80, 'height': 40, 'text': 'Block 2'}
]
# Test data
canvas_width, canvas_height = 400, 300
overlays = [{'x': 350, 'y': 250, 'width': 50, 'height': 50}]
text_blocks = [
{'x': 50, 'y': 50, 'width': 100, 'height': 50, 'text': 'Block 1'},
{'x': 75, 'y': 75, 'width': 80, 'height': 40, 'text': 'Block 2'} # Overlaps
]
# Test workflow
from src.core.text_fitting import calculate_available_text_area
from src.core.text_processor import optimize_text_layout
# Step 1: Calculate available area
available_area = calculate_available_text_area(canvas_width, canvas_height, overlays)
# Step 2: Optimize layout
optimized_blocks = optimize_text_layout(text_blocks, canvas_width, canvas_height)
# Verify integration
assert available_area['width'] == 300
assert available_area['area'] == 60000
assert len(optimized_blocks) == 2
assert optimized_blocks[0]['x'] == 10 # First block positioned in available area
mock_calc_area.assert_called_once_with(canvas_width, canvas_height, overlays)
mock_optimize.assert_called_once_with(text_blocks, canvas_width, canvas_height)
class TestErrorHandlingIntegration:
"""Integration tests for error handling across modules"""
@pytest.mark.integration
def test_graceful_degradation_on_font_errors(self):
"""Test that the system degrades gracefully when font operations fail"""
with patch('PIL.ImageFont.truetype') as mock_truetype:
mock_truetype.side_effect = OSError("Font not found")
# Test that font size finding falls back gracefully
from src.core.text_fitting import find_optimal_font_size
result = find_optimal_font_size("Test", "/fake/font.ttf", 200, 100)
assert result == 8 # Should fall back to minimum size
@pytest.mark.integration
def test_error_handling_in_text_processing_chain(self):
"""Test error handling when text processing components fail"""
with patch('src.core.text_processor.wrap_text_to_width') as mock_wrap:
mock_wrap.side_effect = Exception("Text wrapping failed")
# Test that multiline processing handles wrap failures
from src.core.text_processor import process_multiline_text
result = process_multiline_text("Test text", Mock(), 200, 100)
# Should return fallback result instead of crashing
assert 'lines' in result
assert 'total_height' in result
assert 'line_count' in result