144 lines
5.7 KiB
Python
144 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test to demonstrate and verify fix for the line splitting bug where
|
|
text is lost at line breaks due to improper hyphenation handling.
|
|
"""
|
|
|
|
import unittest
|
|
from unittest.mock import patch, Mock
|
|
from pyWebLayout.concrete.text import Line
|
|
from pyWebLayout.abstract.inline import Word
|
|
from pyWebLayout.style import Font
|
|
from pyWebLayout.style.layout import Alignment
|
|
|
|
|
|
class TestLineSplittingBug(unittest.TestCase):
|
|
"""Test cases for the line splitting bug"""
|
|
|
|
def setUp(self):
|
|
"""Set up test fixtures"""
|
|
self.font = Font(
|
|
font_path=None,
|
|
font_size=12,
|
|
colour=(0, 0, 0)
|
|
)
|
|
self.spacing = (5, 10)
|
|
self.origin = (0, 0)
|
|
self.size = (100, 20) # Narrow line to force hyphenation
|
|
|
|
@patch('pyWebLayout.abstract.inline.pyphen')
|
|
def test_hyphenation_preserves_word_boundaries(self, mock_pyphen_module):
|
|
"""Test that hyphenation properly preserves word boundaries"""
|
|
# Mock pyphen to return a multi-part hyphenated word
|
|
mock_dic = Mock()
|
|
mock_pyphen_module.Pyphen.return_value = mock_dic
|
|
|
|
# Simulate hyphenating "supercalifragilisticexpialidocious"
|
|
# into multiple parts: "super-", "cali-", "fragi-", "listic-", "expiali-", "docious"
|
|
mock_dic.inserted.return_value = "super-cali-fragi-listic-expiali-docious"
|
|
|
|
line = Line(self.spacing, self.origin, self.size, self.font)
|
|
|
|
# Add the word that will be hyphenated
|
|
overflow = line.add_word("supercalifragilisticexpialidocious")
|
|
|
|
# The overflow should be the next part only, not all remaining parts joined
|
|
# In the current buggy implementation, this would return "cali-fragi-listic-expiali-docious"
|
|
# But it should return "cali-" (the next single part)
|
|
print(f"Overflow returned: '{overflow}'")
|
|
|
|
# Check that the first part was added to the line
|
|
self.assertEqual(len(line.renderable_words), 1)
|
|
first_word_text = line.renderable_words[0].word.text
|
|
self.assertEqual(first_word_text, "super-")
|
|
|
|
# The overflow should be just the next part, not all parts joined
|
|
# This assertion will fail with the current bug, showing the issue
|
|
self.assertEqual(overflow, "cali-") # Should be next part only
|
|
|
|
# NOT this (which is what the bug produces):
|
|
# self.assertEqual(overflow, "cali-fragi-listic-expiali-docious")
|
|
|
|
@patch('pyWebLayout.abstract.inline.pyphen')
|
|
def test_single_word_overflow_behavior(self, mock_pyphen_module):
|
|
"""Test that overflow returns only the next part, not all remaining parts joined"""
|
|
# Mock pyphen to return a simple two-part hyphenated word
|
|
mock_dic = Mock()
|
|
mock_pyphen_module.Pyphen.return_value = mock_dic
|
|
mock_dic.inserted.return_value = "very-long"
|
|
|
|
# Create a narrow line that will force hyphenation
|
|
line = Line(self.spacing, (0, 0), (40, 20), self.font)
|
|
|
|
# Add the word that will be hyphenated
|
|
overflow = line.add_word("verylong")
|
|
|
|
# Check that the first part was added to the line
|
|
self.assertEqual(len(line.renderable_words), 1)
|
|
first_word_text = line.renderable_words[0].word.text
|
|
self.assertEqual(first_word_text, "very-")
|
|
|
|
# The overflow should be just the next part ("long"), not multiple parts joined
|
|
# This tests the core fix for the line splitting bug
|
|
self.assertEqual(overflow, "long")
|
|
|
|
print(f"First part in line: '{first_word_text}'")
|
|
print(f"Overflow returned: '{overflow}'")
|
|
|
|
def test_simple_overflow_case(self):
|
|
"""Test a simple word overflow without hyphenation to verify baseline behavior"""
|
|
line = Line(self.spacing, self.origin, (50, 20), self.font)
|
|
|
|
# Add a word that fits
|
|
result1 = line.add_word("short")
|
|
self.assertIsNone(result1)
|
|
|
|
# Add a word that doesn't fit (should overflow)
|
|
result2 = line.add_word("verylongword")
|
|
self.assertEqual(result2, "verylongword")
|
|
|
|
# Only the first word should be in the line
|
|
self.assertEqual(len(line.renderable_words), 1)
|
|
self.assertEqual(line.renderable_words[0].word.text, "short")
|
|
|
|
|
|
def demonstrate_bug():
|
|
"""Demonstrate the bug with a practical example"""
|
|
print("=" * 60)
|
|
print("DEMONSTRATING LINE SPLITTING BUG")
|
|
print("=" * 60)
|
|
|
|
font = Font(font_path=None, font_size=12, colour=(0, 0, 0))
|
|
|
|
# Create a very narrow line that will force hyphenation
|
|
line = Line((3, 6), (0, 0), (80, 20), font)
|
|
|
|
# Try to add a long word that should be hyphenated
|
|
with patch('pyWebLayout.abstract.inline.pyphen') as mock_pyphen_module:
|
|
mock_dic = Mock()
|
|
mock_pyphen_module.Pyphen.return_value = mock_dic
|
|
mock_dic.inserted.return_value = "hyper-long-example-word"
|
|
|
|
overflow = line.add_word("hyperlongexampleword")
|
|
|
|
print(f"Original word: 'hyperlongexampleword'")
|
|
print(f"Hyphenated to: 'hyper-long-example-word'")
|
|
print(f"First part added to line: '{line.renderable_words[0].word.text if line.renderable_words else 'None'}'")
|
|
print(f"Overflow returned: '{overflow}'")
|
|
print()
|
|
print("PROBLEM: The overflow should be 'long-' (next part only)")
|
|
print("but instead it returns 'long-example-word' (all remaining parts joined)")
|
|
print("This causes word boundary information to be lost!")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# First demonstrate the bug
|
|
demonstrate_bug()
|
|
|
|
print("\n" + "=" * 60)
|
|
print("RUNNING UNIT TESTS")
|
|
print("=" * 60)
|
|
|
|
# Run unit tests
|
|
unittest.main()
|