diff --git a/tests/logitech_receiver/test_hidpp20_complex.py b/tests/logitech_receiver/test_hidpp20_complex.py new file mode 100644 index 00000000..be17e52e --- /dev/null +++ b/tests/logitech_receiver/test_hidpp20_complex.py @@ -0,0 +1,178 @@ +from dataclasses import dataclass, field +from typing import Any, Optional + +import pytest + +from lib.logitech_receiver import hidpp20, hidpp20_constants, special_keys + + +@dataclass +class Response: + response: Optional[str] + request_id: int + params: Any + no_reply: bool = False + + +@dataclass +class Device: + name: str = "DEVICE" + online: bool = True + protocol: float = 2.0 + responses: Any = field(default_factory=list) + + def request(self, id, params=None, no_reply=False): + if params is None: + params = [] + print("REQUEST ", self.name, hex(id), params) + for r in self.responses: + if id == r.request_id and params == r.params: + print("RESPONSE", self.name, hex(r.request_id), r.params, r.response) + return bytes.fromhex(r.response) if r.response is not None else None + + def feature_request(self, feature, function=0x00, *params, no_reply=False): + if self.protocol >= 2.0: + return hidpp20.feature_request(self, feature, function, *params, no_reply=no_reply) + + +device_offline = Device("REGISTERS", False) +device_registers = Device("OFFLINE", True, 1.0) +device_nofeatures = Device("NOFEATURES", True, 4.5) +device_zerofeatures = Device("ZEROFEATURES", True, 4.5, [Response("0000", 0x0000, b"\x00\x01")]) +device_broken = Device("BROKEN", True, 4.5, [Response("0000", 0x0000, b"\x00\x01"), Response(None, 0x0100, [])]) + +responses_standard = [ + Response("0100", 0x0000, b"\x00\x01"), + Response("05000300", 0x0000, b"\x1b\x04"), + Response("0500", 0x0100, []), + Response("01000000", 0x0110, 0x02), + Response("1B040003", 0x0110, 0x05), + Response("00110012AB010203CD00", 0x0510, 0), + Response("01110022AB010203CD00", 0x0510, 1), + Response("03110032AB010204CD00", 0x0510, 3), + Response("00010111AB010203CD00", 0x0510, 2), + Response("00030333AB010203CD00", 0x0510, 4), +] +device_standard = Device("STANDARD", True, 4.5, responses_standard) + + +@pytest.mark.parametrize( + "device, expected_result, expected_count", + [ + (device_offline, False, 0), + (device_registers, False, 0), + (device_nofeatures, False, 0), + (device_zerofeatures, False, 0), + (device_broken, False, 0), + (device_standard, True, 6), + ], +) +def test_FeaturesArray_check(device, expected_result, expected_count): + featuresarray = hidpp20.FeaturesArray(device) + + result = featuresarray._check() + result2 = featuresarray._check() + + assert result == expected_result + assert result2 == expected_result + assert (hidpp20_constants.FEATURE.ROOT in featuresarray) == expected_result + assert len(featuresarray) == expected_count + assert bool(featuresarray) == expected_result + + +@pytest.mark.parametrize( + "device, expected0, expected1, expected2, expected5, expected5v", + [ + (device_zerofeatures, None, None, None, None, None), + (device_standard, 0x0000, 0x0001, 0x0100, hidpp20_constants.FEATURE.REPROG_CONTROLS_V4, 3), + ], +) +def test_FeaturesArray_get_feature(device, expected0, expected1, expected2, expected5, expected5v): + featuresarray = hidpp20.FeaturesArray(device) + device.features = featuresarray + + result0 = featuresarray.get_feature(0) + result1 = featuresarray.get_feature(1) + result2 = featuresarray.get_feature(2) + result5 = featuresarray.get_feature(5) + result2r = featuresarray.get_feature(2) + result5v = featuresarray.get_feature_version(hidpp20_constants.FEATURE.REPROG_CONTROLS_V4) + + assert result0 == expected0 + assert result1 == expected1 + assert result2 == expected2 + assert result2r == expected2 + assert result5 == expected5 + assert result5v == expected5v + + +@pytest.mark.parametrize( + "device, expected0, expected1, expected2, expected1v", + [(device_zerofeatures, None, None, None, None), (device_standard, 0, 5, None, 3)], +) +def test_FeaturesArray_getitem(device, expected0, expected1, expected2, expected1v): + featuresarray = hidpp20.FeaturesArray(device) + device.features = featuresarray + + result_get0 = featuresarray[hidpp20_constants.FEATURE.ROOT] + result_get1 = featuresarray[hidpp20_constants.FEATURE.REPROG_CONTROLS_V4] + result_get2 = featuresarray[hidpp20_constants.FEATURE.GKEY] + result_1v = featuresarray.get_feature_version(hidpp20_constants.FEATURE.REPROG_CONTROLS_V4) + + assert result_get0 == expected0 + assert result_get1 == expected1 + assert result_get2 == expected2 + assert result_1v == expected1v + + +@pytest.mark.parametrize( + "device, index", [(device_zerofeatures, -1), (device_zerofeatures, 5), (device_standard, -1), (device_standard, 6)] +) +def test_KeysArrayV4_query_key_indexerror(device, index): + keysarray = hidpp20.KeysArrayV4(device, 5) + + with pytest.raises(IndexError): + keysarray._query_key(index) + + +@pytest.mark.parametrize("device, index, cid", [(device_standard, 0, 0x0011), (device_standard, 4, 0x0003)]) +def test_KeysArrayV4_query_key(device, index, cid): + keysarray = hidpp20.KeysArrayV4(device, 5) + + keysarray._query_key(index) + + assert keysarray.keys[index]._cid == cid + + +@pytest.mark.parametrize( + "device, count, index, cid, tid, flags, pos, group, gmask", + [ + (device_standard, 4, 0, 0x0011, 0x0012, 0xCDAB, 1, 2, 3), + (device_standard, 6, 1, 0x0111, 0x0022, 0xCDAB, 1, 2, 3), + (device_standard, 8, 3, 0x0311, 0x0032, 0xCDAB, 1, 2, 4), + ], +) +def test_KeysArrayV4__getitem(device, count, index, cid, tid, flags, pos, group, gmask): + keysarray = hidpp20.KeysArrayV4(device, count) + + result = keysarray[index] + + assert result._device == device + assert result.index == index + assert result._cid == cid + assert result._tid == tid + assert result._flags == flags + assert result.pos == pos + assert result.group == group + assert result._gmask == gmask + + +@pytest.mark.parametrize( + "key, index", [(special_keys.CONTROL.Volume_Up, 2), (special_keys.CONTROL.Mute, 4), (special_keys.CONTROL.Next, None)] +) +def test_KeysArrayV4_index(key, index): + keysarray = hidpp20.KeysArrayV4(device_standard, 7) + + result = keysarray.index(key) + + assert result == index