yet more tests

This commit is contained in:
Duncan Tourolle 2025-11-08 19:52:19 +01:00
parent 00314c9b4f
commit 1ea870eef5
2 changed files with 279 additions and 0 deletions

View File

@ -0,0 +1,137 @@
"""
Test that LinkedWord objects remain as LinkText even when hyphenated.
This is a regression test for the bug where hyphenated LinkedWords
were being converted to regular Text objects instead of LinkText.
"""
import unittest
from PIL import Image, ImageDraw
from pyWebLayout.concrete.text import Line
from pyWebLayout.concrete.functional import LinkText
from pyWebLayout.abstract.inline import LinkedWord
from pyWebLayout.abstract.functional import LinkType
from pyWebLayout.style import Font, Alignment
class TestLinkedWordHyphenation(unittest.TestCase):
"""Test that LinkedWords become LinkText objects even when hyphenated."""
def setUp(self):
"""Set up test canvas and drawing context."""
self.canvas = Image.new('RGB', (800, 600), color='white')
self.draw = ImageDraw.Draw(self.canvas)
self.font = Font(font_size=12)
def test_short_linkedword_no_hyphenation(self):
"""Test that a short LinkedWord that fits becomes a LinkText."""
# Create a line with enough space
line = Line(
spacing=(5, 15),
origin=(0, 0),
size=(200, 30),
draw=self.draw,
halign=Alignment.LEFT
)
# Create a LinkedWord that will fit without hyphenation
linked_word = LinkedWord(
text="click",
style=self.font,
location="action:test",
link_type=LinkType.API
)
# Add the word to the line
success, overflow = line.add_word(linked_word)
# Verify it was added successfully
self.assertTrue(success)
self.assertIsNone(overflow)
# Verify it became a LinkText object
self.assertEqual(len(line._text_objects), 1)
self.assertIsInstance(line._text_objects[0], LinkText)
self.assertEqual(line._text_objects[0].link.location, "action:test")
def test_long_linkedword_with_hyphenation(self):
"""Test that a long LinkedWord that needs hyphenation preserves LinkText."""
# Create a narrow line to force hyphenation
line = Line(
spacing=(5, 15),
origin=(0, 0),
size=(80, 30),
draw=self.draw,
halign=Alignment.LEFT
)
# Create a long LinkedWord that will need hyphenation
linked_word = LinkedWord(
text="https://example.com/very-long-url",
style=self.font,
location="https://example.com/very-long-url",
link_type=LinkType.EXTERNAL
)
# Add the word to the line
success, overflow = line.add_word(linked_word)
# The word should either:
# 1. Fit completely and be a LinkText
# 2. Be hyphenated, and BOTH parts should be LinkText
if overflow is not None:
# Word was hyphenated
# The first part should be in the line
self.assertTrue(success)
self.assertGreater(len(line._text_objects), 0)
# Both parts should be LinkText (this is the bug we're testing for)
for text_obj in line._text_objects:
self.assertIsInstance(text_obj, LinkText,
f"Hyphenated LinkedWord part should be LinkText, got {type(text_obj)}")
self.assertEqual(text_obj.link.location, linked_word.location)
# The overflow should also be LinkText if it's hyphenated
if isinstance(overflow, LinkText):
self.assertEqual(overflow.link.location, linked_word.location)
else:
# Word fit without hyphenation
self.assertTrue(success)
self.assertEqual(len(line._text_objects), 1)
self.assertIsInstance(line._text_objects[0], LinkText)
def test_linkedword_title_preserved_after_hyphenation(self):
"""Test that link metadata (title) is preserved when hyphenated."""
# Create a narrow line
line = Line(
spacing=(5, 15),
origin=(0, 0),
size=(60, 30),
draw=self.draw,
halign=Alignment.LEFT
)
# Create a LinkedWord with title that will likely be hyphenated
linked_word = LinkedWord(
text="documentation",
style=self.font,
location="https://docs.example.com",
link_type=LinkType.EXTERNAL,
title="View Documentation"
)
# Add the word
success, overflow = line.add_word(linked_word)
# Verify metadata is preserved
if overflow is not None:
# If hyphenated, both parts should have link metadata
for text_obj in line._text_objects:
if isinstance(text_obj, LinkText):
self.assertEqual(text_obj.link.location, "https://docs.example.com")
self.assertEqual(text_obj.link.title, "View Documentation")
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,142 @@
"""
End-to-end test for HTML links in EreaderLayoutManager.
This test mimics exactly what the dreader application does:
1. Load HTML with links via parse_html_string
2. Create an EreaderLayoutManager
3. Render a page
4. Query for interactive elements
This should reveal if links are actually interactive after full rendering.
"""
import unittest
from pyWebLayout.io.readers.html_extraction import parse_html_string
from pyWebLayout.layout.ereader_manager import EreaderLayoutManager
from pyWebLayout.abstract.inline import LinkedWord
from pyWebLayout.concrete.functional import LinkText
class TestHTMLLinksInEreader(unittest.TestCase):
"""Test HTML link interactivity in the full ereader pipeline."""
def test_settings_overlay_links_are_interactive(self):
"""Test that settings overlay HTML creates interactive links."""
# This is realistic settings overlay HTML
html = '''
<div>
<h2>Settings</h2>
<p>
<a href="action:back_to_library">Back to Library</a>
</p>
<p>
Font Size:
<a href="setting:font_decrease">[-]</a>
<a href="setting:font_increase">[+]</a>
</p>
</div>
'''
# Step 1: Parse HTML to blocks
blocks = parse_html_string(html)
# Verify LinkedWords were created
all_linked_words = []
for block in blocks:
if hasattr(block, 'words'):
for word in block.words:
if isinstance(word, LinkedWord):
all_linked_words.append(word)
self.assertGreater(len(all_linked_words), 0, "Should create LinkedWords from HTML")
print(f"\n Created {len(all_linked_words)} LinkedWords from HTML")
# Step 2: Create EreaderLayoutManager (like the dreader app does)
page_size = (400, 600)
manager = EreaderLayoutManager(
blocks=blocks,
page_size=page_size,
document_id="test_settings"
)
# Step 3: Get the rendered page
page = manager.get_current_page()
self.assertIsNotNone(page)
# Step 4: Render to image
rendered_image = page.render()
self.assertIsNotNone(rendered_image)
print(f" Rendered page: {rendered_image.size}")
# Step 5: Find all interactive elements by scanning the page
# This is the CRITICAL test - are there LinkText objects in the page?
interactive_elements = []
# Scan through all children of the page
if hasattr(page, '_children'):
for child in page._children:
# Check if child is a Line
if hasattr(child, '_text_objects'):
for text_obj in child._text_objects:
if isinstance(text_obj, LinkText):
interactive_elements.append({
'type': 'LinkText',
'text': text_obj._text,
'location': text_obj.link.location,
'is_interactive': hasattr(text_obj, 'execute')
})
print(f" Found {len(interactive_elements)} LinkText objects in rendered page")
for elem in interactive_elements:
print(f" - '{elem['text']}' -> {elem['location']}")
# THIS IS THE KEY ASSERTION
self.assertGreater(len(interactive_elements), 0,
"Settings overlay should have interactive LinkText objects after rendering!")
# Verify the expected links are present
locations = {elem['location'] for elem in interactive_elements}
self.assertIn("action:back_to_library", locations,
"Should find 'Back to Library' link")
self.assertIn("setting:font_decrease", locations,
"Should find font decrease link")
self.assertIn("setting:font_increase", locations,
"Should find font increase link")
def test_query_point_detects_links(self):
"""Test that query_point can detect LinkText objects."""
html = '<p><a href="action:test">Click here</a> to test.</p>'
blocks = parse_html_string(html)
manager = EreaderLayoutManager(
blocks=blocks,
page_size=(400, 200),
document_id="test_query"
)
page = manager.get_current_page()
page.render()
# Try to query various points on the page
# We don't know exact coordinates, so scan a grid
found_link = False
for y in range(20, 100, 10):
for x in range(20, 380, 20):
result = page.query_point((x, y))
if result and result.is_interactive:
print(f"\n Found interactive element at ({x}, {y})")
print(f" Type: {result.object_type}")
print(f" Link target: {result.link_target}")
print(f" Text: {result.text}")
found_link = True
self.assertEqual(result.link_target, "action:test")
break
if found_link:
break
self.assertTrue(found_link,
"Should be able to detect link via query_point somewhere on the page")
if __name__ == '__main__':
unittest.main()