From a756308e79f82d42c17daf5850573e73f313f51b Mon Sep 17 00:00:00 2001 From: jan iversen Date: Sat, 4 Sep 2021 00:43:07 +0200 Subject: [PATCH] Update template/test_binary_sensor.py to use pytest (#55220) --- .../components/template/test_binary_sensor.py | 1019 ++++++----------- 1 file changed, 359 insertions(+), 660 deletions(-) diff --git a/tests/components/template/test_binary_sensor.py b/tests/components/template/test_binary_sensor.py index ccadef5aa96..92b8d6f773f 100644 --- a/tests/components/template/test_binary_sensor.py +++ b/tests/components/template/test_binary_sensor.py @@ -3,6 +3,8 @@ from datetime import timedelta import logging from unittest.mock import patch +import pytest + from homeassistant import setup from homeassistant.components import binary_sensor from homeassistant.const import ( @@ -18,55 +20,43 @@ import homeassistant.util.dt as dt_util from tests.common import async_fire_time_changed +ON = "on" +OFF = "off" -async def test_setup_legacy(hass): - """Test the setup.""" - config = { - "binary_sensor": { - "platform": "template", - "sensors": { - "test": { - "friendly_name": "virtual thingy", - "value_template": "{{ True }}", - "device_class": "motion", - } + +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + "binary_sensor": { + "platform": "template", + "sensors": { + "test": { + "friendly_name": "virtual thingy", + "value_template": "{{ True }}", + "device_class": "motion", + } + }, }, - } - } - assert await setup.async_setup_component(hass, binary_sensor.DOMAIN, config) - await hass.async_block_till_done() + }, + ], +) +async def test_setup_legacy(hass, start_ha): + """Test the setup.""" state = hass.states.get("binary_sensor.test") assert state is not None assert state.name == "virtual thingy" - assert state.state == "on" + assert state.state == ON assert state.attributes["device_class"] == "motion" -async def test_setup_no_sensors(hass): - """Test setup with no sensors.""" - assert await setup.async_setup_component( - hass, binary_sensor.DOMAIN, {"binary_sensor": {"platform": "template"}} - ) - await hass.async_block_till_done() - assert len(hass.states.async_entity_ids()) == 0 - - -async def test_setup_invalid_device(hass): - """Test the setup with invalid devices.""" - assert await setup.async_setup_component( - hass, - binary_sensor.DOMAIN, +@pytest.mark.parametrize("count,domain", [(0, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + {"binary_sensor": {"platform": "template"}}, {"binary_sensor": {"platform": "template", "sensors": {"foo bar": {}}}}, - ) - await hass.async_block_till_done() - assert len(hass.states.async_entity_ids()) == 0 - - -async def test_setup_invalid_device_class(hass): - """Test setup with invalid sensor class.""" - assert await setup.async_setup_component( - hass, - binary_sensor.DOMAIN, { "binary_sensor": { "platform": "template", @@ -78,32 +68,23 @@ async def test_setup_invalid_device_class(hass): }, } }, - ) - await hass.async_block_till_done() - assert len(hass.states.async_entity_ids()) == 0 - - -async def test_setup_invalid_missing_template(hass): - """Test setup with invalid and missing template.""" - assert await setup.async_setup_component( - hass, - binary_sensor.DOMAIN, { "binary_sensor": { "platform": "template", "sensors": {"test": {"device_class": "motion"}}, } }, - ) - await hass.async_block_till_done() - assert len(hass.states.async_entity_ids()) == 0 + ], +) +async def test_setup_invalid_sensors(hass, count, start_ha): + """Test setup with no sensors.""" + assert len(hass.states.async_entity_ids()) == count -async def test_icon_template(hass): - """Test icon template.""" - assert await setup.async_setup_component( - hass, - binary_sensor.DOMAIN, +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ { "binary_sensor": { "platform": "template", @@ -115,16 +96,14 @@ async def test_icon_template(hass): "'Works' %}" "mdi:check" "{% endif %}", - } + }, }, - } + }, }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - + ], +) +async def test_icon_template(hass, start_ha): + """Test icon template.""" state = hass.states.get("binary_sensor.test_template_sensor") assert state.attributes.get("icon") == "" @@ -134,11 +113,10 @@ async def test_icon_template(hass): assert state.attributes["icon"] == "mdi:check" -async def test_entity_picture_template(hass): - """Test entity_picture template.""" - assert await setup.async_setup_component( - hass, - binary_sensor.DOMAIN, +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ { "binary_sensor": { "platform": "template", @@ -150,16 +128,14 @@ async def test_entity_picture_template(hass): "'Works' %}" "/local/sensor.png" "{% endif %}", - } + }, }, - } + }, }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - + ], +) +async def test_entity_picture_template(hass, start_ha): + """Test entity_picture template.""" state = hass.states.get("binary_sensor.test_template_sensor") assert state.attributes.get("entity_picture") == "" @@ -169,11 +145,10 @@ async def test_entity_picture_template(hass): assert state.attributes["entity_picture"] == "/local/sensor.png" -async def test_attribute_templates(hass): - """Test attribute_templates template.""" - assert await setup.async_setup_component( - hass, - binary_sensor.DOMAIN, +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ { "binary_sensor": { "platform": "template", @@ -183,16 +158,14 @@ async def test_attribute_templates(hass): "attribute_templates": { "test_attribute": "It {{ states.sensor.test_state.state }}." }, - } + }, }, - } + }, }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - + ], +) +async def test_attribute_templates(hass, start_ha): + """Test attribute_templates template.""" state = hass.states.get("binary_sensor.test_template_sensor") assert state.attributes.get("test_attribute") == "It ." hass.states.async_set("sensor.test_state", "Works2") @@ -203,501 +176,228 @@ async def test_attribute_templates(hass): assert state.attributes["test_attribute"] == "It Works." -async def test_match_all(hass): - """Test template that is rerendered on any state lifecycle.""" +@pytest.fixture +async def setup_mock(): + """Do setup of sensor mock.""" with patch( "homeassistant.components.template.binary_sensor." "BinarySensorTemplate._update_state" ) as _update_state: - assert await setup.async_setup_component( - hass, - binary_sensor.DOMAIN, - { - "binary_sensor": { - "platform": "template", - "sensors": { - "match_all_template_sensor": { - "value_template": ( - "{% for state in states %}" - "{% if state.entity_id == 'sensor.humidity' %}" - "{{ state.entity_id }}={{ state.state }}" - "{% endif %}" - "{% endfor %}" - ), - }, + yield _update_state + + +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + "binary_sensor": { + "platform": "template", + "sensors": { + "match_all_template_sensor": { + "value_template": ( + "{% for state in states %}" + "{% if state.entity_id == 'sensor.humidity' %}" + "{{ state.entity_id }}={{ state.state }}" + "{% endif %}" + "{% endfor %}" + ), }, - } + }, + } + }, + ], +) +async def test_match_all(hass, setup_mock, start_ha): + """Test template that is rerendered on any state lifecycle.""" + init_calls = len(setup_mock.mock_calls) + + hass.states.async_set("sensor.any_state", "update") + await hass.async_block_till_done() + assert len(setup_mock.mock_calls) == init_calls + + +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + "binary_sensor": { + "platform": "template", + "sensors": { + "test": { + "friendly_name": "virtual thingy", + "value_template": "{{ states.sensor.test_state.state == 'on' }}", + "device_class": "motion", + }, + }, }, - ) - - await hass.async_start() - await hass.async_block_till_done() - init_calls = len(_update_state.mock_calls) - - hass.states.async_set("sensor.any_state", "update") - await hass.async_block_till_done() - assert len(_update_state.mock_calls) == init_calls - - -async def test_event(hass): + }, + ], +) +async def test_event(hass, start_ha): """Test the event.""" - config = { - "binary_sensor": { - "platform": "template", - "sensors": { - "test": { - "friendly_name": "virtual thingy", - "value_template": "{{ states.sensor.test_state.state == 'on' }}", - "device_class": "motion", - } + state = hass.states.get("binary_sensor.test") + assert state.state == OFF + + hass.states.async_set("sensor.test_state", ON) + await hass.async_block_till_done() + + state = hass.states.get("binary_sensor.test") + assert state.state == ON + + +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + "binary_sensor": { + "platform": "template", + "sensors": { + "test_on": { + "friendly_name": "virtual thingy", + "value_template": "{{ states.sensor.test_state.state == 'on' }}", + "device_class": "motion", + "delay_on": 5, + }, + "test_off": { + "friendly_name": "virtual thingy", + "value_template": "{{ states.sensor.test_state.state == 'on' }}", + "device_class": "motion", + "delay_off": 5, + }, + }, }, - } - } - assert await setup.async_setup_component(hass, binary_sensor.DOMAIN, config) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - -async def test_template_delay_on(hass): + }, + { + "binary_sensor": { + "platform": "template", + "sensors": { + "test_on": { + "friendly_name": "virtual thingy", + "value_template": "{{ states.sensor.test_state.state == 'on' }}", + "device_class": "motion", + "delay_on": '{{ ({ "seconds": 10 / 2 }) }}', + }, + "test_off": { + "friendly_name": "virtual thingy", + "value_template": "{{ states.sensor.test_state.state == 'on' }}", + "device_class": "motion", + "delay_off": '{{ ({ "seconds": 10 / 2 }) }}', + }, + }, + }, + }, + { + "binary_sensor": { + "platform": "template", + "sensors": { + "test_on": { + "friendly_name": "virtual thingy", + "value_template": "{{ states.sensor.test_state.state == 'on' }}", + "device_class": "motion", + "delay_on": '{{ ({ "seconds": states("input_number.delay")|int }) }}', + }, + "test_off": { + "friendly_name": "virtual thingy", + "value_template": "{{ states.sensor.test_state.state == 'on' }}", + "device_class": "motion", + "delay_off": '{{ ({ "seconds": states("input_number.delay")|int }) }}', + }, + }, + }, + }, + ], +) +async def test_template_delay_on_off(hass, start_ha): """Test binary sensor template delay on.""" - config = { - "binary_sensor": { - "platform": "template", - "sensors": { - "test": { - "friendly_name": "virtual thingy", - "value_template": "{{ states.sensor.test_state.state == 'on' }}", - "device_class": "motion", - "delay_on": 5, - } - }, - } - } - await setup.async_setup_component(hass, binary_sensor.DOMAIN, config) + assert hass.states.get("binary_sensor.test_on").state == OFF + assert hass.states.get("binary_sensor.test_off").state == OFF + hass.states.async_set("input_number.delay", 5) + hass.states.async_set("sensor.test_state", ON) await hass.async_block_till_done() - await hass.async_start() - - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" + assert hass.states.get("binary_sensor.test_on").state == OFF + assert hass.states.get("binary_sensor.test_off").state == ON future = dt_util.utcnow() + timedelta(seconds=5) async_fire_time_changed(hass, future) await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" + assert hass.states.get("binary_sensor.test_on").state == ON + assert hass.states.get("binary_sensor.test_off").state == ON # check with time changes - hass.states.async_set("sensor.test_state", "off") + hass.states.async_set("sensor.test_state", OFF) await hass.async_block_till_done() + assert hass.states.get("binary_sensor.test_on").state == OFF + assert hass.states.get("binary_sensor.test_off").state == ON - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - hass.states.async_set("sensor.test_state", "on") + hass.states.async_set("sensor.test_state", ON) await hass.async_block_till_done() + assert hass.states.get("binary_sensor.test_on").state == OFF + assert hass.states.get("binary_sensor.test_off").state == ON - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - hass.states.async_set("sensor.test_state", "off") + hass.states.async_set("sensor.test_state", OFF) await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" + assert hass.states.get("binary_sensor.test_on").state == OFF + assert hass.states.get("binary_sensor.test_off").state == ON future = dt_util.utcnow() + timedelta(seconds=5) async_fire_time_changed(hass, future) await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" + assert hass.states.get("binary_sensor.test_on").state == OFF + assert hass.states.get("binary_sensor.test_off").state == OFF -async def test_template_delay_off(hass): - """Test binary sensor template delay off.""" - config = { - "binary_sensor": { - "platform": "template", - "sensors": { - "test": { - "friendly_name": "virtual thingy", - "value_template": "{{ states.sensor.test_state.state == 'on' }}", - "device_class": "motion", - "delay_off": 5, - } +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + "binary_sensor": { + "platform": "template", + "sensors": { + "test": { + "friendly_name": "virtual thingy", + "value_template": "true", + "device_class": "motion", + "delay_off": 5, + }, + }, }, - } - } - hass.states.async_set("sensor.test_state", "on") - await setup.async_setup_component(hass, binary_sensor.DOMAIN, config) - await hass.async_block_till_done() - await hass.async_start() - - hass.states.async_set("sensor.test_state", "off") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - future = dt_util.utcnow() + timedelta(seconds=5) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - # check with time changes - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - hass.states.async_set("sensor.test_state", "off") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - future = dt_util.utcnow() + timedelta(seconds=5) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - -async def test_template_with_templated_delay_on(hass): - """Test binary sensor template with template delay on.""" - config = { - "binary_sensor": { - "platform": "template", - "sensors": { - "test": { - "friendly_name": "virtual thingy", - "value_template": "{{ states.sensor.test_state.state == 'on' }}", - "device_class": "motion", - "delay_on": '{{ ({ "seconds": 6 / 2 }) }}', - } - }, - } - } - await setup.async_setup_component(hass, binary_sensor.DOMAIN, config) - await hass.async_block_till_done() - await hass.async_start() - - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - future = dt_util.utcnow() + timedelta(seconds=3) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - # check with time changes - hass.states.async_set("sensor.test_state", "off") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - hass.states.async_set("sensor.test_state", "off") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - future = dt_util.utcnow() + timedelta(seconds=3) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - -async def test_template_with_templated_delay_off(hass): - """Test binary sensor template with template delay off.""" - config = { - "binary_sensor": { - "platform": "template", - "sensors": { - "test": { - "friendly_name": "virtual thingy", - "value_template": "{{ states.sensor.test_state.state == 'on' }}", - "device_class": "motion", - "delay_off": '{{ ({ "seconds": 6 / 2 }) }}', - } - }, - } - } - hass.states.async_set("sensor.test_state", "on") - await setup.async_setup_component(hass, binary_sensor.DOMAIN, config) - await hass.async_block_till_done() - await hass.async_start() - - hass.states.async_set("sensor.test_state", "off") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - future = dt_util.utcnow() + timedelta(seconds=3) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - # check with time changes - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - hass.states.async_set("sensor.test_state", "off") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - future = dt_util.utcnow() + timedelta(seconds=3) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - -async def test_template_with_delay_on_based_on_input(hass): - """Test binary sensor template with template delay on based on input number.""" - config = { - "binary_sensor": { - "platform": "template", - "sensors": { - "test": { - "friendly_name": "virtual thingy", - "value_template": "{{ states.sensor.test_state.state == 'on' }}", - "device_class": "motion", - "delay_on": '{{ ({ "seconds": states("input_number.delay")|int }) }}', - } - }, - } - } - await setup.async_setup_component(hass, binary_sensor.DOMAIN, config) - await hass.async_block_till_done() - await hass.async_start() - - hass.states.async_set("sensor.test_state", "off") - await hass.async_block_till_done() - - hass.states.async_set("input_number.delay", 3) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - future = dt_util.utcnow() + timedelta(seconds=3) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - # set input to 4 seconds - hass.states.async_set("sensor.test_state", "off") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - hass.states.async_set("input_number.delay", 4) - await hass.async_block_till_done() - - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - future = dt_util.utcnow() + timedelta(seconds=2) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - future = dt_util.utcnow() + timedelta(seconds=4) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - -async def test_template_with_delay_off_based_on_input(hass): - """Test binary sensor template with template delay off based on input number.""" - config = { - "binary_sensor": { - "platform": "template", - "sensors": { - "test": { - "friendly_name": "virtual thingy", - "value_template": "{{ states.sensor.test_state.state == 'on' }}", - "device_class": "motion", - "delay_off": '{{ ({ "seconds": states("input_number.delay")|int }) }}', - } - }, - } - } - await setup.async_setup_component(hass, binary_sensor.DOMAIN, config) - await hass.async_block_till_done() - await hass.async_start() - - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - hass.states.async_set("input_number.delay", 3) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - hass.states.async_set("sensor.test_state", "off") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - future = dt_util.utcnow() + timedelta(seconds=3) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - # set input to 4 seconds - hass.states.async_set("sensor.test_state", "on") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - hass.states.async_set("input_number.delay", 4) - await hass.async_block_till_done() - - hass.states.async_set("sensor.test_state", "off") - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - future = dt_util.utcnow() + timedelta(seconds=2) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "on" - - future = dt_util.utcnow() + timedelta(seconds=4) - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.test") - assert state.state == "off" - - -async def test_available_without_availability_template(hass): + }, + ], +) +async def test_available_without_availability_template(hass, start_ha): """Ensure availability is true without an availability_template.""" - config = { - "binary_sensor": { - "platform": "template", - "sensors": { - "test": { - "friendly_name": "virtual thingy", - "value_template": "true", - "device_class": "motion", - "delay_off": 5, - } - }, - } - } - await setup.async_setup_component(hass, binary_sensor.DOMAIN, config) - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - state = hass.states.get("binary_sensor.test") assert state.state != STATE_UNAVAILABLE assert state.attributes[ATTR_DEVICE_CLASS] == "motion" -async def test_availability_template(hass): - """Test availability template.""" - config = { - "binary_sensor": { - "platform": "template", - "sensors": { - "test": { - "friendly_name": "virtual thingy", - "value_template": "true", - "device_class": "motion", - "delay_off": 5, - "availability_template": "{{ is_state('sensor.test_state','on') }}", - } +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + "binary_sensor": { + "platform": "template", + "sensors": { + "test": { + "friendly_name": "virtual thingy", + "value_template": "true", + "device_class": "motion", + "delay_off": 5, + "availability_template": "{{ is_state('sensor.test_state','on') }}", + }, + }, }, - } - } - await setup.async_setup_component(hass, binary_sensor.DOMAIN, config) - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - + }, + ], +) +async def test_availability_template(hass, start_ha): + """Test availability template.""" hass.states.async_set("sensor.test_state", STATE_OFF) await hass.async_block_till_done() @@ -712,13 +412,10 @@ async def test_availability_template(hass): assert state.attributes[ATTR_DEVICE_CLASS] == "motion" -async def test_invalid_attribute_template(hass, caplog): - """Test that errors are logged if rendering template fails.""" - hass.states.async_set("binary_sensor.test_sensor", "true") - - await setup.async_setup_component( - hass, - binary_sensor.DOMAIN, +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ { "binary_sensor": { "platform": "template", @@ -730,24 +427,23 @@ async def test_invalid_attribute_template(hass, caplog): }, } }, - } + }, }, - ) - await hass.async_block_till_done() + ], +) +async def test_invalid_attribute_template(hass, caplog, start_ha): + """Test that errors are logged if rendering template fails.""" + hass.states.async_set("binary_sensor.test_sensor", "true") assert len(hass.states.async_all()) == 2 - await hass.async_start() - await hass.async_block_till_done() - - assert "test_attribute" in caplog.text - assert "TemplateError" in caplog.text + text = str([x.getMessage() for x in caplog.get_records("setup")]) + assert ("test_attribute") in text + assert ("TemplateError") in text -async def test_invalid_availability_template_keeps_component_available(hass, caplog): - """Test that an invalid availability keeps the device available.""" - - await setup.async_setup_component( - hass, - binary_sensor.DOMAIN, +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ { "binary_sensor": { "platform": "template", @@ -755,22 +451,24 @@ async def test_invalid_availability_template_keeps_component_available(hass, cap "my_sensor": { "value_template": "{{ states.binary_sensor.test_sensor }}", "availability_template": "{{ x - 12 }}", - } + }, }, - } + }, }, - ) - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() + ], +) +async def test_invalid_availability_template_keeps_component_available( + hass, caplog, start_ha +): + """Test that an invalid availability keeps the device available.""" assert hass.states.get("binary_sensor.my_sensor").state != STATE_UNAVAILABLE - assert ("UndefinedError: 'x' is undefined") in caplog.text + text = str([x.getMessage() for x in caplog.get_records("setup")]) + assert ("UndefinedError: \\'x\\' is undefined") in text async def test_no_update_template_match_all(hass, caplog): """Test that we do not update sensors that match on all.""" - hass.states.async_set("binary_sensor.test_sensor", "true") hass.state = CoreState.not_running @@ -799,29 +497,30 @@ async def test_no_update_template_match_all(hass, caplog): }, ) await hass.async_block_till_done() + hass.states.async_set("binary_sensor.test_sensor", "true") assert len(hass.states.async_all()) == 5 - assert hass.states.get("binary_sensor.all_state").state == "off" - assert hass.states.get("binary_sensor.all_icon").state == "off" - assert hass.states.get("binary_sensor.all_entity_picture").state == "off" - assert hass.states.get("binary_sensor.all_attribute").state == "off" + assert hass.states.get("binary_sensor.all_state").state == OFF + assert hass.states.get("binary_sensor.all_icon").state == OFF + assert hass.states.get("binary_sensor.all_entity_picture").state == OFF + assert hass.states.get("binary_sensor.all_attribute").state == OFF hass.bus.async_fire(EVENT_HOMEASSISTANT_START) await hass.async_block_till_done() - assert hass.states.get("binary_sensor.all_state").state == "on" - assert hass.states.get("binary_sensor.all_icon").state == "on" - assert hass.states.get("binary_sensor.all_entity_picture").state == "on" - assert hass.states.get("binary_sensor.all_attribute").state == "on" + assert hass.states.get("binary_sensor.all_state").state == ON + assert hass.states.get("binary_sensor.all_icon").state == ON + assert hass.states.get("binary_sensor.all_entity_picture").state == ON + assert hass.states.get("binary_sensor.all_attribute").state == ON hass.states.async_set("binary_sensor.test_sensor", "false") await hass.async_block_till_done() - assert hass.states.get("binary_sensor.all_state").state == "on" + assert hass.states.get("binary_sensor.all_state").state == ON # Will now process because we have one valid template - assert hass.states.get("binary_sensor.all_icon").state == "off" - assert hass.states.get("binary_sensor.all_entity_picture").state == "off" - assert hass.states.get("binary_sensor.all_attribute").state == "off" + assert hass.states.get("binary_sensor.all_icon").state == OFF + assert hass.states.get("binary_sensor.all_entity_picture").state == OFF + assert hass.states.get("binary_sensor.all_attribute").state == OFF await hass.helpers.entity_component.async_update_entity("binary_sensor.all_state") await hass.helpers.entity_component.async_update_entity("binary_sensor.all_icon") @@ -832,24 +531,23 @@ async def test_no_update_template_match_all(hass, caplog): "binary_sensor.all_attribute" ) - assert hass.states.get("binary_sensor.all_state").state == "on" - assert hass.states.get("binary_sensor.all_icon").state == "off" - assert hass.states.get("binary_sensor.all_entity_picture").state == "off" - assert hass.states.get("binary_sensor.all_attribute").state == "off" + assert hass.states.get("binary_sensor.all_state").state == ON + assert hass.states.get("binary_sensor.all_icon").state == OFF + assert hass.states.get("binary_sensor.all_entity_picture").state == OFF + assert hass.states.get("binary_sensor.all_attribute").state == OFF -async def test_unique_id(hass): - """Test unique_id option only creates one binary sensor per id.""" - await setup.async_setup_component( - hass, - "template", +@pytest.mark.parametrize("count,domain", [(1, "template")]) +@pytest.mark.parametrize( + "config", + [ { "template": { "unique_id": "group-id", "binary_sensor": { "name": "top-level", "unique_id": "sensor-id", - "state": "on", + "state": ON, }, }, "binary_sensor": { @@ -866,12 +564,10 @@ async def test_unique_id(hass): }, }, }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - + ], +) +async def test_unique_id(hass, start_ha): + """Test unique_id option only creates one binary sensor per id.""" assert len(hass.states.async_all()) == 2 ent_reg = entity_registry.async_get(hass) @@ -889,28 +585,29 @@ async def test_unique_id(hass): ) -async def test_template_validation_error(hass, caplog): - """Test binary sensor template delay on.""" - caplog.set_level(logging.ERROR) - config = { - "binary_sensor": { - "platform": "template", - "sensors": { - "test": { - "friendly_name": "virtual thingy", - "value_template": "True", - "icon_template": "{{ states.sensor.test_state.state }}", - "device_class": "motion", - "delay_on": 5, +@pytest.mark.parametrize("count,domain", [(1, binary_sensor.DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + "binary_sensor": { + "platform": "template", + "sensors": { + "test": { + "friendly_name": "virtual thingy", + "value_template": "True", + "icon_template": "{{ states.sensor.test_state.state }}", + "device_class": "motion", + "delay_on": 5, + }, }, }, }, - } - await setup.async_setup_component(hass, binary_sensor.DOMAIN, config) - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - + ], +) +async def test_template_validation_error(hass, caplog, start_ha): + """Test binary sensor template delay on.""" + caplog.set_level(logging.ERROR) state = hass.states.get("binary_sensor.test") assert state.attributes.get("icon") == "" @@ -931,11 +628,10 @@ async def test_template_validation_error(hass, caplog): assert state.attributes.get("icon") is None -async def test_trigger_entity(hass): - """Test trigger entity works.""" - assert await setup.async_setup_component( - hass, - "template", +@pytest.mark.parametrize("count,domain", [(2, "template")]) +@pytest.mark.parametrize( + "config", + [ { "template": [ {"invalid": "config"}, @@ -981,24 +677,25 @@ async def test_trigger_entity(hass): }, ], }, - ) - + ], +) +async def test_trigger_entity(hass, start_ha): + """Test trigger entity works.""" await hass.async_block_till_done() - state = hass.states.get("binary_sensor.hello_name") assert state is not None - assert state.state == "off" + assert state.state == OFF state = hass.states.get("binary_sensor.bare_minimum") assert state is not None - assert state.state == "off" + assert state.state == OFF context = Context() hass.bus.async_fire("test_event", {"beer": 2}, context=context) await hass.async_block_till_done() state = hass.states.get("binary_sensor.hello_name") - assert state.state == "on" + assert state.state == ON assert state.attributes.get("device_class") == "battery" assert state.attributes.get("icon") == "mdi:pirate" assert state.attributes.get("entity_picture") == "/local/dogs.png" @@ -1017,7 +714,7 @@ async def test_trigger_entity(hass): ) state = hass.states.get("binary_sensor.via_list") - assert state.state == "on" + assert state.state == ON assert state.attributes.get("device_class") == "battery" assert state.attributes.get("icon") == "mdi:pirate" assert state.attributes.get("entity_picture") == "/local/dogs.png" @@ -1029,30 +726,32 @@ async def test_trigger_entity(hass): hass.bus.async_fire("test_event", {"beer": 2, "uno_mas": "si"}) await hass.async_block_till_done() state = hass.states.get("binary_sensor.via_list") - assert state.state == "on" + assert state.state == ON assert state.attributes.get("another") == "si" -async def test_template_with_trigger_templated_delay_on(hass): - """Test binary sensor template with template delay on.""" - config = { - "template": { - "trigger": {"platform": "event", "event_type": "test_event"}, - "binary_sensor": { - "name": "test", - "state": "{{ trigger.event.data.beer == 2 }}", - "device_class": "motion", - "delay_on": '{{ ({ "seconds": 6 / 2 }) }}', - "auto_off": '{{ ({ "seconds": 1 + 1 }) }}', +@pytest.mark.parametrize("count,domain", [(1, "template")]) +@pytest.mark.parametrize( + "config", + [ + { + "template": { + "trigger": {"platform": "event", "event_type": "test_event"}, + "binary_sensor": { + "name": "test", + "state": "{{ trigger.event.data.beer == 2 }}", + "device_class": "motion", + "delay_on": '{{ ({ "seconds": 6 / 2 }) }}', + "auto_off": '{{ ({ "seconds": 1 + 1 }) }}', + }, }, - } - } - await setup.async_setup_component(hass, "template", config) - await hass.async_block_till_done() - await hass.async_start() - + }, + ], +) +async def test_template_with_trigger_templated_delay_on(hass, start_ha): + """Test binary sensor template with template delay on.""" state = hass.states.get("binary_sensor.test") - assert state.state == "off" + assert state.state == OFF context = Context() hass.bus.async_fire("test_event", {"beer": 2}, context=context) @@ -1063,7 +762,7 @@ async def test_template_with_trigger_templated_delay_on(hass): await hass.async_block_till_done() state = hass.states.get("binary_sensor.test") - assert state.state == "on" + assert state.state == ON # Now wait for the auto-off future = dt_util.utcnow() + timedelta(seconds=2) @@ -1071,4 +770,4 @@ async def test_template_with_trigger_templated_delay_on(hass): await hass.async_block_till_done() state = hass.states.get("binary_sensor.test") - assert state.state == "off" + assert state.state == OFF