from collections import deque from edge.models import Keypoint, BBox from edge.tracking import Track, TrackFrame from edge.detectors.zone import point_in_polygon, Zone, ZoneIntrusionDetector, ZoneConfig SQUARE = [(0, 0), (100, 0), (100, 100), (0, 100)] def test_point_in_polygon_basic(): assert point_in_polygon(50, 50, SQUARE) is True assert point_in_polygon(150, 50, SQUARE) is False def _track_with_ankles(ax, ay, t): kps = [Keypoint(ax, ay, 0.9) for _ in range(17)] kps[15] = Keypoint(ax, ay, 0.9) # L_ANKLE kps[16] = Keypoint(ax, ay, 0.9) # R_ANKLE return Track(1, deque([TrackFrame(t, BBox(ax - 10, ay - 60, ax + 10, ay), kps)], maxlen=90)) def test_intrusion_fires_after_debounce(): z = Zone("z1", "restricted", SQUARE) det = ZoneIntrusionDetector([z], ZoneConfig(debounce_s=0.5)) tr = _track_with_ankles(50, 50, 0.0) assert det.update(tr, now=0.0) == [] tr = _track_with_ankles(50, 50, 0.6) out = det.update(tr, now=0.6) assert out == [{"zone_id": "z1", "level": "restricted"}] def test_leaving_zone_resets(): z = Zone("z1", "warning", SQUARE) det = ZoneIntrusionDetector([z], ZoneConfig(debounce_s=0.5)) det.update(_track_with_ankles(50, 50, 0.0), now=0.0) det.update(_track_with_ankles(200, 200, 0.6), now=0.6) # 이탈 out = det.update(_track_with_ankles(50, 50, 1.0), now=1.0) # 재진입, 디바운스 재시작 assert out == []