Update coverage badges [skip ci]
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
"""
|
||||
Tests for the highlight API on EreaderLayoutManager (R7).
|
||||
|
||||
core/highlight.py was fully implemented and tested but unreachable: the manager
|
||||
had no highlight API, so highlighting could not be used through the library's
|
||||
own interface. These tests cover the wiring, not the dataclass - that is
|
||||
tests/core/test_highlight.py.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from pyWebLayout.core.highlight import Highlight, HighlightColor
|
||||
from pyWebLayout.io.readers.html_extraction import parse_html_string
|
||||
from pyWebLayout.layout.ereader_manager import EreaderLayoutManager
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def manager(tmp_path):
|
||||
blocks = parse_html_string(
|
||||
"<p>" + " ".join(f"word{i}" for i in range(300)) + "</p>")
|
||||
manager = EreaderLayoutManager(blocks, page_size=(400, 600),
|
||||
document_id="highlights",
|
||||
bookmarks_dir=str(tmp_path))
|
||||
yield manager
|
||||
manager.shutdown()
|
||||
|
||||
|
||||
def text_points(page, limit=None):
|
||||
"""Points on the rendered page that land on a text object."""
|
||||
found = []
|
||||
for y in range(0, 120, 2):
|
||||
for x in range(0, 400, 2):
|
||||
result = page.query_point((x, y))
|
||||
if result is not None and result.object_type == "text" and result.text:
|
||||
found.append((x, y))
|
||||
if limit and len(found) >= limit:
|
||||
return found
|
||||
return found
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def point_on_text(manager):
|
||||
page = manager.get_current_page()
|
||||
page.render()
|
||||
return text_points(page, limit=1)[0]
|
||||
|
||||
|
||||
class TestHighlightPoint:
|
||||
def test_highlighting_a_word_returns_a_stored_highlight(self, manager, point_on_text):
|
||||
highlight = manager.highlight_point(point_on_text)
|
||||
|
||||
assert isinstance(highlight, Highlight)
|
||||
assert highlight.text
|
||||
assert manager.list_highlights() == [highlight]
|
||||
|
||||
def test_colour_note_and_tags_are_kept(self, manager, point_on_text):
|
||||
highlight = manager.highlight_point(
|
||||
point_on_text, color=HighlightColor.GREEN.value,
|
||||
note="a note", tags=["review"])
|
||||
|
||||
assert highlight.color == HighlightColor.GREEN.value
|
||||
assert highlight.note == "a note"
|
||||
assert highlight.tags == ["review"]
|
||||
|
||||
def test_highlighting_empty_space_returns_none(self, manager):
|
||||
manager.get_current_page().render()
|
||||
|
||||
assert manager.highlight_point((399, 599)) is None
|
||||
assert manager.list_highlights() == []
|
||||
|
||||
def test_the_originating_position_is_recorded(self, manager, point_on_text):
|
||||
highlight = manager.highlight_point(point_on_text)
|
||||
|
||||
assert highlight.position == manager.current_position.to_dict()
|
||||
|
||||
|
||||
class TestHighlightRange:
|
||||
def test_a_selection_spans_multiple_words(self, manager):
|
||||
page = manager.get_current_page()
|
||||
page.render()
|
||||
points = text_points(page)
|
||||
|
||||
highlight = manager.highlight_range(points[0], points[-1])
|
||||
|
||||
assert highlight is not None
|
||||
assert len(highlight.text.split()) > 1
|
||||
assert len(highlight.bounds) > 1
|
||||
|
||||
def test_a_selection_hitting_no_text_returns_none(self, manager):
|
||||
manager.get_current_page().render()
|
||||
|
||||
assert manager.highlight_range((398, 596), (399, 599)) is None
|
||||
|
||||
|
||||
class TestHighlightsAreScopedToTheirPage:
|
||||
def test_current_page_highlights_do_not_leak_across_pages(self, manager, point_on_text):
|
||||
manager.highlight_point(point_on_text)
|
||||
assert len(manager.get_highlights_for_current_page()) == 1
|
||||
|
||||
manager.next_page()
|
||||
|
||||
assert manager.get_highlights_for_current_page() == []
|
||||
assert len(manager.list_highlights()) == 1, "still in the document, just not here"
|
||||
|
||||
def test_returning_to_the_page_finds_it_again(self, manager, point_on_text):
|
||||
highlight = manager.highlight_point(point_on_text)
|
||||
manager.next_page()
|
||||
manager.previous_page()
|
||||
|
||||
assert manager.get_highlights_for_current_page() == [highlight]
|
||||
|
||||
|
||||
class TestPersistence:
|
||||
def test_highlights_survive_a_restart(self, manager, point_on_text, tmp_path):
|
||||
highlight = manager.highlight_point(point_on_text, note="kept")
|
||||
manager.shutdown()
|
||||
|
||||
reopened = EreaderLayoutManager(
|
||||
manager.blocks, page_size=(400, 600), document_id="highlights",
|
||||
bookmarks_dir=str(tmp_path))
|
||||
try:
|
||||
restored = reopened.list_highlights()
|
||||
assert len(restored) == 1
|
||||
assert restored[0].id == highlight.id
|
||||
assert restored[0].note == "kept"
|
||||
assert restored[0].position == highlight.position
|
||||
finally:
|
||||
reopened.shutdown()
|
||||
|
||||
def test_highlights_share_the_bookmarks_directory_by_default(self, manager,
|
||||
point_on_text, tmp_path):
|
||||
manager.highlight_point(point_on_text)
|
||||
|
||||
assert (tmp_path / "highlights_highlights.json").exists()
|
||||
|
||||
def test_removing_a_highlight_persists(self, manager, point_on_text, tmp_path):
|
||||
highlight = manager.highlight_point(point_on_text)
|
||||
|
||||
assert manager.remove_highlight(highlight.id) is True
|
||||
assert manager.remove_highlight(highlight.id) is False
|
||||
|
||||
reopened = EreaderLayoutManager(
|
||||
manager.blocks, page_size=(400, 600), document_id="highlights",
|
||||
bookmarks_dir=str(tmp_path))
|
||||
try:
|
||||
assert reopened.list_highlights() == []
|
||||
finally:
|
||||
reopened.shutdown()
|
||||
|
||||
def test_clear_removes_everything(self, manager, point_on_text):
|
||||
manager.highlight_point(point_on_text)
|
||||
|
||||
manager.clear_highlights()
|
||||
|
||||
assert manager.list_highlights() == []
|
||||
|
||||
def test_a_corrupt_store_does_not_stop_the_book_opening(self, tmp_path):
|
||||
(tmp_path / "broken_highlights.json").write_text("{not json")
|
||||
blocks = parse_html_string("<p>hello world</p>")
|
||||
|
||||
manager = EreaderLayoutManager(blocks, page_size=(400, 600),
|
||||
document_id="broken",
|
||||
bookmarks_dir=str(tmp_path))
|
||||
try:
|
||||
assert manager.list_highlights() == []
|
||||
assert manager.get_current_page() is not None
|
||||
finally:
|
||||
manager.shutdown()
|
||||
Reference in New Issue
Block a user