pyWebLayout/tests/test_new_pagination_system.py
2025-06-08 17:17:09 +02:00

192 lines
7.4 KiB
Python

#!/usr/bin/env python3
"""
Unit tests for the new external pagination system.
Tests the BlockPaginator and handler architecture to ensure it works correctly
with different block types using the unittest framework.
"""
import unittest
from pyWebLayout.abstract.block import Paragraph, Heading, HeadingLevel
from pyWebLayout.abstract.inline import Word
from pyWebLayout.concrete.page import Page
from pyWebLayout.style.fonts import Font
from pyWebLayout.typesetting.block_pagination import BlockPaginator, PaginationResult
class TestNewPaginationSystem(unittest.TestCase):
"""Test cases for the new pagination system."""
def setUp(self):
"""Set up test fixtures."""
self.font = Font(font_size=16)
self.heading_font = Font(font_size=20)
def create_test_paragraph(self, text: str, font: Font = None) -> Paragraph:
"""Create a test paragraph with the given text."""
if font is None:
font = self.font
paragraph = Paragraph(font)
words = text.split()
for word_text in words:
word = Word(word_text, font)
paragraph.add_word(word)
return paragraph
def create_test_heading(self, text: str, level: HeadingLevel = HeadingLevel.H1) -> Heading:
"""Create a test heading with the given text."""
heading = Heading(level, self.heading_font)
words = text.split()
for word_text in words:
word = Word(word_text, self.heading_font)
heading.add_word(word)
return heading
def test_paragraph_pagination(self):
"""Test paragraph pagination with line breaking."""
# Create a long paragraph
long_text = " ".join(["This is a very long paragraph that should be broken across multiple lines."] * 10)
paragraph = self.create_test_paragraph(long_text)
# Create a page with limited height
page = Page(size=(400, 200)) # Small page
# Test the pagination handler
paginator = BlockPaginator()
result = paginator.paginate_block(paragraph, page, available_height=100)
# Assertions
self.assertIsInstance(result, PaginationResult)
self.assertIsInstance(result.success, bool)
self.assertIsInstance(result.height_used, (int, float))
self.assertGreaterEqual(result.height_used, 0)
def test_page_filling(self):
"""Test filling a page with multiple blocks."""
# Create test blocks
blocks = [
self.create_test_heading("Chapter 1: Introduction"),
self.create_test_paragraph("This is the first paragraph of the chapter. It contains some introductory text."),
self.create_test_paragraph("This is the second paragraph. It has more content and should flow nicely."),
self.create_test_heading("Section 1.1: Overview", HeadingLevel.H2),
self.create_test_paragraph("This is a paragraph under the section. It has even more content that might not fit on the same page."),
self.create_test_paragraph("This is another long paragraph that definitely won't fit. " * 20),
]
# Create a page
page = Page(size=(600, 400))
# Fill the page
next_index, remainder_blocks = page.fill_with_blocks(blocks)
# Assertions
self.assertIsInstance(next_index, int)
self.assertGreaterEqual(next_index, 0)
self.assertLessEqual(next_index, len(blocks))
self.assertIsInstance(remainder_blocks, list)
self.assertGreaterEqual(len(page._children), 0)
# Try to render the page
try:
page_image = page.render()
self.assertIsNotNone(page_image)
self.assertEqual(len(page_image.size), 2) # Should have width and height
except Exception as e:
self.fail(f"Page rendering failed: {e}")
def test_multi_page_creation(self):
"""Test creating multiple pages from a list of blocks."""
# Create many test blocks
blocks = []
for i in range(5): # Reduced for faster testing
blocks.append(self.create_test_heading(f"Chapter {i+1}"))
for j in range(2): # Reduced for faster testing
long_text = f"This is paragraph {j+1} of chapter {i+1}. " * 10
blocks.append(self.create_test_paragraph(long_text))
self.assertGreater(len(blocks), 0)
# Create pages until all blocks are processed
pages = []
remaining_blocks = blocks
page_count = 0
while remaining_blocks and page_count < 10: # Safety limit
page = Page(size=(600, 400))
next_index, remainder_blocks = page.fill_with_blocks(remaining_blocks)
if page._children:
pages.append(page)
page_count += 1
# Update remaining blocks
if remainder_blocks:
remaining_blocks = remainder_blocks
elif next_index < len(remaining_blocks):
remaining_blocks = remaining_blocks[next_index:]
else:
remaining_blocks = []
# Safety check to prevent infinite loops
if not page._children and remaining_blocks:
break
# Assertions
self.assertGreater(len(pages), 0, "Should create at least one page")
self.assertLessEqual(page_count, 10, "Should not exceed safety limit")
# Try to render a few pages
rendered_count = 0
for page in pages[:2]: # Test first 2 pages
try:
page_image = page.render()
rendered_count += 1
self.assertIsNotNone(page_image)
except Exception as e:
self.fail(f"Page rendering failed: {e}")
self.assertGreater(rendered_count, 0, "Should render at least one page")
def test_empty_blocks_list(self):
"""Test handling of empty blocks list."""
page = Page(size=(600, 400))
next_index, remainder_blocks = page.fill_with_blocks([])
self.assertEqual(next_index, 0)
self.assertEqual(len(remainder_blocks), 0)
self.assertEqual(len(page._children), 0)
def test_single_block(self):
"""Test handling of single block."""
blocks = [self.create_test_paragraph("Single paragraph test.")]
page = Page(size=(600, 400))
next_index, remainder_blocks = page.fill_with_blocks(blocks)
self.assertEqual(next_index, 1)
self.assertEqual(len(remainder_blocks), 0)
self.assertGreater(len(page._children), 0)
def test_pagination_result_properties(self):
"""Test PaginationResult object properties."""
paragraph = self.create_test_paragraph("Test paragraph for pagination result.")
page = Page(size=(400, 200))
paginator = BlockPaginator()
result = paginator.paginate_block(paragraph, page, available_height=100)
# Test that result has expected properties
self.assertTrue(hasattr(result, 'success'))
self.assertTrue(hasattr(result, 'height_used'))
self.assertTrue(hasattr(result, 'remainder'))
self.assertTrue(hasattr(result, 'can_continue'))
if __name__ == '__main__':
unittest.main()