@@ -28,6 +28,11 @@ class TestDocumentLayouter:
|
||||
self.mock_page.can_fit_line = Mock(return_value=True)
|
||||
self.mock_page.add_child = Mock()
|
||||
|
||||
# Create mock page style with all required numeric properties
|
||||
self.mock_page.style = Mock()
|
||||
self.mock_page.style.max_font_size = 72 # Reasonable maximum font size
|
||||
self.mock_page.style.line_spacing_multiplier = 1.2 # Standard line spacing
|
||||
|
||||
# Create mock style resolver
|
||||
self.mock_style_resolver = Mock()
|
||||
self.mock_page.style_resolver = self.mock_style_resolver
|
||||
@@ -51,12 +56,20 @@ class TestDocumentLayouter:
|
||||
self.mock_concrete_style.word_spacing_max = 8.0
|
||||
self.mock_concrete_style.text_align = "left"
|
||||
|
||||
# Create mock font that returns proper metrics
|
||||
# Create mock font that returns proper numeric metrics (not Mock objects)
|
||||
mock_font = Mock()
|
||||
mock_font.getmetrics.return_value = (12, 4) # (ascent, descent)
|
||||
# CRITICAL: getmetrics() must return actual numeric values, not Mock objects
|
||||
# This prevents "TypeError: '>' not supported between instances of 'Mock' and 'Mock'"
|
||||
mock_font.getmetrics.return_value = (12, 4) # (ascent, descent) as actual integers
|
||||
mock_font.font = mock_font # For accessing .font property
|
||||
|
||||
self.mock_concrete_style.create_font = Mock()
|
||||
# Create mock font object that can be used by create_font
|
||||
mock_font_instance = Mock()
|
||||
mock_font_instance.font = mock_font
|
||||
mock_font_instance.font_size = 16
|
||||
mock_font_instance.colour = (0, 0, 0)
|
||||
mock_font_instance.background = (255, 255, 255, 0)
|
||||
self.mock_concrete_style.create_font = Mock(return_value=mock_font_instance)
|
||||
|
||||
# Update mock words to have proper style with font
|
||||
for word in self.mock_words:
|
||||
@@ -66,11 +79,15 @@ class TestDocumentLayouter:
|
||||
word.style.colour = (0, 0, 0)
|
||||
word.style.background = None
|
||||
|
||||
@patch('pyWebLayout.layout.document_layouter.StyleResolver')
|
||||
@patch('pyWebLayout.layout.document_layouter.ConcreteStyleRegistry')
|
||||
@patch('pyWebLayout.layout.document_layouter.Line')
|
||||
def test_paragraph_layouter_basic_flow(self, mock_line_class, mock_style_registry_class):
|
||||
def test_paragraph_layouter_basic_flow(self, mock_line_class, mock_style_registry_class, mock_style_resolver_class):
|
||||
"""Test basic paragraph layouter functionality."""
|
||||
# Setup mocks
|
||||
# Setup mocks for StyleResolver and ConcreteStyleRegistry
|
||||
mock_style_resolver = Mock()
|
||||
mock_style_resolver_class.return_value = mock_style_resolver
|
||||
|
||||
mock_style_registry = Mock()
|
||||
mock_style_registry_class.return_value = mock_style_registry
|
||||
mock_style_registry.get_concrete_style.return_value = self.mock_concrete_style
|
||||
@@ -88,8 +105,9 @@ class TestDocumentLayouter:
|
||||
assert failed_word_index is None
|
||||
assert remaining_pretext is None
|
||||
|
||||
# Verify style registry was used correctly
|
||||
mock_style_registry_class.assert_called_once_with(self.mock_page.style_resolver)
|
||||
# Verify StyleResolver and ConcreteStyleRegistry were created correctly
|
||||
mock_style_resolver_class.assert_called_once()
|
||||
mock_style_registry_class.assert_called_once_with(mock_style_resolver)
|
||||
mock_style_registry.get_concrete_style.assert_called_once_with(self.mock_paragraph.style)
|
||||
|
||||
# Verify Line was created with correct spacing constraints
|
||||
@@ -98,16 +116,27 @@ class TestDocumentLayouter:
|
||||
call_args = mock_line_class.call_args
|
||||
assert call_args[1]['spacing'] == expected_spacing
|
||||
|
||||
@patch('pyWebLayout.layout.document_layouter.StyleResolver')
|
||||
@patch('pyWebLayout.layout.document_layouter.ConcreteStyleRegistry')
|
||||
@patch('pyWebLayout.layout.document_layouter.Line')
|
||||
def test_paragraph_layouter_word_spacing_constraints_extraction(self, mock_line_class, mock_style_registry_class):
|
||||
def test_paragraph_layouter_word_spacing_constraints_extraction(self, mock_line_class, mock_style_registry_class, mock_style_resolver_class):
|
||||
"""Test that word spacing constraints are correctly extracted from style."""
|
||||
# Create concrete style with specific constraints
|
||||
concrete_style = Mock()
|
||||
concrete_style.word_spacing_min = 5.5
|
||||
concrete_style.word_spacing_max = 15.2
|
||||
concrete_style.text_align = "justify"
|
||||
concrete_style.create_font = Mock()
|
||||
|
||||
# Create a mock font that concrete_style.create_font returns
|
||||
mock_font = Mock()
|
||||
mock_font.font = Mock()
|
||||
mock_font.font.getmetrics.return_value = (12, 4)
|
||||
mock_font.font_size = 16
|
||||
concrete_style.create_font = Mock(return_value=mock_font)
|
||||
|
||||
# Setup StyleResolver and ConcreteStyleRegistry mocks
|
||||
mock_style_resolver = Mock()
|
||||
mock_style_resolver_class.return_value = mock_style_resolver
|
||||
|
||||
mock_style_registry = Mock()
|
||||
mock_style_registry_class.return_value = mock_style_registry
|
||||
@@ -252,39 +281,51 @@ class TestDocumentLayouter:
|
||||
)
|
||||
assert result == (True, None, None)
|
||||
|
||||
@patch('pyWebLayout.layout.document_layouter.paragraph_layouter')
|
||||
def test_document_layouter_layout_document_success(self, mock_paragraph_layouter):
|
||||
def test_document_layouter_layout_document_success(self):
|
||||
"""Test DocumentLayouter.layout_document with successful layout."""
|
||||
mock_paragraph_layouter.return_value = (True, None, None)
|
||||
from pyWebLayout.abstract import Paragraph
|
||||
|
||||
paragraphs = [self.mock_paragraph, Mock(), Mock()]
|
||||
# Create Mock paragraphs that pass isinstance checks
|
||||
paragraphs = [
|
||||
Mock(spec=Paragraph),
|
||||
Mock(spec=Paragraph),
|
||||
Mock(spec=Paragraph)
|
||||
]
|
||||
|
||||
with patch('pyWebLayout.layout.document_layouter.ConcreteStyleRegistry'):
|
||||
layouter = DocumentLayouter(self.mock_page)
|
||||
|
||||
# Mock the layout_paragraph method to return success
|
||||
layouter.layout_paragraph = Mock(return_value=(True, None, None))
|
||||
|
||||
result = layouter.layout_document(paragraphs)
|
||||
|
||||
assert result is True
|
||||
assert mock_paragraph_layouter.call_count == 3
|
||||
assert layouter.layout_paragraph.call_count == 3
|
||||
|
||||
@patch('pyWebLayout.layout.document_layouter.paragraph_layouter')
|
||||
def test_document_layouter_layout_document_failure(self, mock_paragraph_layouter):
|
||||
def test_document_layouter_layout_document_failure(self):
|
||||
"""Test DocumentLayouter.layout_document with layout failure."""
|
||||
# First paragraph succeeds, second fails
|
||||
mock_paragraph_layouter.side_effect = [
|
||||
(True, None, None), # First paragraph succeeds
|
||||
(False, 3, None), # Second paragraph fails
|
||||
]
|
||||
from pyWebLayout.abstract import Paragraph
|
||||
|
||||
paragraphs = [self.mock_paragraph, Mock()]
|
||||
# Create Mock paragraphs that pass isinstance checks
|
||||
paragraphs = [
|
||||
Mock(spec=Paragraph),
|
||||
Mock(spec=Paragraph)
|
||||
]
|
||||
|
||||
with patch('pyWebLayout.layout.document_layouter.ConcreteStyleRegistry'):
|
||||
layouter = DocumentLayouter(self.mock_page)
|
||||
|
||||
# Mock the layout_paragraph method: first succeeds, second fails
|
||||
layouter.layout_paragraph = Mock(side_effect=[
|
||||
(True, None, None), # First paragraph succeeds
|
||||
(False, 3, None), # Second paragraph fails
|
||||
])
|
||||
|
||||
result = layouter.layout_document(paragraphs)
|
||||
|
||||
assert result is False
|
||||
assert mock_paragraph_layouter.call_count == 2
|
||||
assert layouter.layout_paragraph.call_count == 2
|
||||
|
||||
def test_real_style_integration(self):
|
||||
"""Test integration with real style system."""
|
||||
|
||||
Reference in New Issue
Block a user