pyWebLayout/tests/concrete/test_alignment_handlers.py

338 lines
12 KiB
Python

#!/usr/bin/env python3
"""
Unit tests for the alignment handler system.
Tests the various alignment handlers (Left, Center, Right, Justify) and their integration with Line objects.
"""
import unittest
from pyWebLayout.concrete.text import (
Line, Text, LeftAlignmentHandler, CenterRightAlignmentHandler, JustifyAlignmentHandler
)
from pyWebLayout.style import Alignment
from pyWebLayout.style import Font
from pyWebLayout.abstract import Word
from PIL import Image, ImageDraw
class TestAlignmentHandlers(unittest.TestCase):
"""Test cases for the alignment handler system"""
def setUp(self):
"""Set up test fixtures"""
self.font = Font()
self.test_words = [Word(text, self.font)
for text in ["This", "is", "a", "test", "sentence"]]
self.line_width = 300
self.line_height = 30
self.spacing = (5, 20) # min_spacing, max_spacing
self.origin = (0, 0)
self.size = (self.line_width, self.line_height)
# Create a real PIL image (canvas) for testing
self.canvas = Image.new('RGB', (800, 600), color='white')
# Create a real ImageDraw object
self.draw = ImageDraw.Draw(self.canvas)
# Create a real Font object
self.style = Font()
def test_left_alignment_handler_assignment(self):
"""Test that Line correctly assigns LeftAlignmentHandler for LEFT alignment"""
left_line = Line(
self.spacing,
self.origin,
self.size,
self.draw,
font=self.style,
halign=Alignment.LEFT)
self.assertIsInstance(left_line._alignment_handler, LeftAlignmentHandler)
def test_center_alignment_handler_assignment(self):
"""Test that Line correctly assigns CenterRightAlignmentHandler for CENTER alignment"""
center_line = Line(
self.spacing,
self.origin,
self.size,
self.draw,
font=self.style,
halign=Alignment.CENTER)
self.assertIsInstance(
center_line._alignment_handler,
CenterRightAlignmentHandler)
# Check that it's configured for CENTER alignment
self.assertEqual(center_line._alignment_handler._alignment, Alignment.CENTER)
def test_right_alignment_handler_assignment(self):
"""Test that Line correctly assigns CenterRightAlignmentHandler for RIGHT alignment"""
right_line = Line(
self.spacing,
self.origin,
self.size,
self.draw,
font=self.style,
halign=Alignment.RIGHT)
self.assertIsInstance(
right_line._alignment_handler,
CenterRightAlignmentHandler)
# Check that it's configured for RIGHT alignment
self.assertEqual(right_line._alignment_handler._alignment, Alignment.RIGHT)
def test_justify_alignment_handler_assignment(self):
"""Test that Line correctly assigns JustifyAlignmentHandler for JUSTIFY alignment"""
justify_line = Line(
self.spacing,
self.origin,
self.size,
self.draw,
font=self.style,
halign=Alignment.JUSTIFY)
self.assertIsInstance(justify_line._alignment_handler, JustifyAlignmentHandler)
def test_left_alignment_word_addition(self):
"""Test adding words to a left-aligned line"""
left_line = Line(
self.spacing,
self.origin,
self.size,
self.draw,
halign=Alignment.LEFT)
# Add words until line is full or we run out
words_added = 0
for word in self.test_words:
result, part = left_line.add_word(word)
if not result:
# Word didn't fit
break
else:
words_added += 1
# Should have added at least some words
self.assertGreater(words_added, 0)
self.assertEqual(len(left_line.text_objects), words_added)
def test_center_alignment_word_addition(self):
"""Test adding words to a center-aligned line"""
center_line = Line(
self.spacing,
self.origin,
self.size,
self.draw,
font=self.style,
halign=Alignment.CENTER)
# Add words until line is full or we run out
words_added = 0
for word in self.test_words:
result, part = center_line.add_word(word)
if not result:
# Word didn't fit
break
else:
words_added += 1
# Should have added at least some words
self.assertGreater(words_added, 0)
self.assertEqual(len(center_line.text_objects), words_added)
def test_right_alignment_word_addition(self):
"""Test adding words to a right-aligned line"""
right_line = Line(
self.spacing,
self.origin,
self.size,
self.draw,
font=self.style,
halign=Alignment.RIGHT)
# Add words until line is full or we run out
words_added = 0
for word in self.test_words:
result, part = right_line.add_word(word)
if not result:
# Word didn't fit
break
else:
words_added += 1
# Should have added at least some words
self.assertGreater(words_added, 0)
self.assertEqual(len(right_line.text_objects), words_added)
def test_justify_alignment_word_addition(self):
"""Test adding words to a justified line"""
justify_line = Line(
self.spacing,
self.origin,
self.size,
self.draw,
font=self.style,
halign=Alignment.JUSTIFY)
# Add words until line is full or we run out
words_added = 0
for word in self.test_words:
result, part = justify_line.add_word(word)
if not result:
# Word didn't fit
break
else:
words_added += 1
# Should have added at least some words
self.assertGreater(words_added, 0)
self.assertEqual(len(justify_line.text_objects), words_added)
def test_handler_spacing_and_position_calculations(self):
"""Test spacing and position calculations for different alignment handlers"""
# Create sample text objects
text_objects = [Text(word, self.style, self.draw)
for word in ["Hello", "World"]]
# Test each handler type
handlers = [
("Left", LeftAlignmentHandler()),
("Center", CenterRightAlignmentHandler(Alignment.CENTER)),
("Right", CenterRightAlignmentHandler(Alignment.RIGHT)),
("Justify", JustifyAlignmentHandler())
]
for name, handler in handlers:
with self.subTest(handler=name):
spacing_calc, position, overflow = handler.calculate_spacing_and_position(
text_objects, self.line_width, self.spacing[0], self.spacing[1])
# Check that spacing is a valid number
self.assertIsInstance(spacing_calc, (int, float))
self.assertGreaterEqual(spacing_calc, 0)
# Check that position is a valid number
self.assertIsInstance(position, (int, float))
self.assertGreaterEqual(position, 0)
# Check that overflow is a boolean
self.assertIsInstance(overflow, bool)
# Position should be within line width (unless overflow)
if not overflow:
self.assertLessEqual(position, self.line_width)
def test_left_handler_spacing_calculation(self):
"""Test specific spacing calculation for left alignment"""
handler = LeftAlignmentHandler()
text_objects = [Text(word, self.style, self.draw)
for word in ["Hello", "World"]]
spacing_calc, position, overflow = handler.calculate_spacing_and_position(
text_objects, self.line_width, self.spacing[0], self.spacing[1])
# Left alignment should have position at 0
self.assertEqual(position, 0)
# Should not overflow with reasonable text
self.assertFalse(overflow)
def test_center_handler_spacing_calculation(self):
"""Test specific spacing calculation for center alignment"""
handler = CenterRightAlignmentHandler(Alignment.CENTER)
text_objects = [Text(word, self.style, self.draw)
for word in ["Hello", "World"]]
spacing_calc, position, overflow = handler.calculate_spacing_and_position(
text_objects, self.line_width, self.spacing[0], self.spacing[1])
# Center alignment should have position > 0 (centered) if no overflow
if not overflow:
self.assertGreaterEqual(position, 0)
def test_right_handler_spacing_calculation(self):
"""Test specific spacing calculation for right alignment"""
handler = CenterRightAlignmentHandler(Alignment.RIGHT)
text_objects = [Text(word, self.style, self.draw)
for word in ["Hello", "World"]]
spacing_calc, position, overflow = handler.calculate_spacing_and_position(
text_objects, self.line_width, self.spacing[0], self.spacing[1])
# Right alignment should have position >= 0
self.assertGreaterEqual(position, 0)
def test_justify_handler_spacing_calculation(self):
"""Test specific spacing calculation for justify alignment"""
handler = JustifyAlignmentHandler()
text_objects = [Text(word, self.style, self.draw)
for word in ["Hello", "World"]]
spacing_calc, position, overflow = handler.calculate_spacing_and_position(
text_objects, self.line_width, self.spacing[0], self.spacing[1])
# Justify alignment should have position at 0
self.assertEqual(position, 0)
# Check spacing is reasonable
self.assertGreaterEqual(spacing_calc, 0)
def test_empty_line_alignment_handlers(self):
"""Test alignment handlers with empty lines"""
alignments = [
Alignment.LEFT,
Alignment.CENTER,
Alignment.RIGHT,
Alignment.JUSTIFY]
for alignment in alignments:
with self.subTest(alignment=alignment):
line = Line(
self.spacing,
self.origin,
self.size,
self.draw,
font=self.style,
halign=alignment)
# Empty line should still have a handler
self.assertIsNotNone(line._alignment_handler)
# Should be able to render empty line
line.render()
def test_single_word_line_alignment(self):
"""Test alignment handlers with single word lines"""
alignments = [
Alignment.LEFT,
Alignment.CENTER,
Alignment.RIGHT,
Alignment.JUSTIFY]
for alignment in alignments:
with self.subTest(alignment=alignment):
line = Line(
self.spacing,
self.origin,
self.size,
self.draw,
font=self.style,
halign=alignment)
# Create a test word
test_word = Word("test", self.style)
# Add a single word
result, part = line.add_word(test_word)
self.assertTrue(result) # Should fit
self.assertIsNone(part) # No overflow part
# Should be able to render single word line
line.render()
self.assertEqual(len(line.text_objects), 1)
if __name__ == '__main__':
unittest.main()