diff --git a/tests/fakeprotocol_smart.py b/tests/fakeprotocol_smart.py index 448729ca..c6a29019 100644 --- a/tests/fakeprotocol_smart.py +++ b/tests/fakeprotocol_smart.py @@ -544,7 +544,7 @@ class FakeSmartTransport(BaseTransport): self.fixture_name, set() ).add(method) return retval - elif method in ["set_qs_info", "fw_download"]: + elif method in ["set_qs_info", "fw_download", "play_alarm", "stop_alarm"]: return {"error_code": 0} elif method == "set_dynamic_light_effect_rule_enable": self._set_dynamic_light_effect(info, params) diff --git a/tests/smart/modules/test_alarm.py b/tests/smart/modules/test_alarm.py new file mode 100644 index 00000000..e520d8a3 --- /dev/null +++ b/tests/smart/modules/test_alarm.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +import pytest +from pytest_mock import MockerFixture + +from kasa import Module +from kasa.smart import SmartDevice +from kasa.smart.modules import Alarm + +from ...device_fixtures import get_parent_and_child_modules, parametrize + +alarm = parametrize("has alarm", component_filter="alarm", protocol_filter={"SMART"}) + + +@alarm +@pytest.mark.parametrize( + ("feature", "prop_name", "type"), + [ + ("alarm", "active", bool), + ("alarm_source", "source", str | None), + ("alarm_sound", "alarm_sound", str), + ("alarm_volume", "alarm_volume", str), + ], +) +async def test_features(dev: SmartDevice, feature: str, prop_name: str, type: type): + """Test that features are registered and work as expected.""" + alarm = next(get_parent_and_child_modules(dev, Module.Alarm)) + assert alarm is not None + + prop = getattr(alarm, prop_name) + assert isinstance(prop, type) + + feat = alarm._device.features[feature] + assert feat.value == prop + assert isinstance(feat.value, type) + + +@alarm +@pytest.mark.parametrize( + ("kwargs", "request_params"), + [ + pytest.param({"volume": "low"}, {"alarm_volume": "low"}, id="volume"), + pytest.param({"duration": 1}, {"alarm_duration": 1}, id="duration"), + pytest.param({"sound": "Test"}, {"alarm_type": "Test"}, id="sound"), + ], +) +async def test_play(dev: SmartDevice, kwargs, request_params, mocker: MockerFixture): + """Test that play parameters are handled correctly.""" + alarm: Alarm = next(get_parent_and_child_modules(dev, Module.Alarm)) + call_spy = mocker.spy(alarm, "call") + await alarm.play(**kwargs) + + call_spy.assert_called_with("play_alarm", request_params) + + +@alarm +async def test_stop(dev: SmartDevice, mocker: MockerFixture): + """Test that stop creates the correct call.""" + alarm: Alarm = next(get_parent_and_child_modules(dev, Module.Alarm)) + call_spy = mocker.spy(alarm, "call") + await alarm.stop() + + call_spy.assert_called_with("stop_alarm") + + +@alarm +@pytest.mark.parametrize( + ("method", "value", "target_key"), + [ + pytest.param("set_alarm_sound", "Test", "type", id="set_alarm_sound"), + pytest.param("set_alarm_volume", "low", "volume", id="set_alarm_volume"), + pytest.param("set_alarm_duration", 10, "duration", id="set_alarm_duration"), + ], +) +async def test_set_alarm_configure( + dev: SmartDevice, + mocker: MockerFixture, + method: str, + value: str | int, + target_key: str, +): + """Test that set_alarm_sound creates the correct call.""" + alarm: Alarm = next(get_parent_and_child_modules(dev, Module.Alarm)) + call_spy = mocker.spy(alarm, "call") + await getattr(alarm, method)(value) + + expected_params = {"duration": mocker.ANY, "type": mocker.ANY, "volume": mocker.ANY} + expected_params[target_key] = value + + call_spy.assert_called_with("set_alarm_configure", expected_params)