from __future__ import annotations import tempfile import unittest from pathlib import Path from unittest.mock import patch from PIL import Image from production_build_agents.tools.face_detection import detect_faces def _candidate(*, score: float, size: float = 48) -> list[float]: return [8, 8, size, size, *([0.0] * 10), score] class FaceDetectionTest(unittest.TestCase): def _detect( self, candidates: list[list[float]], ) -> dict: with tempfile.TemporaryDirectory() as temp_dir: root = Path(temp_dir) source = root / "source.png" Image.new("RGB", (128, 96), "white").save(source) with patch( "production_build_agents.tools.face_detection" "._detect_candidates", return_value=candidates, ): return detect_faces(source.as_posix(), output_dir=root / "out") def test_face_decision_requires_confident_visible_face(self) -> None: result = self._detect([_candidate(score=0.91)]) self.assertEqual(result["decision"], "FACE") self.assertEqual(result["face_count"], 1) self.assertEqual(result["candidate_count"], 1) self.assertTrue(result["faces"][0]["accepted"]) self.assertEqual(len(result["input_sha256"]), 64) self.assertEqual(len(result["model_sha256"]), 64) def test_no_candidate_is_no_face(self) -> None: result = self._detect([]) self.assertEqual(result["decision"], "NO_FACE") self.assertEqual(result["face_count"], 0) self.assertEqual(result["candidate_count"], 0) def test_low_confidence_or_tiny_candidate_is_uncertain(self) -> None: for candidate in ( _candidate(score=0.55), _candidate(score=0.91, size=12), ): with self.subTest(candidate=candidate): result = self._detect([candidate]) self.assertEqual(result["decision"], "UNCERTAIN") self.assertEqual(result["face_count"], 0)