"""The tests for the lock component.""" from __future__ import annotations from typing import Any from unittest.mock import MagicMock import pytest from homeassistant.components.lock import ( ATTR_CODE, DOMAIN, SERVICE_LOCK, SERVICE_OPEN, SERVICE_UNLOCK, STATE_JAMMED, STATE_LOCKED, STATE_LOCKING, STATE_UNLOCKED, STATE_UNLOCKING, LockEntity, LockEntityFeature, _async_lock, _async_open, _async_unlock, ) from homeassistant.core import HomeAssistant, ServiceCall class MockLockEntity(LockEntity): """Mock lock to use in tests.""" def __init__( self, code_format: str | None = None, supported_features: LockEntityFeature = LockEntityFeature(0), ) -> None: """Initialize mock lock entity.""" self._attr_supported_features = supported_features self.calls_open = MagicMock() if code_format is not None: self._attr_code_format = code_format async def async_lock(self, **kwargs: Any) -> None: """Lock the lock.""" self._attr_is_locking = False self._attr_is_locked = True async def async_unlock(self, **kwargs: Any) -> None: """Unlock the lock.""" self._attr_is_unlocking = False self._attr_is_locked = False async def async_open(self, **kwargs: Any) -> None: """Open the door latch.""" self.calls_open(kwargs) async def test_lock_default(hass: HomeAssistant) -> None: """Test lock entity with defaults.""" lock = MockLockEntity() lock.hass = hass assert lock.code_format is None assert lock.state is None async def test_lock_states(hass: HomeAssistant) -> None: """Test lock entity states.""" # pylint: disable=protected-access lock = MockLockEntity() lock.hass = hass assert lock.state is None lock._attr_is_locking = True assert lock.is_locking assert lock.state == STATE_LOCKING await _async_lock(lock, ServiceCall(DOMAIN, SERVICE_LOCK, {})) assert lock.is_locked assert lock.state == STATE_LOCKED lock._attr_is_unlocking = True assert lock.is_unlocking assert lock.state == STATE_UNLOCKING await _async_unlock(lock, ServiceCall(DOMAIN, SERVICE_UNLOCK, {})) assert not lock.is_locked assert lock.state == STATE_UNLOCKED lock._attr_is_jammed = True assert lock.is_jammed assert lock.state == STATE_JAMMED assert not lock.is_locked async def test_lock_open_with_code(hass: HomeAssistant) -> None: """Test lock entity with open service.""" lock = MockLockEntity( code_format=r"^\d{4}$", supported_features=LockEntityFeature.OPEN ) lock.hass = hass assert lock.state_attributes == {"code_format": r"^\d{4}$"} with pytest.raises(ValueError): await _async_open(lock, ServiceCall(DOMAIN, SERVICE_OPEN, {})) with pytest.raises(ValueError): await _async_open(lock, ServiceCall(DOMAIN, SERVICE_OPEN, {ATTR_CODE: ""})) with pytest.raises(ValueError): await _async_open(lock, ServiceCall(DOMAIN, SERVICE_OPEN, {ATTR_CODE: "HELLO"})) await _async_open(lock, ServiceCall(DOMAIN, SERVICE_OPEN, {ATTR_CODE: "1234"})) assert lock.calls_open.call_count == 1 async def test_lock_lock_with_code(hass: HomeAssistant) -> None: """Test lock entity with open service.""" lock = MockLockEntity(code_format=r"^\d{4}$") lock.hass = hass await _async_unlock(lock, ServiceCall(DOMAIN, SERVICE_UNLOCK, {ATTR_CODE: "1234"})) assert not lock.is_locked with pytest.raises(ValueError): await _async_lock(lock, ServiceCall(DOMAIN, SERVICE_LOCK, {})) with pytest.raises(ValueError): await _async_lock(lock, ServiceCall(DOMAIN, SERVICE_LOCK, {ATTR_CODE: ""})) with pytest.raises(ValueError): await _async_lock(lock, ServiceCall(DOMAIN, SERVICE_LOCK, {ATTR_CODE: "HELLO"})) await _async_lock(lock, ServiceCall(DOMAIN, SERVICE_LOCK, {ATTR_CODE: "1234"})) assert lock.is_locked async def test_lock_unlock_with_code(hass: HomeAssistant) -> None: """Test unlock entity with open service.""" lock = MockLockEntity(code_format=r"^\d{4}$") lock.hass = hass await _async_lock(lock, ServiceCall(DOMAIN, SERVICE_UNLOCK, {ATTR_CODE: "1234"})) assert lock.is_locked with pytest.raises(ValueError): await _async_unlock(lock, ServiceCall(DOMAIN, SERVICE_UNLOCK, {})) with pytest.raises(ValueError): await _async_unlock(lock, ServiceCall(DOMAIN, SERVICE_UNLOCK, {ATTR_CODE: ""})) with pytest.raises(ValueError): await _async_unlock( lock, ServiceCall(DOMAIN, SERVICE_UNLOCK, {ATTR_CODE: "HELLO"}) ) await _async_unlock(lock, ServiceCall(DOMAIN, SERVICE_UNLOCK, {ATTR_CODE: "1234"})) assert not lock.is_locked