Add support for validating and serializing selectors (#66565)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
2ca6ec0290
commit
ec67dcb620
3 changed files with 342 additions and 131 deletions
|
@ -2,7 +2,10 @@
|
|||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.helpers import selector
|
||||
from homeassistant.helpers import config_validation as cv, selector
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
FAKE_UUID = "a266a680b608c32770e6c45bfe6b8411"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -20,6 +23,8 @@ def test_valid_base_schema(schema):
|
|||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
(
|
||||
None,
|
||||
"not_a_dict",
|
||||
{},
|
||||
{"non_existing": {}},
|
||||
# Two keys
|
||||
|
@ -38,173 +43,268 @@ def test_validate_selector():
|
|||
assert schema == selector.validate_selector(schema)
|
||||
|
||||
|
||||
def _test_selector(
|
||||
selector_type, schema, valid_selections, invalid_selections, converter=None
|
||||
):
|
||||
"""Help test a selector."""
|
||||
|
||||
def default_converter(x):
|
||||
return x
|
||||
|
||||
if converter is None:
|
||||
converter = default_converter
|
||||
|
||||
# Validate selector configuration
|
||||
selector.validate_selector({selector_type: schema})
|
||||
|
||||
# Use selector in schema and validate
|
||||
vol_schema = vol.Schema({"selection": selector.selector({selector_type: schema})})
|
||||
for selection in valid_selections:
|
||||
assert vol_schema({"selection": selection}) == {
|
||||
"selection": converter(selection)
|
||||
}
|
||||
for selection in invalid_selections:
|
||||
with pytest.raises(vol.Invalid):
|
||||
vol_schema({"selection": selection})
|
||||
|
||||
# Serialize selector
|
||||
selector_instance = selector.selector({selector_type: schema})
|
||||
assert cv.custom_serializer(selector_instance) == {
|
||||
"selector": {selector_type: selector_instance.config}
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(
|
||||
{},
|
||||
{"integration": "zha"},
|
||||
{"manufacturer": "mock-manuf"},
|
||||
{"model": "mock-model"},
|
||||
{"manufacturer": "mock-manuf", "model": "mock-model"},
|
||||
{"integration": "zha", "manufacturer": "mock-manuf", "model": "mock-model"},
|
||||
{"entity": {"device_class": "motion"}},
|
||||
{
|
||||
"integration": "zha",
|
||||
"manufacturer": "mock-manuf",
|
||||
"model": "mock-model",
|
||||
"entity": {"domain": "binary_sensor", "device_class": "motion"},
|
||||
},
|
||||
(None, ("abc123",), (None,)),
|
||||
({}, ("abc123",), (None,)),
|
||||
({"integration": "zha"}, ("abc123",), (None,)),
|
||||
({"manufacturer": "mock-manuf"}, ("abc123",), (None,)),
|
||||
({"model": "mock-model"}, ("abc123",), (None,)),
|
||||
({"manufacturer": "mock-manuf", "model": "mock-model"}, ("abc123",), (None,)),
|
||||
(
|
||||
{"integration": "zha", "manufacturer": "mock-manuf", "model": "mock-model"},
|
||||
("abc123",),
|
||||
(None,),
|
||||
),
|
||||
({"entity": {"device_class": "motion"}}, ("abc123",), (None,)),
|
||||
(
|
||||
{
|
||||
"integration": "zha",
|
||||
"manufacturer": "mock-manuf",
|
||||
"model": "mock-model",
|
||||
"entity": {"domain": "binary_sensor", "device_class": "motion"},
|
||||
},
|
||||
("abc123",),
|
||||
(None,),
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_device_selector_schema(schema):
|
||||
def test_device_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test device selector."""
|
||||
selector.validate_selector({"device": schema})
|
||||
_test_selector("device", schema, valid_selections, invalid_selections)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(
|
||||
{},
|
||||
{"integration": "zha"},
|
||||
{"domain": "light"},
|
||||
{"device_class": "motion"},
|
||||
{"integration": "zha", "domain": "light"},
|
||||
{"integration": "zha", "domain": "binary_sensor", "device_class": "motion"},
|
||||
({}, ("sensor.abc123", FAKE_UUID), (None, "abc123")),
|
||||
({"integration": "zha"}, ("sensor.abc123", FAKE_UUID), (None, "abc123")),
|
||||
({"domain": "light"}, ("light.abc123", FAKE_UUID), (None, "sensor.abc123")),
|
||||
({"device_class": "motion"}, ("sensor.abc123", FAKE_UUID), (None, "abc123")),
|
||||
(
|
||||
{"integration": "zha", "domain": "light"},
|
||||
("light.abc123", FAKE_UUID),
|
||||
(None, "sensor.abc123"),
|
||||
),
|
||||
(
|
||||
{"integration": "zha", "domain": "binary_sensor", "device_class": "motion"},
|
||||
("binary_sensor.abc123", FAKE_UUID),
|
||||
(None, "sensor.abc123"),
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_entity_selector_schema(schema):
|
||||
def test_entity_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test entity selector."""
|
||||
selector.validate_selector({"entity": schema})
|
||||
_test_selector("entity", schema, valid_selections, invalid_selections)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(
|
||||
{},
|
||||
{"entity": {}},
|
||||
{"entity": {"domain": "light"}},
|
||||
{"entity": {"domain": "binary_sensor", "device_class": "motion"}},
|
||||
{
|
||||
"entity": {
|
||||
"domain": "binary_sensor",
|
||||
"device_class": "motion",
|
||||
"integration": "demo",
|
||||
}
|
||||
},
|
||||
{"device": {"integration": "demo", "model": "mock-model"}},
|
||||
{
|
||||
"entity": {"domain": "binary_sensor", "device_class": "motion"},
|
||||
"device": {"integration": "demo", "model": "mock-model"},
|
||||
},
|
||||
({}, ("abc123",), (None,)),
|
||||
({"entity": {}}, ("abc123",), (None,)),
|
||||
({"entity": {"domain": "light"}}, ("abc123",), (None,)),
|
||||
(
|
||||
{"entity": {"domain": "binary_sensor", "device_class": "motion"}},
|
||||
("abc123",),
|
||||
(None,),
|
||||
),
|
||||
(
|
||||
{
|
||||
"entity": {
|
||||
"domain": "binary_sensor",
|
||||
"device_class": "motion",
|
||||
"integration": "demo",
|
||||
}
|
||||
},
|
||||
("abc123",),
|
||||
(None,),
|
||||
),
|
||||
(
|
||||
{"device": {"integration": "demo", "model": "mock-model"}},
|
||||
("abc123",),
|
||||
(None,),
|
||||
),
|
||||
(
|
||||
{
|
||||
"entity": {"domain": "binary_sensor", "device_class": "motion"},
|
||||
"device": {"integration": "demo", "model": "mock-model"},
|
||||
},
|
||||
("abc123",),
|
||||
(None,),
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_area_selector_schema(schema):
|
||||
def test_area_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test area selector."""
|
||||
selector.validate_selector({"area": schema})
|
||||
_test_selector("area", schema, valid_selections, invalid_selections)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(
|
||||
{"min": 10, "max": 50},
|
||||
{"min": -100, "max": 100, "step": 5},
|
||||
{"min": -20, "max": -10, "mode": "box"},
|
||||
{"min": 0, "max": 100, "unit_of_measurement": "seconds", "mode": "slider"},
|
||||
{"min": 10, "max": 1000, "mode": "slider", "step": 0.5},
|
||||
(
|
||||
{"min": 10, "max": 50},
|
||||
(
|
||||
10,
|
||||
50,
|
||||
),
|
||||
(9, 51),
|
||||
),
|
||||
({"min": -100, "max": 100, "step": 5}, (), ()),
|
||||
({"min": -20, "max": -10, "mode": "box"}, (), ()),
|
||||
(
|
||||
{"min": 0, "max": 100, "unit_of_measurement": "seconds", "mode": "slider"},
|
||||
(),
|
||||
(),
|
||||
),
|
||||
({"min": 10, "max": 1000, "mode": "slider", "step": 0.5}, (), ()),
|
||||
),
|
||||
)
|
||||
def test_number_selector_schema(schema):
|
||||
def test_number_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test number selector."""
|
||||
selector.validate_selector({"number": schema})
|
||||
_test_selector("number", schema, valid_selections, invalid_selections)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
({},),
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(({}, ("abc123",), (None,)),),
|
||||
)
|
||||
def test_addon_selector_schema(schema):
|
||||
def test_addon_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test add-on selector."""
|
||||
selector.validate_selector({"addon": schema})
|
||||
_test_selector("addon", schema, valid_selections, invalid_selections)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
({},),
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(({}, (1, "one", None), ()),), # Everything can be coarced to bool
|
||||
)
|
||||
def test_boolean_selector_schema(schema):
|
||||
def test_boolean_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test boolean selector."""
|
||||
selector.validate_selector({"boolean": schema})
|
||||
_test_selector("boolean", schema, valid_selections, invalid_selections, bool)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
({},),
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(({}, ("00:00:00",), ("blah", None)),),
|
||||
)
|
||||
def test_time_selector_schema(schema):
|
||||
def test_time_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test time selector."""
|
||||
selector.validate_selector({"time": schema})
|
||||
_test_selector(
|
||||
"time", schema, valid_selections, invalid_selections, dt_util.parse_time
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(
|
||||
{},
|
||||
{"entity": {}},
|
||||
{"entity": {"domain": "light"}},
|
||||
{"entity": {"domain": "binary_sensor", "device_class": "motion"}},
|
||||
{
|
||||
"entity": {
|
||||
"domain": "binary_sensor",
|
||||
"device_class": "motion",
|
||||
"integration": "demo",
|
||||
}
|
||||
},
|
||||
{"device": {"integration": "demo", "model": "mock-model"}},
|
||||
{
|
||||
"entity": {"domain": "binary_sensor", "device_class": "motion"},
|
||||
"device": {"integration": "demo", "model": "mock-model"},
|
||||
},
|
||||
({}, ({"entity_id": ["sensor.abc123"]},), ("abc123", None)),
|
||||
({"entity": {}}, (), ()),
|
||||
({"entity": {"domain": "light"}}, (), ()),
|
||||
({"entity": {"domain": "binary_sensor", "device_class": "motion"}}, (), ()),
|
||||
(
|
||||
{
|
||||
"entity": {
|
||||
"domain": "binary_sensor",
|
||||
"device_class": "motion",
|
||||
"integration": "demo",
|
||||
}
|
||||
},
|
||||
(),
|
||||
(),
|
||||
),
|
||||
({"device": {"integration": "demo", "model": "mock-model"}}, (), ()),
|
||||
(
|
||||
{
|
||||
"entity": {"domain": "binary_sensor", "device_class": "motion"},
|
||||
"device": {"integration": "demo", "model": "mock-model"},
|
||||
},
|
||||
(),
|
||||
(),
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_target_selector_schema(schema):
|
||||
def test_target_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test target selector."""
|
||||
selector.validate_selector({"target": schema})
|
||||
_test_selector("target", schema, valid_selections, invalid_selections)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
({},),
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(({}, ("abc123",), ()),),
|
||||
)
|
||||
def test_action_selector_schema(schema):
|
||||
def test_action_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test action sequence selector."""
|
||||
selector.validate_selector({"action": schema})
|
||||
_test_selector("action", schema, valid_selections, invalid_selections)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
({},),
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(({}, ("abc123",), ()),),
|
||||
)
|
||||
def test_object_selector_schema(schema):
|
||||
def test_object_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test object selector."""
|
||||
selector.validate_selector({"object": schema})
|
||||
_test_selector("object", schema, valid_selections, invalid_selections)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
({}, {"multiline": True}, {"multiline": False}),
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(
|
||||
({}, ("abc123",), (None,)),
|
||||
({"multiline": True}, (), ()),
|
||||
({"multiline": False}, (), ()),
|
||||
),
|
||||
)
|
||||
def test_text_selector_schema(schema):
|
||||
def test_text_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test text selector."""
|
||||
selector.validate_selector({"text": schema})
|
||||
_test_selector("text", schema, valid_selections, invalid_selections)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
({"options": ["red", "green", "blue"]},),
|
||||
"schema,valid_selections,invalid_selections",
|
||||
(
|
||||
(
|
||||
{"options": ["red", "green", "blue"]},
|
||||
("red", "green", "blue"),
|
||||
("cat", 0, None),
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_select_selector_schema(schema):
|
||||
def test_select_selector_schema(schema, valid_selections, invalid_selections):
|
||||
"""Test select selector."""
|
||||
selector.validate_selector({"select": schema})
|
||||
_test_selector("select", schema, valid_selections, invalid_selections)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue