This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
"""
|
||||
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 be RGBA for transparency
|
||||
self.assertEqual(result_img.mode, 'RGBA')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user