#!/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()