233 lines
8.9 KiB
Python
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()
|