import pytest from pydantic import ValidationError from shared.contracts import ( AnchorDecision, CacheTileRecord, FdrEvent, FramePacket, PositionEstimate, TelemetrySample, VioStatePacket, VprCandidate, ) def test_runtime_dtos_accept_valid_minimal_values() -> None: # Arrange timestamp_ns = 1_000_000 # Act contracts = [ FramePacket( frame_id="frame-1", timestamp_ns=timestamp_ns, image_ref="frames/frame-1", calibration_id="calib-1", occlusion="clear", quality=0.95, ), TelemetrySample( timestamp_ns=timestamp_ns, imu={"accel_x": 0.1}, attitude={"roll": 0.0}, altitude_m=950.0, airspeed_mps=16.0, gps_health="lost", ), VioStatePacket( timestamp_ns=timestamp_ns, relative_pose={"x": 1.0}, velocity_mps=(1.0, 0.0, 0.0), tracking_quality=0.8, ), PositionEstimate( timestamp_ns=timestamp_ns, latitude_deg=49.9, longitude_deg=36.2, altitude_m=950.0, covariance_semimajor_m=12.0, source_label="satellite_anchored", fix_type=3, horizontal_accuracy_m=12.0, anchor_age_ms=200, ), VprCandidate( chunk_id="chunk-1", tile_id="tile-1", score=0.87, footprint={"min_lat": 49.0}, freshness_status="fresh", ), AnchorDecision( candidate_id="candidate-1", accepted=True, estimated_pose={"x": 1.0}, inliers=42, mean_reprojection_error_px=0.8, ), CacheTileRecord( tile_id="tile-1", crs="EPSG:3857", meters_per_pixel=0.3, capture_date="2026-05-03", signature_hash="sha256:abc", trust_level="trusted", freshness_status="fresh", provenance="suite-satellite-service", ), FdrEvent( event_type="health", timestamp_ns=timestamp_ns, component="shared.contracts", severity="info", payload_ref="fdr://segment/1", mission_id="mission-1", run_id="run-1", ), ] # Assert assert len(contracts) == 8 def test_missing_required_timestamp_is_rejected_with_structured_error() -> None: # Act with pytest.raises(ValidationError) as error: FramePacket( frame_id="frame-1", image_ref="frames/frame-1", calibration_id="calib-1", occlusion="clear", quality=0.95, ) # Assert assert error.value.errors()[0]["loc"] == ("timestamp_ns",) assert error.value.errors()[0]["type"] == "missing" def test_raw_frame_retention_is_rejected() -> None: # Act with pytest.raises(ValidationError) as error: FramePacket( frame_id="frame-1", timestamp_ns=1, image_ref="frames/frame-1", calibration_id="calib-1", occlusion="clear", quality=0.95, raw_frame_retained=True, ) # Assert assert "raw frame payloads must be referenced" in str(error.value) def test_position_accuracy_cannot_under_report_covariance() -> None: # Act with pytest.raises(ValidationError) as error: PositionEstimate( timestamp_ns=1, latitude_deg=49.9, longitude_deg=36.2, altitude_m=950.0, covariance_semimajor_m=50.0, source_label="satellite_anchored", fix_type=3, horizontal_accuracy_m=10.0, anchor_age_ms=200, ) # Assert assert "must not under-report" in str(error.value) def test_accepted_anchor_requires_estimated_pose() -> None: # Act with pytest.raises(ValidationError) as error: AnchorDecision( candidate_id="candidate-1", accepted=True, inliers=42, mean_reprojection_error_px=0.8, ) # Assert assert "accepted anchor decisions require estimated_pose" in str(error.value)