#!/usr/bin/env python3 """ Unit tests for paragraph layout fixes. Tests the paragraph layout system and page rendering functionality. """ import unittest import os from PIL import Image from pyWebLayout.concrete.page import Page from pyWebLayout.style.fonts import Font from pyWebLayout.abstract.block import Paragraph from pyWebLayout.abstract.inline import Word from pyWebLayout.typesetting.paragraph_layout import ParagraphLayout from pyWebLayout.style.layout import Alignment class TestParagraphLayoutFix(unittest.TestCase): """Test cases for paragraph layout fixes""" def setUp(self): """Set up test fixtures""" self.font = Font(font_size=14) self.words_text = [ "This", "is", "a", "very", "long", "paragraph", "that", "should", "definitely", "wrap", "across", "multiple", "lines", "when", "rendered", "in", "a", "narrow", "width", "container", "to", "test", "the", "paragraph", "layout", "system", "and", "ensure", "proper", "line", "breaking", "functionality", "works", "correctly", "as", "expected." ] # Clean up any existing test images test_images = [ "test_paragraph_layout_output.png", "test_small_page.png", "test_large_page.png" ] for img in test_images: if os.path.exists(img): os.remove(img) def tearDown(self): """Clean up after tests""" # Clean up test images after each test test_images = [ "test_paragraph_layout_output.png", "test_small_page.png", "test_large_page.png" ] for img in test_images: if os.path.exists(img): os.remove(img) def test_paragraph_layout_directly(self): """Test the paragraph layout system directly""" # Create a paragraph with multiple words paragraph = Paragraph() # Add many words to force line breaking for word_text in self.words_text: word = Word(word_text, self.font) paragraph.add_word(word) # Create paragraph layout with narrow width to force wrapping layout = ParagraphLayout( line_width=300, # Narrow width line_height=20, word_spacing=(3, 8), line_spacing=3, halign=Alignment.LEFT ) # Layout the paragraph lines = layout.layout_paragraph(paragraph) # Assertions self.assertGreater(len(lines), 1, "Should have multiple lines") self.assertIsInstance(lines, list) # Check each line has content for i, line in enumerate(lines): if hasattr(line, 'text_objects'): word_count = len(line.text_objects) self.assertGreater(word_count, 0, f"Line {i+1} should have words") def test_page_with_long_paragraph(self): """Test a page with manual content creation""" # Since Page doesn't support HTML loading, test basic page functionality # Create a page with narrower width page = Page(size=(400, 600)) # Verify page creation self.assertEqual(page._size[0], 400) self.assertEqual(page._size[1], 600) self.assertIsInstance(page._children, list) # Try to render the empty page image = page.render() # Assertions self.assertIsInstance(image, Image.Image) self.assertEqual(image.size, (400, 600)) # Save for inspection image.save("test_paragraph_layout_output.png") self.assertTrue(os.path.exists("test_paragraph_layout_output.png")) def test_simple_text_vs_paragraph(self): """Test different page configurations""" # Test 1: Small page page1 = Page(size=(400, 200)) self.assertIsInstance(page1._children, list) # Test 2: Large page page2 = Page(size=(800, 400)) self.assertIsInstance(page2._children, list) # Render both img1 = page1.render() img2 = page2.render() # Verify renders self.assertIsInstance(img1, Image.Image) self.assertIsInstance(img2, Image.Image) self.assertEqual(img1.size, (400, 200)) self.assertEqual(img2.size, (800, 400)) # Save images img1.save("test_small_page.png") img2.save("test_large_page.png") # Verify files were created self.assertTrue(os.path.exists("test_small_page.png")) self.assertTrue(os.path.exists("test_large_page.png")) def test_paragraph_creation_with_words(self): """Test creating paragraphs with multiple words""" paragraph = Paragraph() # Add words to paragraph for word_text in self.words_text[:5]: # Use first 5 words word = Word(word_text, self.font) paragraph.add_word(word) # Verify paragraph has words self.assertGreater(len(paragraph._words), 0) def test_paragraph_layout_configuration(self): """Test different paragraph layout configurations""" layouts = [ # Wide layout ParagraphLayout( line_width=600, line_height=20, word_spacing=(3, 8), line_spacing=3, halign=Alignment.LEFT ), # Narrow layout ParagraphLayout( line_width=200, line_height=16, word_spacing=(2, 6), line_spacing=2, halign=Alignment.CENTER ), # Justified layout ParagraphLayout( line_width=400, line_height=18, word_spacing=(4, 10), line_spacing=4, halign=Alignment.JUSTIFY ) ] # Create test paragraph paragraph = Paragraph() for word_text in self.words_text[:10]: # Use first 10 words word = Word(word_text, self.font) paragraph.add_word(word) # Test each layout for i, layout in enumerate(layouts): with self.subTest(layout=i): lines = layout.layout_paragraph(paragraph) self.assertIsInstance(lines, list) if len(paragraph._words) > 0: self.assertGreater(len(lines), 0, f"Layout {i} should produce lines") def test_empty_paragraph_layout(self): """Test laying out an empty paragraph""" paragraph = Paragraph() layout = ParagraphLayout( line_width=300, line_height=20, word_spacing=(3, 8), line_spacing=3, halign=Alignment.LEFT ) lines = layout.layout_paragraph(paragraph) # Empty paragraph should still return a list (might be empty) self.assertIsInstance(lines, list) def test_single_word_paragraph(self): """Test paragraph with single word""" paragraph = Paragraph() word = Word("Hello", self.font) paragraph.add_word(word) layout = ParagraphLayout( line_width=300, line_height=20, word_spacing=(3, 8), line_spacing=3, halign=Alignment.LEFT ) lines = layout.layout_paragraph(paragraph) # Single word should produce at least one line self.assertGreater(len(lines), 0) if len(lines) > 0 and hasattr(lines[0], 'text_objects'): self.assertGreater(len(lines[0].text_objects), 0) def test_different_alignments(self): """Test paragraph layout with different alignments""" alignments = [Alignment.LEFT, Alignment.CENTER, Alignment.RIGHT, Alignment.JUSTIFY] # Create test paragraph paragraph = Paragraph() for word_text in self.words_text[:8]: word = Word(word_text, self.font) paragraph.add_word(word) for alignment in alignments: with self.subTest(alignment=alignment): layout = ParagraphLayout( line_width=300, line_height=20, word_spacing=(3, 8), line_spacing=3, halign=alignment ) lines = layout.layout_paragraph(paragraph) self.assertIsInstance(lines, list) if len(paragraph._words) > 0: self.assertGreater(len(lines), 0) if __name__ == '__main__': unittest.main()