pyWebLayout/test_complete_line_splitting_fix.py

190 lines
7.3 KiB
Python

#!/usr/bin/env python3
"""
Comprehensive test to verify both the line-level hyphenation fix
and the paragraph-level overflow fix are working correctly.
"""
from unittest.mock import patch, Mock
from pyWebLayout.concrete.text import Line
from pyWebLayout.abstract.block import Paragraph
from pyWebLayout.abstract.inline import Word
from pyWebLayout.typesetting.paragraph_layout import ParagraphLayout
from pyWebLayout.style import Font
def test_complete_fix():
"""Test that both line-level and paragraph-level fixes work together"""
print("Testing complete line splitting fix...")
font = Font(font_path=None, font_size=12, colour=(0, 0, 0))
# Test 1: Direct line hyphenation fix
print("\n1. Testing direct line hyphenation fix:")
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 = "can-vas"
line = Line((3, 6), (0, 0), (50, 20), font)
overflow = line.add_word("canvas")
first_part = line.renderable_words[0].word.text if line.renderable_words else "None"
print(f" Word: 'canvas' -> hyphenated to 'can-vas'")
print(f" First part in line: '{first_part}'")
print(f" Overflow: '{overflow}'")
if overflow == "vas":
print(" ✓ Line-level fix working: overflow contains only next part")
else:
print(" ✗ Line-level fix failed")
return False
# Test 2: Paragraph-level overflow handling
print("\n2. Testing paragraph-level overflow handling:")
with patch('pyWebLayout.abstract.inline.pyphen') as mock_pyphen_module:
mock_dic = Mock()
mock_pyphen_module.Pyphen.return_value = mock_dic
# Mock different hyphenation patterns
def mock_inserted(text, hyphen='-'):
patterns = {
"canvas": "can-vas",
"vas": "vas", # No hyphenation needed for short words
"pants": "pants",
}
return patterns.get(text, text)
mock_dic.inserted.side_effect = mock_inserted
# Create a paragraph with the problematic sentence
paragraph = Paragraph(style=font)
words_text = ["and", "a", "pair", "of", "canvas", "pants", "but", "it"]
for word_text in words_text:
word = Word(word_text, font)
paragraph.add_word(word)
# Layout the paragraph with narrow lines to force wrapping
layout = ParagraphLayout(
line_width=60, # Narrow to force wrapping
line_height=20,
word_spacing=(3, 6)
)
lines = layout.layout_paragraph(paragraph)
print(f" Created paragraph with words: {words_text}")
print(f" Rendered into {len(lines)} lines:")
all_rendered_text = []
for i, line in enumerate(lines):
line_words = [word.word.text for word in line.renderable_words]
line_text = ' '.join(line_words)
all_rendered_text.extend(line_words)
print(f" Line {i+1}: {line_text}")
# Check that no text was lost
original_text_parts = []
for word in words_text:
if word == "canvas":
# Should be split into "can-" and "vas"
original_text_parts.extend(["can-", "vas"])
else:
original_text_parts.append(word)
print(f" Expected text parts: {original_text_parts}")
print(f" Actual text parts: {all_rendered_text}")
# Reconstruct text by removing hyphens and joining
expected_clean = ''.join(word.rstrip('-') for word in original_text_parts)
actual_clean = ''.join(word.rstrip('-') for word in all_rendered_text)
print(f" Expected clean text: '{expected_clean}'")
print(f" Actual clean text: '{actual_clean}'")
if expected_clean == actual_clean:
print(" ✓ Paragraph-level fix working: no text lost in overflow")
else:
print(" ✗ Paragraph-level fix failed: text was lost")
return False
# Test 3: Real-world scenario with the specific "canvas" case
print("\n3. Testing real-world canvas scenario:")
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 = "can-vas"
# Test the specific reported issue
paragraph = Paragraph(style=font)
sentence = "and a pair of canvas pants but"
words = sentence.split()
for word_text in words:
word = Word(word_text, font)
paragraph.add_word(word)
layout = ParagraphLayout(
line_width=120, # Width that causes "canvas" to hyphenate at line end
line_height=20,
word_spacing=(3, 6)
)
lines = layout.layout_paragraph(paragraph)
print(f" Original sentence: '{sentence}'")
print(f" Rendered into {len(lines)} lines:")
rendered_lines_text = []
for i, line in enumerate(lines):
line_words = [word.word.text for word in line.renderable_words]
line_text = ' '.join(line_words)
rendered_lines_text.append(line_text)
print(f" Line {i+1}: '{line_text}'")
# Check if we see the pattern "can-" at end of line and "vas" at start of next
found_proper_split = False
for i in range(len(rendered_lines_text) - 1):
current_line = rendered_lines_text[i]
next_line = rendered_lines_text[i + 1]
if "can-" in current_line and ("vas" in next_line or next_line.startswith("vas")):
found_proper_split = True
print(f" ✓ Found proper canvas split: '{current_line}' -> '{next_line}'")
break
if found_proper_split:
print(" ✓ Real-world scenario working: 'vas' is preserved")
else:
# Check if all original words are preserved (even without hyphenation)
all_words_preserved = True
for word in words:
found = False
for line_text in rendered_lines_text:
if word in line_text or word.rstrip('-') in line_text.replace('-', ''):
found = True
break
if not found:
print(f" ✗ Word '{word}' not found in rendered output")
all_words_preserved = False
if all_words_preserved:
print(" ✓ All words preserved (even if hyphenation pattern differs)")
else:
print(" ✗ Some words were lost")
return False
print("\n" + "="*60)
print("ALL TESTS PASSED - COMPLETE LINE SPLITTING FIX WORKS!")
print("="*60)
print("✓ Line-level hyphenation returns only next part")
print("✓ Paragraph-level overflow handling preserves all text")
print("✓ Real-world scenarios work correctly")
return True
if __name__ == "__main__":
test_complete_fix()