This commit is contained in:
parent
210358913a
commit
ff5f840646
174
tests/test_line_overflow.py
Normal file
174
tests/test_line_overflow.py
Normal file
@ -0,0 +1,174 @@
|
||||
"""
|
||||
Test for line overflow behavior in pyWebLayout/concrete/text.py
|
||||
|
||||
This test demonstrates how line overflow is triggered when words cannot fit
|
||||
in progressively shorter lines. Uses a simple sentence with non-hyphenatable words.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import numpy as np
|
||||
from PIL import ImageFont
|
||||
from pyWebLayout.concrete.text import Line, Text
|
||||
from pyWebLayout.style import Font, FontStyle, FontWeight
|
||||
from pyWebLayout.style.layout import Alignment
|
||||
|
||||
|
||||
class TestLineOverflow(unittest.TestCase):
|
||||
"""Test line overflow behavior with progressively shorter lines."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures with a basic font and simple sentence."""
|
||||
# Create a simple font for testing
|
||||
self.font = Font()
|
||||
|
||||
# Simple sentence with short, non-hyphenatable words
|
||||
self.simple_words = ["cat", "dog", "pig", "rat", "ox", "bee", "fly", "ant"]
|
||||
|
||||
def test_line_overflow_progression(self):
|
||||
"""Test that line overflow is triggered as line width decreases."""
|
||||
# Start with a reasonably wide line that can fit all words
|
||||
initial_width = 800
|
||||
line_height = 50
|
||||
spacing = (5, 20) # min_spacing, max_spacing
|
||||
|
||||
# Test results storage
|
||||
results = []
|
||||
|
||||
# Test with progressively shorter lines
|
||||
for width in range(initial_width, 50, -50): # Decrease by 50px each time
|
||||
# Create a new line with current width
|
||||
origin = np.array([0, 0])
|
||||
size = (width, line_height)
|
||||
line = Line(spacing, origin, size, self.font, halign=Alignment.LEFT)
|
||||
|
||||
# Try to add words until overflow occurs
|
||||
words_added = []
|
||||
overflow_word = None
|
||||
|
||||
for word in self.simple_words:
|
||||
result = line.add_word(word, self.font)
|
||||
if result is None:
|
||||
# Word fit in line
|
||||
words_added.append(word)
|
||||
else:
|
||||
# Overflow occurred
|
||||
overflow_word = word
|
||||
break
|
||||
|
||||
# Record the test result
|
||||
test_result = {
|
||||
'width': width,
|
||||
'words_added': words_added.copy(),
|
||||
'overflow_word': overflow_word,
|
||||
'total_words_fit': len(words_added)
|
||||
}
|
||||
results.append(test_result)
|
||||
|
||||
# Print progress for visibility
|
||||
print(f"Width {width}px: Fit {len(words_added)} words: {' '.join(words_added)}")
|
||||
if overflow_word:
|
||||
print(f" -> Overflow on word: '{overflow_word}'")
|
||||
|
||||
# Assertions to verify expected behavior
|
||||
self.assertTrue(len(results) > 0, "Should have test results")
|
||||
|
||||
# First (widest) line should fit more words than later lines
|
||||
first_result = results[0]
|
||||
last_result = results[-1]
|
||||
|
||||
self.assertGreaterEqual(
|
||||
first_result['total_words_fit'],
|
||||
last_result['total_words_fit'],
|
||||
"Wider lines should fit at least as many words as narrower lines"
|
||||
)
|
||||
|
||||
# At some point, overflow should occur (not all words fit)
|
||||
overflow_occurred = any(r['overflow_word'] is not None for r in results)
|
||||
self.assertTrue(overflow_occurred, "Line overflow should occur with narrow lines")
|
||||
|
||||
# Very narrow lines should fit fewer words
|
||||
narrow_results = [r for r in results if r['width'] < 200]
|
||||
if narrow_results:
|
||||
# At least one narrow line should have triggered overflow
|
||||
narrow_overflow = any(r['overflow_word'] is not None for r in narrow_results)
|
||||
self.assertTrue(narrow_overflow, "Narrow lines should trigger overflow")
|
||||
|
||||
def test_single_word_overflow(self):
|
||||
"""Test overflow behavior when even a single word doesn't fit."""
|
||||
# Create a very narrow line
|
||||
narrow_width = 30
|
||||
line_height = 50
|
||||
spacing = (5, 20)
|
||||
|
||||
origin = np.array([0, 0])
|
||||
size = (narrow_width, line_height)
|
||||
line = Line(spacing, origin, size, self.font, halign=Alignment.LEFT)
|
||||
|
||||
# Try to add a word that likely won't fit
|
||||
test_word = "elephant" # Longer word that should overflow
|
||||
result = line.add_word(test_word, self.font)
|
||||
|
||||
# The implementation may partially fit the word and return the remaining part
|
||||
|
||||
# Some overflow occurred - either full word or remaining part
|
||||
self.assertIsInstance(result, str, "Should return remaining text as string")
|
||||
self.assertGreater(len(result), 0, "Remaining text should not be empty")
|
||||
|
||||
# Check that some part was fitted
|
||||
self.assertGreater(len(line.text_objects), 0, "Should have fitted at least some characters")
|
||||
|
||||
# The fitted part + remaining part should equal the original word
|
||||
fitted_text = line.text_objects[0].text if line.text_objects else ""
|
||||
self.assertEqual(fitted_text + result, test_word,
|
||||
f"Fitted part '{fitted_text}' + remaining '{result}' should equal '{test_word}'")
|
||||
|
||||
print(f"Word '{test_word}' partially fit: '{fitted_text}' fitted, '{result}' remaining")
|
||||
|
||||
|
||||
def test_empty_line_behavior(self):
|
||||
"""Test behavior when adding words to an empty line."""
|
||||
width = 300
|
||||
line_height = 50
|
||||
spacing = (5, 20)
|
||||
|
||||
origin = np.array([0, 0])
|
||||
size = (width, line_height)
|
||||
line = Line(spacing, origin, size, self.font, halign=Alignment.LEFT)
|
||||
|
||||
# Initially empty
|
||||
self.assertEqual(len(line.text_objects), 0, "Line should start empty")
|
||||
|
||||
# Add first word
|
||||
result = line.add_word("cat", self.font)
|
||||
self.assertIsNone(result, "First word should fit in reasonable width")
|
||||
self.assertEqual(len(line.text_objects), 1, "Should have one text object")
|
||||
self.assertEqual(line.text_objects[0].text, "cat", "Text should match added word")
|
||||
|
||||
def test_progressive_overflow_demonstration(self):
|
||||
"""Demonstrate the exact point where overflow begins."""
|
||||
# Use a specific set of short words
|
||||
words = ["a", "bb", "ccc", "dd", "e"]
|
||||
|
||||
# Start wide and narrow down until we find the overflow point
|
||||
for width in range(200, 10, -10):
|
||||
origin = np.array([0, 0])
|
||||
size = (width, 50)
|
||||
line = Line((3, 15), origin, size, self.font, halign=Alignment.LEFT)
|
||||
|
||||
words_that_fit = []
|
||||
for word in words:
|
||||
result = line.add_word(word, self.font)
|
||||
if result is None:
|
||||
words_that_fit.append(word)
|
||||
else:
|
||||
# This is where overflow started
|
||||
print(f"Overflow at width {width}px: '{' '.join(words_that_fit)}' + '{word}' (overflow)")
|
||||
self.assertGreater(len(words_that_fit), 0, "Should fit at least some words before overflow")
|
||||
return # Test successful
|
||||
|
||||
# If we get here, no overflow occurred even at minimum width
|
||||
print("No overflow occurred - all words fit even in narrowest line")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(verbosity=2)
|
||||
Loading…
x
Reference in New Issue
Block a user