hass-core/tests/helpers/test_intent.py
CtrlZvi 1433cdaa12
Prefer shorter keys for intent matching (#43672)
When using fuzzy matching to match entity names for intents, whichever
entity is first is preferred in the case of equal matches. This leads
to situations where entities with similar names (such as entities named
for their area and then specific area location) may be used when the
whole area is wanted.

I ran into this with the my Phillips Hue lights. I have each individual
light named such that its room is the first part of the name, and its
location within the room after. So my living room has:
Living Room West
Living Room Northwest
Living Room North
Living Room Northeast

I then have a group for the whole room:
Living Room

Because the group is the last of the entities, trying to adjust the
whole room only activates one light, because all of the lights match
equally well.

By preferring the shortest of equal matches, we prefer keys that have
the least amount of extra information, causing "Living Room" to match
the group instead of an individual light.
2021-01-27 12:16:19 +01:00

58 lines
1.9 KiB
Python

"""Tests for the intent helpers."""
import pytest
import voluptuous as vol
from homeassistant.core import State
from homeassistant.helpers import config_validation as cv, intent
class MockIntentHandler(intent.IntentHandler):
"""Provide a mock intent handler."""
def __init__(self, slot_schema):
"""Initialize the mock handler."""
self.slot_schema = slot_schema
def test_async_match_state():
"""Test async_match_state helper."""
state1 = State("light.kitchen", "on")
state2 = State("switch.kitchen", "on")
state = intent.async_match_state(None, "kitch", [state1, state2])
assert state is state1
def test_async_validate_slots():
"""Test async_validate_slots of IntentHandler."""
handler1 = MockIntentHandler({vol.Required("name"): cv.string})
with pytest.raises(vol.error.MultipleInvalid):
handler1.async_validate_slots({})
with pytest.raises(vol.error.MultipleInvalid):
handler1.async_validate_slots({"name": 1})
with pytest.raises(vol.error.MultipleInvalid):
handler1.async_validate_slots({"name": "kitchen"})
handler1.async_validate_slots({"name": {"value": "kitchen"}})
handler1.async_validate_slots(
{"name": {"value": "kitchen"}, "probability": {"value": "0.5"}}
)
def test_fuzzy_match():
"""Test _fuzzymatch."""
state1 = State("light.living_room_northwest", "off")
state2 = State("light.living_room_north", "off")
state3 = State("light.living_room_northeast", "off")
state4 = State("light.living_room_west", "off")
state5 = State("light.living_room", "off")
states = [state1, state2, state3, state4, state5]
state = intent._fuzzymatch("Living Room", states, lambda state: state.name)
assert state == state5
state = intent._fuzzymatch(
"Living Room Northwest", states, lambda state: state.name
)
assert state == state1