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

144 lines
6.8 KiB
Python

"""Attached confirmation: live decisions, physical targets and safe saved layouts."""
from copy import deepcopy
from dataclasses import replace
import pytest
from openpilot.starpilot.ui.large_speed_geometry import CONFIRMATION_SCALE
from openpilot.starpilot.ui.onroad_customization import default_document, validate_document
from openpilot.starpilot.ui.onroad_state import AlertSize, OnroadAlert, OnroadInput, manual_slc_confirmation, slc_controls, speed_limit_bounds
from openpilot.starpilot.ui.presentation import Profile
from openpilot.starpilot.ui.tests.test_slc_ui_actions import state, tap_sign, tap_control
from openpilot.starpilot.ui.onroad_state import SlcActionKind
@pytest.mark.parametrize('profile', list(Profile))
def test_closed_and_open_card_share_anchor_and_physically_scaled_targets(profile):
current, emitted = state(), []
touch = OnroadInput(emitted.append, profile)
before = speed_limit_bounds(profile, current)
tap_sign(touch, current)
assert not emitted
opened = touch.present(current)
after = speed_limit_bounds(profile, opened)
assert before is not None and after is not None
assert before[1::2] == after[1::2]
assert before[0 if profile == Profile.LARGE else 2] == after[0 if profile == Profile.LARGE else 2]
first, last = slc_controls(profile, opened)
scale = CONFIRMATION_SCALE[profile]
assert (first.bounds[2] - first.bounds[0]) / scale == pytest.approx(144)
assert (first.bounds[3] - first.bounds[1]) / scale == pytest.approx(112)
assert (last.bounds[0] - first.bounds[2]) / scale == pytest.approx(8)
assert (first.bounds[0] - after[0]) / scale == pytest.approx(8)
assert (after[2] - last.bounds[2]) / scale == pytest.approx(8)
torque = current.customization['layouts'][str(profile)]['torque_bar']
assert after[3] < torque['y']
if profile == Profile.COMPACT:
assert after == (148., 8, 460., 160.)
assert after[0] > 146
@pytest.mark.parametrize('profile', list(Profile))
@pytest.mark.parametrize('action', [SlcActionKind.ACCEPT, SlcActionKind.REJECT])
def test_touch_choice_remains_available_without_wheel_confirmation(profile, action):
current = replace(state(), longitudinal_active=False, slc_system_long_available=False,
slc_wheel_confirmation_available=False)
emitted = []
touch = OnroadInput(emitted.append, profile)
tap_sign(touch, current)
tap_control(touch, current, action)
assert [request.kind for request in emitted] == [action]
@pytest.mark.parametrize('profile', list(Profile))
@pytest.mark.parametrize('change', ['actions_hidden', 'sign_hidden', 'automatic', 'alert', 'toyota_guidance', 'stale'])
def test_unavailable_confirmation_has_no_empty_chooser_or_action(profile, change):
from openpilot.starpilot.ui.onroad_state import ObservationKind
current, emitted = state(), []
touch = OnroadInput(emitted.append, profile)
tap_sign(touch, current)
if change in ('actions_hidden', 'sign_hidden'):
doc = deepcopy(current.customization)
key = 'speed_limit_actions' if change == 'actions_hidden' else 'cruise_limits' if profile == Profile.LARGE else 'speed_limit'
doc['layouts'][str(profile)][key]['enabled'] = False
current = replace(current, customization=doc)
elif change == 'automatic':
current = replace(current, speed_limit=replace(current.speed_limit, automatic_adoption_pending=True))
elif change == 'alert':
current = replace(current, alert=OnroadAlert(size=AlertSize.SMALL))
elif change == 'toyota_guidance':
current = replace(current, toyota_cruise_status='raise_dash', toyota_cruise_target_kph=100.)
else:
current = replace(current, speed_limit=replace(current.speed_limit, kind=ObservationKind.STALE, speed_limit_mps=None))
assert not manual_slc_confirmation(profile, current)
assert not touch.present(current).slc_prompt_open
assert not slc_controls(profile, current)
assert not emitted
@pytest.mark.parametrize('profile', list(Profile))
def test_new_layouts_reject_torque_overlap_and_legacy_migration_is_targeted(profile):
doc = default_document()
owner = 'cruise_limits' if profile == Profile.LARGE else 'speed_limit'
doc['layouts'][str(profile)][owner]['y'] = 700 if profile == Profile.LARGE else 50
with pytest.raises(ValueError, match='confirmation'):
validate_document(doc)
doc['version'] = 11
doc['layouts']['large']['current_speed']['x'] = 800
doc['palette']['text'] = '#ABCDEFEE'
original = deepcopy(doc)
migrated = validate_document(doc)
assert doc == original
assert migrated['version'] == 12
assert migrated['palette'] == doc['palette']
assert migrated['layouts']['large']['current_speed'] == doc['layouts']['large']['current_speed']
assert migrated['layouts'][str(profile)][owner]['y'] == default_document()['layouts'][str(profile)][owner]['y']
assert validate_document(migrated) == migrated
def test_legacy_sources_keep_guidance_below_the_row_and_above_the_gauge():
doc = default_document()
doc.update(version=11, speedSources=True, speedSourcesCard=True)
doc['layouts']['large']['speed_limit_actions']['y'] = 351
migrated = validate_document(doc)
assert migrated['layouts']['large']['speed_limit_actions']['y'] == 367
assert validate_document(migrated) == migrated
def test_large_confirmation_clears_the_taller_torque_arc_when_sidebar_is_hidden():
doc = default_document()
doc['layouts']['large']['cruise_limits']['y'] = 550
with pytest.raises(ValueError, match='confirmation'):
validate_document(doc)
doc['layouts']['large']['speed_limit_actions']['enabled'] = False
assert validate_document(doc) == doc
def test_large_sources_cannot_be_clipped_below_a_custom_confirmation():
doc = default_document()
doc['speedSources'] = True
doc['layouts']['large']['cruise_limits'].update(x=1520, y=790)
doc['layouts']['large']['speed_limit_actions'].update(x=250, y=400)
with pytest.raises(ValueError, match='confirmation'):
validate_document(doc)
doc['version'] = 11
migrated = validate_document(doc)
assert validate_document(migrated) == migrated
assert migrated['layouts']['large']['speed_limit_actions'] == doc['layouts']['large']['speed_limit_actions']
@pytest.mark.parametrize('reverse', [False, True])
def test_compact_driver_camera_has_no_hidden_confirmation_targets(reverse):
from openpilot.starpilot.ui.appearance_preferences import CameraViewChoice
current = state()
current = replace(current, reverse_driver_camera=reverse,
appearance=replace(current.appearance, camera_view=CameraViewChoice.AUTO if reverse else CameraViewChoice.DRIVER))
assert not manual_slc_confirmation(Profile.COMPACT, current)
assert not slc_controls(Profile.COMPACT, replace(current, slc_prompt_open=True))
def unexpected_action(_request):
raise AssertionError('Hidden confirmation emitted an action')
touch = OnroadInput(unexpected_action, Profile.COMPACT)
touch.press(250, 90, current)
assert not touch.claimed