Working version for ebook rendering!!
This commit is contained in:
@@ -244,6 +244,79 @@ class TestPageImplementation(unittest.TestCase):
|
||||
# Test that children are in the correct order
|
||||
for i, child in enumerate(page.children):
|
||||
self.assertEqual(child._text, f"Child {i}")
|
||||
|
||||
def test_page_can_fit_line_boundary_checking(self):
|
||||
"""Test that can_fit_line correctly checks bottom boundary"""
|
||||
# Create page with known dimensions
|
||||
# Page: 800x600, border: 40, padding: (10, 10, 10, 10)
|
||||
# Content area starts at y=50 (border + padding_top = 40 + 10)
|
||||
# Content area ends at y=550 (height - border - padding_bottom = 600 - 40 - 10)
|
||||
style = PageStyle(
|
||||
border_width=40,
|
||||
padding=(10, 10, 10, 10)
|
||||
)
|
||||
page = Page(size=(800, 600), style=style)
|
||||
|
||||
# Initial y_offset should be at border + padding_top = 50
|
||||
self.assertEqual(page._current_y_offset, 50)
|
||||
|
||||
# Test 1: Line that fits comfortably
|
||||
line_height = 20
|
||||
max_y = 600 - 40 - 10 # 550
|
||||
self.assertTrue(page.can_fit_line(line_height))
|
||||
# Would end at 50 + 20 = 70, well within 550
|
||||
|
||||
# Test 2: Simulate adding lines to fill the page
|
||||
# Available height: 550 - 50 = 500 pixels
|
||||
# With 20-pixel lines, we can fit 25 lines exactly
|
||||
for i in range(24): # Add 24 lines
|
||||
self.assertTrue(page.can_fit_line(20), f"Line {i+1} should fit")
|
||||
# Simulate adding a line by updating y_offset
|
||||
page._current_y_offset += 20
|
||||
|
||||
# After 24 lines: y_offset = 50 + (24 * 20) = 530
|
||||
self.assertEqual(page._current_y_offset, 530)
|
||||
|
||||
# Test 3: One more 20-pixel line should fit (530 + 20 = 550, exactly at boundary)
|
||||
self.assertTrue(page.can_fit_line(20))
|
||||
page._current_y_offset += 20
|
||||
self.assertEqual(page._current_y_offset, 550)
|
||||
|
||||
# Test 4: Now another line should NOT fit (550 + 20 = 570 > 550)
|
||||
self.assertFalse(page.can_fit_line(20))
|
||||
|
||||
# Test 5: Even a 1-pixel line should not fit (550 + 1 = 551 > 550)
|
||||
self.assertFalse(page.can_fit_line(1))
|
||||
|
||||
# Test 6: Edge case - exactly at boundary, 0-height line should fit
|
||||
self.assertTrue(page.can_fit_line(0))
|
||||
|
||||
def test_page_can_fit_line_with_different_styles(self):
|
||||
"""Test can_fit_line with different page styles"""
|
||||
# Test with no border or padding
|
||||
style_no_border = PageStyle(border_width=0, padding=(0, 0, 0, 0))
|
||||
page_no_border = Page(size=(100, 100), style=style_no_border)
|
||||
|
||||
# With no border/padding, y_offset starts at 0
|
||||
self.assertEqual(page_no_border._current_y_offset, 0)
|
||||
|
||||
# Can fit a 100-pixel line exactly
|
||||
self.assertTrue(page_no_border.can_fit_line(100))
|
||||
|
||||
# Cannot fit a 101-pixel line
|
||||
self.assertFalse(page_no_border.can_fit_line(101))
|
||||
|
||||
# Test with large border and padding
|
||||
style_large = PageStyle(border_width=20, padding=(15, 15, 15, 15))
|
||||
page_large = Page(size=(200, 200), style=style_large)
|
||||
|
||||
# y_offset starts at border + padding_top = 20 + 15 = 35
|
||||
self.assertEqual(page_large._current_y_offset, 35)
|
||||
|
||||
# Max y = 200 - 20 - 15 = 165
|
||||
# Available height = 165 - 35 = 130 pixels
|
||||
self.assertTrue(page_large.can_fit_line(130))
|
||||
self.assertFalse(page_large.can_fit_line(131))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -16,43 +16,12 @@ from pyWebLayout.layout.document_layouter import paragraph_layouter, DocumentLay
|
||||
from pyWebLayout.style.abstract_style import AbstractStyle
|
||||
from pyWebLayout.style.concrete_style import ConcreteStyle, StyleResolver, RenderingContext
|
||||
from pyWebLayout.style.fonts import Font
|
||||
from pyWebLayout.style.page_style import PageStyle
|
||||
from pyWebLayout.concrete.page import Page
|
||||
from pyWebLayout.concrete.text import Line, Text
|
||||
from pyWebLayout.abstract.inline import Word
|
||||
|
||||
|
||||
class MockPage:
|
||||
"""A realistic mock page that behaves like a real page."""
|
||||
|
||||
def __init__(self, width=400, height=600, max_lines=20):
|
||||
self.border_size = 20
|
||||
self._current_y_offset = 50
|
||||
self.available_width = width
|
||||
self.available_height = height
|
||||
self.max_lines = max_lines
|
||||
self.lines_added = 0
|
||||
self.children = []
|
||||
|
||||
# Create a real drawing context
|
||||
self.image = Image.new('RGB', (width + 40, height + 100), 'white')
|
||||
self.draw = ImageDraw.Draw(self.image)
|
||||
|
||||
# Create a real style resolver
|
||||
context = RenderingContext(base_font_size=16)
|
||||
self.style_resolver = StyleResolver(context)
|
||||
|
||||
def can_fit_line(self, line_height):
|
||||
"""Check if another line can fit on the page."""
|
||||
remaining_height = self.available_height - self._current_y_offset
|
||||
can_fit = remaining_height >= line_height and self.lines_added < self.max_lines
|
||||
return can_fit
|
||||
|
||||
def add_child(self, child):
|
||||
"""Add a child element (like a Line) to the page."""
|
||||
self.children.append(child)
|
||||
self.lines_added += 1
|
||||
return True
|
||||
|
||||
|
||||
class MockWord(Word):
|
||||
"""A simple mock word that extends the real Word class."""
|
||||
|
||||
@@ -106,8 +75,9 @@ class TestDocumentLayouterIntegration:
|
||||
|
||||
def test_single_page_layout_with_real_components(self):
|
||||
"""Test layout on a single page using real Line and Text objects."""
|
||||
# Create a page that can fit content
|
||||
page = MockPage(width=500, height=400, max_lines=10)
|
||||
# Create a real page that can fit content
|
||||
page_style = PageStyle(border_width=20, padding=(10, 10, 10, 10))
|
||||
page = Page(size=(500, 400), style=page_style)
|
||||
|
||||
# Create a paragraph with realistic content
|
||||
paragraph = MockParagraph(
|
||||
@@ -125,7 +95,6 @@ class TestDocumentLayouterIntegration:
|
||||
|
||||
# Verify lines were added to page
|
||||
assert len(page.children) > 0
|
||||
assert page.lines_added > 0
|
||||
|
||||
# Verify actual Line objects were created
|
||||
for child in page.children:
|
||||
@@ -135,8 +104,9 @@ class TestDocumentLayouterIntegration:
|
||||
|
||||
def test_multi_page_scenario_with_page_overflow(self):
|
||||
"""Test realistic multi-page scenario with actual page overflow."""
|
||||
# Create a very small page that will definitely overflow
|
||||
small_page = MockPage(width=150, height=80, max_lines=1) # Extremely small page
|
||||
# Create a very small real page that will definitely overflow
|
||||
small_page_style = PageStyle(border_width=5, padding=(5, 5, 5, 5))
|
||||
small_page = Page(size=(150, 80), style=small_page_style)
|
||||
|
||||
# Create a long paragraph that will definitely overflow
|
||||
long_text = " ".join([f"verylongword{i:02d}" for i in range(20)]) # 20 long words
|
||||
@@ -157,13 +127,13 @@ class TestDocumentLayouterIntegration:
|
||||
# If it failed, verify overflow handling
|
||||
assert failed_word_index is not None # Should indicate where it failed
|
||||
assert failed_word_index < len(paragraph.words) # Should be within word range
|
||||
assert len(small_page.children) <= small_page.max_lines
|
||||
print(f"✓ Multi-page test: Page overflow at word {failed_word_index}, {len(small_page.children)} lines fit")
|
||||
|
||||
def test_word_spacing_constraints_in_real_lines(self):
|
||||
"""Test that word spacing constraints are properly used in real Line objects."""
|
||||
# Create page
|
||||
page = MockPage(width=400, height=300)
|
||||
# Create real page
|
||||
page_style = PageStyle(border_width=20, padding=(10, 10, 10, 10))
|
||||
page = Page(size=(400, 300), style=page_style)
|
||||
|
||||
# Create paragraph with specific spacing constraints
|
||||
paragraph = MockParagraph(
|
||||
@@ -197,7 +167,8 @@ class TestDocumentLayouterIntegration:
|
||||
]
|
||||
|
||||
for alignment_name, style in alignments_to_test:
|
||||
page = MockPage(width=350, height=200)
|
||||
page_style = PageStyle(border_width=20, padding=(10, 10, 10, 10))
|
||||
page = Page(size=(350, 200), style=page_style)
|
||||
paragraph = MockParagraph(
|
||||
"This sentence will test different alignment strategies with word spacing.",
|
||||
style
|
||||
@@ -217,8 +188,9 @@ class TestDocumentLayouterIntegration:
|
||||
|
||||
def test_realistic_document_with_multiple_pages(self):
|
||||
"""Test a realistic document that spans multiple pages."""
|
||||
# Create multiple pages
|
||||
pages = [MockPage(width=400, height=300, max_lines=5) for _ in range(3)]
|
||||
# Create multiple real pages
|
||||
page_style = PageStyle(border_width=20, padding=(10, 10, 10, 10))
|
||||
pages = [Page(size=(400, 300), style=page_style) for _ in range(3)]
|
||||
|
||||
# Create a document with multiple paragraphs
|
||||
paragraphs = [
|
||||
@@ -275,7 +247,8 @@ class TestDocumentLayouterIntegration:
|
||||
|
||||
def test_word_spacing_constraint_resolution_integration(self):
|
||||
"""Test the complete integration from AbstractStyle to Line spacing."""
|
||||
page = MockPage()
|
||||
page_style = PageStyle(border_width=20, padding=(10, 10, 10, 10))
|
||||
page = Page(size=(400, 600), style=page_style)
|
||||
|
||||
# Test different constraint scenarios
|
||||
test_cases = [
|
||||
@@ -300,8 +273,9 @@ class TestDocumentLayouterIntegration:
|
||||
]
|
||||
|
||||
for case in test_cases:
|
||||
# Create fresh page for each test
|
||||
test_page = MockPage()
|
||||
# Create fresh real page for each test
|
||||
test_page_style = PageStyle(border_width=20, padding=(10, 10, 10, 10))
|
||||
test_page = Page(size=(400, 600), style=test_page_style)
|
||||
paragraph = MockParagraph(
|
||||
"Testing constraint resolution with different scenarios.",
|
||||
case["style"]
|
||||
@@ -322,8 +296,9 @@ class TestDocumentLayouterIntegration:
|
||||
|
||||
def test_hyphenation_with_word_spacing_constraints(self):
|
||||
"""Test that hyphenation works correctly with word spacing constraints."""
|
||||
# Create a narrow page to force hyphenation
|
||||
narrow_page = MockPage(width=200, height=300)
|
||||
# Create a narrow real page to force hyphenation
|
||||
narrow_page_style = PageStyle(border_width=20, padding=(10, 10, 10, 10))
|
||||
narrow_page = Page(size=(200, 300), style=narrow_page_style)
|
||||
|
||||
# Create paragraph with long words that will need hyphenation
|
||||
paragraph = MockParagraph(
|
||||
|
||||
Reference in New Issue
Block a user