@@ -9,9 +9,11 @@ import pytest
|
||||
from unittest.mock import Mock, MagicMock, patch
|
||||
from typing import List, Optional
|
||||
|
||||
from pyWebLayout.layout.document_layouter import paragraph_layouter, DocumentLayouter
|
||||
from pyWebLayout.layout.document_layouter import paragraph_layouter, table_layouter, DocumentLayouter
|
||||
from pyWebLayout.style.abstract_style import AbstractStyle
|
||||
from pyWebLayout.style.concrete_style import ConcreteStyle, StyleResolver, RenderingContext
|
||||
from pyWebLayout.abstract.block import Table, TableRow, TableCell
|
||||
from pyWebLayout.concrete.table import TableStyle
|
||||
|
||||
|
||||
class TestDocumentLayouter:
|
||||
@@ -577,6 +579,179 @@ class TestMultiPageLayout:
|
||||
print(f" - Word spacing constraints: {concrete_style.word_spacing_min}-{concrete_style.word_spacing_max}px")
|
||||
|
||||
|
||||
class TestTableLayouter:
|
||||
"""Test cases for table layouter functionality."""
|
||||
|
||||
def setup_method(self):
|
||||
"""Set up test fixtures before each test method."""
|
||||
# Create mock page
|
||||
self.mock_page = Mock()
|
||||
self.mock_page.border_size = 20
|
||||
self.mock_page._current_y_offset = 50
|
||||
self.mock_page.available_width = 600
|
||||
self.mock_page.size = (800, 1000)
|
||||
|
||||
# Create mock draw and canvas
|
||||
self.mock_draw = Mock()
|
||||
self.mock_canvas = Mock()
|
||||
self.mock_page.draw = self.mock_draw
|
||||
self.mock_page._canvas = self.mock_canvas
|
||||
|
||||
# Create mock table
|
||||
self.mock_table = Mock(spec=Table)
|
||||
|
||||
# Create mock style resolver
|
||||
self.mock_style_resolver = Mock()
|
||||
self.mock_page.style_resolver = self.mock_style_resolver
|
||||
|
||||
@patch('pyWebLayout.layout.document_layouter.TableRenderer')
|
||||
def test_table_layouter_success(self, mock_table_renderer_class):
|
||||
"""Test table_layouter with successful table rendering."""
|
||||
# Setup mock renderer
|
||||
mock_renderer = Mock()
|
||||
mock_table_renderer_class.return_value = mock_renderer
|
||||
mock_renderer.size = (500, 200) # Table fits on page
|
||||
|
||||
# Call function
|
||||
result = table_layouter(self.mock_table, self.mock_page)
|
||||
|
||||
# Verify results
|
||||
assert result is True
|
||||
|
||||
# Verify TableRenderer was created with correct parameters
|
||||
mock_table_renderer_class.assert_called_once_with(
|
||||
table=self.mock_table,
|
||||
origin=(20, 50), # (border_size, current_y_offset)
|
||||
available_width=600,
|
||||
draw=self.mock_draw,
|
||||
style=None,
|
||||
canvas=self.mock_canvas
|
||||
)
|
||||
|
||||
# Verify render was called
|
||||
mock_renderer.render.assert_called_once()
|
||||
|
||||
# Verify y_offset was updated
|
||||
assert self.mock_page._current_y_offset == 250 # 50 + 200
|
||||
|
||||
@patch('pyWebLayout.layout.document_layouter.TableRenderer')
|
||||
def test_table_layouter_with_custom_style(self, mock_table_renderer_class):
|
||||
"""Test table_layouter with custom TableStyle."""
|
||||
# Create custom style
|
||||
custom_style = TableStyle(
|
||||
border_width=2,
|
||||
border_color=(100, 100, 100),
|
||||
cell_padding=(10, 10, 10, 10)
|
||||
)
|
||||
|
||||
# Setup mock renderer
|
||||
mock_renderer = Mock()
|
||||
mock_table_renderer_class.return_value = mock_renderer
|
||||
mock_renderer.size = (500, 150)
|
||||
|
||||
# Call function with style
|
||||
result = table_layouter(self.mock_table, self.mock_page, style=custom_style)
|
||||
|
||||
# Verify TableRenderer was created with custom style
|
||||
assert result is True
|
||||
call_args = mock_table_renderer_class.call_args
|
||||
assert call_args[1]['style'] == custom_style
|
||||
|
||||
@patch('pyWebLayout.layout.document_layouter.TableRenderer')
|
||||
def test_table_layouter_table_too_large(self, mock_table_renderer_class):
|
||||
"""Test table_layouter when table doesn't fit on page."""
|
||||
# Setup mock renderer with table larger than available space
|
||||
mock_renderer = Mock()
|
||||
mock_table_renderer_class.return_value = mock_renderer
|
||||
mock_renderer.size = (500, 1000) # Table height exceeds available space
|
||||
|
||||
# Available height = page_size[1] - y_offset - border_size
|
||||
# = 1000 - 50 - 20 = 930, but table is 1000 pixels tall
|
||||
|
||||
# Call function
|
||||
result = table_layouter(self.mock_table, self.mock_page)
|
||||
|
||||
# Verify failure
|
||||
assert result is False
|
||||
|
||||
# Verify render was NOT called
|
||||
mock_renderer.render.assert_not_called()
|
||||
|
||||
# Verify y_offset was NOT updated
|
||||
assert self.mock_page._current_y_offset == 50
|
||||
|
||||
@patch('pyWebLayout.layout.document_layouter.ConcreteStyleRegistry')
|
||||
def test_document_layouter_layout_table(self, mock_style_registry_class):
|
||||
"""Test DocumentLayouter.layout_table method."""
|
||||
# Setup mocks
|
||||
mock_style_registry = Mock()
|
||||
mock_style_registry_class.return_value = mock_style_registry
|
||||
|
||||
layouter = DocumentLayouter(self.mock_page)
|
||||
|
||||
# Mock the table_layouter function
|
||||
with patch('pyWebLayout.layout.document_layouter.table_layouter') as mock_table_layouter:
|
||||
mock_table_layouter.return_value = True
|
||||
|
||||
custom_style = TableStyle(border_width=1)
|
||||
result = layouter.layout_table(self.mock_table, style=custom_style)
|
||||
|
||||
# Verify the function was called correctly
|
||||
mock_table_layouter.assert_called_once_with(
|
||||
self.mock_table, self.mock_page, custom_style
|
||||
)
|
||||
assert result is True
|
||||
|
||||
def test_document_layouter_layout_document_with_table(self):
|
||||
"""Test DocumentLayouter.layout_document with Table elements."""
|
||||
from pyWebLayout.abstract import Paragraph
|
||||
from pyWebLayout.abstract.block import Image as AbstractImage
|
||||
|
||||
# Create mixed elements
|
||||
elements = [
|
||||
Mock(spec=Paragraph),
|
||||
Mock(spec=Table),
|
||||
Mock(spec=AbstractImage),
|
||||
Mock(spec=Table)
|
||||
]
|
||||
|
||||
with patch('pyWebLayout.layout.document_layouter.ConcreteStyleRegistry'):
|
||||
layouter = DocumentLayouter(self.mock_page)
|
||||
|
||||
# Mock the layout methods
|
||||
layouter.layout_paragraph = Mock(return_value=(True, None, None))
|
||||
layouter.layout_table = Mock(return_value=True)
|
||||
layouter.layout_image = Mock(return_value=True)
|
||||
|
||||
result = layouter.layout_document(elements)
|
||||
|
||||
# Verify all elements were laid out
|
||||
assert result is True
|
||||
assert layouter.layout_paragraph.call_count == 1
|
||||
assert layouter.layout_table.call_count == 2
|
||||
assert layouter.layout_image.call_count == 1
|
||||
|
||||
def test_document_layouter_layout_document_table_failure(self):
|
||||
"""Test DocumentLayouter.layout_document when table layout fails."""
|
||||
# Create elements with table that will fail
|
||||
elements = [
|
||||
Mock(spec=Table),
|
||||
Mock(spec=Table)
|
||||
]
|
||||
|
||||
with patch('pyWebLayout.layout.document_layouter.ConcreteStyleRegistry'):
|
||||
layouter = DocumentLayouter(self.mock_page)
|
||||
|
||||
# Mock layout_table: first succeeds, second fails
|
||||
layouter.layout_table = Mock(side_effect=[True, False])
|
||||
|
||||
result = layouter.layout_document(elements)
|
||||
|
||||
# Verify it stopped after failure
|
||||
assert result is False
|
||||
assert layouter.layout_table.call_count == 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run specific tests for debugging
|
||||
test = TestDocumentLayouter()
|
||||
|
||||
Reference in New Issue
Block a user