Scope washer/dryer cycle translations to the device's own course table
Course codes on the shared /course/vs/0 contract aren't guaranteed consistent across board generations: washer/combo devices report course table Table_02, dryer devices Table_03 (x.com.samsung.da.st.courseTable, previously fully ignored), and every code in washer_cycle/dryer_cycle was confirmed exclusively against those. FlexWash's older DA_WM_A51 board reports Table_00 instead -- applying the same translations there risked showing a wrong name for any code that happens to numerically collide between tables, not just an untranslated one. SelectDesc.translation_key can now be a callable (resources -> key or None), mirroring the existing pattern for `options`. laundry.cycle_select gains optional table_href/validated_table params: when given, the renamed washer_cycle_table_02/dryer_cycle_table_03 keys only apply when the device's own course table matches exactly -- a different table, or no table id at all, gets no translation_key (raw code display) rather than a guess. dishwasher's call site is unchanged (static key, unconditional): no equivalent table-id resource exists in any dump seen, and no evidence its course codes vary by table the way washer/dryer's do. entity.py and select.py resolve a callable translation_key once (via coordinator.last_resources) and reuse that resolved value everywhere _display() needs it, rather than re-checking the raw descriptor field.
This commit is contained in:
12 files changed
+124
-27
No files matched your search
@@ -59,11 +59,17 @@ def test_power_watts_gated_for_dead_sentinel():
|
||||
|
||||
|
||||
def test_course_bound_to_shared_course_vs_0():
|
||||
"""Dryer course uses the shared /course/vs/0 cycle select with dryer_cycle
|
||||
translations, consistent with washer/dishwasher."""
|
||||
"""Dryer course uses the shared /course/vs/0 cycle select with
|
||||
dryer_cycle_table_03 translations, consistent with washer/dishwasher --
|
||||
gated on the device's own course table matching Table_03, the only one
|
||||
dryer_cycle_table_03's names were confirmed against (see
|
||||
laundry.cycle_select)."""
|
||||
assert dryer.DRYER_COURSE.href == '/course/vs/0'
|
||||
desc = next(e for e in dryer.DRYER_COURSE.entities if e.key == 'cycle')
|
||||
assert desc.translation_key == 'dryer_cycle'
|
||||
assert callable(desc.translation_key)
|
||||
validated = {'/st/dryercourse/vs/0': {'x.com.samsung.da.st.courseTable': 'Table_03'}}
|
||||
assert desc.translation_key(validated) == 'dryer_cycle_table_03'
|
||||
assert desc.translation_key({}) is None
|
||||
assert desc.options is laundry.cycle_options
|
||||
rep = {'x.com.samsung.da.options': ['Course_16', 'GMT_02']}
|
||||
assert desc.rep_fn(rep) == '16'
|
||||
|
||||
@@ -145,6 +145,46 @@ class TestCycleSelect:
|
||||
assert desc.write_fn('1D', {}) is None
|
||||
|
||||
|
||||
class TestCycleSelectTableGating:
|
||||
"""translation_key becomes a resolver, not a plain string, once
|
||||
table_href/validated_table are given -- washer/dryer's real call sites
|
||||
(issue: course codes aren't guaranteed consistent across board
|
||||
generations sharing the same /course/vs/0 contract; FlexWash's older
|
||||
board reports a different course table than every device the shipped
|
||||
translations were confirmed against)."""
|
||||
|
||||
def _desc(self):
|
||||
return laundry.cycle_select(
|
||||
translation_key='washer_cycle_table_02', icon='x',
|
||||
table_href='/st/washercourse/vs/0', validated_table='Table_02',
|
||||
)
|
||||
|
||||
def test_static_string_when_no_table_params_given(self):
|
||||
"""dishwasher's call site -- no equivalent table-id resource in any
|
||||
dump seen, no evidence of the same cross-board risk -- keeps the
|
||||
plain static key unconditionally."""
|
||||
desc = laundry.cycle_select(translation_key='dishwasher_cycle', icon='x')
|
||||
assert desc.translation_key == 'dishwasher_cycle'
|
||||
|
||||
def test_resolves_to_the_key_when_table_matches(self):
|
||||
desc = self._desc()
|
||||
resources = {'/st/washercourse/vs/0': {'x.com.samsung.da.st.courseTable': 'Table_02'}}
|
||||
assert callable(desc.translation_key)
|
||||
assert desc.translation_key(resources) == 'washer_cycle_table_02'
|
||||
|
||||
def test_resolves_to_none_for_a_different_table(self):
|
||||
desc = self._desc()
|
||||
resources = {'/st/washercourse/vs/0': {'x.com.samsung.da.st.courseTable': 'Table_00'}}
|
||||
assert desc.translation_key(resources) is None
|
||||
|
||||
def test_resolves_to_none_when_table_id_is_unknown(self):
|
||||
"""Absence isn't evidence of a match -- no href, or an empty rep,
|
||||
gets no translation_key either, not the family default."""
|
||||
desc = self._desc()
|
||||
assert desc.translation_key({}) is None
|
||||
assert desc.translation_key({'/st/washercourse/vs/0': {}}) is None
|
||||
|
||||
|
||||
class TestBuzzerSound:
|
||||
def test_href(self):
|
||||
assert laundry.BUZZER_SOUND.href == '/buzzersound/vs/0'
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
"""Tests for select-option display casing (custom_components/localthings/select.py)."""
|
||||
from custom_components.localthings.registry.entities import SelectDesc
|
||||
from custom_components.localthings.select import _display
|
||||
|
||||
_UNTRANSLATED = SelectDesc(key='x', options=())
|
||||
_TRANSLATED = SelectDesc(key='y', options=(), translation_key='door_alert')
|
||||
_UNTRANSLATED = None
|
||||
_TRANSLATED = 'door_alert'
|
||||
|
||||
|
||||
def test_display_titlecases_a_fully_lowercase_device_native_token():
|
||||
|
||||
@@ -61,8 +61,16 @@ class TestWasherCourse:
|
||||
assert washer.WASHER_COURSE.href == '/course/vs/0'
|
||||
|
||||
def test_translation_key(self):
|
||||
"""Table-gated (issue: FlexWash's older board reports a different
|
||||
course table, Table_00, than every device washer_cycle_table_02's
|
||||
names were confirmed against, Table_02) -- see laundry.cycle_select."""
|
||||
desc = next(e for e in washer.WASHER_COURSE.entities if e.key == 'cycle')
|
||||
assert desc.translation_key == 'washer_cycle'
|
||||
assert callable(desc.translation_key)
|
||||
validated = {'/st/washercourse/vs/0': {'x.com.samsung.da.st.courseTable': 'Table_02'}}
|
||||
assert desc.translation_key(validated) == 'washer_cycle_table_02'
|
||||
other_table = {'/st/washercourse/vs/0': {'x.com.samsung.da.st.courseTable': 'Table_00'}}
|
||||
assert desc.translation_key(other_table) is None
|
||||
assert desc.translation_key({}) is None
|
||||
|
||||
def test_reads_raw_course_code_from_options_array(self):
|
||||
"""rep_fn returns the raw device code; display names come from
|
||||
|
||||
Reference in new issue
Block a user