317 lines
10 KiB
Python
317 lines
10 KiB
Python
"""
|
|
Integration tests for EbookReader highlighting functionality.
|
|
|
|
Tests the highlighting API in EbookReader including:
|
|
- highlight_word()
|
|
- highlight_selection()
|
|
- remove_highlight()
|
|
- list_highlights()
|
|
- get_highlights_for_current_page()
|
|
- clear_highlights()
|
|
- Highlight rendering on pages
|
|
"""
|
|
|
|
import unittest
|
|
import tempfile
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
from PIL import Image
|
|
|
|
from dreader.application import EbookReader
|
|
from pyWebLayout.core.highlight import HighlightColor
|
|
|
|
|
|
class TestEbookReaderHighlighting(unittest.TestCase):
|
|
"""Test EbookReader highlighting API"""
|
|
|
|
def setUp(self):
|
|
"""Create temporary directories and reader"""
|
|
self.temp_dir = tempfile.mkdtemp()
|
|
self.bookmarks_dir = Path(self.temp_dir) / "bookmarks"
|
|
self.highlights_dir = Path(self.temp_dir) / "highlights"
|
|
|
|
self.reader = EbookReader(
|
|
page_size=(800, 1000),
|
|
bookmarks_dir=str(self.bookmarks_dir),
|
|
highlights_dir=str(self.highlights_dir)
|
|
)
|
|
|
|
def tearDown(self):
|
|
"""Clean up"""
|
|
self.reader.close()
|
|
shutil.rmtree(self.temp_dir)
|
|
|
|
def test_highlight_manager_not_initialized_before_load(self):
|
|
"""Test that highlight manager is None before loading a book"""
|
|
self.assertIsNone(self.reader.highlight_manager)
|
|
|
|
def test_highlight_manager_initialized_after_load(self):
|
|
"""Test that highlight manager is initialized after loading"""
|
|
success = self.reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
self.assertIsNotNone(self.reader.highlight_manager)
|
|
self.assertEqual(self.reader.highlight_manager.document_id, "test")
|
|
|
|
def test_highlight_word_without_book(self):
|
|
"""Test highlighting returns None when no book loaded"""
|
|
highlight_id = self.reader.highlight_word(100, 100)
|
|
self.assertIsNone(highlight_id)
|
|
|
|
def test_highlight_word(self):
|
|
"""Test highlighting a word at a pixel location"""
|
|
success = self.reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
|
|
# Get a page to ensure content is rendered
|
|
page_img = self.reader.get_current_page()
|
|
self.assertIsNotNone(page_img)
|
|
|
|
# Try to highlight a word (coordinates may not hit text in test)
|
|
highlight_id = self.reader.highlight_word(
|
|
200, 300,
|
|
color=HighlightColor.YELLOW.value,
|
|
note="Test highlight"
|
|
)
|
|
|
|
# If we hit text, should return an ID
|
|
if highlight_id:
|
|
self.assertIsInstance(highlight_id, str)
|
|
self.assertGreater(len(highlight_id), 0)
|
|
|
|
# Verify it was added
|
|
highlights = self.reader.list_highlights()
|
|
self.assertGreater(len(highlights), 0)
|
|
|
|
def test_highlight_selection(self):
|
|
"""Test highlighting a range of words"""
|
|
success = self.reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
|
|
# Get a page
|
|
page_img = self.reader.get_current_page()
|
|
self.assertIsNotNone(page_img)
|
|
|
|
# Try to highlight a selection
|
|
highlight_id = self.reader.highlight_selection(
|
|
start=(100, 200),
|
|
end=(400, 250),
|
|
color=HighlightColor.BLUE.value,
|
|
tags=["selection", "test"]
|
|
)
|
|
|
|
# If selection hit text, should return an ID
|
|
if highlight_id:
|
|
self.assertIsInstance(highlight_id, str)
|
|
|
|
highlights = self.reader.list_highlights()
|
|
found = False
|
|
for h in highlights:
|
|
if h.id == highlight_id:
|
|
found = True
|
|
self.assertEqual(h.color, HighlightColor.BLUE.value)
|
|
self.assertIn("selection", h.tags)
|
|
break
|
|
self.assertTrue(found)
|
|
|
|
def test_list_highlights_empty(self):
|
|
"""Test listing highlights when none exist"""
|
|
success = self.reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
|
|
highlights = self.reader.list_highlights()
|
|
self.assertEqual(len(highlights), 0)
|
|
|
|
def test_remove_highlight(self):
|
|
"""Test removing a highlight"""
|
|
success = self.reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
|
|
page_img = self.reader.get_current_page()
|
|
|
|
# Create a highlight directly via manager for testing
|
|
from pyWebLayout.core.highlight import Highlight
|
|
|
|
highlight = Highlight(
|
|
id="test-highlight",
|
|
bounds=[(100, 200, 50, 15)],
|
|
color=HighlightColor.YELLOW.value,
|
|
text="Test"
|
|
)
|
|
self.reader.highlight_manager.add_highlight(highlight)
|
|
|
|
# Verify it exists
|
|
self.assertEqual(len(self.reader.list_highlights()), 1)
|
|
|
|
# Remove it
|
|
result = self.reader.remove_highlight("test-highlight")
|
|
self.assertTrue(result)
|
|
|
|
# Verify it's gone
|
|
self.assertEqual(len(self.reader.list_highlights()), 0)
|
|
|
|
def test_remove_nonexistent_highlight(self):
|
|
"""Test removing a highlight that doesn't exist"""
|
|
success = self.reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
|
|
result = self.reader.remove_highlight("nonexistent")
|
|
self.assertFalse(result)
|
|
|
|
def test_clear_highlights(self):
|
|
"""Test clearing all highlights"""
|
|
success = self.reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
|
|
# Add some highlights directly
|
|
from pyWebLayout.core.highlight import Highlight
|
|
|
|
for i in range(3):
|
|
highlight = Highlight(
|
|
id=f"test-{i}",
|
|
bounds=[(100 + i * 50, 200, 50, 15)],
|
|
color=HighlightColor.YELLOW.value,
|
|
text=f"Word{i}"
|
|
)
|
|
self.reader.highlight_manager.add_highlight(highlight)
|
|
|
|
self.assertEqual(len(self.reader.list_highlights()), 3)
|
|
|
|
self.reader.clear_highlights()
|
|
self.assertEqual(len(self.reader.list_highlights()), 0)
|
|
|
|
def test_get_highlights_for_current_page(self):
|
|
"""Test getting highlights for current page"""
|
|
success = self.reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
|
|
# Add highlights at different locations
|
|
from pyWebLayout.core.highlight import Highlight
|
|
|
|
# On page
|
|
highlight1 = Highlight(
|
|
id="on-page",
|
|
bounds=[(100, 200, 50, 15)],
|
|
color=HighlightColor.YELLOW.value,
|
|
text="OnPage"
|
|
)
|
|
|
|
# Off page (beyond page height)
|
|
highlight2 = Highlight(
|
|
id="off-page",
|
|
bounds=[(100, 5000, 50, 15)],
|
|
color=HighlightColor.YELLOW.value,
|
|
text="OffPage"
|
|
)
|
|
|
|
self.reader.highlight_manager.add_highlight(highlight1)
|
|
self.reader.highlight_manager.add_highlight(highlight2)
|
|
|
|
# Get highlights for current page
|
|
page_highlights = self.reader.get_highlights_for_current_page()
|
|
|
|
# Should only get the on-page highlight
|
|
self.assertEqual(len(page_highlights), 1)
|
|
self.assertEqual(page_highlights[0].id, "on-page")
|
|
|
|
def test_get_current_page_with_highlights(self):
|
|
"""Test that get_current_page renders highlights"""
|
|
success = self.reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
|
|
# Get page without highlights
|
|
page_no_highlights = self.reader.get_current_page(include_highlights=False)
|
|
self.assertIsNotNone(page_no_highlights)
|
|
|
|
# Add a highlight
|
|
from pyWebLayout.core.highlight import Highlight
|
|
|
|
highlight = Highlight(
|
|
id="test",
|
|
bounds=[(100, 200, 50, 15)],
|
|
color=HighlightColor.YELLOW.value,
|
|
text="Test"
|
|
)
|
|
self.reader.highlight_manager.add_highlight(highlight)
|
|
|
|
# Get page with highlights
|
|
page_with_highlights = self.reader.get_current_page(include_highlights=True)
|
|
self.assertIsNotNone(page_with_highlights)
|
|
|
|
# Both should be valid images
|
|
self.assertIsInstance(page_no_highlights, Image.Image)
|
|
self.assertIsInstance(page_with_highlights, Image.Image)
|
|
|
|
# Should have same size
|
|
self.assertEqual(page_no_highlights.size, page_with_highlights.size)
|
|
|
|
def test_highlight_persistence(self):
|
|
"""Test that highlights persist across reader instances"""
|
|
# Load book and add highlight
|
|
success = self.reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
|
|
from pyWebLayout.core.highlight import Highlight
|
|
|
|
highlight = Highlight(
|
|
id="persistent",
|
|
bounds=[(100, 200, 50, 15)],
|
|
color=HighlightColor.YELLOW.value,
|
|
text="Persisted"
|
|
)
|
|
self.reader.highlight_manager.add_highlight(highlight)
|
|
self.assertEqual(len(self.reader.list_highlights()), 1)
|
|
|
|
# Close reader
|
|
self.reader.close()
|
|
|
|
# Create new reader for same book
|
|
new_reader = EbookReader(
|
|
page_size=(800, 1000),
|
|
bookmarks_dir=str(self.bookmarks_dir),
|
|
highlights_dir=str(self.highlights_dir)
|
|
)
|
|
success = new_reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
|
|
# Should load existing highlights
|
|
highlights = new_reader.list_highlights()
|
|
self.assertEqual(len(highlights), 1)
|
|
self.assertEqual(highlights[0].id, "persistent")
|
|
self.assertEqual(highlights[0].text, "Persisted")
|
|
|
|
new_reader.close()
|
|
|
|
def test_render_highlights_helper(self):
|
|
"""Test the _render_highlights helper method"""
|
|
success = self.reader.load_epub("tests/data/test.epub")
|
|
self.assertTrue(success)
|
|
|
|
# Create a simple test image
|
|
from PIL import Image as PILImage
|
|
test_img = PILImage.new('RGB', (100, 100), color='white')
|
|
|
|
from pyWebLayout.core.highlight import Highlight
|
|
|
|
highlights = [
|
|
Highlight(
|
|
id="h1",
|
|
bounds=[(10, 10, 30, 20)],
|
|
color=(255, 255, 0, 100),
|
|
text="Test"
|
|
)
|
|
]
|
|
|
|
# Render highlights
|
|
result_img = self.reader._render_highlights(test_img, highlights)
|
|
|
|
self.assertIsNotNone(result_img)
|
|
self.assertIsInstance(result_img, PILImage.Image)
|
|
self.assertEqual(result_img.size, test_img.size)
|
|
# Result should preserve the input mode
|
|
self.assertEqual(result_img.mode, 'RGB')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|