From 692f61110937d129aafe3750d5598973f154250b Mon Sep 17 00:00:00 2001 From: jan iversen Date: Tue, 14 Sep 2021 22:51:46 +0200 Subject: [PATCH] Update template/test_fan.py to use pytest (#56215) --- tests/components/template/test_fan.py | 1212 +++++++++---------------- 1 file changed, 428 insertions(+), 784 deletions(-) diff --git a/tests/components/template/test_fan.py b/tests/components/template/test_fan.py index b5820cd5c76..82f89be9b0a 100644 --- a/tests/components/template/test_fan.py +++ b/tests/components/template/test_fan.py @@ -11,6 +11,7 @@ from homeassistant.components.fan import ( ATTR_SPEED, DIRECTION_FORWARD, DIRECTION_REVERSE, + DOMAIN, SPEED_HIGH, SPEED_LOW, SPEED_MEDIUM, @@ -18,7 +19,7 @@ from homeassistant.components.fan import ( ) from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE -from tests.common import assert_setup_component, async_mock_service +from tests.common import assert_setup_component from tests.components.fan import common _TEST_FAN = "fan.test_fan" @@ -38,229 +39,161 @@ _OSC_INPUT = "input_select.osc" _DIRECTION_INPUT_SELECT = "input_select.direction" -@pytest.fixture -def calls(hass): - """Track calls to a mock service.""" - return async_mock_service(hass, "test", "automation") - - -# Configuration tests # -async def test_missing_optional_config(hass, calls): - """Test: missing optional template is ok.""" - with assert_setup_component(1, "fan"): - assert await setup.async_setup_component( - hass, - "fan", - { - "fan": { - "platform": "template", - "fans": { - "test_fan": { - "value_template": "{{ 'on' }}", - "turn_on": {"service": "script.fan_on"}, - "turn_off": {"service": "script.fan_off"}, - } - }, - } - }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - _verify(hass, STATE_ON, None, None, None, None, None) - - -async def test_missing_value_template_config(hass, calls): - """Test: missing 'value_template' will fail.""" - with assert_setup_component(0, "fan"): - assert await setup.async_setup_component( - hass, - "fan", - { - "fan": { - "platform": "template", - "fans": { - "test_fan": { - "turn_on": {"service": "script.fan_on"}, - "turn_off": {"service": "script.fan_off"}, - } - }, - } - }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - assert hass.states.async_all() == [] - - -async def test_missing_turn_on_config(hass, calls): - """Test: missing 'turn_on' will fail.""" - with assert_setup_component(0, "fan"): - assert await setup.async_setup_component( - hass, - "fan", - { - "fan": { - "platform": "template", - "fans": { - "test_fan": { - "value_template": "{{ 'on' }}", - "turn_off": {"service": "script.fan_off"}, - } - }, - } - }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - assert hass.states.async_all() == [] - - -async def test_missing_turn_off_config(hass, calls): - """Test: missing 'turn_off' will fail.""" - with assert_setup_component(0, "fan"): - assert await setup.async_setup_component( - hass, - "fan", - { - "fan": { - "platform": "template", - "fans": { - "test_fan": { - "value_template": "{{ 'on' }}", - "turn_on": {"service": "script.fan_on"}, - } - }, - } - }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - assert hass.states.async_all() == [] - - -async def test_invalid_config(hass, calls): - """Test: missing 'turn_off' will fail.""" - with assert_setup_component(0, "fan"): - assert await setup.async_setup_component( - hass, - "fan", - { +@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + DOMAIN: { "platform": "template", "fans": { "test_fan": { "value_template": "{{ 'on' }}", "turn_on": {"service": "script.fan_on"}, + "turn_off": {"service": "script.fan_off"}, } }, - }, - ) + } + }, + ], +) +async def test_missing_optional_config(hass, start_ha): + """Test: missing optional template is ok.""" + _verify(hass, STATE_ON, None, None, None, None, None) - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() +@pytest.mark.parametrize("count,domain", [(0, DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + DOMAIN: { + "platform": "template", + "fans": { + "platform": "template", + "fans": { + "test_fan": { + "turn_on": {"service": "script.fan_on"}, + "turn_off": {"service": "script.fan_off"}, + } + }, + }, + } + }, + { + DOMAIN: { + "platform": "template", + "fans": { + "platform": "template", + "fans": { + "test_fan": { + "value_template": "{{ 'on' }}", + "turn_off": {"service": "script.fan_off"}, + } + }, + }, + } + }, + { + DOMAIN: { + "platform": "template", + "fans": { + "platform": "template", + "fans": { + "test_fan": { + "value_template": "{{ 'on' }}", + "turn_on": {"service": "script.fan_on"}, + } + }, + }, + } + }, + { + DOMAIN: { + "platform": "template", + "fans": { + "platform": "template", + "fans": { + "test_fan": { + "value_template": "{{ 'on' }}", + "turn_on": {"service": "script.fan_on"}, + } + }, + }, + } + }, + ], +) +async def test_wrong_template_config(hass, start_ha): + """Test: missing 'value_template' will fail.""" assert hass.states.async_all() == [] -# End of configuration tests # - - -# Template tests # -async def test_templates_with_entities(hass, calls): - """Test tempalates with values from other entities.""" - value_template = """ +@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + DOMAIN: { + "platform": "template", + "fans": { + "test_fan": { + "value_template": """ {% if is_state('input_boolean.state', 'True') %} {{ 'on' }} {% else %} {{ 'off' }} {% endif %} - """ - - with assert_setup_component(1, "fan"): - assert await setup.async_setup_component( - hass, - "fan", - { - "fan": { - "platform": "template", - "fans": { - "test_fan": { - "value_template": value_template, - "percentage_template": "{{ states('input_number.percentage') }}", - "speed_template": "{{ states('input_select.speed') }}", - "preset_mode_template": "{{ states('input_select.preset_mode') }}", - "oscillating_template": "{{ states('input_select.osc') }}", - "direction_template": "{{ states('input_select.direction') }}", - "speed_count": "3", - "set_percentage": { - "service": "script.fans_set_speed", - "data_template": {"percentage": "{{ percentage }}"}, - }, - "turn_on": {"service": "script.fan_on"}, - "turn_off": {"service": "script.fan_off"}, - } - }, - } - }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - + """, + "percentage_template": "{{ states('input_number.percentage') }}", + "speed_template": "{{ states('input_select.speed') }}", + "preset_mode_template": "{{ states('input_select.preset_mode') }}", + "oscillating_template": "{{ states('input_select.osc') }}", + "direction_template": "{{ states('input_select.direction') }}", + "speed_count": "3", + "set_percentage": { + "service": "script.fans_set_speed", + "data_template": {"percentage": "{{ percentage }}"}, + }, + "turn_on": {"service": "script.fan_on"}, + "turn_off": {"service": "script.fan_off"}, + } + }, + } + }, + ], +) +async def test_templates_with_entities(hass, start_ha): + """Test tempalates with values from other entities.""" _verify(hass, STATE_OFF, None, 0, None, None, None) hass.states.async_set(_STATE_INPUT_BOOLEAN, True) hass.states.async_set(_SPEED_INPUT_SELECT, SPEED_MEDIUM) hass.states.async_set(_OSC_INPUT, "True") - hass.states.async_set(_DIRECTION_INPUT_SELECT, DIRECTION_FORWARD) - await hass.async_block_till_done() - _verify(hass, STATE_ON, SPEED_MEDIUM, 66, True, DIRECTION_FORWARD, None) - - hass.states.async_set(_PERCENTAGE_INPUT_NUMBER, 33) - await hass.async_block_till_done() - _verify(hass, STATE_ON, SPEED_LOW, 33, True, DIRECTION_FORWARD, None) - - hass.states.async_set(_PERCENTAGE_INPUT_NUMBER, 66) - await hass.async_block_till_done() - _verify(hass, STATE_ON, SPEED_MEDIUM, 66, True, DIRECTION_FORWARD, None) - - hass.states.async_set(_PERCENTAGE_INPUT_NUMBER, 100) - await hass.async_block_till_done() - _verify(hass, STATE_ON, SPEED_HIGH, 100, True, DIRECTION_FORWARD, None) - - hass.states.async_set(_PERCENTAGE_INPUT_NUMBER, "dog") - await hass.async_block_till_done() - _verify(hass, STATE_ON, None, 0, True, DIRECTION_FORWARD, None) + for set_state, set_value, speed, value in [ + (_DIRECTION_INPUT_SELECT, DIRECTION_FORWARD, SPEED_MEDIUM, 66), + (_PERCENTAGE_INPUT_NUMBER, 33, SPEED_LOW, 33), + (_PERCENTAGE_INPUT_NUMBER, 66, SPEED_MEDIUM, 66), + (_PERCENTAGE_INPUT_NUMBER, 100, SPEED_HIGH, 100), + (_PERCENTAGE_INPUT_NUMBER, "dog", None, 0), + ]: + hass.states.async_set(set_state, set_value) + await hass.async_block_till_done() + _verify(hass, STATE_ON, speed, value, True, DIRECTION_FORWARD, None) hass.states.async_set(_STATE_INPUT_BOOLEAN, False) await hass.async_block_till_done() _verify(hass, STATE_OFF, None, 0, True, DIRECTION_FORWARD, None) -async def test_templates_with_entities_and_invalid_percentage(hass, calls): - """Test templates with values from other entities.""" - hass.states.async_set("sensor.percentage", "0") - - with assert_setup_component(1, "fan"): - assert await setup.async_setup_component( - hass, - "fan", +@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) +@pytest.mark.parametrize( + "config,entity,tests", + [ + ( { - "fan": { + DOMAIN: { "platform": "template", "fans": { "test_fan": { @@ -272,50 +205,19 @@ async def test_templates_with_entities_and_invalid_percentage(hass, calls): }, } }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - _verify(hass, STATE_ON, SPEED_OFF, 0, None, None, None) - - hass.states.async_set("sensor.percentage", "33") - await hass.async_block_till_done() - - _verify(hass, STATE_ON, SPEED_LOW, 33, None, None, None) - - hass.states.async_set("sensor.percentage", "invalid") - await hass.async_block_till_done() - - _verify(hass, STATE_ON, None, 0, None, None, None) - - hass.states.async_set("sensor.percentage", "5000") - await hass.async_block_till_done() - - _verify(hass, STATE_ON, None, 0, None, None, None) - - hass.states.async_set("sensor.percentage", "100") - await hass.async_block_till_done() - - _verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None) - - hass.states.async_set("sensor.percentage", "0") - await hass.async_block_till_done() - - _verify(hass, STATE_ON, SPEED_OFF, 0, None, None, None) - - -async def test_templates_with_entities_and_preset_modes(hass, calls): - """Test templates with values from other entities.""" - hass.states.async_set("sensor.preset_mode", "0") - - with assert_setup_component(1, "fan"): - assert await setup.async_setup_component( - hass, - "fan", + "sensor.percentage", + [ + ("0", 0, SPEED_OFF, None), + ("33", 33, SPEED_LOW, None), + ("invalid", 0, None, None), + ("5000", 0, None, None), + ("100", 100, SPEED_HIGH, None), + ("0", 0, SPEED_OFF, None), + ], + ), + ( { - "fan": { + DOMAIN: { "platform": "template", "fans": { "test_fan": { @@ -328,43 +230,62 @@ async def test_templates_with_entities_and_preset_modes(hass, calls): }, } }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - _verify(hass, STATE_ON, None, None, None, None, None) - - hass.states.async_set("sensor.preset_mode", "invalid") - await hass.async_block_till_done() - - _verify(hass, STATE_ON, None, None, None, None, None) - - hass.states.async_set("sensor.preset_mode", "auto") - await hass.async_block_till_done() - - _verify(hass, STATE_ON, "auto", None, None, None, "auto") - - hass.states.async_set("sensor.preset_mode", "smart") - await hass.async_block_till_done() - - _verify(hass, STATE_ON, "smart", None, None, None, "smart") - - hass.states.async_set("sensor.preset_mode", "invalid") - await hass.async_block_till_done() - _verify(hass, STATE_ON, None, None, None, None, None) + "sensor.preset_mode", + [ + ("0", None, None, None), + ("invalid", None, None, None), + ("auto", None, "auto", "auto"), + ("smart", None, "smart", "smart"), + ("invalid", None, None, None), + ], + ), + ], +) +async def test_templates_with_entities2(hass, entity, tests, start_ha): + """Test templates with values from other entities.""" + for set_percentage, test_percentage, speed, test_type in tests: + hass.states.async_set(entity, set_percentage) + await hass.async_block_till_done() + _verify(hass, STATE_ON, speed, test_percentage, None, None, test_type) -async def test_template_with_unavailable_entities(hass, calls): - """Test unavailability with value_template.""" +@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + DOMAIN: { + "platform": "template", + "fans": { + "test_fan": { + "availability_template": "{{ is_state('availability_boolean.state', 'on') }}", + "value_template": "{{ 'on' }}", + "speed_template": "{{ 'medium' }}", + "oscillating_template": "{{ 1 == 1 }}", + "direction_template": "{{ 'forward' }}", + "turn_on": {"service": "script.fan_on"}, + "turn_off": {"service": "script.fan_off"}, + } + }, + } + }, + ], +) +async def test_availability_template_with_entities(hass, start_ha): + """Test availability tempalates with values from other entities.""" + for state, test_assert in [(STATE_ON, True), (STATE_OFF, False)]: + hass.states.async_set(_STATE_AVAILABILITY_BOOLEAN, state) + await hass.async_block_till_done() + assert (hass.states.get(_TEST_FAN).state != STATE_UNAVAILABLE) == test_assert - with assert_setup_component(1, "fan"): - assert await setup.async_setup_component( - hass, - "fan", + +@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) +@pytest.mark.parametrize( + "config, states", + [ + ( { - "fan": { + DOMAIN: { "platform": "template", "fans": { "test_fan": { @@ -375,23 +296,11 @@ async def test_template_with_unavailable_entities(hass, calls): }, } }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - assert hass.states.get(_TEST_FAN).state == STATE_OFF - - -async def test_template_with_unavailable_parameters(hass, calls): - """Test unavailability of speed, direction and oscillating parameters.""" - - with assert_setup_component(1, "fan"): - assert await setup.async_setup_component( - hass, - "fan", + [STATE_OFF, None, None, None, None], + ), + ( { - "fan": { + DOMAIN: { "platform": "template", "fans": { "test_fan": { @@ -405,67 +314,11 @@ async def test_template_with_unavailable_parameters(hass, calls): }, } }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - _verify(hass, STATE_ON, None, 0, None, None, None) - - -async def test_availability_template_with_entities(hass, calls): - """Test availability tempalates with values from other entities.""" - - with assert_setup_component(1, "fan"): - assert await setup.async_setup_component( - hass, - "fan", + [STATE_ON, None, 0, None, None], + ), + ( { - "fan": { - "platform": "template", - "fans": { - "test_fan": { - "availability_template": "{{ is_state('availability_boolean.state', 'on') }}", - "value_template": "{{ 'on' }}", - "speed_template": "{{ 'medium' }}", - "oscillating_template": "{{ 1 == 1 }}", - "direction_template": "{{ 'forward' }}", - "turn_on": {"service": "script.fan_on"}, - "turn_off": {"service": "script.fan_off"}, - } - }, - } - }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - # When template returns true.. - hass.states.async_set(_STATE_AVAILABILITY_BOOLEAN, STATE_ON) - await hass.async_block_till_done() - - # Device State should not be unavailable - assert hass.states.get(_TEST_FAN).state != STATE_UNAVAILABLE - - # When Availability template returns false - hass.states.async_set(_STATE_AVAILABILITY_BOOLEAN, STATE_OFF) - await hass.async_block_till_done() - - # device state should be unavailable - assert hass.states.get(_TEST_FAN).state == STATE_UNAVAILABLE - - -async def test_templates_with_valid_values(hass, calls): - """Test templates with valid values.""" - with assert_setup_component(1, "fan"): - assert await setup.async_setup_component( - hass, - "fan", - { - "fan": { + DOMAIN: { "platform": "template", "fans": { "test_fan": { @@ -479,23 +332,11 @@ async def test_templates_with_valid_values(hass, calls): }, } }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - _verify(hass, STATE_ON, SPEED_MEDIUM, 66, True, DIRECTION_FORWARD, None) - - -async def test_templates_invalid_values(hass, calls): - """Test templates with invalid values.""" - with assert_setup_component(1, "fan"): - assert await setup.async_setup_component( - hass, - "fan", + [STATE_ON, SPEED_MEDIUM, 66, True, DIRECTION_FORWARD], + ), + ( { - "fan": { + DOMAIN: { "platform": "template", "fans": { "test_fan": { @@ -509,437 +350,249 @@ async def test_templates_invalid_values(hass, calls): }, } }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - _verify(hass, STATE_OFF, None, 0, None, None, None) + [STATE_OFF, None, 0, None, None], + ), + ], +) +async def test_template_with_unavailable_entities(hass, states, start_ha): + """Test unavailability with value_template.""" + _verify(hass, states[0], states[1], states[2], states[3], states[4], None) -async def test_invalid_availability_template_keeps_component_available(hass, caplog): +@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ + { + DOMAIN: { + "platform": "template", + "fans": { + "test_fan": { + "value_template": "{{ 'on' }}", + "availability_template": "{{ x - 12 }}", + "speed_template": "{{ states('input_select.speed') }}", + "preset_mode_template": "{{ states('input_select.preset_mode') }}", + "oscillating_template": "{{ states('input_select.osc') }}", + "direction_template": "{{ states('input_select.direction') }}", + "turn_on": {"service": "script.fan_on"}, + "turn_off": {"service": "script.fan_off"}, + } + }, + } + }, + ], +) +async def test_invalid_availability_template_keeps_component_available( + hass, start_ha, caplog_setup_text +): """Test that an invalid availability keeps the device available.""" - - with assert_setup_component(1, "fan"): - assert await setup.async_setup_component( - hass, - "fan", - { - "fan": { - "platform": "template", - "fans": { - "test_fan": { - "value_template": "{{ 'on' }}", - "availability_template": "{{ x - 12 }}", - "speed_template": "{{ states('input_select.speed') }}", - "preset_mode_template": "{{ states('input_select.preset_mode') }}", - "oscillating_template": "{{ states('input_select.osc') }}", - "direction_template": "{{ states('input_select.direction') }}", - "turn_on": {"service": "script.fan_on"}, - "turn_off": {"service": "script.fan_off"}, - } - }, - } - }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - assert hass.states.get("fan.test_fan").state != STATE_UNAVAILABLE - - assert "TemplateError" in caplog.text - assert "x" in caplog.text + assert "TemplateError" in caplog_setup_text + assert "x" in caplog_setup_text -# End of template tests # - - -# Function tests # -async def test_on_off(hass, calls): +async def test_on_off(hass): """Test turn on and turn off.""" await _register_components(hass) - # Turn on fan - await common.async_turn_on(hass, _TEST_FAN) - - # verify - assert hass.states.get(_STATE_INPUT_BOOLEAN).state == STATE_ON - _verify(hass, STATE_ON, None, 0, None, None, None) - - # Turn off fan - await common.async_turn_off(hass, _TEST_FAN) - - # verify - assert hass.states.get(_STATE_INPUT_BOOLEAN).state == STATE_OFF - _verify(hass, STATE_OFF, None, 0, None, None, None) + for func, state in [ + (common.async_turn_on, STATE_ON), + (common.async_turn_off, STATE_OFF), + ]: + await func(hass, _TEST_FAN) + assert hass.states.get(_STATE_INPUT_BOOLEAN).state == state + _verify(hass, state, None, 0, None, None, None) -async def test_on_with_speed(hass, calls): - """Test turn on with speed.""" - await _register_components(hass) - - # Turn on fan with high speed - await common.async_turn_on(hass, _TEST_FAN, SPEED_HIGH) - - # verify - assert hass.states.get(_STATE_INPUT_BOOLEAN).state == STATE_ON - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 100 - _verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None) - - -async def test_set_speed(hass, calls): +async def test_set_speed(hass): """Test set valid speed.""" await _register_components(hass, preset_modes=["auto", "smart"]) - # Turn on fan await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's speed to high - await common.async_set_speed(hass, _TEST_FAN, SPEED_HIGH) - - # verify - assert hass.states.get(_SPEED_INPUT_SELECT).state == SPEED_HIGH - _verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None) - - # Set fan's speed to medium - await common.async_set_speed(hass, _TEST_FAN, SPEED_MEDIUM) - - # verify - assert hass.states.get(_SPEED_INPUT_SELECT).state == SPEED_MEDIUM - _verify(hass, STATE_ON, SPEED_MEDIUM, 66, None, None, None) - - # Set fan's speed to off - await common.async_set_speed(hass, _TEST_FAN, SPEED_OFF) - - # verify - assert hass.states.get(_SPEED_INPUT_SELECT).state == SPEED_OFF - _verify(hass, STATE_OFF, SPEED_OFF, 0, None, None, None) + for cmd, t_state, type, state, value in [ + (SPEED_HIGH, SPEED_HIGH, SPEED_HIGH, STATE_ON, 100), + (SPEED_MEDIUM, SPEED_MEDIUM, SPEED_MEDIUM, STATE_ON, 66), + (SPEED_OFF, SPEED_OFF, SPEED_OFF, STATE_OFF, 0), + (SPEED_MEDIUM, SPEED_MEDIUM, SPEED_MEDIUM, STATE_ON, 66), + ("invalid", SPEED_MEDIUM, SPEED_MEDIUM, STATE_ON, 66), + ]: + await common.async_set_speed(hass, _TEST_FAN, cmd) + assert hass.states.get(_SPEED_INPUT_SELECT).state == t_state + _verify(hass, state, type, value, None, None, None) -async def test_set_percentage(hass, calls): - """Test set valid speed percentage.""" - await _register_components(hass) - - # Turn on fan - await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's percentage speed to 100 - await common.async_set_percentage(hass, _TEST_FAN, 100) - - # verify - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 100 - - _verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None) - - # Set fan's percentage speed to 66 - await common.async_set_percentage(hass, _TEST_FAN, 66) - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 66 - - _verify(hass, STATE_ON, SPEED_MEDIUM, 66, None, None, None) - - # Set fan's percentage speed to 0 - await common.async_set_percentage(hass, _TEST_FAN, 0) - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 0 - - _verify(hass, STATE_OFF, SPEED_OFF, 0, None, None, None) - - # Set fan's percentage speed to 50 - await common.async_turn_on(hass, _TEST_FAN, percentage=50) - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 50 - - _verify(hass, STATE_ON, SPEED_MEDIUM, 50, None, None, None) - - -async def test_increase_decrease_speed(hass, calls): - """Test set valid increase and decrease speed.""" - await _register_components(hass, speed_count=3) - - # Turn on fan - await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's percentage speed to 100 - await common.async_set_percentage(hass, _TEST_FAN, 100) - - # verify - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 100 - - _verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None) - - # Set fan's percentage speed to 66 - await common.async_decrease_speed(hass, _TEST_FAN) - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 66 - - _verify(hass, STATE_ON, SPEED_MEDIUM, 66, None, None, None) - - # Set fan's percentage speed to 33 - await common.async_decrease_speed(hass, _TEST_FAN) - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 33 - - _verify(hass, STATE_ON, SPEED_LOW, 33, None, None, None) - - # Set fan's percentage speed to 0 - await common.async_decrease_speed(hass, _TEST_FAN) - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 0 - - _verify(hass, STATE_OFF, SPEED_OFF, 0, None, None, None) - - # Set fan's percentage speed to 33 - await common.async_increase_speed(hass, _TEST_FAN) - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 33 - - _verify(hass, STATE_ON, SPEED_LOW, 33, None, None, None) - - -async def test_increase_decrease_speed_default_speed_count(hass, calls): - """Test set valid increase and decrease speed.""" - await _register_components( - hass, - ) - - # Turn on fan - await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's percentage speed to 100 - await common.async_set_percentage(hass, _TEST_FAN, 100) - - # verify - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 100 - - _verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None) - - # Set fan's percentage speed to 99 - await common.async_decrease_speed(hass, _TEST_FAN) - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 99 - - _verify(hass, STATE_ON, SPEED_HIGH, 99, None, None, None) - - # Set fan's percentage speed to 98 - await common.async_decrease_speed(hass, _TEST_FAN) - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 98 - - _verify(hass, STATE_ON, SPEED_HIGH, 98, None, None, None) - - for _ in range(32): - await common.async_decrease_speed(hass, _TEST_FAN) - assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 66 - - _verify(hass, STATE_ON, SPEED_MEDIUM, 66, None, None, None) - - -async def test_set_invalid_speed_from_initial_stage(hass, calls): - """Test set invalid speed when fan is in initial state.""" - await _register_components(hass) - - # Turn on fan - await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's speed to 'invalid' - await common.async_set_speed(hass, _TEST_FAN, "invalid") - - # verify speed is unchanged - assert hass.states.get(_SPEED_INPUT_SELECT).state == "" - _verify(hass, STATE_ON, None, 0, None, None, None) - - -async def test_set_invalid_speed(hass, calls): +async def test_set_invalid_speed(hass): """Test set invalid speed when fan has valid speed.""" await _register_components(hass) - # Turn on fan await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's speed to high - await common.async_set_speed(hass, _TEST_FAN, SPEED_HIGH) - - # verify - assert hass.states.get(_SPEED_INPUT_SELECT).state == SPEED_HIGH - _verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None) - - # Set fan's speed to 'invalid' - await common.async_set_speed(hass, _TEST_FAN, "invalid") - - # verify speed is unchanged - assert hass.states.get(_SPEED_INPUT_SELECT).state == SPEED_HIGH - _verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None) + for extra in [SPEED_HIGH, "invalid"]: + await common.async_set_speed(hass, _TEST_FAN, extra) + assert hass.states.get(_SPEED_INPUT_SELECT).state == SPEED_HIGH + _verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None) -async def test_custom_speed_list(hass, calls): +async def test_custom_speed_list(hass): """Test set custom speed list.""" await _register_components(hass, ["1", "2", "3"]) - # Turn on fan await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's speed to '1' - await common.async_set_speed(hass, _TEST_FAN, "1") - - # verify - assert hass.states.get(_SPEED_INPUT_SELECT).state == "1" - _verify(hass, STATE_ON, "1", 33, None, None, None) - - # Set fan's speed to 'medium' which is invalid - await common.async_set_speed(hass, _TEST_FAN, SPEED_MEDIUM) - - # verify that speed is unchanged - assert hass.states.get(_SPEED_INPUT_SELECT).state == "1" - _verify(hass, STATE_ON, "1", 33, None, None, None) - - -async def test_preset_modes(hass, calls): - """Test preset_modes.""" - await _register_components( - hass, ["off", "low", "medium", "high", "auto", "smart"], ["auto", "smart"] - ) - - # Turn on fan - await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's preset_mode to "auto" - await common.async_set_preset_mode(hass, _TEST_FAN, "auto") - - # verify - assert hass.states.get(_PRESET_MODE_INPUT_SELECT).state == "auto" - - # Set fan's preset_mode to "smart" - await common.async_set_preset_mode(hass, _TEST_FAN, "smart") - - # Verify fan's preset_mode is "smart" - assert hass.states.get(_PRESET_MODE_INPUT_SELECT).state == "smart" - - # Set fan's preset_mode to "invalid" - await common.async_set_preset_mode(hass, _TEST_FAN, "invalid") - - # Verify fan's preset_mode is still "smart" - assert hass.states.get(_PRESET_MODE_INPUT_SELECT).state == "smart" - - # Set fan's preset_mode to "auto" - await common.async_turn_on(hass, _TEST_FAN, preset_mode="auto") - - # verify - assert hass.states.get(_PRESET_MODE_INPUT_SELECT).state == "auto" - - -async def test_set_osc(hass, calls): - """Test set oscillating.""" - await _register_components(hass) - - # Turn on fan - await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's osc to True - await common.async_oscillate(hass, _TEST_FAN, True) - - # verify - assert hass.states.get(_OSC_INPUT).state == "True" - _verify(hass, STATE_ON, None, 0, True, None, None) - - # Set fan's osc to False - await common.async_oscillate(hass, _TEST_FAN, False) - - # verify - assert hass.states.get(_OSC_INPUT).state == "False" - _verify(hass, STATE_ON, None, 0, False, None, None) - - -async def test_set_invalid_osc_from_initial_state(hass, calls): - """Test set invalid oscillating when fan is in initial state.""" - await _register_components(hass) - - # Turn on fan - await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's osc to 'invalid' - with pytest.raises(vol.Invalid): - await common.async_oscillate(hass, _TEST_FAN, "invalid") - - # verify - assert hass.states.get(_OSC_INPUT).state == "" - _verify(hass, STATE_ON, None, 0, None, None, None) - - -async def test_set_invalid_osc(hass, calls): - """Test set invalid oscillating when fan has valid osc.""" - await _register_components(hass) - - # Turn on fan - await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's osc to True - await common.async_oscillate(hass, _TEST_FAN, True) - - # verify - assert hass.states.get(_OSC_INPUT).state == "True" - _verify(hass, STATE_ON, None, 0, True, None, None) - - # Set fan's osc to None - with pytest.raises(vol.Invalid): - await common.async_oscillate(hass, _TEST_FAN, None) - - # verify osc is unchanged - assert hass.states.get(_OSC_INPUT).state == "True" - _verify(hass, STATE_ON, None, 0, True, None, None) - - -async def test_set_direction(hass, calls): - """Test set valid direction.""" - await _register_components(hass) - - # Turn on fan - await common.async_turn_on(hass, _TEST_FAN) - - # Set fan's direction to forward - await common.async_set_direction(hass, _TEST_FAN, DIRECTION_FORWARD) - - # verify - assert hass.states.get(_DIRECTION_INPUT_SELECT).state == DIRECTION_FORWARD - _verify(hass, STATE_ON, None, 0, None, DIRECTION_FORWARD, None) - - # Set fan's direction to reverse - await common.async_set_direction(hass, _TEST_FAN, DIRECTION_REVERSE) - - # verify - assert hass.states.get(_DIRECTION_INPUT_SELECT).state == DIRECTION_REVERSE - _verify(hass, STATE_ON, None, 0, None, DIRECTION_REVERSE, None) + for extra in ["1", SPEED_MEDIUM]: + await common.async_set_speed(hass, _TEST_FAN, extra) + assert hass.states.get(_SPEED_INPUT_SELECT).state == "1" + _verify(hass, STATE_ON, "1", 33, None, None, None) async def test_set_invalid_direction_from_initial_stage(hass, calls): """Test set invalid direction when fan is in initial state.""" await _register_components(hass) - # Turn on fan await common.async_turn_on(hass, _TEST_FAN) - # Set fan's direction to 'invalid' await common.async_set_direction(hass, _TEST_FAN, "invalid") - - # verify direction is unchanged assert hass.states.get(_DIRECTION_INPUT_SELECT).state == "" _verify(hass, STATE_ON, None, 0, None, None, None) -async def test_set_invalid_direction(hass, calls): +async def test_set_osc(hass): + """Test set oscillating.""" + await _register_components(hass) + + await common.async_turn_on(hass, _TEST_FAN) + for state in [True, False]: + await common.async_oscillate(hass, _TEST_FAN, state) + assert hass.states.get(_OSC_INPUT).state == str(state) + _verify(hass, STATE_ON, None, 0, state, None, None) + + +async def test_set_direction(hass): + """Test set valid direction.""" + await _register_components(hass) + + await common.async_turn_on(hass, _TEST_FAN) + for cmd in [DIRECTION_FORWARD, DIRECTION_REVERSE]: + await common.async_set_direction(hass, _TEST_FAN, cmd) + assert hass.states.get(_DIRECTION_INPUT_SELECT).state == cmd + _verify(hass, STATE_ON, None, 0, None, cmd, None) + + +async def test_set_invalid_direction(hass): """Test set invalid direction when fan has valid direction.""" await _register_components(hass) - # Turn on fan await common.async_turn_on(hass, _TEST_FAN) + for cmd in [DIRECTION_FORWARD, "invalid"]: + await common.async_set_direction(hass, _TEST_FAN, cmd) + assert hass.states.get(_DIRECTION_INPUT_SELECT).state == DIRECTION_FORWARD + _verify(hass, STATE_ON, None, 0, None, DIRECTION_FORWARD, None) - # Set fan's direction to forward - await common.async_set_direction(hass, _TEST_FAN, DIRECTION_FORWARD) - # verify - assert hass.states.get(_DIRECTION_INPUT_SELECT).state == DIRECTION_FORWARD - _verify(hass, STATE_ON, None, 0, None, DIRECTION_FORWARD, None) +async def test_on_with_speed(hass): + """Test turn on with speed.""" + await _register_components(hass) - # Set fan's direction to 'invalid' - await common.async_set_direction(hass, _TEST_FAN, "invalid") + await common.async_turn_on(hass, _TEST_FAN, SPEED_HIGH) + assert hass.states.get(_STATE_INPUT_BOOLEAN).state == STATE_ON + assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 100 + _verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None) - # verify direction is unchanged - assert hass.states.get(_DIRECTION_INPUT_SELECT).state == DIRECTION_FORWARD - _verify(hass, STATE_ON, None, 0, None, DIRECTION_FORWARD, None) + +async def test_preset_modes(hass): + """Test preset_modes.""" + await _register_components( + hass, ["off", "low", "medium", "high", "auto", "smart"], ["auto", "smart"] + ) + + await common.async_turn_on(hass, _TEST_FAN) + for extra, state in [ + ("auto", "auto"), + ("smart", "smart"), + ("invalid", "smart"), + ]: + await common.async_set_preset_mode(hass, _TEST_FAN, extra) + assert hass.states.get(_PRESET_MODE_INPUT_SELECT).state == state + + await common.async_turn_on(hass, _TEST_FAN, preset_mode="auto") + assert hass.states.get(_PRESET_MODE_INPUT_SELECT).state == "auto" + + +async def test_set_percentage(hass): + """Test set valid speed percentage.""" + await _register_components(hass) + + await common.async_turn_on(hass, _TEST_FAN) + for type, state, value in [ + (SPEED_HIGH, STATE_ON, 100), + (SPEED_MEDIUM, STATE_ON, 66), + (SPEED_OFF, STATE_OFF, 0), + ]: + await common.async_set_percentage(hass, _TEST_FAN, value) + assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == value + _verify(hass, state, type, value, None, None, None) + + await common.async_turn_on(hass, _TEST_FAN, percentage=50) + assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 50 + _verify(hass, STATE_ON, SPEED_MEDIUM, 50, None, None, None) + + +async def test_increase_decrease_speed(hass): + """Test set valid increase and decrease speed.""" + await _register_components(hass, speed_count=3) + + await common.async_turn_on(hass, _TEST_FAN) + for func, extra, state, type, value in [ + (common.async_set_percentage, 100, STATE_ON, SPEED_HIGH, 100), + (common.async_decrease_speed, None, STATE_ON, SPEED_MEDIUM, 66), + (common.async_decrease_speed, None, STATE_ON, SPEED_LOW, 33), + (common.async_decrease_speed, None, STATE_OFF, SPEED_OFF, 0), + (common.async_increase_speed, None, STATE_ON, SPEED_LOW, 33), + ]: + await func(hass, _TEST_FAN, extra) + assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == value + _verify(hass, state, type, value, None, None, None) + + +async def test_increase_decrease_speed_default_speed_count(hass): + """Test set valid increase and decrease speed.""" + await _register_components(hass) + + await common.async_turn_on(hass, _TEST_FAN) + for func, extra, state, type, value in [ + (common.async_set_percentage, 100, STATE_ON, SPEED_HIGH, 100), + (common.async_decrease_speed, None, STATE_ON, SPEED_HIGH, 99), + (common.async_decrease_speed, None, STATE_ON, SPEED_HIGH, 98), + (common.async_decrease_speed, 31, STATE_ON, SPEED_HIGH, 67), + (common.async_decrease_speed, None, STATE_ON, SPEED_MEDIUM, 66), + ]: + await func(hass, _TEST_FAN, extra) + assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == value + _verify(hass, state, type, value, None, None, None) + + +async def test_set_invalid_osc_from_initial_state(hass): + """Test set invalid oscillating when fan is in initial state.""" + await _register_components(hass) + + await common.async_turn_on(hass, _TEST_FAN) + with pytest.raises(vol.Invalid): + await common.async_oscillate(hass, _TEST_FAN, "invalid") + assert hass.states.get(_OSC_INPUT).state == "" + _verify(hass, STATE_ON, None, 0, None, None, None) + + +async def test_set_invalid_osc(hass): + """Test set invalid oscillating when fan has valid osc.""" + await _register_components(hass) + + await common.async_turn_on(hass, _TEST_FAN) + await common.async_oscillate(hass, _TEST_FAN, True) + assert hass.states.get(_OSC_INPUT).state == "True" + _verify(hass, STATE_ON, None, 0, True, None, None) + + with pytest.raises(vol.Invalid): + await common.async_oscillate(hass, _TEST_FAN, None) + assert hass.states.get(_OSC_INPUT).state == "True" + _verify(hass, STATE_ON, None, 0, True, None, None) def _verify( @@ -1103,13 +756,12 @@ async def _register_components( await hass.async_block_till_done() -async def test_unique_id(hass): - """Test unique_id option only creates one fan per id.""" - await setup.async_setup_component( - hass, - "fan", +@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ { - "fan": { + DOMAIN: { "platform": "template", "fans": { "test_template_fan_01": { @@ -1137,14 +789,12 @@ 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 fan per id.""" assert len(hass.states.async_all()) == 1 @@ -1221,13 +871,12 @@ async def test_implemented_percentage(hass, speed_count, percentage_step): assert attributes["percentage_step"] == percentage_step -async def test_implemented_preset_mode(hass): - """Test a fan that implements preset_mode.""" - await setup.async_setup_component( - hass, - "fan", +@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ { - "fan": { + DOMAIN: { "platform": "template", "fans": { "mechanical_ventilation": { @@ -1276,14 +925,12 @@ async def test_implemented_preset_mode(hass): ], }, }, - }, + } }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - + ], +) +async def test_implemented_preset_mode(hass, start_ha): + """Test a fan that implements preset_mode.""" assert len(hass.states.async_all()) == 1 state = hass.states.get("fan.mechanical_ventilation") @@ -1291,13 +938,12 @@ async def test_implemented_preset_mode(hass): assert attributes["percentage"] is None -async def test_implemented_speed(hass): - """Test a fan that implements speed.""" - await setup.async_setup_component( - hass, - "fan", +@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) +@pytest.mark.parametrize( + "config", + [ { - "fan": { + DOMAIN: { "platform": "template", "fans": { "mechanical_ventilation": { @@ -1346,14 +992,12 @@ async def test_implemented_speed(hass): ], }, }, - }, + } }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - + ], +) +async def test_implemented_speed(hass, start_ha): + """Test a fan that implements speed.""" assert len(hass.states.async_all()) == 1 state = hass.states.get("fan.mechanical_ventilation")