from __future__ import annotations import unittest from datetime import datetime, timezone from cold_display_guard.vision import ( Frame, Region, RuntimeVisionSettings, ZoneOccupancyDetector, point_in_polygon, ) def solid_frame(width: int, height: int, value: int) -> Frame: return Frame(width=width, height=height, rgb=bytes([value, value, value]) * width * height) def patched_frame(width: int, height: int, base: int, patch: tuple[int, int, int, int, int]) -> Frame: x1, y1, x2, y2, value = patch pixels = bytearray(bytes([base, base, base]) * width * height) for y in range(y1, y2): for x in range(x1, x2): offset = (y * width + x) * 3 pixels[offset : offset + 3] = bytes([value, value, value]) return Frame(width=width, height=height, rgb=bytes(pixels)) class VisionTests(unittest.TestCase): def test_point_in_polygon(self) -> None: polygon = ((0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)) self.assertTrue(point_in_polygon(0.5, 0.5, polygon)) self.assertFalse(point_in_polygon(1.5, 0.5, polygon)) def test_detector_reports_occupied_after_baseline_changes(self) -> None: detector = ZoneOccupancyDetector( [Region("r1c1", ((0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)))], trash_region=None, settings=RuntimeVisionSettings( baseline_frames=1, sample_stride_pixels=4, occupancy_mean_delta=10, occupancy_texture_delta=10, ), ) now = datetime(2026, 4, 28, 10, 0, tzinfo=timezone.utc) baseline_counts, _, _ = detector.observe(solid_frame(32, 32, 30), now) changed_counts, _, _ = detector.observe(patched_frame(32, 32, 30, (0, 0, 32, 32, 90)), now) self.assertEqual(baseline_counts, {"r1c1": 0}) self.assertEqual(changed_counts, {"r1c1": 1}) def test_detector_reports_trash_motion(self) -> None: trash = Region("trash", ((0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0))) detector = ZoneOccupancyDetector( [], trash_region=trash, settings=RuntimeVisionSettings(sample_stride_pixels=4, trash_motion_delta=10), ) now = datetime(2026, 4, 28, 10, 0, tzinfo=timezone.utc) _, first_deposit, _ = detector.observe(solid_frame(32, 32, 30), now) _, second_deposit, _ = detector.observe(solid_frame(32, 32, 90), now) self.assertEqual(first_deposit, 0) self.assertEqual(second_deposit, 1) if __name__ == "__main__": unittest.main()