"""Smoke tests for LineCrossCounter (src/counting.py). Pure-Python: needs only numpy.""" from src.counting import LineCrossCounter from src.interfaces import Detection def _det(tid, y1, cx=500.0): return Detection( bbox=(cx - 20, y1, cx + 20, y1 + 60), confidence=0.9, class_id=0, class_name="sack", track_id=tid, ) def _counter(): return LineCrossCounter(line_y=100, line_x_start=0, line_x_end=1000, margin=20) def test_loading_above_then_below(): c = _counter() assert c.update([_det(1, y1=10)]) == [] # above line events = c.update([_det(1, y1=150)]) # below line assert len(events) == 1 assert events[0]["direction"] == "loading" assert c.loading_count == 1 def test_below_first_counts_as_unloading_not_loading(): c = _counter() assert c.update([_det(2, y1=150)]) == [] # appeared below first assert c.update([_det(2, y1=10)]) != [] # moved above => unloading assert c.unloading_count == 1 assert c.loading_count == 0 def test_track_counted_once_per_direction(): c = _counter() c.update([_det(3, y1=10)]) c.update([_det(3, y1=150)]) c.update([_det(3, y1=10)]) c.update([_det(3, y1=150)]) assert c.loading_count == 1 # track_id counted once for loading def test_outside_x_bounds_skipped(): c = _counter() c.update([_det(4, y1=10, cx=500.0)]) assert c.update([_det(4, y1=150, cx=5000.0)]) == [] assert c.loading_count == 0 def test_net_and_reset(): c = _counter() c.update([_det(5, y1=10)]) c.update([_det(5, y1=150)]) assert c.net_count == 1 c.reset() assert (c.loading_count, c.unloading_count, c.net_count) == (0, 0, 0)