"""AZ-921 AC-4 — VioOutput.scale_quality DTO contract.""" from __future__ import annotations import typing from dataclasses import fields import numpy as np from gps_denied_onboard._types.nav import ( FeatureQuality, ImuBias, ScaleQuality, VioOutput, ) from gps_denied_onboard.helpers.se3_utils import SE3, matrix_to_se3 def _imu_bias() -> ImuBias: return ImuBias( accel_bias=(0.0, 0.0, 0.0), gyro_bias=(0.0, 0.0, 0.0), ) def _feature_quality() -> FeatureQuality: return FeatureQuality( tracked=10, new=2, lost=1, mean_parallax=1.0, mre_px=0.5, ) def _identity_se3() -> SE3: return matrix_to_se3(np.eye(4, dtype=np.float64)) def test_vio_output_default_scale_quality_is_unknown_for_back_compat() -> None: # Arrange / Act — constructor MUST work without scale_quality so # legacy strategies (OKVIS2, VINS-Mono) that have not been updated # for AZ-921 stay bug-for-bug compatible. vio = VioOutput( frame_id="frame-0", relative_pose_T=_identity_se3(), pose_covariance_6x6=np.eye(6, dtype=np.float64), imu_bias=_imu_bias(), feature_quality=_feature_quality(), emitted_at_ns=1_000_000_000, ) # Assert assert vio.scale_quality == "unknown" def test_vio_output_accepts_each_scale_quality_value() -> None: # Arrange accepted_values = ("metric", "direction_only", "unknown") # Act / Assert for value in accepted_values: vio = VioOutput( frame_id="frame-0", relative_pose_T=_identity_se3(), pose_covariance_6x6=np.eye(6, dtype=np.float64), imu_bias=_imu_bias(), feature_quality=_feature_quality(), emitted_at_ns=1_000_000_000, scale_quality=value, ) assert vio.scale_quality == value def test_scale_quality_literal_pins_the_three_documented_values() -> None: # Arrange / Act — the Literal type from the typing module exposes # its parameters via __args__, which lets the contract test pin # the exact accepted-string set rather than relying on a string # comparison alone. args = typing.get_args(ScaleQuality) # Assert assert set(args) == {"metric", "direction_only", "unknown"} def test_vio_output_dataclass_exposes_scale_quality_field() -> None: # Arrange / Act field_names = {f.name for f in fields(VioOutput)} # Assert assert "scale_quality" in field_names