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