from src.config_loader import CrossingSettings from src.crossing_detector import CrossingDetector from src.models import BoundingBox, PixelTriggerLine, TrackPoint def settings(**overrides: object) -> CrossingSettings: values = dict(enabled=True, count_once_per_track=True, deadband_pixels=3, minimum_displacement_pixels=10, minimum_track_points=3, require_confirmed_track=True) values.update(overrides) return CrossingSettings(**values) # type: ignore[arg-type] def points(values: list[float], vertical: bool = True) -> list[TrackPoint]: result = [] for frame, value in enumerate(values, 1): x, y = (value, 20.0) if vertical else (20.0, value) result.append(TrackPoint(float(frame), str(frame), frame, x, y, x, y, BoundingBox(0, 0, 2, 2))) return result def test_vertical_directions_and_no_crossing() -> None: detector = CrossingDetector(settings(), PixelTriggerLine("vertical", 50)) assert detector.detect(1, points([30, 45, 60]), True) == "left_to_right" assert detector.detect(2, points([70, 55, 40]), True) == "right_to_left" assert detector.detect(3, points([20, 30, 40]), True) is None def test_deadband_displacement_confirmation_and_once() -> None: detector = CrossingDetector(settings(), PixelTriggerLine("vertical", 50)) assert detector.detect(1, points([46, 49, 54]), True) is None assert CrossingDetector(settings(minimum_displacement_pixels=30), PixelTriggerLine("vertical", 50)).detect(2, points([40, 50, 60]), True) is None assert detector.detect(4, points([30, 45, 60]), False) is None assert detector.detect(4, points([30, 45, 60]), True) == "left_to_right" assert detector.detect(4, points([60, 50, 30]), True) is None def test_horizontal_directions() -> None: detector = CrossingDetector(settings(), PixelTriggerLine("horizontal", 50)) assert detector.detect(1, points([30, 45, 60], vertical=False), True) == "top_to_bottom" assert detector.detect(2, points([70, 55, 40], vertical=False), True) == "bottom_to_top"