import pytest from pydantic import ValidationError from camera_ingest_calibration import ( CalibrationMetadata, CameraFrameIngestor, NavigationFrame, ) def _calibration() -> CalibrationMetadata: return CalibrationMetadata( calibration_id="calib-front-1", camera_model="global-shutter", image_width_px=1920, image_height_px=1080, focal_length_px=840.0, distortion_model="plumb_bob", ) def test_valid_frame_packet_contains_metadata_reports_and_normalization_hint() -> None: # Arrange frame = NavigationFrame( frame_id="frame-1", timestamp_ns=1_000, image_ref="replay/frame-1.jpg", mean_luma=0.7, contrast=0.6, north_up_degrees=12.5, ) # Act packet = CameraFrameIngestor().ingest(frame, _calibration()) # Assert assert packet.contract.timestamp_ns == 1_000 assert packet.contract.calibration_id == "calib-front-1" assert packet.quality_report.state == "usable" assert packet.occlusion_report.state == "clear" assert packet.normalization_hint.should_normalize_downstream is True def test_total_occlusion_marks_frame_unusable_for_vio_and_anchor() -> None: # Arrange frame = NavigationFrame( frame_id="frame-blackout", timestamp_ns=2_000, image_ref="replay/frame-blackout.jpg", mean_luma=0.01, contrast=0.01, ) # Act packet = CameraFrameIngestor().ingest(frame, _calibration()) # Assert assert packet.occlusion_report.state == "total" assert packet.usable_for_vio is False assert packet.usable_for_anchor is False def test_raw_frame_payload_retention_is_rejected() -> None: # Act with pytest.raises(ValidationError) as error: NavigationFrame( frame_id="frame-raw", timestamp_ns=3_000, image_ref="replay/frame-raw.jpg", mean_luma=0.7, contrast=0.6, raw_frame_retained=True, ) # Assert assert "references only" in str(error.value)