diff --git a/.coveragerc b/.coveragerc index d3465668bfb..322c7e1af48 100644 --- a/.coveragerc +++ b/.coveragerc @@ -873,9 +873,6 @@ omit = homeassistant/components/rest/switch.py homeassistant/components/ring/camera.py homeassistant/components/ripple/sensor.py - homeassistant/components/rituals_perfume_genie/binary_sensor.py - homeassistant/components/rituals_perfume_genie/number.py - homeassistant/components/rituals_perfume_genie/select.py homeassistant/components/rocketchat/notify.py homeassistant/components/roomba/__init__.py homeassistant/components/roomba/binary_sensor.py diff --git a/tests/components/rituals_perfume_genie/common.py b/tests/components/rituals_perfume_genie/common.py index 35555e2b842..1f12d3e651e 100644 --- a/tests/components/rituals_perfume_genie/common.py +++ b/tests/components/rituals_perfume_genie/common.py @@ -10,12 +10,12 @@ from homeassistant.core import HomeAssistant from tests.common import MockConfigEntry -def mock_config_entry(uniqe_id: str, entry_id: str = "an_entry_id") -> MockConfigEntry: +def mock_config_entry(unique_id: str, entry_id: str = "an_entry_id") -> MockConfigEntry: """Return a mock Config Entry for the Rituals Perfume Genie integration.""" return MockConfigEntry( domain=DOMAIN, title="name@example.com", - unique_id=uniqe_id, + unique_id=unique_id, data={ACCOUNT_HASH: "an_account_hash"}, entry_id=entry_id, ) @@ -32,6 +32,8 @@ def mock_diffuser( is_on: bool = True, name: str = "Genie", perfume: str = "Ritual of Sakura", + perfume_amount: int = 2, + room_size_square_meter: int = 60, version: str = "4.0", wifi_percentage: int = 75, ) -> MagicMock: @@ -47,6 +49,10 @@ def mock_diffuser( diffuser_mock.is_on = is_on diffuser_mock.name = name diffuser_mock.perfume = perfume + diffuser_mock.perfume_amount = perfume_amount + diffuser_mock.room_size_square_meter = room_size_square_meter + diffuser_mock.set_perfume_amount = AsyncMock() + diffuser_mock.set_room_size_square_meter = AsyncMock() diffuser_mock.turn_off = AsyncMock() diffuser_mock.turn_on = AsyncMock() diffuser_mock.update_data = AsyncMock() @@ -55,12 +61,12 @@ def mock_diffuser( return diffuser_mock -def mock_diffuser_v1_battery_cartridge(): +def mock_diffuser_v1_battery_cartridge() -> MagicMock: """Create and return a mock version 1 Diffuser with battery and a cartridge.""" return mock_diffuser(hublot="lot123v1") -def mock_diffuser_v2_no_battery_no_cartridge(): +def mock_diffuser_v2_no_battery_no_cartridge() -> MagicMock: """Create and return a mock version 2 Diffuser without battery and cartridge.""" return mock_diffuser( hublot="lot123v2", diff --git a/tests/components/rituals_perfume_genie/test_binary_sensor.py b/tests/components/rituals_perfume_genie/test_binary_sensor.py new file mode 100644 index 00000000000..f2e499655ca --- /dev/null +++ b/tests/components/rituals_perfume_genie/test_binary_sensor.py @@ -0,0 +1,30 @@ +"""Tests for the Rituals Perfume Genie binary sensor platform.""" +from homeassistant.components.binary_sensor import DEVICE_CLASS_BATTERY_CHARGING +from homeassistant.components.rituals_perfume_genie.binary_sensor import CHARGING_SUFFIX +from homeassistant.const import ATTR_DEVICE_CLASS, STATE_ON +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry + +from .common import ( + init_integration, + mock_config_entry, + mock_diffuser_v1_battery_cartridge, +) + + +async def test_binary_sensors(hass: HomeAssistant) -> None: + """Test the creation and values of the Rituals Perfume Genie binary sensor.""" + config_entry = mock_config_entry(unique_id="binary_sensor_test_diffuser_v1") + diffuser = mock_diffuser_v1_battery_cartridge() + await init_integration(hass, config_entry, [diffuser]) + registry = entity_registry.async_get(hass) + hublot = diffuser.hublot + + state = hass.states.get("binary_sensor.genie_battery_charging") + assert state + assert state.state == STATE_ON + assert state.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_BATTERY_CHARGING + + entry = registry.async_get("binary_sensor.genie_battery_charging") + assert entry + assert entry.unique_id == f"{hublot}{CHARGING_SUFFIX}" diff --git a/tests/components/rituals_perfume_genie/test_init.py b/tests/components/rituals_perfume_genie/test_init.py index 887417a41f8..ea79a99da0e 100644 --- a/tests/components/rituals_perfume_genie/test_init.py +++ b/tests/components/rituals_perfume_genie/test_init.py @@ -12,7 +12,7 @@ from .common import init_integration, mock_config_entry async def test_config_entry_not_ready(hass: HomeAssistant): """Test the Rituals configuration entry setup if connection to Rituals is missing.""" - config_entry = mock_config_entry(uniqe_id="id_123_not_ready") + config_entry = mock_config_entry(unique_id="id_123_not_ready") config_entry.add_to_hass(hass) with patch( "homeassistant.components.rituals_perfume_genie.Account.get_devices", @@ -24,7 +24,7 @@ async def test_config_entry_not_ready(hass: HomeAssistant): async def test_config_entry_unload(hass: HomeAssistant) -> None: """Test the Rituals Perfume Genie configuration entry setup and unloading.""" - config_entry = mock_config_entry(uniqe_id="id_123_unload") + config_entry = mock_config_entry(unique_id="id_123_unload") await init_integration(hass, config_entry) await hass.config_entries.async_unload(config_entry.entry_id) diff --git a/tests/components/rituals_perfume_genie/test_number.py b/tests/components/rituals_perfume_genie/test_number.py new file mode 100644 index 00000000000..fc3937897b9 --- /dev/null +++ b/tests/components/rituals_perfume_genie/test_number.py @@ -0,0 +1,161 @@ +"""Tests for the Rituals Perfume Genie number platform.""" +from __future__ import annotations + +import pytest + +from homeassistant.components.homeassistant import SERVICE_UPDATE_ENTITY +from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN +from homeassistant.components.number.const import ( + ATTR_MAX, + ATTR_MIN, + ATTR_VALUE, + SERVICE_SET_VALUE, +) +from homeassistant.components.rituals_perfume_genie.number import ( + MAX_PERFUME_AMOUNT, + MIN_PERFUME_AMOUNT, + PERFUME_AMOUNT_SUFFIX, +) +from homeassistant.const import ATTR_ENTITY_ID, ATTR_ICON +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry +from homeassistant.setup import async_setup_component + +from .common import ( + init_integration, + mock_config_entry, + mock_diffuser, + mock_diffuser_v1_battery_cartridge, +) + + +async def test_number_entity(hass: HomeAssistant) -> None: + """Test the creation and values of the diffuser number entity.""" + config_entry = mock_config_entry(unique_id="number_test") + diffuser = mock_diffuser(hublot="lot123", perfume_amount=2) + await init_integration(hass, config_entry, [diffuser]) + + registry = entity_registry.async_get(hass) + + state = hass.states.get("number.genie_perfume_amount") + assert state + assert state.state == str(diffuser.perfume_amount) + assert state.attributes[ATTR_ICON] == "mdi:gauge" + assert state.attributes[ATTR_MIN] == MIN_PERFUME_AMOUNT + assert state.attributes[ATTR_MAX] == MAX_PERFUME_AMOUNT + + entry = registry.async_get("number.genie_perfume_amount") + assert entry + assert entry.unique_id == f"{diffuser.hublot}{PERFUME_AMOUNT_SUFFIX}" + + +async def test_set_number_value(hass: HomeAssistant) -> None: + """Test setting the diffuser number entity value.""" + config_entry = mock_config_entry(unique_id="number_set_value_test") + diffuser = mock_diffuser_v1_battery_cartridge() + await init_integration(hass, config_entry, [diffuser]) + await async_setup_component(hass, "homeassistant", {}) + diffuser.perfume_amount = 1 + + state = hass.states.get("number.genie_perfume_amount") + assert state + assert state.state == "2" + + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + {ATTR_ENTITY_ID: "number.genie_perfume_amount", ATTR_VALUE: 1}, + blocking=True, + ) + await hass.services.async_call( + "homeassistant", + SERVICE_UPDATE_ENTITY, + {ATTR_ENTITY_ID: ["number.genie_perfume_amount"]}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get("number.genie_perfume_amount") + assert state + assert state.state == "1" + + +async def test_set_number_value_out_of_range(hass: HomeAssistant): + """Test setting the diffuser number entity value out of range.""" + config_entry = mock_config_entry(unique_id="number_set_value_out_of_range_test") + diffuser = mock_diffuser(hublot="lot123", perfume_amount=2) + await init_integration(hass, config_entry, [diffuser]) + await async_setup_component(hass, "homeassistant", {}) + + state = hass.states.get("number.genie_perfume_amount") + assert state + assert state.state == "2" + + with pytest.raises(ValueError): + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + {ATTR_ENTITY_ID: "number.genie_perfume_amount", ATTR_VALUE: 4}, + blocking=True, + ) + await hass.services.async_call( + "homeassistant", + SERVICE_UPDATE_ENTITY, + {ATTR_ENTITY_ID: ["number.genie_perfume_amount"]}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get("number.genie_perfume_amount") + assert state + assert state.state == "2" + + with pytest.raises(ValueError): + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + {ATTR_ENTITY_ID: "number.genie_perfume_amount", ATTR_VALUE: 0}, + blocking=True, + ) + await hass.services.async_call( + "homeassistant", + SERVICE_UPDATE_ENTITY, + {ATTR_ENTITY_ID: ["number.genie_perfume_amount"]}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get("number.genie_perfume_amount") + assert state + assert state.state == "2" + + +async def test_set_number_value_to_float(hass: HomeAssistant): + """Test setting the diffuser number entity value to a float.""" + config_entry = mock_config_entry(unique_id="number_set_value_to_float_test") + diffuser = mock_diffuser(hublot="lot123", perfume_amount=3) + await init_integration(hass, config_entry, [diffuser]) + await async_setup_component(hass, "homeassistant", {}) + + state = hass.states.get("number.genie_perfume_amount") + assert state + assert state.state == "3" + + with pytest.raises(ValueError): + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + {ATTR_ENTITY_ID: "number.genie_perfume_amount", ATTR_VALUE: 1.5}, + blocking=True, + ) + await hass.services.async_call( + "homeassistant", + SERVICE_UPDATE_ENTITY, + {ATTR_ENTITY_ID: ["number.genie_perfume_amount"]}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get("number.genie_perfume_amount") + assert state + assert state.state == "3" diff --git a/tests/components/rituals_perfume_genie/test_select.py b/tests/components/rituals_perfume_genie/test_select.py new file mode 100644 index 00000000000..fb159166fb7 --- /dev/null +++ b/tests/components/rituals_perfume_genie/test_select.py @@ -0,0 +1,100 @@ +"""Tests for the Rituals Perfume Genie select platform.""" +import pytest + +from homeassistant.components.homeassistant import SERVICE_UPDATE_ENTITY +from homeassistant.components.rituals_perfume_genie.select import ROOM_SIZE_SUFFIX +from homeassistant.components.select import DOMAIN as SELECT_DOMAIN +from homeassistant.components.select.const import ATTR_OPTION, ATTR_OPTIONS +from homeassistant.const import ( + AREA_SQUARE_METERS, + ATTR_ENTITY_ID, + ATTR_ICON, + SERVICE_SELECT_OPTION, +) +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry +from homeassistant.setup import async_setup_component + +from .common import init_integration, mock_config_entry, mock_diffuser + + +async def test_select_entity(hass: HomeAssistant) -> None: + """Test the creation and state of the diffuser select entity.""" + config_entry = mock_config_entry(unique_id="select_test") + diffuser = mock_diffuser(hublot="lot123", room_size_square_meter=60) + await init_integration(hass, config_entry, [diffuser]) + + registry = entity_registry.async_get(hass) + + state = hass.states.get("select.genie_room_size") + assert state + assert state.state == str(diffuser.room_size_square_meter) + assert state.attributes[ATTR_ICON] == "mdi:ruler-square" + assert state.attributes[ATTR_OPTIONS] == ["15", "30", "60", "100"] + + entry = registry.async_get("select.genie_room_size") + assert entry + assert entry.unique_id == f"{diffuser.hublot}{ROOM_SIZE_SUFFIX}" + assert entry.unit_of_measurement == AREA_SQUARE_METERS + + +async def test_select_option(hass: HomeAssistant) -> None: + """Test selecting of a option.""" + config_entry = mock_config_entry(unique_id="select_invalid_option_test") + diffuser = mock_diffuser(hublot="lot123", room_size_square_meter=60) + await init_integration(hass, config_entry, [diffuser]) + await async_setup_component(hass, "homeassistant", {}) + diffuser.room_size_square_meter = 30 + + state = hass.states.get("select.genie_room_size") + assert state + assert state.state == "60" + + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + {ATTR_ENTITY_ID: "select.genie_room_size", ATTR_OPTION: "30"}, + blocking=True, + ) + await hass.services.async_call( + "homeassistant", + SERVICE_UPDATE_ENTITY, + {ATTR_ENTITY_ID: ["select.genie_room_size"]}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get("select.genie_room_size") + assert state + assert state.state == "30" + + +async def test_select_invalid_option(hass: HomeAssistant) -> None: + """Test selecting an invalid option.""" + config_entry = mock_config_entry(unique_id="select_invalid_option_test") + diffuser = mock_diffuser(hublot="lot123", room_size_square_meter=60) + await init_integration(hass, config_entry, [diffuser]) + await async_setup_component(hass, "homeassistant", {}) + + state = hass.states.get("select.genie_room_size") + assert state + assert state.state == "60" + + with pytest.raises(ValueError): + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + {ATTR_ENTITY_ID: "select.genie_room_size", ATTR_OPTION: "120"}, + blocking=True, + ) + await hass.services.async_call( + "homeassistant", + SERVICE_UPDATE_ENTITY, + {ATTR_ENTITY_ID: ["select.genie_room_size"]}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get("select.genie_room_size") + assert state + assert state.state == "60" diff --git a/tests/components/rituals_perfume_genie/test_sensor.py b/tests/components/rituals_perfume_genie/test_sensor.py index 477353d3b83..2c72d429a99 100644 --- a/tests/components/rituals_perfume_genie/test_sensor.py +++ b/tests/components/rituals_perfume_genie/test_sensor.py @@ -26,7 +26,7 @@ from .common import ( async def test_sensors_diffuser_v1_battery_cartridge(hass: HomeAssistant) -> None: """Test the creation and values of the Rituals Perfume Genie sensors.""" - config_entry = mock_config_entry(uniqe_id="id_123_sensor_test_diffuser_v1") + config_entry = mock_config_entry(unique_id="id_123_sensor_test_diffuser_v1") diffuser = mock_diffuser_v1_battery_cartridge() await init_integration(hass, config_entry, [diffuser]) registry = entity_registry.async_get(hass) @@ -73,7 +73,7 @@ async def test_sensors_diffuser_v1_battery_cartridge(hass: HomeAssistant) -> Non async def test_sensors_diffuser_v2_no_battery_no_cartridge(hass: HomeAssistant) -> None: """Test the creation and values of the Rituals Perfume Genie sensors.""" - config_entry = mock_config_entry(uniqe_id="id_123_sensor_test_diffuser_v2") + config_entry = mock_config_entry(unique_id="id_123_sensor_test_diffuser_v2") await init_integration( hass, config_entry, [mock_diffuser_v2_no_battery_no_cartridge()] diff --git a/tests/components/rituals_perfume_genie/test_switch.py b/tests/components/rituals_perfume_genie/test_switch.py index a2691da0e0e..960923a1b77 100644 --- a/tests/components/rituals_perfume_genie/test_switch.py +++ b/tests/components/rituals_perfume_genie/test_switch.py @@ -25,7 +25,7 @@ from .common import ( async def test_switch_entity(hass: HomeAssistant) -> None: """Test the creation and values of the Rituals Perfume Genie diffuser switch.""" - config_entry = mock_config_entry(uniqe_id="id_123_switch_set_state_test") + config_entry = mock_config_entry(unique_id="id_123_switch_test") diffuser = mock_diffuser_v1_battery_cartridge() await init_integration(hass, config_entry, [diffuser]) @@ -43,7 +43,7 @@ async def test_switch_entity(hass: HomeAssistant) -> None: async def test_switch_handle_coordinator_update(hass: HomeAssistant) -> None: """Test handling a coordinator update.""" - config_entry = mock_config_entry(uniqe_id="id_123_switch_set_state_test") + config_entry = mock_config_entry(unique_id="switch_handle_coordinator_update_test") diffuser = mock_diffuser_v1_battery_cartridge() await init_integration(hass, config_entry, [diffuser]) await async_setup_component(hass, "homeassistant", {}) @@ -74,7 +74,7 @@ async def test_switch_handle_coordinator_update(hass: HomeAssistant) -> None: async def test_set_switch_state(hass: HomeAssistant) -> None: """Test changing the diffuser switch entity state.""" - config_entry = mock_config_entry(uniqe_id="id_123_switch_set_state_test") + config_entry = mock_config_entry(unique_id="id_123_switch_set_state_test") await init_integration(hass, config_entry, [mock_diffuser_v1_battery_cartridge()]) state = hass.states.get("switch.genie")