292 lines
13 KiB
Python
292 lines
13 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
|
|
import numpy as np
|
|
from unittest.mock import Mock
|
|
|
|
from pyWebLayout.concrete.text import Line, Text, LeftAlignmentHandler, CenterRightAlignmentHandler, JustifyAlignmentHandler
|
|
from pyWebLayout.style.layout import Alignment
|
|
from pyWebLayout.style import Font
|
|
|
|
|
|
class TestAlignmentHandlers(unittest.TestCase):
|
|
"""Test cases for the alignment handler system"""
|
|
|
|
def setUp(self):
|
|
"""Set up test fixtures"""
|
|
self.font = Font()
|
|
self.test_words = ["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)
|
|
|
|
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.font, 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.font, 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.font, 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.font, 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.font, halign=Alignment.LEFT)
|
|
|
|
# Add words until line is full or we run out
|
|
words_added = 0
|
|
for word in self.test_words:
|
|
result = left_line.add_word(word)
|
|
if result:
|
|
# Word didn't fit, should return the word
|
|
self.assertEqual(result, word)
|
|
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.font, halign=Alignment.CENTER)
|
|
|
|
# Add words until line is full or we run out
|
|
words_added = 0
|
|
for word in self.test_words:
|
|
result = center_line.add_word(word)
|
|
if result:
|
|
# Word didn't fit, should return the word
|
|
self.assertEqual(result, word)
|
|
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.font, halign=Alignment.RIGHT)
|
|
|
|
# Add words until line is full or we run out
|
|
words_added = 0
|
|
for word in self.test_words:
|
|
result = right_line.add_word(word)
|
|
if result:
|
|
# Word didn't fit, should return the word
|
|
self.assertEqual(result, word)
|
|
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.font, halign=Alignment.JUSTIFY)
|
|
|
|
# Add words until line is full or we run out
|
|
words_added = 0
|
|
for word in self.test_words:
|
|
result = justify_line.add_word(word)
|
|
if result:
|
|
# Word didn't fit, should return the word
|
|
self.assertEqual(result, word)
|
|
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.font) 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 = 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)
|
|
|
|
# Position should be within line width
|
|
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.font) for word in ["Hello", "World"]]
|
|
|
|
spacing_calc, position = 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)
|
|
|
|
# Spacing should be minimum spacing for left alignment
|
|
self.assertEqual(spacing_calc, self.spacing[0])
|
|
|
|
def test_center_handler_spacing_calculation(self):
|
|
"""Test specific spacing calculation for center alignment"""
|
|
handler = CenterRightAlignmentHandler(Alignment.CENTER)
|
|
text_objects = [Text(word, self.font) for word in ["Hello", "World"]]
|
|
|
|
spacing_calc, position = handler.calculate_spacing_and_position(
|
|
text_objects, self.line_width, self.spacing[0], self.spacing[1])
|
|
|
|
# Center alignment should have position > 0 (centered)
|
|
self.assertGreater(position, 0)
|
|
|
|
# Spacing should be minimum spacing for center alignment
|
|
self.assertEqual(spacing_calc, self.spacing[0])
|
|
|
|
def test_right_handler_spacing_calculation(self):
|
|
"""Test specific spacing calculation for right alignment"""
|
|
handler = CenterRightAlignmentHandler(Alignment.RIGHT)
|
|
text_objects = [Text(word, self.font) for word in ["Hello", "World"]]
|
|
|
|
spacing_calc, position = handler.calculate_spacing_and_position(
|
|
text_objects, self.line_width, self.spacing[0], self.spacing[1])
|
|
|
|
# Right alignment should have position at the right edge minus content width
|
|
self.assertGreater(position, 0)
|
|
|
|
# Spacing should be minimum spacing for right alignment
|
|
self.assertEqual(spacing_calc, self.spacing[0])
|
|
|
|
def test_justify_handler_spacing_calculation(self):
|
|
"""Test specific spacing calculation for justify alignment"""
|
|
handler = JustifyAlignmentHandler()
|
|
text_objects = [Text(word, self.font) for word in ["Hello", "World"]]
|
|
|
|
spacing_calc, position = 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)
|
|
|
|
# Spacing should be calculated to fill the line (between min and max)
|
|
self.assertGreaterEqual(spacing_calc, self.spacing[0])
|
|
self.assertLessEqual(spacing_calc, self.spacing[1])
|
|
|
|
def test_hyphenation_decisions(self):
|
|
"""Test hyphenation decisions for different alignment handlers"""
|
|
text_objects = [Text(word, self.font) for word in ["Hello", "World"]]
|
|
test_word_width = 50
|
|
available_width = 40 # Word doesn't fit
|
|
|
|
handlers = [
|
|
("Left", LeftAlignmentHandler()),
|
|
("Center", CenterRightAlignmentHandler(Alignment.CENTER)),
|
|
("Right", CenterRightAlignmentHandler(Alignment.RIGHT)),
|
|
("Justify", JustifyAlignmentHandler())
|
|
]
|
|
|
|
for name, handler in handlers:
|
|
with self.subTest(handler=name):
|
|
should_hyphenate = handler.should_try_hyphenation(
|
|
text_objects, test_word_width, available_width, self.spacing[0], self.font)
|
|
|
|
# Should return a boolean
|
|
self.assertIsInstance(should_hyphenate, bool)
|
|
|
|
def test_hyphenation_decision_logic(self):
|
|
"""Test specific hyphenation decision logic"""
|
|
text_objects = [Text(word, self.font) for word in ["Hello"]]
|
|
|
|
# Test with word that doesn't fit
|
|
handler = LeftAlignmentHandler()
|
|
should_hyphenate_large = handler.should_try_hyphenation(
|
|
text_objects, 100, 50, self.spacing[0], self.font)
|
|
|
|
# Test with word that fits
|
|
should_hyphenate_small = handler.should_try_hyphenation(
|
|
text_objects, 30, 50, self.spacing[0], self.font)
|
|
|
|
# Large word should suggest hyphenation, small word should not
|
|
self.assertIsInstance(should_hyphenate_large, bool)
|
|
self.assertIsInstance(should_hyphenate_small, bool)
|
|
|
|
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.font, halign=alignment)
|
|
|
|
# Empty line should still have a handler
|
|
self.assertIsNotNone(line._alignment_handler)
|
|
|
|
# Should be able to render empty line
|
|
result = line.render()
|
|
self.assertIsNotNone(result)
|
|
|
|
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.font, halign=alignment)
|
|
|
|
# Add a single word
|
|
result = line.add_word("test")
|
|
self.assertIsNone(result) # Should fit
|
|
|
|
# Should be able to render single word line
|
|
rendered = line.render()
|
|
self.assertIsNotNone(rendered)
|
|
self.assertEqual(len(line.text_objects), 1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|