#!/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()