The sar3d processor is rewritten as a checked port of Multi_antenna_3D_clean_v1.ipynb: NVRTC kernels, timing from the trace stamps, notebook parameter names and one cubic SAR_VOXEL_M. It adds front, side, top and 3D views, drops gpr_cpp and the parity tools, and the GUI speed now applies only while the socket speed is ignored.
114 lines
4.3 KiB
Python
114 lines
4.3 KiB
Python
"""Tests for GUI profile persistence."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import unittest
|
|
|
|
from python_app.models.gui_profile_model import (
|
|
GuiPassThroughStateModel,
|
|
GuiProcessingStateModel,
|
|
GuiProfileModel,
|
|
GuiSar3dStateModel,
|
|
GuiStateModel,
|
|
)
|
|
|
|
|
|
class GuiProfileCodecTest(unittest.TestCase):
|
|
def test_pass_through_combo_filter_round_trips(self) -> None:
|
|
profile = GuiProfileModel(
|
|
gui=GuiStateModel(
|
|
processing=GuiProcessingStateModel(
|
|
pass_through=GuiPassThroughStateModel(combo_filter="0:0,1:0")
|
|
)
|
|
)
|
|
)
|
|
|
|
encoded = profile.to_dict()
|
|
decoded = GuiProfileModel.from_dict(encoded)
|
|
|
|
self.assertIsNotNone(decoded.gui)
|
|
assert decoded.gui is not None
|
|
self.assertEqual(decoded.gui.processing.pass_through.combo_filter, "0:0,1:0")
|
|
self.assertEqual(encoded["gui"]["processing"]["pass_through"]["combo_filter"], "0:0,1:0")
|
|
|
|
def test_pass_through_unwrap_phase_round_trips(self) -> None:
|
|
profile = GuiProfileModel(
|
|
gui=GuiStateModel(
|
|
processing=GuiProcessingStateModel(
|
|
pass_through=GuiPassThroughStateModel(unwrap_phase=True)
|
|
)
|
|
)
|
|
)
|
|
|
|
encoded = profile.to_dict()
|
|
decoded = GuiProfileModel.from_dict(encoded)
|
|
|
|
assert decoded.gui is not None
|
|
self.assertTrue(decoded.gui.processing.pass_through.unwrap_phase)
|
|
self.assertTrue(encoded["gui"]["processing"]["pass_through"]["unwrap_phase"])
|
|
|
|
def test_default_profile_round_trips_idempotently(self) -> None:
|
|
# Full-subtree idempotence catches field-drop/mis-map regressions across every
|
|
# sub-model, which the single combo_filter round-trip above cannot.
|
|
once = GuiProfileModel().to_dict()
|
|
twice = GuiProfileModel.from_dict(once).to_dict()
|
|
self.assertEqual(once["gui"], twice["gui"])
|
|
|
|
def test_sar3d_section_round_trips(self) -> None:
|
|
sar3d = GuiSar3dStateModel(
|
|
input_positions="0,2",
|
|
output_positions="1,3",
|
|
min_depth_m=2.5,
|
|
max_depth_m=9.0,
|
|
start_freq_mhz=2000.0,
|
|
stop_freq_mhz=5500.0,
|
|
speed_m_s=1.42,
|
|
ignore_socket_speed_enabled=True,
|
|
look_angle_deg=6.5,
|
|
frame_radius=3,
|
|
voxel_m=0.035,
|
|
bp_ground_depth_m=1.1,
|
|
comp_range_power=0.5,
|
|
use_compensation=False,
|
|
normalize_each_frame=False,
|
|
)
|
|
profile = GuiProfileModel(gui=GuiStateModel(processing=GuiProcessingStateModel(sar3d=sar3d)))
|
|
|
|
decoded = GuiProfileModel.from_dict(profile.to_dict())
|
|
|
|
assert decoded.gui is not None
|
|
self.assertEqual(decoded.gui.processing.sar3d, sar3d)
|
|
|
|
def test_missing_gui_section_yields_none(self) -> None:
|
|
self.assertIsNone(GuiProfileModel.from_dict({}).gui)
|
|
|
|
def test_unsupported_version_is_rejected(self) -> None:
|
|
with self.assertRaisesRegex(ValueError, "version"):
|
|
GuiProfileModel.from_dict({"gui": {"version": 2}})
|
|
|
|
def test_invalid_combo_mode_is_rejected(self) -> None:
|
|
with self.assertRaisesRegex(ValueError, "combo_mode"):
|
|
GuiProfileModel.from_dict({"gui": {"switches": {"combo_mode": "bogus"}}})
|
|
|
|
def test_wrong_typed_field_is_rejected(self) -> None:
|
|
with self.assertRaises(ValueError): # combos_text must be a JSON string, not a number
|
|
GuiProfileModel.from_dict({"gui": {"switches": {"combos_text": 123}}})
|
|
|
|
def test_legacy_gpr_payload_migrates_selected_mode(self) -> None:
|
|
# An old payload that selects 'gpr' but carries a legacy root gpr.mode is migrated.
|
|
decoded = GuiProfileModel.from_dict({
|
|
"gui": {"processing": {"selected_mode": "gpr"}},
|
|
"gpr": {"relative_permittivity": 4.0, "mode": "point"},
|
|
})
|
|
assert decoded.gui is not None
|
|
self.assertEqual(decoded.gui.processing.selected_mode, "legacy_gpr")
|
|
|
|
def test_modern_gpr_selection_is_not_migrated(self) -> None:
|
|
decoded = GuiProfileModel.from_dict({"gui": {"processing": {"selected_mode": "gpr"}}})
|
|
assert decoded.gui is not None
|
|
self.assertEqual(decoded.gui.processing.selected_mode, "gpr")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|