1
0
mirror of https://github.com/home-assistant/core.git synced 2026-04-02 00:20:30 +01:00
Files
core/tests/components/liebherr/test_select.py
2026-03-20 16:02:49 +01:00

306 lines
8.8 KiB
Python

"""Test the Liebherr select platform."""
import copy
import dataclasses
from datetime import timedelta
from typing import Any
from unittest.mock import MagicMock, patch
from freezegun.api import FrozenDateTimeFactory
from pyliebherrhomeapi import (
BioFreshPlusMode,
Device,
DeviceState,
DeviceType,
HydroBreezeControl,
HydroBreezeMode,
IceMakerControl,
IceMakerMode,
TemperatureControl,
TemperatureUnit,
ZonePosition,
)
from pyliebherrhomeapi.exceptions import LiebherrConnectionError
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.select import (
ATTR_OPTION,
DOMAIN as SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from .conftest import MOCK_DEVICE, MOCK_DEVICE_STATE
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
@pytest.fixture
def platforms() -> list[Platform]:
"""Fixture to specify platforms to test."""
return [Platform.SELECT]
@pytest.fixture(autouse=True)
def enable_all_entities(entity_registry_enabled_by_default: None) -> None:
"""Make sure all entities are enabled."""
@pytest.mark.usefixtures("init_integration")
async def test_selects(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test all select entities with multi-zone device."""
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
@pytest.mark.parametrize(
("entity_id", "option", "method", "kwargs"),
[
(
"select.test_fridge_bottom_zone_icemaker",
"on",
"set_ice_maker",
{
"device_id": "test_device_id",
"zone_id": 2,
"mode": IceMakerMode.ON,
},
),
(
"select.test_fridge_bottom_zone_icemaker",
"max_ice",
"set_ice_maker",
{
"device_id": "test_device_id",
"zone_id": 2,
"mode": IceMakerMode.MAX_ICE,
},
),
(
"select.test_fridge_top_zone_hydrobreeze",
"high",
"set_hydro_breeze",
{
"device_id": "test_device_id",
"zone_id": 1,
"mode": HydroBreezeMode.HIGH,
},
),
(
"select.test_fridge_top_zone_hydrobreeze",
"off",
"set_hydro_breeze",
{
"device_id": "test_device_id",
"zone_id": 1,
"mode": HydroBreezeMode.OFF,
},
),
(
"select.test_fridge_top_zone_biofresh_plus",
"zero_minus_two",
"set_bio_fresh_plus",
{
"device_id": "test_device_id",
"zone_id": 1,
"mode": BioFreshPlusMode.ZERO_MINUS_TWO,
},
),
],
)
@pytest.mark.usefixtures("init_integration")
async def test_select_service_calls(
hass: HomeAssistant,
mock_liebherr_client: MagicMock,
entity_id: str,
option: str,
method: str,
kwargs: dict[str, Any],
) -> None:
"""Test select option service calls."""
initial_call_count = mock_liebherr_client.get_device_state.call_count
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{ATTR_ENTITY_ID: entity_id, ATTR_OPTION: option},
blocking=True,
)
getattr(mock_liebherr_client, method).assert_called_once_with(**kwargs)
# Verify coordinator refresh was triggered
assert mock_liebherr_client.get_device_state.call_count > initial_call_count
@pytest.mark.parametrize(
("entity_id", "method", "option"),
[
("select.test_fridge_bottom_zone_icemaker", "set_ice_maker", "off"),
("select.test_fridge_top_zone_hydrobreeze", "set_hydro_breeze", "off"),
(
"select.test_fridge_top_zone_biofresh_plus",
"set_bio_fresh_plus",
"zero_zero",
),
],
)
@pytest.mark.usefixtures("init_integration")
async def test_select_failure(
hass: HomeAssistant,
mock_liebherr_client: MagicMock,
entity_id: str,
method: str,
option: str,
) -> None:
"""Test select fails gracefully on connection error."""
getattr(mock_liebherr_client, method).side_effect = LiebherrConnectionError(
"Connection failed"
)
with pytest.raises(
HomeAssistantError,
match="An error occurred while communicating with the device",
):
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{ATTR_ENTITY_ID: entity_id, ATTR_OPTION: option},
blocking=True,
)
@pytest.mark.usefixtures("init_integration")
async def test_select_when_control_missing(
hass: HomeAssistant,
mock_liebherr_client: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test select entity behavior when control is removed."""
entity_id = "select.test_fridge_bottom_zone_icemaker"
state = hass.states.get(entity_id)
assert state is not None
assert state.state == "off"
# Device stops reporting select controls
mock_liebherr_client.get_device_state.side_effect = lambda *a, **kw: DeviceState(
device=MOCK_DEVICE, controls=[]
)
freezer.tick(timedelta(seconds=61))
async_fire_time_changed(hass)
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state is not None
assert state.state == STATE_UNAVAILABLE
async def test_single_zone_select(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
entity_registry: er.EntityRegistry,
mock_liebherr_client: MagicMock,
mock_config_entry: MockConfigEntry,
platforms: list[Platform],
) -> None:
"""Test single zone device uses name without zone suffix."""
device = Device(
device_id="single_zone_id",
nickname="Single Zone Fridge",
device_type=DeviceType.FRIDGE,
device_name="K2601",
)
mock_liebherr_client.get_devices.return_value = [device]
single_zone_state = DeviceState(
device=device,
controls=[
TemperatureControl(
zone_id=1,
zone_position=ZonePosition.TOP,
name="Fridge",
type="fridge",
value=4,
target=4,
min=2,
max=8,
unit=TemperatureUnit.CELSIUS,
),
IceMakerControl(
name="icemaker",
type="IceMakerControl",
zone_id=1,
zone_position=ZonePosition.TOP,
ice_maker_mode=IceMakerMode.ON,
has_max_ice=False,
),
HydroBreezeControl(
name="hydrobreeze",
type="HydroBreezeControl",
zone_id=1,
current_mode=HydroBreezeMode.OFF,
),
],
)
mock_liebherr_client.get_device_state.side_effect = lambda *a, **kw: copy.deepcopy(
single_zone_state
)
mock_config_entry.add_to_hass(hass)
with patch("homeassistant.components.liebherr.PLATFORMS", platforms):
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
@pytest.mark.usefixtures("init_integration")
async def test_select_current_option_none_mode(
hass: HomeAssistant,
mock_liebherr_client: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test select entity state when control mode returns None."""
entity_id = "select.test_fridge_top_zone_hydrobreeze"
state = hass.states.get(entity_id)
assert state is not None
assert state.state == "low"
# Simulate update where mode is None
none_mode_controls = [
dataclasses.replace(control, current_mode=None)
if isinstance(control, HydroBreezeControl)
else control
for control in MOCK_DEVICE_STATE.controls
]
state_with_none_mode = dataclasses.replace(
MOCK_DEVICE_STATE, controls=none_mode_controls
)
mock_liebherr_client.get_device_state.side_effect = lambda *a, **kw: copy.deepcopy(
state_with_none_mode
)
freezer.tick(timedelta(seconds=61))
async_fire_time_changed(hass)
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state is not None
assert state.state == STATE_UNKNOWN