"""Tests for the BSB-Lan button platform.""" from unittest.mock import MagicMock from bsblan import BSBLANError, DeviceTime from freezegun.api import FrozenDateTimeFactory import pytest from syrupy.assertion import SnapshotAssertion from homeassistant.components.bsblan.const import DOMAIN from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS from homeassistant.const import ATTR_ENTITY_ID, Platform from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er from homeassistant.util import dt as dt_util from . import setup_with_selected_platforms from tests.common import MockConfigEntry, snapshot_platform ENTITY_SYNC_TIME = "button.bsb_lan_sync_time" async def test_button_entity_properties( hass: HomeAssistant, mock_bsblan: MagicMock, mock_config_entry: MockConfigEntry, snapshot: SnapshotAssertion, entity_registry: er.EntityRegistry, ) -> None: """Test the button entity properties.""" await setup_with_selected_platforms(hass, mock_config_entry, [Platform.BUTTON]) await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) async def test_button_press_syncs_time( hass: HomeAssistant, mock_bsblan: MagicMock, mock_config_entry: MockConfigEntry, freezer: FrozenDateTimeFactory, ) -> None: """Test pressing the sync time button syncs the device time.""" await setup_with_selected_platforms(hass, mock_config_entry, [Platform.BUTTON]) # Mock device time that differs from HA time mock_bsblan.time.return_value = DeviceTime.model_validate_json( '{"time": {"name": "Time",' ' "value": "01.01.2020 00:00:00",' ' "unit": "", "desc": "",' ' "dataType": 0, "readonly": 0, "error": 0}}' ) # Press the button await hass.services.async_call( BUTTON_DOMAIN, SERVICE_PRESS, {ATTR_ENTITY_ID: ENTITY_SYNC_TIME}, blocking=True, ) # Verify time() was called to check current device time assert mock_bsblan.time.called # Verify set_time() was called with current HA time current_time_str = dt_util.now().strftime("%d.%m.%Y %H:%M:%S") mock_bsblan.set_time.assert_called_once_with(current_time_str) async def test_button_press_no_update_when_same( hass: HomeAssistant, mock_bsblan: MagicMock, mock_config_entry: MockConfigEntry, freezer: FrozenDateTimeFactory, ) -> None: """Test button press doesn't update when time matches.""" await setup_with_selected_platforms(hass, mock_config_entry, [Platform.BUTTON]) # Mock device time that matches HA time current_time_str = dt_util.now().strftime("%d.%m.%Y %H:%M:%S") mock_bsblan.time.return_value = DeviceTime.model_validate_json( f'{{"time": {{"name": "Time",' f' "value": "{current_time_str}",' f' "unit": "", "desc": "",' f' "dataType": 0, "readonly": 0, "error": 0}}}}' ) # Press the button await hass.services.async_call( BUTTON_DOMAIN, SERVICE_PRESS, {ATTR_ENTITY_ID: ENTITY_SYNC_TIME}, blocking=True, ) # Verify time() was called assert mock_bsblan.time.called # Verify set_time() was NOT called since times match assert not mock_bsblan.set_time.called async def test_button_press_error_handling( hass: HomeAssistant, mock_bsblan: MagicMock, mock_config_entry: MockConfigEntry, ) -> None: """Test button press handles errors gracefully.""" await setup_with_selected_platforms(hass, mock_config_entry, [Platform.BUTTON]) # Mock time() to raise an error mock_bsblan.time.side_effect = BSBLANError("Connection failed") # Press the button - should raise HomeAssistantError with pytest.raises(HomeAssistantError) as exc: await hass.services.async_call( BUTTON_DOMAIN, SERVICE_PRESS, {ATTR_ENTITY_ID: ENTITY_SYNC_TIME}, blocking=True, ) assert exc.value.translation_domain == DOMAIN assert exc.value.translation_key == "sync_time_failed" assert exc.value.translation_placeholders == { "device_name": "BSB-LAN", "error": "Connection failed", } async def test_button_press_set_time_error( hass: HomeAssistant, mock_bsblan: MagicMock, mock_config_entry: MockConfigEntry, ) -> None: """Test button press handles set_time errors.""" await setup_with_selected_platforms(hass, mock_config_entry, [Platform.BUTTON]) # Mock device time that differs mock_bsblan.time.return_value = DeviceTime.model_validate_json( '{"time": {"name": "Time",' ' "value": "01.01.2020 00:00:00",' ' "unit": "", "desc": "",' ' "dataType": 0, "readonly": 0, "error": 0}}' ) # Mock set_time() to raise an error mock_bsblan.set_time.side_effect = BSBLANError("Write failed") # Press the button - should raise HomeAssistantError with pytest.raises(HomeAssistantError) as exc: await hass.services.async_call( BUTTON_DOMAIN, SERVICE_PRESS, {ATTR_ENTITY_ID: ENTITY_SYNC_TIME}, blocking=True, ) assert exc.value.translation_domain == DOMAIN assert exc.value.translation_key == "sync_time_failed" assert exc.value.translation_placeholders == { "device_name": "BSB-LAN", "error": "Write failed", }