Files
StarPilot/openpilot/starpilot/ui/tests/test_slc_offset_feature.py
T

524 lines
27 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""SLC native offset actions and both unit paths against real temporary Params."""
from pathlib import Path
from dataclasses import replace
from types import SimpleNamespace as NS
from typing import Any, cast
import tempfile
import unittest
from unittest.mock import patch
from openpilot.common.params import Params
from openpilot.starpilot.speed_limits import offset_document as od
from openpilot.starpilot.speed_limits.runtime_settings import read_params
from openpilot.starpilot.ui.feature_settings_owner import FeatureSettingsOwner
from openpilot.starpilot.ui.feature_settings_state import FeatureSettingsRequest, row_change
from openpilot.starpilot.ui.slc_offset_feature import DOCUMENT_KEY, SlcOffsetOwner, native_parked
class SlcOffsetFeatureTests(unittest.TestCase):
def setUp(self):
temporary = tempfile.TemporaryDirectory()
self.addCleanup(temporary.cleanup)
self.params = Params(temporary.name)
self.parked = True
self.cp: NS | None = NS(carFingerprint="TOYOTA_COROLLA_TSS2", openpilotLongitudinalControl=True, pcmCruise=False,
notCar=False, dashcamOnly=False, passive=False)
self.owner = FeatureSettingsOwner(self.params, lambda _group: self.parked,
vehicle_fingerprint=lambda: self.cp.carFingerprint if self.cp else None,
vehicle_params=lambda: self.cp)
self.units = SlcOffsetOwner(self.params, lambda: self.parked, lambda: self.cp)
def raw(self, key):
path = Path(self.params.get_param_path(key))
return path.read_bytes() if path.exists() else None
def row(self, key):
state = self.owner.snapshot("slc", parked=self.parked, system_long=True, lateral_context=True, metric=False)
return next(item for item in state.rows if item.key == key)
@staticmethod
def confirm(row):
return FeatureSettingsRequest(row.key, row.source, "confirm", confirmation=True,
related_source=row.related_source, vehicle_fingerprint=row.vehicle_fingerprint,
capability=row.capability, dependencies=row.dependencies)
def test_native_offroad_uses_retained_fresh_authority_adapter(self):
ui = NS()
with patch("openpilot.starpilot.ui.runtime_snapshot.RuntimeSnapshotAdapter") as factory:
factory.return_value.confirmed_offroad.side_effect = [True, False]
self.assertTrue(native_parked(ui))
self.assertFalse(native_parked(ui))
factory.assert_called_once_with(ui)
def test_pcm_cruise_longitudinal_can_adopt_and_enable_slc(self):
assert self.cp is not None
self.cp.carFingerprint = "TOYOTA_HIGHLANDER_TSS2"
self.cp.pcmCruise = True
state = self.owner.snapshot("slc", parked=True, system_long=False, lateral_context=True, metric=False)
adopt = next(row for row in state.rows if row.key == "slc_adopt")
self.assertTrue(adopt.available)
self.assertTrue(self.owner.apply(self.confirm(adopt)))
row = self.row("SpeedLimitController")
self.assertTrue(row.available)
request = row_change(row)
assert request is not None
self.assertTrue(self.owner.apply(request))
self.cp.openpilotLongitudinalControl = False
self.assertFalse(self.row("SpeedLimitController").available)
def test_valid_legacy_enable_preserves_sources_and_invalid_offsets_deny(self):
for legacy in (None, b"5"):
with self.subTest(legacy=legacy):
self.params.put_bool("SpeedLimitController", False, block=True)
if legacy is not None:
Path(self.params.get_param_path("Offset1")).write_bytes(legacy)
original = tuple(self.raw(key) for key in ("IsMetric", *(f"Offset{i}" for i in range(1, 8))))
row = self.row("SpeedLimitController")
self.assertTrue(row.available)
request = row_change(row)
assert request is not None
self.assertTrue(self.owner.apply(request))
self.assertTrue(read_params(self.params).enabled)
self.assertIsNone(self.raw(DOCUMENT_KEY))
self.assertEqual(tuple(self.raw(key) for key in ("IsMetric", *(f"Offset{i}" for i in range(1, 8)))), original)
for key, raw in (("Offset1", b"bad"), (DOCUMENT_KEY, b"{bad"),
(DOCUMENT_KEY, od.encode(od.NEEDS_REVIEW)), ("IsMetric", b"bad")):
with self.subTest(key=key, raw=raw):
for saved in ("Offset1", DOCUMENT_KEY, "IsMetric"):
path = Path(self.params.get_param_path(saved))
path.unlink(missing_ok=True)
self.params.put_bool("SpeedLimitController", False, block=True)
Path(self.params.get_param_path(key)).write_bytes(raw)
row = self.row("SpeedLimitController")
self.assertFalse(row.available)
self.assertIn("Repair invalid", row.reason)
self.assertFalse(self.owner.slc_offsets.ready_to_enable())
def test_unavailable_control_explains_vehicle_and_context_gate(self):
assert self.cp is not None
cp = self.cp
self.cp = None
self.assertIn("Select or connect", self.row("SpeedLimitController").reason)
self.cp = cp
cp.openpilotLongitudinalControl = False
self.assertIn("StarPilot speed control is unavailable", self.row("SpeedLimitController").reason)
cp.openpilotLongitudinalControl = True
self.parked = False
self.assertIn("settings context is unavailable", self.row("SpeedLimitController").reason)
def test_explicit_adopt_edit_and_global_units_preserve_exact_si(self):
self.params.put_bool("IsMetric", False, block=True)
self.params.put("Offset1", 5.0, block=True)
self.params.put("Offset7", -2.0, block=True)
old = (self.raw("Offset1"), self.raw("Offset7"))
before = read_params(self.params).offsets
self.assertTrue(self.row("SpeedLimitController").available)
adopt = self.row("slc_adopt")
self.assertFalse(self.owner.apply(FeatureSettingsRequest(adopt.key, adopt.source, "confirm",
vehicle_fingerprint=adopt.vehicle_fingerprint,
capability=adopt.capability, dependencies=adopt.dependencies)))
self.assertTrue(self.owner.apply(self.confirm(adopt)))
self.assertTrue(self.row("SpeedLimitController").available)
self.assertEqual(read_params(self.params).offsets, before)
self.assertEqual((self.raw("Offset1"), self.raw("Offset7")), old)
first = self.row("Offset1")
self.assertTrue(first.available)
self.assertEqual(row_change(first).direction, 1)
first_edit = row_change(first)
assert first_edit is not None
self.assertTrue(self.owner.apply(first_edit))
document = od.decode(self.raw(DOCUMENT_KEY))
self.assertAlmostEqual(document.offsets_mps[0], 6 * od.MPH_TO_MPS)
self.assertEqual(document.schedule().bands[-1].offset_mps, 0.0)
self.assertTrue(self.units.change_units(True, b"0"))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)), document)
metric_row = self.row("Offset1")
self.assertIn("km/h", metric_row.label)
metric_edit = row_change(metric_row)
assert metric_edit is not None
self.assertTrue(self.owner.apply(metric_edit))
adjusted = od.decode(self.raw(DOCUMENT_KEY))
self.assertAlmostEqual(adjusted.offsets_mps[0] - document.offsets_mps[0], od.KPH_TO_MPS)
self.assertTrue(self.units.change_units(False, b"1"))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)), adjusted)
self.assertEqual((self.raw("Offset1"), self.raw("Offset7")), old)
def test_range_labels_follow_saved_si_bounds_without_rewriting_them(self):
document = od.OffsetDocument(od.IMPERIAL_BOUNDS, (0.0,) * 7)
self.params.put(DOCUMENT_KEY, od.to_value(document), block=True)
original = self.raw(DOCUMENT_KEY)
rows = [self.row(f"Offset{index}").label for index in range(1, 8)]
self.assertEqual(rows, [f"{low}–<{high} mph offset" for low, high in
(("0", "25"), ("25", "34"), ("34", "44"), ("44", "54"),
("54", "64"), ("64", "74"), ("74", "99"))])
state = self.owner.snapshot("slc", parked=True, system_long=True, lateral_context=True, metric=False)
self.assertTrue(any(row.label == "99 mph and above" and row.value == "Zero offset" for row in state.rows))
self.assertEqual(self.raw(DOCUMENT_KEY), original)
self.assertTrue(self.units.change_units(True, None))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)), document)
self.assertEqual(self.row("Offset4").label, "71–<87 km/h offset")
def test_editor_rejects_offsets_that_cannot_produce_a_positive_target_in_the_band(self):
for metric, offset in ((False, -30), (True, -45)):
with self.subTest(metric=metric):
self.params.put_bool("IsMetric", metric, block=True)
document = od.OffsetDocument(od.IMPERIAL_BOUNDS, (0.0,) * 7)
self.params.put(DOCUMENT_KEY, od.to_value(document), block=True)
original = self.raw(DOCUMENT_KEY)
row = self.row("Offset1")
request = row_change(row)
assert request is not None
self.assertGreater(row.minimum, offset)
self.assertFalse(self.owner.apply(replace(request, value=str(offset), direction=0)))
self.assertEqual(self.raw(DOCUMENT_KEY), original)
# Useful reductions remain supported, including in the first band.
self.assertTrue(self.owner.apply(replace(request, value="-1", direction=0)))
def test_stepper_can_repair_an_unsafe_saved_offset_and_clamps_at_the_band_minimum(self):
document = od.OffsetDocument(od.IMPERIAL_BOUNDS, (-30 * od.MPH_TO_MPS, 0, 0, 0, 0, 0, 0))
self.params.put(DOCUMENT_KEY, od.to_value(document), block=True)
row = self.row('Offset1')
request = row_change(row)
assert request is not None
self.assertTrue(self.owner.apply(request))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)).offsets_mps[0], row.minimum * od.MPH_TO_MPS)
# Unit conversion can leave a fractional value less than one step above the minimum.
document = od.OffsetDocument(od.IMPERIAL_BOUNDS, ((row.minimum + .5) * od.MPH_TO_MPS, 0, 0, 0, 0, 0, 0))
self.params.put(DOCUMENT_KEY, od.to_value(document), block=True)
request = row_change(self.row('Offset1'), -1)
assert request is not None
self.assertTrue(self.owner.apply(request))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)).offsets_mps[0], row.minimum * od.MPH_TO_MPS)
def test_onroad_adopted_offsets_edit_without_repair_authority(self):
self.params.put_bool("IsMetric", False, block=True)
document = od.OffsetDocument(od.IMPERIAL_BOUNDS, (0.0,) * 7)
self.params.put(DOCUMENT_KEY, od.to_value(document), block=True)
owner = FeatureSettingsOwner(self.params, lambda group: group != "parked_preferences",
vehicle_fingerprint=lambda: self.cp.carFingerprint if self.cp else None,
vehicle_params=lambda: self.cp)
state = owner.snapshot("slc", parked=False, system_long=True, lateral_context=True, metric=False,
configure_while_driving=True)
offset = next(row for row in state.rows if row.key == "Offset2")
reset = next(row for row in state.rows if row.key == "slc_reset")
self.assertTrue(offset.available)
self.assertFalse(reset.available)
request = row_change(offset)
assert request is not None
self.assertTrue(owner.apply(request))
self.assertFalse(owner.apply(self.confirm(reset)))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)).offsets_mps[1], od.MPH_TO_MPS)
self.params.put_bool("IsMetric", True, block=True)
self.assertFalse(owner.apply(request))
def test_global_units_do_not_require_openpilot_longitudinal_or_a_fingerprint(self):
for cp in (None, NS(carFingerprint="STOCK_CRUISE", openpilotLongitudinalControl=False,
notCar=False, dashcamOnly=False, passive=False)):
with self.subTest(vehicle=cp):
self.cp = cp
self.params.remove(DOCUMENT_KEY)
self.params.put_bool("IsMetric", False, block=True)
self.params.put("Offset1", 5.0, block=True)
self.assertTrue(self.units.change_units(True, b"0"))
document = od.decode(self.raw(DOCUMENT_KEY))
self.assertEqual(document, od.adopt_legacy(False, (5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)))
self.assertEqual(self.raw("IsMetric"), b"1")
self.assertEqual(self.raw("Offset1"), b"5.0")
def test_off_and_display_only_corrupt_legacy_allow_unit_change(self):
Path(self.params.get_param_path("Offset1")).write_bytes(b"nan")
Path(self.params.get_param_path("IsMetric")).write_bytes(b"bad")
self.params.put_bool("ShowSpeedLimits", True, block=True)
self.cp = None # global display setting cannot require a supported car when SLC is off
self.parked = False
self.assertTrue(self.units.change_units(True, b"bad"))
self.assertIsNone(self.raw(DOCUMENT_KEY))
self.assertEqual(self.raw("Offset1"), b"nan")
self.assertEqual(self.raw("IsMetric"), b"1")
def test_valid_legacy_unit_migration_waits_for_park_even_with_slc_off(self):
self.params.put_bool("IsMetric", False, block=True)
self.params.put("Offset1", 5.0, block=True)
self.params.put_bool("SpeedLimitController", False, block=True)
self.parked = False
self.assertFalse(self.units.change_units(True, b"0"))
self.assertIsNone(self.raw(DOCUMENT_KEY))
self.assertEqual(self.raw("IsMetric"), b"0")
def test_saved_on_corrupt_legacy_writes_marker_before_unit(self):
self.params.put_bool("SpeedLimitController", True, block=True)
Path(self.params.get_param_path("Offset3")).write_bytes(b"bad")
self.assertTrue(self.units.change_units(True, None))
self.assertIs(od.decode(self.raw(DOCUMENT_KEY)), od.NEEDS_REVIEW)
self.assertEqual(self.raw("IsMetric"), b"1")
self.assertFalse(read_params(self.params).enabled)
reset = self.row("slc_reset")
self.assertTrue(self.owner.apply(self.confirm(reset)))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)).offsets_mps, (0.0,) * 7)
self.assertTrue(read_params(self.params).enabled)
self.assertEqual(self.raw("Offset3"), b"bad")
def test_marker_failure_veto_and_stale_source_recheck(self):
self.params.put_bool("SpeedLimitController", True, block=True)
Path(self.params.get_param_path("Offset1")).write_bytes(b"bad")
original = self.params.put
def fails_marker(key, value, block=False):
if key == DOCUMENT_KEY:
raise OSError("write failed")
return original(key, value, block=block)
with patch.object(self.params, "put", side_effect=fails_marker):
self.assertFalse(self.units.change_units(True, None))
self.assertIsNone(self.raw("IsMetric"))
self.assertIsNone(self.raw(DOCUMENT_KEY))
Path(self.params.get_param_path("Offset1")).write_bytes(b"1")
adopt = self.row("slc_adopt")
Path(self.params.get_param_path("Offset1")).write_bytes(b"2")
self.assertFalse(self.owner.apply(self.confirm(adopt)))
self.assertIsNone(self.raw(DOCUMENT_KEY))
def test_absent_corrupt_legacy_reset_recovers_without_changing_saved_switch(self):
for saved_on in (False, True):
with self.subTest(saved_on=saved_on):
if saved_on:
self.params.put_bool("SpeedLimitController", True, block=True)
Path(self.params.get_param_path("Offset1")).write_bytes(b"bad")
self.assertFalse(read_params(self.params).enabled)
reset = self.row("slc_reset")
self.assertTrue(reset.available)
self.assertIsNone(reset.source)
self.assertFalse(self.owner.apply(FeatureSettingsRequest("slc_reset", None, "confirm",
confirmation=False, related_source=reset.related_source,
capability=reset.capability, dependencies=reset.dependencies)))
self.assertTrue(self.owner.apply(self.confirm(reset)))
document = od.decode(self.raw(DOCUMENT_KEY))
self.assertEqual(document, od.adopt_legacy(False, (0.0,) * 7))
self.assertEqual(self.raw("Offset1"), b"bad")
self.assertEqual(self.raw("SpeedLimitController"), b"1" if saved_on else None)
self.assertEqual(read_params(self.params).enabled, saved_on)
Path(self.params.get_param_path(DOCUMENT_KEY)).unlink()
def test_absent_corrupt_reset_rechecks_legacy_and_waits_for_valid_units(self):
legacy = Path(self.params.get_param_path("Offset4"))
legacy.write_bytes(b"bad")
reset = self.row("slc_reset")
legacy.write_bytes(b"different bad")
self.assertFalse(self.owner.apply(self.confirm(reset)))
self.assertIsNone(self.raw(DOCUMENT_KEY))
Path(self.params.get_param_path("IsMetric")).write_bytes(b"invalid")
self.assertFalse(self.row("slc_reset").available)
self.assertFalse(self.owner.apply(self.confirm(self.row("slc_reset"))))
self.assertIsNone(self.raw(DOCUMENT_KEY))
self.assertTrue(self.units.change_units(True, b"invalid"))
self.assertTrue(self.row("slc_reset").available)
self.assertTrue(self.owner.apply(self.confirm(self.row("slc_reset"))))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)).bounds_mps, od.METRIC_BOUNDS)
def test_saved_off_corrupt_unit_change_rechecks_legacy_before_unit_write(self):
legacy = Path(self.params.get_param_path("Offset1"))
legacy.write_bytes(b"bad")
original = self.units._same_unit_source
def mutate_at_final_guard(snap, capability):
legacy.write_bytes(b"changed")
return original(snap, capability)
with patch.object(self.units, "_same_unit_source", side_effect=mutate_at_final_guard):
self.assertFalse(self.units.change_units(True, None))
self.assertIsNone(self.raw("IsMetric"))
self.assertIsNone(self.raw(DOCUMENT_KEY))
def test_stale_unit_capability_and_parked_edit_write_nothing(self):
self.assertTrue(self.owner.apply(self.confirm(self.row("slc_adopt"))))
edit = row_change(self.row("Offset2"))
assert edit is not None
self.params.put_bool("IsMetric", True, block=True)
self.assertFalse(self.owner.apply(edit))
self.params.put_bool("IsMetric", False, block=True)
assert self.cp is not None
self.cp.carFingerprint = "TOYOTA_CAMRY"
self.assertFalse(self.owner.apply(edit))
self.cp.carFingerprint = "TOYOTA_COROLLA_TSS2"
self.parked = False
self.assertFalse(self.owner.apply(edit))
def test_valid_document_ignores_legacy_bytes_and_reset_keeps_bounds(self):
self.assertTrue(self.owner.apply(self.confirm(self.row("slc_adopt"))))
original = od.decode(self.raw(DOCUMENT_KEY))
Path(self.params.get_param_path("Offset1")).write_bytes(b"bad")
self.assertTrue(self.units.change_units(True, None))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)), original)
reset = self.row("slc_reset")
self.assertTrue(self.owner.apply(self.confirm(reset)))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)).bounds_mps, original.bounds_mps)
def test_unit_write_failure_after_adoption_keeps_original_unit_and_si_schedule(self):
self.params.put_bool("SpeedLimitController", True, block=True)
self.params.put("Offset2", 3.0, block=True)
expected = od.adopt_legacy(False, (0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0))
with patch.object(self.params, "put_bool", side_effect=OSError("unit write failed")):
self.assertFalse(self.units.change_units(True, None))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)), expected)
self.assertIsNone(self.raw("IsMetric"))
self.assertEqual(self.raw("Offset2"), b"3.0")
def test_corrupt_document_and_units_require_explicit_repairs(self):
self.params.put_bool("SpeedLimitController", True, block=True)
Path(self.params.get_param_path(DOCUMENT_KEY)).write_bytes(b"{broken")
Path(self.params.get_param_path("IsMetric")).write_bytes(b"broken")
self.assertTrue(self.units.change_units(True, b"broken"))
self.assertEqual(self.raw(DOCUMENT_KEY), b"{broken")
self.assertFalse(read_params(self.params).enabled)
reset = self.row("slc_reset")
self.assertTrue(self.owner.apply(self.confirm(reset)))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)).offsets_mps, (0.0,) * 7)
self.assertTrue(read_params(self.params).enabled)
def test_all_seven_edits_and_stale_unit_request(self):
self.assertTrue(self.owner.apply(self.confirm(self.row("slc_adopt"))))
for index in range(1, 8):
row = self.row(f"Offset{index}")
edit = row_change(row, -1)
assert edit is not None
self.assertTrue(self.owner.apply(edit))
document = od.decode(self.raw(DOCUMENT_KEY))
self.assertEqual(document.offsets_mps, (-od.MPH_TO_MPS,) * 7)
self.assertEqual(document.schedule().bands[-1].offset_mps, 0.0)
self.params.put_bool("IsMetric", True, block=True)
self.assertFalse(self.units.change_units(False, None))
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)), document)
def test_large_and_compact_metric_callbacks_use_same_owner_and_restore_veto(self):
from openpilot.selfdrive.ui.layouts.settings.toggles import TogglesLayout
from openpilot.selfdrive.ui.mici.layouts.settings import toggles as compact
self.cp = None
self.params.put("Offset1", 5.0, block=True)
large = TogglesLayout.__new__(TogglesLayout)
large._params = self.params
large._slc_offsets = self.units
large._metric_source = None
large._toggles = {"IsMetric": NS(action_item=NS(set_state=lambda value: setattr(large, "shown", value)))}
large._toggle_defs = {"IsMetric": (lambda: "metric", "", "", False)}
self.enterContext(patch.object(large, "_update_toggles", return_value=None))
self.assertTrue(large._toggle_callback(True, "IsMetric"))
self.assertTrue(large.shown)
self.assertEqual(self.raw("IsMetric"), b"1")
adopted = od.decode(self.raw(DOCUMENT_KEY))
compact_layout = compact.TogglesLayoutMici.__new__(compact.TogglesLayoutMici)
compact_layout._slc_offsets = self.units
self.enterContext(patch.object(compact_layout, "_update_toggles", return_value=None))
compact_layout._metric_source = b"0" # stale displayed source
cast(Any, compact_layout)._metric_toggle = NS(set_checked=lambda value: setattr(compact_layout, "shown", value))
with patch.object(compact, "ui_state", NS(params=self.params)):
compact_layout._on_metric(False)
self.assertTrue(compact_layout.shown)
self.assertEqual(self.raw("IsMetric"), b"1")
compact_layout._metric_source = b"1"
compact_layout._on_metric(False)
self.assertFalse(compact_layout.shown)
self.assertEqual(self.raw("IsMetric"), b"0")
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)), adopted)
def test_both_native_adapters_confirm_adoption_with_displayed_unit_source(self):
from openpilot.starpilot.ui import feature_settings_compact as compact
from openpilot.starpilot.ui.runtime_app import StarShellSession
from openpilot.system.ui.widgets import DialogResult
class Dialog:
def __init__(self, _question, *_args, callback=None, **_kwargs):
self.confirmed = callback or _args[-1]
self.params.put_bool("IsMetric", True, block=True)
row = self.row("slc_adopt")
large = StarShellSession.__new__(StarShellSession)
cast(Any, large).feature_request = self.owner.apply
pushed = []
with patch("openpilot.system.ui.widgets.confirm_dialog.ConfirmDialog", Dialog), \
patch("openpilot.starpilot.ui.runtime_app.gui_app.push_widget", pushed.append):
large._confirm_feature_reset(row)
pushed[-1].confirmed(DialogResult.CONFIRM)
self.assertIsInstance(od.decode(self.raw(DOCUMENT_KEY)), od.OffsetDocument)
Path(self.params.get_param_path(DOCUMENT_KEY)).unlink()
row = self.row("slc_adopt")
compact_adapter = compact.FeatureSettingsCompact(cast(Any, NS(feature_request=self.owner.apply)))
pushed = []
with patch.object(compact, "BigConfirmationDialog", Dialog), \
patch.object(compact.gui_app, "push_widget", pushed.append), \
patch.object(compact.gui_app, "texture", lambda *_args: None):
compact_adapter._confirm_reset(row, lambda: None)
pushed[-1].confirmed()
self.assertIsInstance(od.decode(self.raw(DOCUMENT_KEY)), od.OffsetDocument)
def test_both_native_reset_confirmations_recover_corrupt_legacy_and_recheck_source(self):
from openpilot.starpilot.ui import feature_settings_compact as compact
from openpilot.starpilot.ui.runtime_app import StarShellSession
from openpilot.system.ui.widgets import DialogResult
class Dialog:
def __init__(self, _question, *_args, callback=None, **_kwargs):
self.confirmed = callback or _args[-1]
legacy = Path(self.params.get_param_path("Offset1"))
legacy.write_bytes(b"bad")
large = StarShellSession.__new__(StarShellSession)
cast(Any, large).feature_request = self.owner.apply
pushed = []
with patch("openpilot.system.ui.widgets.confirm_dialog.ConfirmDialog", Dialog), \
patch("openpilot.starpilot.ui.runtime_app.gui_app.push_widget", pushed.append):
large._confirm_feature_reset(self.row("slc_reset"))
legacy.write_bytes(b"changed")
pushed[-1].confirmed(DialogResult.CONFIRM)
self.assertIsNone(self.raw(DOCUMENT_KEY))
large._confirm_feature_reset(self.row("slc_reset"))
pushed[-1].confirmed(DialogResult.CONFIRM)
self.assertFalse(read_params(self.params).enabled)
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)).offsets_mps, (0.0,) * 7)
Path(self.params.get_param_path(DOCUMENT_KEY)).unlink()
self.params.put_bool("SpeedLimitController", True, block=True)
compact_adapter = compact.FeatureSettingsCompact(cast(Any, NS(feature_request=self.owner.apply)))
pushed = []
with patch.object(compact, "BigConfirmationDialog", Dialog), \
patch.object(compact.gui_app, "push_widget", pushed.append), \
patch.object(compact.gui_app, "texture", lambda *_args: None):
compact_adapter._confirm_reset(self.row("slc_reset"), lambda: None)
pushed[-1].confirmed()
self.assertTrue(read_params(self.params).enabled)
self.assertEqual(self.raw("SpeedLimitController"), b"1")
self.assertEqual(od.decode(self.raw(DOCUMENT_KEY)).offsets_mps, (0.0,) * 7)
def test_both_native_reset_dialogs_describe_saved_or_default_ranges(self):
from openpilot.starpilot.ui import feature_settings_compact as compact
from openpilot.starpilot.ui.runtime_app import StarShellSession
class Dialog:
def __init__(self, question, *_args, **_kwargs):
self.question = question
large = StarShellSession.__new__(StarShellSession)
compact_adapter = compact.FeatureSettingsCompact(cast(Any, NS(feature_request=self.owner.apply)))
pushed = []
with patch("openpilot.system.ui.widgets.confirm_dialog.ConfirmDialog", Dialog), \
patch.object(compact, "BigConfirmationDialog", Dialog), \
patch("openpilot.starpilot.ui.runtime_app.gui_app.push_widget", pushed.append), \
patch.object(compact.gui_app, "texture", lambda *_args: None):
Path(self.params.get_param_path("Offset1")).write_bytes(b"bad")
recovery = self.row("slc_reset")
self.assertEqual(recovery.value, "Use default mph speed ranges")
large._confirm_feature_reset(recovery)
compact_adapter._confirm_reset(recovery, lambda: None)
self.assertTrue(all("default mph speed ranges" in dialog.question for dialog in pushed[-2:]))
self.assertTrue(self.owner.apply(self.confirm(recovery)))
saved = self.row("slc_reset")
self.assertEqual(saved.value, "Keep saved speed ranges")
large._confirm_feature_reset(saved)
compact_adapter._confirm_reset(saved, lambda: None)
self.assertTrue(all("Keep saved speed ranges" in dialog.question for dialog in pushed[-2:]))