Update coverage badges [skip ci]
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
"""
|
||||
Tests for pointer interaction on EreaderLayoutManager (R7).
|
||||
|
||||
concrete/interaction_handler.py was 310 lines reachable only from
|
||||
examples/07_pressed_state_demo.py - no library code, no tests. These cover the
|
||||
wiring; the press/hover state on the elements themselves lives in
|
||||
tests/concrete/.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from PIL import Image
|
||||
|
||||
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>Tap <a href="action:go">this link</a> please.</p>'
|
||||
'<p>' + " ".join(f"w{i}" for i in range(400)) + '</p>')
|
||||
manager = EreaderLayoutManager(blocks, page_size=(400, 600),
|
||||
document_id="interaction",
|
||||
bookmarks_dir=str(tmp_path))
|
||||
yield manager
|
||||
manager.shutdown()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def link_point(manager):
|
||||
"""A page coordinate that lands on the interactive link."""
|
||||
page = manager.get_current_page()
|
||||
page.render()
|
||||
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.is_interactive:
|
||||
return (x, y)
|
||||
pytest.fail("fixture document rendered no interactive element")
|
||||
|
||||
|
||||
EMPTY_POINT = (399, 599)
|
||||
|
||||
|
||||
class TestHover:
|
||||
def test_hovering_an_element_produces_a_frame(self, manager, link_point):
|
||||
assert isinstance(manager.handle_hover(link_point), Image.Image)
|
||||
|
||||
def test_hovering_the_same_element_again_reports_no_change(self, manager, link_point):
|
||||
manager.handle_hover(link_point)
|
||||
|
||||
assert manager.handle_hover(link_point) is None, \
|
||||
"an unchanged hover should not force the caller to redraw"
|
||||
|
||||
def test_moving_off_the_element_clears_the_hover(self, manager, link_point):
|
||||
manager.handle_hover(link_point)
|
||||
|
||||
assert isinstance(manager.handle_hover(EMPTY_POINT), Image.Image)
|
||||
|
||||
|
||||
class TestPress:
|
||||
def test_pressing_an_element_produces_a_frame(self, manager, link_point):
|
||||
assert isinstance(manager.handle_touch_down(link_point), Image.Image)
|
||||
|
||||
def test_pressing_empty_space_does_nothing(self, manager):
|
||||
manager.get_current_page().render()
|
||||
|
||||
assert manager.handle_touch_down(EMPTY_POINT) is None
|
||||
|
||||
def test_release_runs_the_link_action(self, manager, link_point):
|
||||
manager.handle_touch_down(link_point)
|
||||
|
||||
frame, result = manager.handle_touch_up(link_point)
|
||||
|
||||
assert isinstance(frame, Image.Image)
|
||||
assert result == "action:go"
|
||||
|
||||
def test_release_without_a_press_is_a_no_op(self, manager):
|
||||
manager.get_current_page().render()
|
||||
|
||||
assert manager.handle_touch_up(EMPTY_POINT) == (None, None)
|
||||
|
||||
def test_a_full_press_release_cycle_leaves_no_state(self, manager, link_point):
|
||||
manager.handle_touch_down(link_point)
|
||||
manager.handle_touch_up(link_point)
|
||||
|
||||
assert manager.handle_touch_up(link_point) == (None, None)
|
||||
|
||||
|
||||
class TestStateFollowsTheDisplayedPage:
|
||||
def test_navigating_rebinds_the_state_machine(self, manager, link_point):
|
||||
before = manager._interaction_state()
|
||||
|
||||
manager.next_page()
|
||||
|
||||
assert manager._interaction_state() is not before, \
|
||||
"press state belongs to one rendered page"
|
||||
|
||||
def test_state_survives_repeated_access_on_one_page(self, manager, link_point):
|
||||
assert manager._interaction_state() is manager._interaction_state()
|
||||
|
||||
def test_reset_is_safe_before_any_interaction(self, manager):
|
||||
manager.reset_interaction_state() # must not raise
|
||||
|
||||
def test_reset_clears_a_pending_press(self, manager, link_point):
|
||||
manager.handle_touch_down(link_point)
|
||||
|
||||
manager.reset_interaction_state()
|
||||
|
||||
assert manager.handle_touch_up(link_point) == (None, None)
|
||||
|
||||
|
||||
class TestPressedRenderingRegression:
|
||||
"""
|
||||
LinkText.render passed [origin, origin + size] - two numpy arrays - to
|
||||
PIL's draw.rectangle, which needs a flat four-scalar box. Rendering any
|
||||
hovered or pressed link raised TypeError. Nothing caught it because the
|
||||
only caller was an example.
|
||||
"""
|
||||
|
||||
def test_rendering_a_hovered_link_does_not_raise(self, manager, link_point):
|
||||
manager.handle_hover(link_point)
|
||||
|
||||
assert isinstance(manager.get_current_page().render(), Image.Image)
|
||||
|
||||
def test_rendering_a_pressed_link_does_not_raise(self, manager, link_point):
|
||||
manager.handle_touch_down(link_point)
|
||||
|
||||
assert isinstance(manager.get_current_page().render(), Image.Image)
|
||||
Reference in New Issue
Block a user