pyWebLayout/tests/test_paragraph_layout_fix.py
2025-06-08 15:11:35 +02:00

258 lines
8.7 KiB
Python

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