Name the two remaining unidentified course codes (0x21 Hygiene Care, 0x4C Air Refresh) by matching the SmartThings app's course-list order against editCourseList in the reporter's dump. Also close three entity gaps the screenshots surfaced that v0.6.0 missed: dry level was read-only despite the app exposing a writable Level 1/2/3 picker; the app's "AI pattern" toggle (AiOption_On/Off) and "Auto cycle link" toggle (/cycleinterface/vs/0, previously globally ignored as always-empty on washer dumps) were both unbound. Scope that ignore to washer.py now that the dryer binds it for real.
86 lines
3.6 KiB
Python
86 lines
3.6 KiB
Python
"""Tests that known-noise hrefs don't show up as coverage gaps.
|
|
|
|
Each device-type registry folds in registry.capabilities.ignored.IGNORED so
|
|
that Bixby/voice/network/OTA housekeeping resources aren't reported as
|
|
unbound. This guards two things at once: that the ignored hrefs are
|
|
actually suppressed, and (via a plain import) that no ignored href
|
|
collides with a real capability declared elsewhere for the same family.
|
|
"""
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from custom_components.localthings.registry.batch import parse_device0_batch
|
|
from custom_components.localthings.registry.by_type import dishwasher, refrigerator
|
|
from custom_components.localthings.registry.capabilities.ignored import IGNORED
|
|
|
|
FIXTURES = Path(__file__).resolve().parent / 'fixtures'
|
|
|
|
_IGNORED_HREFS = {cap.href for cap in IGNORED}
|
|
|
|
|
|
def _load(name: str) -> dict:
|
|
data = json.loads((FIXTURES / name).read_text())
|
|
return parse_device0_batch(data['device0'])
|
|
|
|
|
|
def _unbound_hrefs(resources, registry) -> list[str]:
|
|
unbound = []
|
|
from custom_components.localthings.registry.discovery import discover
|
|
discover(resources, registry.capabilities, registry.pattern_capabilities,
|
|
log=unbound.append)
|
|
return unbound
|
|
|
|
|
|
def test_ignored_hrefs_absent_from_dishwasher_gaps():
|
|
resources = _load('dishwasher_device.json')
|
|
unbound = _unbound_hrefs(resources, dishwasher.REGISTRY)
|
|
present_ignored = _IGNORED_HREFS & set(unbound)
|
|
assert not present_ignored, f"ignored hrefs leaked into gap report: {present_ignored}"
|
|
|
|
|
|
def test_ignored_hrefs_absent_from_refrigerator_gaps():
|
|
resources = _load('refrigerator_device.json')
|
|
unbound = _unbound_hrefs(resources, refrigerator.REGISTRY)
|
|
present_ignored = _IGNORED_HREFS & set(unbound)
|
|
assert not present_ignored, f"ignored hrefs leaked into gap report: {present_ignored}"
|
|
|
|
|
|
def test_dishwasher_fixture_has_no_remaining_gaps():
|
|
"""Sanity check that the gap mechanism isn't silencing everything.
|
|
|
|
Every href in the dishwasher fixture is now either mapped to a
|
|
capability or listed in capabilities.ignored — if this starts failing
|
|
because a genuinely new gap appeared, that's the interesting case to
|
|
look at (add the href to ignored.py or map it, don't just delete this
|
|
assertion).
|
|
"""
|
|
resources = _load('dishwasher_device.json')
|
|
unbound = set(_unbound_hrefs(resources, dishwasher.REGISTRY))
|
|
assert unbound == set()
|
|
|
|
|
|
class TestWasherIgnoredHrefs:
|
|
def test_washer_hrefs_are_ignored(self):
|
|
from custom_components.localthings.registry.capabilities.ignored import IGNORED
|
|
ignored_hrefs = {cap.href for cap in IGNORED}
|
|
for href in (
|
|
'/st/washercourse/vs/0',
|
|
'/wm/welcomemsg/vs/0',
|
|
'/wm/personalcourse/vs/0',
|
|
'/energy/consumption/0',
|
|
'/drlc/0',
|
|
'/operational/state/0',
|
|
):
|
|
assert href in ignored_hrefs, f"{href} should be in ignored.IGNORED"
|
|
|
|
def test_cycleinterface_is_scoped_to_washer_registry(self):
|
|
"""/cycleinterface/vs/0 is empty on every washer dump but real on the
|
|
dryer (issue #14's AUTO_CYCLE_LINK), so it's a washer-scoped ignore
|
|
(washer.CYCLE_INTERFACE_IGNORED) rather than a global one -- a global
|
|
entry would collide with the dryer's real capability."""
|
|
from custom_components.localthings.registry.by_type import washer as washer_registry
|
|
from custom_components.localthings.registry.capabilities.ignored import IGNORED
|
|
|
|
assert '/cycleinterface/vs/0' not in {cap.href for cap in IGNORED}
|
|
assert '/cycleinterface/vs/0' in washer_registry.REGISTRY.capabilities
|