Files
Text-Texture-Generator-for-…/tests/integration/test_text_generation_pipeline.py
2025-09-13 10:38:28 +03:00

204 lines
8.4 KiB
Python

"""
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