"""Stub out homeassistant before any local imports so tests run without HA installed.""" from __future__ import annotations import sys from datetime import timedelta from unittest.mock import MagicMock import pytest # --------------------------------------------------------------------------- # HA module stubs — must happen before coordinator.py is imported # --------------------------------------------------------------------------- class _DataUpdateCoordinator: """Minimal stand-in for DataUpdateCoordinator.""" def __init__(self, hass, logger, *, name, update_interval): self.hass = hass self.name = name self.data: dict = {} class _UpdateFailed(Exception): pass _update_coordinator_stub = MagicMock() _update_coordinator_stub.DataUpdateCoordinator = _DataUpdateCoordinator _update_coordinator_stub.UpdateFailed = _UpdateFailed for _mod in [ "homeassistant", "homeassistant.config_entries", "homeassistant.core", "homeassistant.components", "homeassistant.components.sensor", "homeassistant.components.switch", "homeassistant.const", "homeassistant.helpers", "homeassistant.helpers.device_registry", "homeassistant.helpers.entity_platform", "homeassistant.helpers.restore_state", "homeassistant.helpers.selector", "voluptuous", ]: sys.modules.setdefault(_mod, MagicMock()) sys.modules["homeassistant.helpers.update_coordinator"] = _update_coordinator_stub # --------------------------------------------------------------------------- # Shared test fixtures # --------------------------------------------------------------------------- from custom_components.easee_solar_charging.coordinator import EaseeSolarCoordinator # noqa: E402 from custom_components.easee_solar_charging.const import ( # noqa: E402 CONF_STOP_GRACE_MINUTES, DEFAULT_STOP_GRACE_MINUTES, ) CHARGER_ID = "ehxt9pqp" SOLAR_SENSOR = "sensor.solar_excess" class FakeCoordinator(EaseeSolarCoordinator): """Coordinator with HA wiring stripped out so logic methods can be unit-tested.""" def __init__(self, options: dict | None = None) -> None: # Skip DataUpdateCoordinator.__init__ — not needed for logic-only tests. self.hass = MagicMock() self.charger_id = CHARGER_ID self._solar_excess_sensor = SOLAR_SENSOR self._device_id = None self._last_sent_current = None self._last_sent_at = None self._below_threshold_since = None self.solar_charging_enabled = True self.stop_grace_enabled = True self._entry = MagicMock() self._entry.options = options if options is not None else { CONF_STOP_GRACE_MINUTES: DEFAULT_STOP_GRACE_MINUTES, } @pytest.fixture def coord() -> FakeCoordinator: return FakeCoordinator() def make_state(value: str) -> MagicMock: """Return a minimal HA state mock with the given state string.""" s = MagicMock() s.state = value return s