From d5bcfe98221db55fdf1a20f7d1bb72f87a77fc1a Mon Sep 17 00:00:00 2001 From: Richard Kroegel <42204099+rikroe@users.noreply.github.com> Date: Wed, 26 Jun 2024 12:27:55 +0200 Subject: [PATCH] Improve BMW tests (#119171) Co-authored-by: Richard --- .../bmw_connected_drive/__init__.py | 5 +- .../bmw_connected_drive/test_init.py | 56 ++++++++++++++++++- .../bmw_connected_drive/test_sensor.py | 44 ++++++++++++++- 3 files changed, 101 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/bmw_connected_drive/__init__.py b/homeassistant/components/bmw_connected_drive/__init__.py index 663003a5e4b..bd4e1cf7360 100644 --- a/homeassistant/components/bmw_connected_drive/__init__.py +++ b/homeassistant/components/bmw_connected_drive/__init__.py @@ -72,7 +72,10 @@ def _async_migrate_options_from_data_if_missing( options = dict(entry.options) if CONF_READ_ONLY in data or list(options) != list(DEFAULT_OPTIONS): - options = dict(DEFAULT_OPTIONS, **options) + options = dict( + DEFAULT_OPTIONS, + **{k: v for k, v in options.items() if k in DEFAULT_OPTIONS}, + ) options[CONF_READ_ONLY] = data.pop(CONF_READ_ONLY, False) hass.config_entries.async_update_entry(entry, data=data, options=options) diff --git a/tests/components/bmw_connected_drive/test_init.py b/tests/components/bmw_connected_drive/test_init.py index d648ad65f5d..52bc8a7ce05 100644 --- a/tests/components/bmw_connected_drive/test_init.py +++ b/tests/components/bmw_connected_drive/test_init.py @@ -4,7 +4,11 @@ from unittest.mock import patch import pytest -from homeassistant.components.bmw_connected_drive.const import DOMAIN as BMW_DOMAIN +from homeassistant.components.bmw_connected_drive import DEFAULT_OPTIONS +from homeassistant.components.bmw_connected_drive.const import ( + CONF_READ_ONLY, + DOMAIN as BMW_DOMAIN, +) from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er @@ -18,6 +22,56 @@ VEHICLE_NAME = "i3 (+ REX)" VEHICLE_NAME_SLUG = "i3_rex" +@pytest.mark.usefixtures("bmw_fixture") +@pytest.mark.parametrize( + "options", + [ + DEFAULT_OPTIONS, + {"other_value": 1, **DEFAULT_OPTIONS}, + {}, + ], +) +async def test_migrate_options( + hass: HomeAssistant, + options: dict, +) -> None: + """Test successful migration of options.""" + + config_entry = FIXTURE_CONFIG_ENTRY.copy() + config_entry["options"] = options + + mock_config_entry = MockConfigEntry(**config_entry) + mock_config_entry.add_to_hass(hass) + + assert await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert len( + hass.config_entries.async_get_entry(mock_config_entry.entry_id).options + ) == len(DEFAULT_OPTIONS) + + +@pytest.mark.usefixtures("bmw_fixture") +async def test_migrate_options_from_data(hass: HomeAssistant) -> None: + """Test successful migration of options.""" + + config_entry = FIXTURE_CONFIG_ENTRY.copy() + config_entry["options"] = {} + config_entry["data"].update({CONF_READ_ONLY: False}) + + mock_config_entry = MockConfigEntry(**config_entry) + mock_config_entry.add_to_hass(hass) + + assert await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + updated_config_entry = hass.config_entries.async_get_entry( + mock_config_entry.entry_id + ) + assert len(updated_config_entry.options) == len(DEFAULT_OPTIONS) + assert CONF_READ_ONLY not in updated_config_entry.data + + @pytest.mark.parametrize( ("entitydata", "old_unique_id", "new_unique_id"), [ diff --git a/tests/components/bmw_connected_drive/test_sensor.py b/tests/components/bmw_connected_drive/test_sensor.py index 6607bed280d..c02f6d425cd 100644 --- a/tests/components/bmw_connected_drive/test_sensor.py +++ b/tests/components/bmw_connected_drive/test_sensor.py @@ -2,13 +2,17 @@ from unittest.mock import patch +from bimmer_connected.models import StrEnum +from bimmer_connected.vehicle import fuel_and_battery +from freezegun.api import FrozenDateTimeFactory import pytest from syrupy.assertion import SnapshotAssertion from homeassistant.components.bmw_connected_drive import DOMAIN as BMW_DOMAIN +from homeassistant.components.bmw_connected_drive.const import SCAN_INTERVALS from homeassistant.components.bmw_connected_drive.sensor import SENSOR_TYPES from homeassistant.components.sensor import SensorDeviceClass -from homeassistant.const import Platform +from homeassistant.const import STATE_UNAVAILABLE, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from homeassistant.helpers.translation import async_get_translations @@ -20,7 +24,7 @@ from homeassistant.util.unit_system import ( from . import setup_mocked_integration -from tests.common import snapshot_platform +from tests.common import async_fire_time_changed, snapshot_platform @pytest.mark.freeze_time("2023-06-22 10:30:00+00:00") @@ -107,3 +111,39 @@ async def test_entity_option_translations( } assert sensor_options == translation_states + + +@pytest.mark.usefixtures("bmw_fixture") +async def test_enum_sensor_unknown( + hass: HomeAssistant, monkeypatch: pytest.MonkeyPatch, freezer: FrozenDateTimeFactory +) -> None: + """Test conversion handling of enum sensors.""" + + # Setup component + assert await setup_mocked_integration(hass) + + entity_id = "sensor.i4_edrive40_charging_status" + + # Check normal state + entity = hass.states.get(entity_id) + assert entity.state == "not_charging" + + class ChargingStateUnkown(StrEnum): + """Charging state of electric vehicle.""" + + UNKNOWN = "UNKNOWN" + + # Setup enum returning only UNKNOWN + monkeypatch.setattr( + fuel_and_battery, + "ChargingState", + ChargingStateUnkown, + ) + + freezer.tick(SCAN_INTERVALS["rest_of_world"]) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + # Check normal state + entity = hass.states.get("sensor.i4_edrive40_charging_status") + assert entity.state == STATE_UNAVAILABLE