"""AZ-697 AC-5 — gps_compare helper-move snapshot. The ``l2_horizontal_m`` / ``match_percentage`` / ``GroundTruthRow`` trio moved from ``tests/e2e/replay/_helpers.py`` into production code at ``src/gps_denied_onboard/helpers/gps_compare.py``. This module pins the post-move numerical behaviour so a future refactor of either the helper or the test re-export can't silently drift. The numerical reference values are hand-computed against the WGS84 mean Earth radius used by ``helpers/wgs_converter.py`` (AZ-279). The ``tests/e2e/replay/test_helpers.py`` module continues to import from ``tests/e2e/replay/_helpers`` (which now re-exports from the production location), so both call sites are exercised. Style: every test follows the Arrange / Act / Assert pattern. """ from __future__ import annotations import pytest from gps_denied_onboard.helpers.gps_compare import ( GroundTruthRow, l2_horizontal_m, match_percentage, ) # --------------------------------------------------------------------- # Snapshot: production location vs prior test-helpers location def test_l2_zero_at_same_point() -> None: # Act d = l2_horizontal_m(50.08, 36.11, 50.08, 36.11) # Assert assert d == pytest.approx(0.0, abs=1e-6) def test_l2_one_degree_latitude_is_111km() -> None: # Act d = l2_horizontal_m(50.08, 36.11, 51.08, 36.11) # Assert — one degree of latitude on a sphere of radius 6_371_008.8 m. assert d == pytest.approx(111_195.0, rel=0.001) def test_l2_symmetric() -> None: # Arrange a = (49.991, 36.221) b = (50.080, 36.111) # Act d_ab = l2_horizontal_m(*a, *b) d_ba = l2_horizontal_m(*b, *a) # Assert assert d_ab == pytest.approx(d_ba, rel=1e-12) def test_l2_kharkiv_to_kyiv_known_pair() -> None: # Arrange — externally known reference distance is ~411 km. kharkiv_lat, kharkiv_lon = 49.9935, 36.2304 kyiv_lat, kyiv_lon = 50.4501, 30.5234 # Act d = l2_horizontal_m(kharkiv_lat, kharkiv_lon, kyiv_lat, kyiv_lon) # Assert assert d == pytest.approx(411_000.0, rel=0.005) def test_match_percentage_all_within_threshold() -> None: # Arrange gt = [GroundTruthRow(t_s=0.0, lat_deg=50.0, lon_deg=36.0, alt_m=100.0)] emissions = [ { "emitted_at": 0, "position_wgs84": {"lat_deg": 50.0, "lon_deg": 36.0, "alt_m": 100.0}, } ] # Act pct = match_percentage(emissions, gt, threshold_m=100.0) # Assert assert pct == 1.0 def test_match_percentage_none_within_threshold() -> None: # Arrange gt = [GroundTruthRow(t_s=0.0, lat_deg=50.0, lon_deg=36.0, alt_m=100.0)] emissions = [ { "emitted_at": 0, # ~111 km north of the GT row. "position_wgs84": {"lat_deg": 51.0, "lon_deg": 36.0, "alt_m": 100.0}, } ] # Act pct = match_percentage(emissions, gt, threshold_m=100.0) # Assert assert pct == 0.0 def test_match_percentage_empty_emissions_zero() -> None: # Arrange gt = [GroundTruthRow(t_s=0.0, lat_deg=50.0, lon_deg=36.0, alt_m=100.0)] # Act pct = match_percentage([], gt, threshold_m=100.0) # Assert assert pct == 0.0 def test_match_percentage_empty_ground_truth_raises() -> None: # Act / Assert with pytest.raises(AssertionError, match="ground_truth must be non-empty"): match_percentage( [{"emitted_at": 0, "position_wgs84": {"lat_deg": 50, "lon_deg": 36}}], [], threshold_m=100.0, ) def test_ground_truth_row_is_frozen() -> None: # Arrange row = GroundTruthRow(t_s=0.0, lat_deg=50.0, lon_deg=36.0, alt_m=100.0) # Act / Assert with pytest.raises((AttributeError, TypeError)): row.lat_deg = 51.0 # type: ignore[misc] # --------------------------------------------------------------------- # Snapshot: re-export from prior test-helpers location returns the # same object as the production import. Guarantees there is no second # divergent copy under tests/. def test_test_helpers_reexport_is_identical() -> None: # Act from tests.e2e.replay import _helpers as test_helpers_module # Assert — identity, not just equality. assert test_helpers_module.l2_horizontal_m is l2_horizontal_m assert test_helpers_module.match_percentage is match_percentage assert test_helpers_module.GroundTruthRow is GroundTruthRow