import sys import unittest from pathlib import Path import numpy as np sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) import aggregator import router from classifier import FaceClassifier, calibrated_softmax class Story05ClassifierTests(unittest.TestCase): def test_calibrated_softmax_sums_to_one(self): logits = np.array([[2.0, 1.0], [-1.0, 3.0]], dtype=np.float32) probs = calibrated_softmax(logits, temperature=1.0) np.testing.assert_allclose(probs.sum(axis=1), [1.0, 1.0], atol=1e-6) def test_temperature_scaling_raises_lower_confidence_entropy(self): logits = np.array([[2.0, 0.5]], dtype=np.float32) sharp = calibrated_softmax(logits, temperature=0.5) soft = calibrated_softmax(logits, temperature=2.0) # higher temperature → softer distribution (target class prob moves toward 0.5) self.assertGreater(sharp[0, 0], soft[0, 0]) def test_classifier_placeholder_returns_neutral_probability(self): clf = FaceClassifier(engine_path="/nonexistent/model.trt", temperature=1.0) probs = clf.classify([]) self.assertEqual(probs, []) def test_classifier_placeholder_single_crop_returns_half(self): import tempfile from PIL import Image clf = FaceClassifier(engine_path="/nonexistent/model.trt", temperature=1.0) with tempfile.TemporaryDirectory() as tmpdir: crop = Path(tmpdir) / "crop.jpg" Image.new("RGB", (224, 224)).save(crop) probs = clf.classify([str(crop)]) # placeholder logits are all zeros → softmax → 0.5 for each class self.assertAlmostEqual(probs[0], 0.5, places=5) class Story05AggregatorTests(unittest.TestCase): def test_max_strategy(self): self.assertAlmostEqual(aggregator.aggregate([0.3, 0.8, 0.6], strategy="max"), 0.8) def test_empty_confidences_returns_zero(self): self.assertEqual(aggregator.aggregate([], strategy="max"), 0.0) def test_top_k_mean(self): result = aggregator.aggregate([0.1, 0.9, 0.5, 0.8], strategy="top_k_mean", top_k=2) self.assertAlmostEqual(result, (0.9 + 0.8) / 2, places=5) def test_weighted_mean_clamps_to_unit_interval(self): result = aggregator.aggregate([1.0, 1.0], strategy="weighted_mean", alpha=100.0, beta=0.0) self.assertLessEqual(result, 1.0) self.assertGreaterEqual(result, 0.0) class Story05RouterTests(unittest.TestCase): def test_match_at_high_threshold(self): self.assertEqual(router.route(0.75), router.MATCH) def test_review_between_thresholds(self): self.assertEqual(router.route(0.60), router.REVIEW) def test_skip_below_low_threshold(self): self.assertEqual(router.route(0.44), router.SKIP) def test_inclusive_high_threshold_boundary(self): self.assertEqual(router.route(0.75, t_high=0.75, t_low=0.45), router.MATCH) def test_inclusive_low_threshold_boundary(self): self.assertEqual(router.route(0.45, t_high=0.75, t_low=0.45), router.REVIEW) def test_no_faces_zero_confidence_routes_skip(self): self.assertEqual(router.route(0.0), router.SKIP) if __name__ == "__main__": unittest.main()