Continues narrowing SamsungEntityDescription accesses to the correct subclass and asserting Optional write_fn/match_fn/exists_fn fields are set before calling them, per the pattern established in the previous commit.
88 lines
3.0 KiB
Python
88 lines
3.0 KiB
Python
"""Tests for the NE63A6511SS/AA range (issue #138) -- same no-/information/vs/0,
|
|
no-burner-status shape as issue #74's NE63B8411SS, confirming the existing
|
|
range_no_info detection path still resolves this model with zero unbound
|
|
hrefs, plus oven.OVEN_MODE reading this dump's ConvectionRoast/KeepWarm/
|
|
BreadProof/AirFryer/Dehydrate/SelfClean/SteamClean modes live from its own
|
|
/mode/vs/0 supportedModes rather than needing them hardcoded."""
|
|
|
|
from typing import cast
|
|
|
|
from custom_components.localthings.registry.adapter import flatten
|
|
from custom_components.localthings.registry.by_type import for_device_by_resources
|
|
from custom_components.localthings.registry.capabilities import oven
|
|
from custom_components.localthings.registry.discovery import discover
|
|
from custom_components.localthings.registry.entities import SelectDesc
|
|
from tests.conftest import _load_device
|
|
|
|
|
|
def _range():
|
|
resources = _load_device("range_ne63a6511")
|
|
reg = for_device_by_resources(resources)
|
|
return reg, resources
|
|
|
|
|
|
def _state():
|
|
reg, resources = _range()
|
|
bound = discover(resources, reg.capabilities, reg.pattern_capabilities)
|
|
return flatten(bound, resources)
|
|
|
|
|
|
def test_resolves_to_range_registry():
|
|
reg, _ = _range()
|
|
assert reg is not None and reg.name == "range"
|
|
|
|
|
|
def test_no_unbound_hrefs():
|
|
reg, resources = _range()
|
|
unbound = []
|
|
discover(resources, reg.capabilities, reg.pattern_capabilities, log=unbound.append)
|
|
assert unbound == []
|
|
|
|
|
|
def test_expected_entities_present():
|
|
state = _state()
|
|
for key in (
|
|
"power_switch",
|
|
"oven_setpoint",
|
|
"current_temp_c",
|
|
"oven_mode",
|
|
"machine_state",
|
|
"door_open",
|
|
"cloud_connected",
|
|
"child_lock",
|
|
"cooktop_running_state",
|
|
"warming_center_state",
|
|
):
|
|
assert key in state, key
|
|
|
|
|
|
def test_oven_mode_accepts_this_devices_supported_modes():
|
|
"""This dump's /mode/vs/0 supportedModes reports ConvectionRoast,
|
|
KeepWarm, BreadProof, AirFryer, Dehydrate, SelfClean, and SteamClean --
|
|
none of which were in the static oven._OVEN_MODES fallback, so a
|
|
hardcoded write-validation list would've silently rejected them even
|
|
though the device itself advertises them. write_fn reads supportedModes
|
|
off the live rep (the same one it's called with in production -- see
|
|
coordinator.py's async_send_command), so this passes without needing
|
|
those modes added to any Python list."""
|
|
_, resources = _range()
|
|
live_rep = resources["/mode/vs/0"]
|
|
desc = cast(SelectDesc, oven.OVEN_MODE.entities[0])
|
|
assert desc.options is not None
|
|
assert desc.write_fn is not None
|
|
assert desc.options(resources) == live_rep["x.com.samsung.da.supportedModes"]
|
|
for mode in (
|
|
"ConvectionRoast",
|
|
"KeepWarm",
|
|
"BreadProof",
|
|
"AirFryer",
|
|
"Dehydrate",
|
|
"SelfClean",
|
|
"SteamClean",
|
|
):
|
|
result = desc.write_fn(mode, live_rep)
|
|
assert result is not None
|
|
path, body = result
|
|
assert path == ["mode", "vs", "0"]
|
|
assert body["x.com.samsung.da.modes"] == [mode]
|