From f223b8a190d87f5a52087d4620cb4ecd0e81db71 Mon Sep 17 00:00:00 2001 From: EnjoyingM <6302356+mtielen@users.noreply.github.com> Date: Wed, 26 Feb 2025 23:25:45 +0000 Subject: [PATCH] Add name_fn and test_sensor adoptions --- homeassistant/components/wolflink/sensor.py | 150 ++++++++---------- .../wolflink/snapshots/test_sensor.ambr | 25 +++ tests/components/wolflink/test_sensor.py | 142 +++++++---------- 3 files changed, 148 insertions(+), 169 deletions(-) create mode 100644 tests/components/wolflink/snapshots/test_sensor.ambr diff --git a/homeassistant/components/wolflink/sensor.py b/homeassistant/components/wolflink/sensor.py index 51cdcba193a..7f5244acf4d 100644 --- a/homeassistant/components/wolflink/sensor.py +++ b/homeassistant/components/wolflink/sensor.py @@ -39,6 +39,70 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import COORDINATOR, DEVICE_ID, DOMAIN, MANUFACTURER, PARAMETERS, STATES +@dataclass(kw_only=True, frozen=True) +class WolflinkSensorEntityDescription(SensorEntityDescription): + """Describes Wolflink sensor entity.""" + + name_fn: Callable[[Parameter], str] + supported_fn: Callable[[Parameter], bool] + + +SENSOR_DESCRIPTIONS = [ + WolflinkSensorEntityDescription( + key="temperature", + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + supported_fn=lambda param: isinstance(param, Temperature), + name_fn=lambda param: param.name, + ), + WolflinkSensorEntityDescription( + key="pressure", + device_class=SensorDeviceClass.PRESSURE, + native_unit_of_measurement=UnitOfPressure.BAR, + supported_fn=lambda param: isinstance(param, Pressure), + name_fn=lambda param: param.name, + ), + WolflinkSensorEntityDescription( + key="energy", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + supported_fn=lambda param: isinstance(param, EnergyParameter), + name_fn=lambda param: param.name, + ), + WolflinkSensorEntityDescription( + key="power", + device_class=SensorDeviceClass.POWER, + native_unit_of_measurement=UnitOfPower.KILO_WATT, + supported_fn=lambda param: isinstance(param, PowerParameter), + name_fn=lambda param: param.name, + ), + WolflinkSensorEntityDescription( + key="percentage", + native_unit_of_measurement=PERCENTAGE, + supported_fn=lambda param: isinstance(param, PercentageParameter), + name_fn=lambda param: param.name, + ), + WolflinkSensorEntityDescription( + key="list_item", + translation_key="state", + supported_fn=lambda param: isinstance(param, ListItemParameter), + name_fn=lambda param: param.name, + ), + WolflinkSensorEntityDescription( + key="hours", + icon="mdi:clock", + native_unit_of_measurement=UnitOfTime.HOURS, + supported_fn=lambda param: isinstance(param, HoursParameter), + name_fn=lambda param: param.name, + ), + WolflinkSensorEntityDescription( + key="default", + supported_fn=lambda param: isinstance(param, SimpleParameter), + name_fn=lambda param: param.name, + ), +] + + async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, @@ -50,93 +114,15 @@ async def async_setup_entry( device_id = hass.data[DOMAIN][config_entry.entry_id][DEVICE_ID] entities: list[WolfLinkSensor] = [ - WolfLinkSensor( - coordinator, parameter, device_id, get_entity_description(parameter) - ) + WolfLinkSensor(coordinator, parameter, device_id, description) for parameter in parameters + for description in SENSOR_DESCRIPTIONS + if description.supported_fn(parameter) ] async_add_entities(entities, True) -@dataclass(kw_only=True, frozen=True) -class WolflinkSensorEntityDescription(SensorEntityDescription): - """Describes Wolflink sensor entity.""" - - supported_fn: Callable[[Parameter], bool] - - -SENSOR_DESCRIPTIONS = [ - WolflinkSensorEntityDescription( - key="temperature", - device_class=SensorDeviceClass.TEMPERATURE, - native_unit_of_measurement=UnitOfTemperature.CELSIUS, - supported_fn=lambda param: isinstance(param, Temperature), - ), - WolflinkSensorEntityDescription( - key="pressure", - device_class=SensorDeviceClass.PRESSURE, - native_unit_of_measurement=UnitOfPressure.BAR, - supported_fn=lambda param: isinstance(param, Pressure), - ), - WolflinkSensorEntityDescription( - key="energy", - device_class=SensorDeviceClass.ENERGY, - native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, - supported_fn=lambda param: isinstance(param, EnergyParameter), - ), - WolflinkSensorEntityDescription( - key="power", - device_class=SensorDeviceClass.POWER, - native_unit_of_measurement=UnitOfPower.KILO_WATT, - supported_fn=lambda param: isinstance(param, PowerParameter), - ), - WolflinkSensorEntityDescription( - key="percentage", - native_unit_of_measurement=PERCENTAGE, - supported_fn=lambda param: isinstance(param, PercentageParameter), - ), - WolflinkSensorEntityDescription( - key="list_item", - translation_key="state", - supported_fn=lambda param: isinstance(param, ListItemParameter), - ), - WolflinkSensorEntityDescription( - key="hours", - icon="mdi:clock", - native_unit_of_measurement=UnitOfTime.HOURS, - supported_fn=lambda param: isinstance(param, HoursParameter), - ), - WolflinkSensorEntityDescription( - key="default", - supported_fn=lambda param: isinstance(param, SimpleParameter), - ), -] - - -def get_entity_description(parameter: Parameter) -> WolflinkSensorEntityDescription: - """Return the entity description for a given parameter.""" - for description in SENSOR_DESCRIPTIONS: - if description.supported_fn(parameter): - return WolflinkSensorEntityDescription( - key=parameter.parameter_id, - name=parameter.name, - device_class=description.device_class, - native_unit_of_measurement=description.native_unit_of_measurement, - icon=description.icon, - entity_registry_enabled_default=description.entity_registry_enabled_default, - entity_category=description.entity_category, - has_entity_name=description.has_entity_name, - translation_key=description.translation_key, - supported_fn=description.supported_fn, - ) - return WolflinkSensorEntityDescription( - key=parameter.parameter_id, - name=parameter.name, - supported_fn=lambda param: True, - ) - - class WolfLinkSensor(CoordinatorEntity, SensorEntity): """Base class for all Wolf entities.""" @@ -153,7 +139,7 @@ class WolfLinkSensor(CoordinatorEntity, SensorEntity): super().__init__(coordinator) self.entity_description = description self.wolf_object = wolf_object - self._attr_name = str(description.name) + self._attr_name = description.name_fn(wolf_object) self._attr_unique_id = f"{device_id}:{wolf_object.parameter_id}" self._state = None self._attr_device_info = DeviceInfo( diff --git a/tests/components/wolflink/snapshots/test_sensor.ambr b/tests/components/wolflink/snapshots/test_sensor.ambr new file mode 100644 index 00000000000..e6e6d0c6083 --- /dev/null +++ b/tests/components/wolflink/snapshots/test_sensor.ambr @@ -0,0 +1,25 @@ +# serializer version: 1 +# name: test_sensor[wolf_parameter0] + None +# --- +# name: test_sensor[wolf_parameter1] + None +# --- +# name: test_sensor[wolf_parameter2] + None +# --- +# name: test_sensor[wolf_parameter3] + None +# --- +# name: test_sensor[wolf_parameter4] + None +# --- +# name: test_sensor[wolf_parameter5] + None +# --- +# name: test_sensor[wolf_parameter6] + None +# --- +# name: test_sensor[wolf_parameter7] + None +# --- diff --git a/tests/components/wolflink/test_sensor.py b/tests/components/wolflink/test_sensor.py index 8cd831fbe69..ea4694b6c98 100644 --- a/tests/components/wolflink/test_sensor.py +++ b/tests/components/wolflink/test_sensor.py @@ -3,8 +3,8 @@ from unittest.mock import MagicMock, Mock import pytest +from syrupy import SnapshotAssertion from wolf_comm import ( - PERCENTAGE, EnergyParameter, HoursParameter, ListItemParameter, @@ -20,15 +20,11 @@ from homeassistant.components.wolflink.const import ( COORDINATOR, DEVICE_ID, DOMAIN, - MANUFACTURER, PARAMETERS, ) -from homeassistant.components.wolflink.sensor import ( - WolfLinkSensor, - async_setup_entry, - get_entity_description, -) +from homeassistant.components.wolflink.sensor import WolfLinkSensor, async_setup_entry from homeassistant.const import ( + PERCENTAGE, UnitOfEnergy, UnitOfPower, UnitOfPressure, @@ -44,22 +40,13 @@ from tests.common import MockConfigEntry @pytest.fixture -def mock_coordinator(hass: HomeAssistant) -> MagicMock: - """Mock the Wolf SmartSet Service Coordinator.""" - coordinator = MagicMock() - coordinator.data = {} - hass.data[DOMAIN] = {CONFIG[DEVICE_ID]: {COORDINATOR: coordinator}} - return coordinator - - -@pytest.fixture -def mock_device_id(): +def mock_device_id() -> str: """Fixture for a mock device ID.""" return "1234" @pytest.fixture -def mock_parameter(): +def mock_parameter() -> Parameter: """Fixture for a mock parameter.""" return Mock(spec=Parameter) @@ -78,22 +65,24 @@ async def mock_config_entry( assert device.identifiers == {(DOMAIN, CONFIG[DEVICE_ID])} -def test_wolflink_sensor_native_value(mock_coordinator: MagicMock) -> None: +def test_wolflink_sensor_native_value() -> None: """Test WolflinkSensor native value.""" + coordinator = MagicMock() parameter = MagicMock() parameter.parameter_id = "outside_temp" - sensor = WolfLinkSensor(mock_coordinator, parameter, "mock_device_id", MagicMock()) - mock_coordinator.data = {"outside_temp": [None, 20]} + sensor = WolfLinkSensor(coordinator, parameter, "mock_device_id", MagicMock()) + coordinator.data = {"outside_temp": [None, 20]} assert sensor.native_value == 20 -def test_wolflink_sensor_extra_state_attributes(mock_coordinator: MagicMock) -> None: +def test_wolflink_sensor_extra_state_attributes() -> None: """Test WolflinkSensor extra state attributes.""" + coordinator = MagicMock() parameter = MagicMock() parameter.parameter_id = "outside_temp" parameter.value_id = "value_id" parameter.parent = "parent" - sensor = WolfLinkSensor(mock_coordinator, parameter, "mock_device_id", MagicMock()) + sensor = WolfLinkSensor(coordinator, parameter, "mock_device_id", MagicMock()) attributes = sensor.extra_state_attributes assert attributes["parameter_id"] == "outside_temp" assert attributes["value_id"] == "value_id" @@ -113,12 +102,13 @@ def test_wolflink_sensor_extra_state_attributes(mock_coordinator: MagicMock) -> ) async def test_async_setup_entry( hass: HomeAssistant, - mock_coordinator: MagicMock, parameter: Parameter, + wolf_parameter: Parameter, expected_class: type, expected_unit: str, ) -> None: """Test async_setup_entry for various parameter types.""" + config_entry = MockConfigEntry( domain=DOMAIN, unique_id=str(CONFIG[DEVICE_ID]), data=CONFIG ) @@ -130,8 +120,8 @@ async def test_async_setup_entry( parameter.unit = PERCENTAGE hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = { PARAMETERS: [parameter], - COORDINATOR: mock_coordinator, DEVICE_ID: "1234", + COORDINATOR: MagicMock(), # Ensure COORDINATOR is set up } async_add_entities = MagicMock() @@ -145,70 +135,48 @@ async def test_async_setup_entry( assert entity.native_unit_of_measurement == expected_unit -def test_get_entity_description() -> None: - """Test the get_entity_description function.""" - parameter = Mock(spec=Temperature) - description = get_entity_description(parameter) - assert description.device_class == "temperature" - assert description.native_unit_of_measurement == "°C" - - parameter = Mock(spec=Pressure) - description = get_entity_description(parameter) - assert description.device_class == "pressure" - assert description.native_unit_of_measurement == "bar" - - parameter = Mock(spec=EnergyParameter) - description = get_entity_description(parameter) - assert description.device_class == "energy" - assert description.native_unit_of_measurement == "kWh" - - parameter = Mock(spec=PowerParameter) - description = get_entity_description(parameter) - assert description.device_class == "power" - assert description.native_unit_of_measurement == "kW" - - parameter = Mock(spec=PercentageParameter) - description = get_entity_description(parameter) - assert description.native_unit_of_measurement == PERCENTAGE - - parameter = Mock(spec=ListItemParameter) - description = get_entity_description(parameter) - assert description.translation_key == "state" - - parameter = Mock(spec=HoursParameter) - description = get_entity_description(parameter) - assert description.native_unit_of_measurement == UnitOfTime.HOURS - assert description.icon == "mdi:clock" - - parameter = Mock(spec=SimpleParameter) - description = get_entity_description(parameter) +@pytest.fixture( + params=[ + EnergyParameter(6002800000, "Energy Parameter", "Heating", 6005200000), + ListItemParameter( + 8002800000, + "List Item Parameter", + "Heating", + (["Pump", "on"], ["Heating", "on"]), + 8005200000, + ), + PowerParameter(5002800000, "Power Parameter", "Heating", 5005200000), + Pressure(4002800000, "Pressure Parameter", "Heating", 4005200000), + Temperature(3002800000, "Temperature Parameter", "Solar", 3005200000), + PercentageParameter(2002800000, "Percentage Parameter", "Solar", 2005200000), + HoursParameter(7002800000, "Hours Parameter", "Heating", 7005200000), + SimpleParameter(1002800000, "Simple Parameter", "DHW", 1005200000), + ] +) +def wolf_parameter(request: pytest.FixtureRequest) -> Parameter: + """Fixture for different WolfLink parameter types.""" + return request.param -def test_wolflink_sensor(mock_coordinator, mock_device_id, mock_parameter) -> None: - """Test the WolfLinkSensor class.""" - description = get_entity_description(mock_parameter) - sensor = WolfLinkSensor( - mock_coordinator, mock_parameter, mock_device_id, description +async def test_sensor( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + wolf_parameter: Parameter, +) -> None: + """Test the sensor state for various parameter types.""" + config_entry = MockConfigEntry( + domain=DOMAIN, unique_id=str(CONFIG[DEVICE_ID]), data=CONFIG ) + config_entry.add_to_hass(hass) - assert sensor.entity_description == description - assert sensor.wolf_object == mock_parameter - assert sensor._attr_name == str(description.name) - assert sensor._attr_unique_id == f"{mock_device_id}:{mock_parameter.parameter_id}" - assert sensor._attr_device_info["identifiers"] == {(DOMAIN, str(mock_device_id))} - assert ( - sensor._attr_device_info["configuration_url"] - == "https://www.wolf-smartset.com/" - ) - assert sensor._attr_device_info["manufacturer"] == MANUFACTURER - - # Test native_value property - mock_coordinator.data = {mock_parameter.parameter_id: ("value_id", "state")} - assert sensor.native_value == "state" - - # Test extra_state_attributes property - assert sensor.extra_state_attributes == { - "parameter_id": mock_parameter.parameter_id, - "value_id": mock_parameter.value_id, - "parent": mock_parameter.parent, + hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = { + PARAMETERS: [wolf_parameter], + DEVICE_ID: "1234", + COORDINATOR: MagicMock(), # Ensure COORDINATOR is set up } + async_add_entities = MagicMock() + + await async_setup_entry(hass, config_entry, async_add_entities) + + state = hass.states.get(f"{wolf_parameter.parameter_id}") + assert state == snapshot