dreader-hal/tests/unit/test_gesture.py
2025-11-10 18:06:11 +01:00

208 lines
6.5 KiB
Python

"""
Unit tests for dreader_hal.gesture module.
Tests gesture detection state machine and classification logic.
"""
import pytest
import time
from dreader_hal.gesture import GestureDetector, TouchState
from dreader_hal.types import GestureType
class TestGestureDetector:
"""Tests for GestureDetector class."""
def setup_method(self):
"""Set up fresh detector for each test."""
self.detector = GestureDetector()
def test_initial_state(self):
"""Test detector initial state."""
assert self.detector.state == TouchState.IDLE
assert self.detector.start_pos is None
assert self.detector.current_pos is None
def test_tap_detection(self):
"""Test tap gesture detection."""
# Touch down
self.detector.on_touch_down(100, 100)
assert self.detector.state == TouchState.TOUCHING
# Small delay (less than long press)
time.sleep(0.1)
# Touch up at same position
gesture = self.detector.on_touch_up(105, 105) # 5px movement
assert gesture == GestureType.TAP
assert self.detector.state == TouchState.IDLE
def test_long_press_detection(self):
"""Test long press gesture detection."""
# Touch down
self.detector.on_touch_down(100, 100)
# Wait for long press duration
time.sleep(0.6) # Longer than 0.5s threshold
# Touch up at same position
gesture = self.detector.on_touch_up(105, 105)
assert gesture == GestureType.LONG_PRESS
assert self.detector.state == TouchState.IDLE
def test_swipe_left_detection(self):
"""Test swipe left gesture detection."""
# Touch down
self.detector.on_touch_down(200, 100)
# Quick movement to the left
time.sleep(0.1)
gesture = self.detector.on_touch_up(100, 105) # 100px left, 5px down
assert gesture == GestureType.SWIPE_LEFT
def test_swipe_right_detection(self):
"""Test swipe right gesture detection."""
self.detector.on_touch_down(100, 100)
time.sleep(0.1)
gesture = self.detector.on_touch_up(200, 105) # 100px right
assert gesture == GestureType.SWIPE_RIGHT
def test_swipe_up_detection(self):
"""Test swipe up gesture detection."""
self.detector.on_touch_down(100, 200)
time.sleep(0.1)
gesture = self.detector.on_touch_up(105, 100) # 100px up
assert gesture == GestureType.SWIPE_UP
def test_swipe_down_detection(self):
"""Test swipe down gesture detection."""
self.detector.on_touch_down(100, 100)
time.sleep(0.1)
gesture = self.detector.on_touch_up(105, 200) # 100px down
assert gesture == GestureType.SWIPE_DOWN
def test_drag_start_detection(self):
"""Test drag start detection."""
# Touch down
self.detector.on_touch_down(100, 100)
# Move beyond threshold
gesture = self.detector.on_touch_move(150, 100) # 50px movement
assert gesture == GestureType.DRAG_START
assert self.detector.state == TouchState.MOVING
def test_drag_move_detection(self):
"""Test drag move events."""
# Start dragging
self.detector.on_touch_down(100, 100)
self.detector.on_touch_move(150, 100) # Start drag
# Continue moving
gesture = self.detector.on_touch_move(200, 100)
assert gesture == GestureType.DRAG_MOVE
assert self.detector.state == TouchState.MOVING
def test_drag_end_detection(self):
"""Test drag end."""
# Start dragging
self.detector.on_touch_down(100, 100)
self.detector.on_touch_move(150, 100)
# Touch up
time.sleep(0.6) # Wait long enough to not be a swipe
gesture = self.detector.on_touch_up(200, 100)
assert gesture == GestureType.DRAG_END
def test_reset(self):
"""Test detector reset."""
# Set some state
self.detector.on_touch_down(100, 100)
assert self.detector.state == TouchState.TOUCHING
# Reset
self.detector.reset()
# Check clean state
assert self.detector.state == TouchState.IDLE
assert self.detector.start_pos is None
assert self.detector.current_pos is None
def test_custom_thresholds(self):
"""Test creating detector with custom thresholds."""
detector = GestureDetector(
tap_threshold=50.0,
long_press_duration=1.0
)
assert detector.tap_threshold == 50.0
assert detector.long_press_duration == 1.0
def test_pinch_detection(self):
"""Test two-finger pinch detection."""
# First finger down
self.detector.on_touch_down(100, 100, finger=0)
# Second finger down
self.detector.on_touch_down(200, 100, finger=1)
# Move fingers apart (pinch out)
self.detector.on_touch_move(90, 100, finger=0)
self.detector.on_touch_move(210, 100, finger=1)
# Second finger up
gesture = self.detector.on_touch_up(210, 100, finger=1)
assert gesture == GestureType.PINCH_OUT
def test_check_long_press(self):
"""Test long press check during touch."""
# Touch down
self.detector.on_touch_down(100, 100)
# Check before threshold
time.sleep(0.2)
assert not self.detector.check_long_press()
# Check after threshold
time.sleep(0.4) # Total 0.6s
assert self.detector.check_long_press()
assert self.detector.state == TouchState.LONG_PRESS_DETECTED
def test_no_gesture_on_small_movement(self):
"""Test that small movements during long delay don't trigger swipe."""
self.detector.on_touch_down(100, 100)
time.sleep(0.6) # Wait long
# Small movement
gesture = self.detector.on_touch_up(110, 110) # Only 14px diagonal
# Should be long press, not swipe
assert gesture == GestureType.LONG_PRESS
class TestTouchState:
"""Tests for TouchState enum."""
def test_states_defined(self):
"""Test all required states are defined."""
assert TouchState.IDLE
assert TouchState.TOUCHING
assert TouchState.MOVING
assert TouchState.LONG_PRESS_DETECTED
def test_state_values(self):
"""Test state enum values."""
assert TouchState.IDLE.value == "idle"
assert TouchState.TOUCHING.value == "touching"
assert TouchState.MOVING.value == "moving"
assert TouchState.LONG_PRESS_DETECTED.value == "long_press_detected"