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

233 lines
8.9 KiB
Python

#!/usr/bin/env python3
"""
Unit tests for simple pagination logic without EPUB dependencies.
Tests basic pagination functionality using the unittest framework.
"""
import unittest
from pyWebLayout.concrete.page import Page
from pyWebLayout.concrete.text import Text
from pyWebLayout.style.fonts import Font
from pyWebLayout.abstract.block import Paragraph
from pyWebLayout.abstract.inline import Word
class TestSimplePagination(unittest.TestCase):
"""Test cases for simple pagination functionality."""
def setUp(self):
"""Set up test fixtures."""
self.font = Font(font_size=16)
self.page_size = (700, 550)
self.max_page_height = 510 # Leave room for padding
def create_test_paragraph(self, text_content: str) -> Paragraph:
"""Create a test paragraph with the given text."""
paragraph = Paragraph()
words = text_content.split()
for word_text in words:
word = Word(word_text, self.font)
paragraph.add_word(word)
return paragraph
def test_single_paragraph_pagination(self):
"""Test pagination with a single paragraph."""
text = "This is a simple paragraph for testing pagination functionality."
paragraph = self.create_test_paragraph(text)
page = Page(size=self.page_size)
# Convert block to renderable
renderable = page._convert_block_to_renderable(paragraph)
self.assertIsNotNone(renderable, "Should convert paragraph to renderable")
# Add to page
page.add_child(renderable)
self.assertEqual(len(page._children), 1)
# Layout should work
try:
page.layout()
except Exception as e:
self.fail(f"Layout failed: {e}")
# Render should work
try:
rendered_image = page.render()
self.assertIsNotNone(rendered_image)
self.assertEqual(rendered_image.size, self.page_size)
except Exception as e:
self.fail(f"Render failed: {e}")
def test_multiple_paragraphs_same_page(self):
"""Test adding multiple small paragraphs to the same page."""
paragraphs = [
"First short paragraph.",
"Second short paragraph.",
"Third short paragraph."
]
page = Page(size=self.page_size)
for i, text in enumerate(paragraphs):
paragraph = self.create_test_paragraph(text)
renderable = page._convert_block_to_renderable(paragraph)
self.assertIsNotNone(renderable, f"Should convert paragraph {i+1}")
page.add_child(renderable)
self.assertEqual(len(page._children), len(paragraphs))
# Layout should work with multiple children
try:
page.layout()
except Exception as e:
self.fail(f"Layout with multiple paragraphs failed: {e}")
# Calculate page height
max_bottom = self.calculate_page_height(page)
self.assertLessEqual(max_bottom, self.max_page_height, "Page should not exceed height limit")
def test_page_overflow_detection(self):
"""Test detection of page overflow."""
# Create a very long paragraph that should cause overflow
long_text = " ".join(["This is a very long paragraph with many words."] * 20)
paragraph = self.create_test_paragraph(long_text)
page = Page(size=self.page_size)
renderable = page._convert_block_to_renderable(paragraph)
page.add_child(renderable)
try:
page.layout()
max_bottom = self.calculate_page_height(page)
# Very long content might exceed page height
# This is expected behavior for testing overflow detection
self.assertIsInstance(max_bottom, (int, float))
except Exception as e:
# Layout might fail with very long content, which is acceptable
self.assertIsInstance(e, Exception)
def test_page_height_calculation(self):
"""Test page height calculation method."""
page = Page(size=self.page_size)
# Empty page should have height 0
height = self.calculate_page_height(page)
self.assertEqual(height, 0)
# Add content and check height increases
paragraph = self.create_test_paragraph("Test content for height calculation.")
renderable = page._convert_block_to_renderable(paragraph)
page.add_child(renderable)
page.layout()
height_with_content = self.calculate_page_height(page)
self.assertGreater(height_with_content, 0)
def test_multi_page_scenario(self):
"""Test creating multiple pages from content."""
# Create test content
test_paragraphs = [
"This is the first paragraph with some content.",
"Here is a second paragraph with different content.",
"The third paragraph continues with more text.",
"Fourth paragraph here with additional content.",
"Fifth paragraph with even more content for testing."
]
pages = []
current_page = Page(size=self.page_size)
for i, text in enumerate(test_paragraphs):
paragraph = self.create_test_paragraph(text)
renderable = current_page._convert_block_to_renderable(paragraph)
if renderable:
# Store current state for potential rollback
children_backup = current_page._children.copy()
# Add to current page
current_page.add_child(renderable)
try:
current_page.layout()
max_bottom = self.calculate_page_height(current_page)
# Check if page is too full
if max_bottom > self.max_page_height and len(current_page._children) > 1:
# Rollback and start new page
current_page._children = children_backup
pages.append(current_page)
# Start new page with current content
current_page = Page(size=self.page_size)
current_page.add_child(renderable)
current_page.layout()
except Exception:
# Layout failed, rollback
current_page._children = children_backup
# Add final page if it has content
if current_page._children:
pages.append(current_page)
# Assertions
self.assertGreater(len(pages), 0, "Should create at least one page")
# Test rendering all pages
for i, page in enumerate(pages):
with self.subTest(page=i+1):
self.assertGreater(len(page._children), 0, f"Page {i+1} should have content")
try:
rendered_image = page.render()
self.assertIsNotNone(rendered_image)
self.assertEqual(rendered_image.size, self.page_size)
except Exception as e:
self.fail(f"Page {i+1} render failed: {e}")
def test_empty_paragraph_handling(self):
"""Test handling of empty paragraphs."""
empty_paragraph = self.create_test_paragraph("")
page = Page(size=self.page_size)
# Empty paragraph should still be convertible
renderable = page._convert_block_to_renderable(empty_paragraph)
if renderable: # Some implementations might return None for empty content
page.add_child(renderable)
try:
page.layout()
rendered_image = page.render()
self.assertIsNotNone(rendered_image)
except Exception as e:
self.fail(f"Empty paragraph handling failed: {e}")
def test_conversion_error_handling(self):
"""Test handling of blocks that can't be converted."""
paragraph = self.create_test_paragraph("Test content")
page = Page(size=self.page_size)
# This should normally work
renderable = page._convert_block_to_renderable(paragraph)
self.assertIsNotNone(renderable, "Normal paragraph should convert successfully")
def calculate_page_height(self, page):
"""Helper method to calculate current page height."""
max_bottom = 0
for child in page._children:
if hasattr(child, '_origin') and hasattr(child, '_size'):
child_bottom = child._origin[1] + child._size[1]
max_bottom = max(max_bottom, child_bottom)
return max_bottom
if __name__ == '__main__':
unittest.main()