From 8e631291c1926223d5c9fb3bbc29ff947d0cada4 Mon Sep 17 00:00:00 2001 From: MattHag <16444067+MattHag@users.noreply.github.com> Date: Sat, 12 Jul 2025 02:16:14 +0200 Subject: [PATCH] Implement HID++ 1.0 fake device for some basic requests The fake device is a simplified, working implementation of a HID++ 1.0 device, that behaves similar to the real hardware. This allows tests to be closer to the real world. Related #2905 --- lib/logitech_receiver/hidpp10.py | 2 +- tests/conftest.py | 7 +++++++ tests/fakes/hidpp10_device.py | 18 +++++++++++++++++ tests/logitech_receiver/test_hidpp10.py | 27 +++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tests/fakes/hidpp10_device.py create mode 100644 tests/logitech_receiver/test_hidpp10.py diff --git a/lib/logitech_receiver/hidpp10.py b/lib/logitech_receiver/hidpp10.py index 29399c8c..38a87793 100644 --- a/lib/logitech_receiver/hidpp10.py +++ b/lib/logitech_receiver/hidpp10.py @@ -191,7 +191,7 @@ class Hidpp10: def get_notification_flags(self, device: Device): return self._get_register(device, Registers.NOTIFICATIONS) - def set_notification_flags(self, device: Device, *flag_bits: NotificationFlag): + def set_notification_flags(self, device: Device, *flag_bits: NotificationFlag) -> None: assert device is not None # Avoid a call if the device is not online, diff --git a/tests/conftest.py b/tests/conftest.py index 7ecc4245..4b95e552 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,15 @@ import pytest +from fakes import hidpp10_device + from .fakes import hidpp20_device +@pytest.fixture +def device_hidpp10(): + yield hidpp10_device.Hidpp10Device() + + @pytest.fixture def device(): yield hidpp20_device.Hidpp20Device() diff --git a/tests/fakes/hidpp10_device.py b/tests/fakes/hidpp10_device.py new file mode 100644 index 00000000..a25ffca6 --- /dev/null +++ b/tests/fakes/hidpp10_device.py @@ -0,0 +1,18 @@ +from logitech_receiver.hidpp10_constants import Registers + + +class Hidpp10Device: + def __init__(self): + self._iteration = 0 + + @property + def kind(self): + pass + + def request(self, request_id, *params, no_reply=False): + if request_id == 0x8100 + Registers.BATTERY_STATUS: + return b"fff" + elif request_id == 0x8000: + return bytes([0x10, 0x10, 0x00]) + + raise RuntimeError(f"Unsupported feature: {request_id:04X}") diff --git a/tests/logitech_receiver/test_hidpp10.py b/tests/logitech_receiver/test_hidpp10.py new file mode 100644 index 00000000..51d91878 --- /dev/null +++ b/tests/logitech_receiver/test_hidpp10.py @@ -0,0 +1,27 @@ +from logitech_receiver import hidpp10 +from logitech_receiver import hidpp10_constants +from logitech_receiver.hidpp10_constants import Registers + +_hidpp10 = hidpp10.Hidpp10() + + +def test_read_register(device_hidpp10): + result = hidpp10.read_register( + device_hidpp10, + register=Registers.BATTERY_STATUS, + ) + + assert result == bytes.fromhex("666666") + + +def test_set_notification_flags(mocker, device_hidpp10): + spy_request = mocker.spy(device_hidpp10, "request") + + result = _hidpp10.set_notification_flags( + device_hidpp10, + hidpp10_constants.NotificationFlag.BATTERY_STATUS, + hidpp10_constants.NotificationFlag.WIRELESS, + ) + + spy_request.assert_called_once_with(0x8000 | Registers.NOTIFICATIONS, b"\x10\x01\x00") + assert result is not None