tests: expand tests for device.py

This commit is contained in:
Peter F. Patel-Schneider 2024-04-01 18:13:02 -04:00
parent 269e970aa6
commit c7195881e3
4 changed files with 239 additions and 173 deletions

View File

@ -37,6 +37,21 @@ def open_path(path: Optional[str]) -> int:
return int(path, 16) # can raise exception return int(path, 16) # can raise exception
def ping(responses, handle, devnumber, long_message=False):
for r in responses:
if handle == r.handle and devnumber == r.devnumber and r.id == 0x0010:
return r.response
def request(responses, handle, devnumber, id, *params, no_reply=False, return_error=False, long_message=False, protocol=1.0):
params = b"".join(pack("B", p) if isinstance(p, int) else p for p in params)
print("REQUEST ", hex(handle), hex(devnumber), hex(id), params.hex())
for r in responses:
if handle == r.handle and devnumber == r.devnumber and r.id == id and bytes.fromhex(r.params) == params:
print("RESPONSE", hex(r.handle), hex(r.devnumber), hex(r.id), r.params, r.response)
return bytes.fromhex(r.response) if r.response is not None else None
@dataclass @dataclass
class Response: class Response:
response: Optional[str] response: Optional[str]
@ -51,21 +66,8 @@ def replace_number(responses, number): # change the devnumber for a list of res
return [Response(r.response, r.id, r.params, r.handle, number, r.no_reply) for r in responses] return [Response(r.response, r.id, r.params, r.handle, number, r.no_reply) for r in responses]
def ping(responses, handle, devnumber, long_message=False): def adjust_responses_index(index, responses): # change index-4 responses to index
print("PING ", hex(handle), hex(devnumber) if devnumber else devnumber) return [Response(r.response, r.id - 0x400 + (index << 8), r.params, r.handle, r.devnumber, r.no_reply) for r in responses]
for r in responses:
if handle == r.handle and devnumber == r.devnumber and r.id == 0x0010:
print("RESPONSE", hex(r.handle), hex(r.devnumber), r.response)
return r.response
def request(responses, handle, devnumber, id, *params, no_reply=False, return_error=False, long_message=False, protocol=1.0):
params = b"".join(pack("B", p) if isinstance(p, int) else p for p in params)
print("REQUEST ", hex(handle), hex(devnumber), hex(id), params.hex())
for r in responses:
if handle == r.handle and devnumber == r.devnumber and r.id == id and bytes.fromhex(r.params) == params:
print("RESPONSE", hex(r.handle), hex(r.devnumber), hex(r.id), r.params, r.response)
return bytes.fromhex(r.response) if r.response is not None else None
r_empty = [ # a HID++ device with no responses except for ping r_empty = [ # a HID++ device with no responses except for ping
@ -87,18 +89,30 @@ r_keyboard_2 = [ # a HID++ 2.0 keyboard
Response("030001", 0x0000, "0003"), # device information at 0x03 Response("030001", 0x0000, "0003"), # device information at 0x03
Response("040003", 0x0000, "0100"), # unknown 0100 at 0x04 Response("040003", 0x0000, "0100"), # unknown 0100 at 0x04
Response("050003", 0x0000, "1B04"), # reprogrammable keys V4 at 0x05 Response("050003", 0x0000, "1B04"), # reprogrammable keys V4 at 0x05
Response("060003", 0x0000, "0007"), # device friendly name at 0x06
Response("070003", 0x0000, "0005"), # device name at 0x07
Response("08", 0x0100), # 8 features Response("08", 0x0100), # 8 features
Response("00010001", 0x0110, "01"), # feature set at 0x01 Response("00010001", 0x0110, "01"), # feature set at 0x01
Response("10000001", 0x0110, "02"), # battery status at 0x02 Response("10000001", 0x0110, "02"), # battery status at 0x02
Response("00030001", 0x0110, "03"), # device information at 0x03 Response("00030001", 0x0110, "03"), # device information at 0x03
Response("01000003", 0x0110, "04"), # unknown 0100 at 0x04 Response("01000003", 0x0110, "04"), # unknown 0100 at 0x04
Response("1B040003", 0x0110, "05"), # reprogrammable keys V4 at 0x05 Response("1B040003", 0x0110, "05"), # reprogrammable keys V4 at 0x05
Response("00070003", 0x0000, "06"), # device friendly name at 0x06
Response("00050003", 0x0000, "07"), # device name at 0x07
Response("0212345678000D1234567890ABAA01", 0x0300), # device information Response("0212345678000D1234567890ABAA01", 0x0300), # device information
Response("04", 0x0500), # reprogrammable keys V4
Response("00110012AB010203CD00", 0x0510, "00"), # reprogrammable keys V4 Response("00110012AB010203CD00", 0x0510, "00"), # reprogrammable keys V4
Response("01110022AB010203CD00", 0x0510, "01"), # reprogrammable keys V4 Response("01110022AB010203CD00", 0x0510, "01"), # reprogrammable keys V4
Response("00010111AB010203CD00", 0x0510, "02"), # reprogrammable keys V4 Response("00010111AB010203CD00", 0x0510, "02"), # reprogrammable keys V4
Response("03110032AB010204CD00", 0x0510, "03"), # reprogrammable keys V4 Response("03110032AB010204CD00", 0x0510, "03"), # reprogrammable keys V4
Response("00030333AB010203CD00", 0x0510, "04"), # reprogrammable keys V4 Response("00030333AB010203CD00", 0x0510, "04"), # reprogrammable keys V4
Response("12", 0x0600), # friendly namme
Response("004142434445464748494A4B4C4D4E", 0x0610, "00"),
Response("0E4F50515253000000000000000000", 0x0610, "0E"),
Response("12", 0x0700), # name and kind
Response("4142434445464748494A4B4C4D4E4F", 0x0710, "00"),
Response("505152530000000000000000000000", 0x0710, "0F"),
Response("00", 0x0720),
] ]
r_mouse_1 = [ # a HID++ 1.0 mouse r_mouse_1 = [ # a HID++ 1.0 mouse
@ -130,7 +144,8 @@ r_mouse_3 = [ # a HID++ 2.0 mouse
Response("444544000000000000000000000000", 0x0510, "0F"), # name - last 3 characters Response("444544000000000000000000000000", 0x0510, "0F"), # name - last 3 characters
] ]
responses_key = [
responses_key = [ # responses for Reprogrammable Keys V4 at 0x05
Response("08", 0x0500), # Reprogrammable Keys V4 count Response("08", 0x0500), # Reprogrammable Keys V4 count
Response("00500038010001010400000000000000", 0x0510, "00"), # left button Response("00500038010001010400000000000000", 0x0510, "00"), # left button
Response("00510039010001010400000000000000", 0x0510, "01"), # right button Response("00510039010001010400000000000000", 0x0510, "01"), # right button
@ -163,27 +178,18 @@ responses_key = [
Response("0051FF01005100", 0x0440, "0051FF01005100"), # right button set write Response("0051FF01005100", 0x0440, "0051FF01005100"), # right button set write
] ]
responses_XX = [ # a viable set of responses for Reprogrammable Keys V4 responses_remap = [ # responses for Persistent Remappable Actions at 0x04 and reprogrammable keys at 0x05
Response(4.2, 0x0010), # ping Response("0041", 0x0400),
Response("010001", 0x0000, "0001"), # feature set at 0x01 Response("03", 0x0410),
Response("020003", 0x0000, "1000"), # battery status at 0x02 Response("0301", 0x0410, "00"),
Response("030001", 0x0000, "0003"), # device information at 0x03 Response("0050", 0x0420, "00FF"),
Response("040003", 0x0000, "0100"), # unknown 0100 at 0x04 Response("0050000200010001", 0x0430, "0050FF"), # Left Button
Response("050003", 0x0000, "1B04"), # reprogrammable keys V4 at 0x05 Response("0051", 0x0420, "01FF"),
Response("08", 0x0100), # 8 features Response("0051000200010000", 0x0430, "0051FF"), # Left Button
Response("00010001", 0x0110, "01"), # feature set at 0x01 Response("0052", 0x0420, "02FF"),
Response("10000001", 0x0110, "02"), # battery status at 0x02 Response("0052000100510000", 0x0430, "0052FF"), # key DOWN
Response("00030001", 0x0110, "03"), # device information at 0x03 Response("050002", 0x0000, "1B04"), # REPROGRAMMABLE_KEYS_V4
Response("01000003", 0x0110, "04"), # unknown 0100 at 0x04 ] + responses_key
Response("1B040003", 0x0110, "05"), # reprogrammable keys V4 at 0x05
Response("0212345678000D1234567890ABAA01", 0x0300), # device information
Response("05", 0x0500), # reprogrammable keys V4
Response("00500038610000010100", 0x0510, "00"), # left button
Response("00510039600000010100", 0x0510, "01"), # right button
Response("0052003A110000020300", 0x0510, "02"), # middle button
Response("0053003C710101030700", 0x0510, "03"), # back button
Response("0056003E710102030700", 0x0510, "04"), # forward button
]
responses_gestures = [ # the commented-out messages are not used by either the setting or other testing responses_gestures = [ # the commented-out messages are not used by either the setting or other testing
Response("4203410141020400320480148C21A301", 0x0400, "0000"), # items Response("4203410141020400320480148C21A301", 0x0400, "0000"), # items
@ -233,8 +239,91 @@ responses_gestures = [ # the commented-out messages are not used by either the
Response("000180FF", 0x0480, "000180FF"), # write param 0 Response("000180FF", 0x0480, "000180FF"), # write param 0
] ]
zone_responses_1 = [ # responses for COLOR LED EFFECTS
Response("00000102", 0x0710, "00FF00"),
Response("0000000300040005", 0x0720, "000000"),
Response("0001000B00080009", 0x0720, "000100"),
]
zone_responses_2 = [ # responses for RGB EFFECTS
Response("0000000102", 0x0700, "00FF00"),
Response("0000000300040005", 0x0700, "000000"),
Response("0001000200080009", 0x0700, "000100"),
]
effects_responses_1 = [Response("0100000001", 0x0700)] + zone_responses_1
effects_responses_2 = [Response("FFFF0100000001", 0x0700, "FFFF00")] + zone_responses_2
responses_profiles = [ # OnboardProfile in RAM
Response("0104010101020100FE0200", 0x0900),
Response("000101FF", 0x0950, "00000000"),
Response("FFFFFFFF", 0x0950, "00000004"),
Response("01010290018003000700140028FFFFFF", 0x0950, "00010000"),
Response("FFFF0000000000000000000000000000", 0x0950, "00010010"),
Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "00010020"),
Response("900aFF00800204548000FFFF900aFF00", 0x0950, "00010030"),
Response("800204548000FFFF900aFF0080020454", 0x0950, "00010040"),
Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "00010050"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010060"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010070"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010080"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010090"),
Response("54004500370000000000000000000000", 0x0950, "000100A0"),
Response("00000000000000000000000000000000", 0x0950, "000100B0"),
Response("00000000000000000000000000000000", 0x0950, "000100C0"),
Response("0A01020300500407000000FFFFFFFFFF", 0x0950, "000100D0"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "000100E0"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB", 0x0950, "000100EE"),
]
responses_profiles_rom = [ # OnboardProfile in ROM
Response("0104010101020100FE0200", 0x0900),
Response("00000000", 0x0950, "00000000"),
Response("010101FF", 0x0950, "01000000"),
Response("FFFFFFFF", 0x0950, "01000004"),
Response("01010290018003000700140028FFFFFF", 0x0950, "01010000"),
Response("FFFF0000000000000000000000000000", 0x0950, "01010010"),
Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "01010020"),
Response("900aFF00800204548000FFFF900aFF00", 0x0950, "01010030"),
Response("800204548000FFFF900aFF0080020454", 0x0950, "01010040"),
Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "01010050"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010060"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010070"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010080"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010090"),
Response("54004500370000000000000000000000", 0x0950, "010100A0"),
Response("00000000000000000000000000000000", 0x0950, "010100B0"),
Response("00000000000000000000000000000000", 0x0950, "010100C0"),
Response("0A01020300500407000000FFFFFFFFFF", 0x0950, "010100D0"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "010100E0"),
Response("FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB", 0x0950, "010100EE"),
]
complex_responses_1 = [ # COLOR_LED_EFFECTS
Response(4.2, 0x0010), # ping
Response("010001", 0x0000, "0001"), # FEATURE SET at x01
Response("0A", 0x0100), # 10 features
Response("070001", 0x0000, "8070"), # COLOR_LED_EFFECTS at 0x07
*effects_responses_1,
]
complex_responses_2 = [ # RGB_EFFECTS + reprogrammable keys + persistent actions
Response(4.2, 0x0010), # ping
Response("010001", 0x0000, "0001"), # FEATURE SET at x01
Response("0A", 0x0100), # 10 features
Response("070001", 0x0000, "8071"), # RGB_EFFECTS at 0x07
*effects_responses_2,
Response("040001", 0x0000, "1C00"), # Persistent Remappable Actions at 0x04
*responses_remap,
Response("080001", 0x0000, "6501"), # Gestures at 0x08
*adjust_responses_index(8, responses_gestures),
Response("060003", 0x0000, "1982"), # Backlight 2 at 0x06
Response("010118000001020003000400", 0x0600),
Response("090003", 0x0000, "8100"), # Onboard Profiles at 0x09
*responses_profiles,
]
responses_speedchange = [ responses_speedchange = [
Response("0100", 0x0400), Response("0100", 0x0400),
Response("010001", 0x0000, "0001"), # FEATURE SET at x01
Response("0A", 0x0100), # 10 features
Response("0120", 0x0410, "0120"), Response("0120", 0x0410, "0120"),
Response("050001", 0x0000, "1B04"), # REPROG_CONTROLS_V4 Response("050001", 0x0000, "1B04"), # REPROG_CONTROLS_V4
Response("01", 0x0500), Response("01", 0x0500),
@ -269,9 +358,13 @@ class Device:
led_effects = device.Device.led_effects led_effects = device.Device.led_effects
gestures = device.Device.gestures gestures = device.Device.gestures
__hash__ = device.Device.__hash__ __hash__ = device.Device.__hash__
feature_request = device.Device.feature_request
def __post_init__(self): def __post_init__(self):
self._name = self.name
self._protocol = self.protocol
self.persister = configuration._DeviceEntry() self.persister = configuration._DeviceEntry()
self.features = hidpp20.FeaturesArray(self)
self.settings = [] self.settings = []
if self.feature is not None: if self.feature is not None:
self.features = hidpp20.FeaturesArray(self) self.features = hidpp20.FeaturesArray(self)
@ -281,20 +374,18 @@ class Device:
self.setting_callback = lambda x, y, z: None self.setting_callback = lambda x, y, z: None
self.add_notification_handler = lambda x, y: None self.add_notification_handler = lambda x, y: None
def request(self, id, *params, no_reply=False): def request(self, id, *params, no_reply=False, long_message=False, protocol=2.0):
if params is None:
params = []
params = b"".join(pack("B", p) if isinstance(p, int) else p for p in params) params = b"".join(pack("B", p) if isinstance(p, int) else p for p in params)
print("REQUEST ", self.name, hex(id), params.hex().upper()) print("REQUEST ", self._name, hex(id), params.hex().upper())
for r in self.responses: for r in self.responses:
if id == r.id and params == bytes.fromhex(r.params): if id == r.id and params == bytes.fromhex(r.params):
print("RESPONSE", self.name, hex(r.id), r.params, r.response) print("RESPONSE", self._name, hex(r.id), r.params, r.response)
return bytes.fromhex(r.response) if isinstance(r.response, str) else r.response return bytes.fromhex(r.response) if isinstance(r.response, str) else r.response
print("RESPONSE", self.name, None) print("RESPONSE", self._name, None)
def feature_request(self, feature, function=0x00, *params, no_reply=False): def ping(self, handle=None, devnumber=None, long_message=False):
if self.protocol >= 2.0: print("PING", self._protocol)
return hidpp20.feature_request(self, feature, function, *params, no_reply=no_reply) return self._protocol
def match_requests(number, responses, call_args_list): def match_requests(number, responses, call_args_list):

View File

@ -21,13 +21,15 @@ from unittest import mock
import pytest import pytest
from logitech_receiver import common
from logitech_receiver import device from logitech_receiver import device
from logitech_receiver import hidpp20
from . import hidpp from . import hidpp
@pytest.fixture @pytest.fixture
def mock_base(): def mock_base(): # allow override of base functions
with mock.patch("logitech_receiver.base.open_path", return_value=None) as mock_open_path: with mock.patch("logitech_receiver.base.open_path", return_value=None) as mock_open_path:
with mock.patch("logitech_receiver.base.request", return_value=None) as mock_request: with mock.patch("logitech_receiver.base.request", return_value=None) as mock_request:
with mock.patch("logitech_receiver.base.ping", return_value=None) as mock_ping: with mock.patch("logitech_receiver.base.ping", return_value=None) as mock_ping:
@ -72,7 +74,29 @@ def test_DeviceFactory(device_info, responses, success, mock_base):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"device_info, responses, handle, _name, _codename, number, protocol", "device_info, responses, codename, name, kind",
[
(di_CCCC, hidpp.r_empty, "?? (CCCC)", "Unknown device CCCC", "?"),
(di_C318, hidpp.r_keyboard_1, "?? (C318)", "Unknown device C318", "?"),
(di_B530, hidpp.r_keyboard_2, "ABCDEFGHIJKLMNOPQR", "ABCDEFGHIJKLMNOPQR", common.NamedInt(1, "keyboard")),
],
)
def test_Device_name(device_info, responses, codename, name, kind, mock_base):
mock_base[0].side_effect = hidpp.open_path
mock_base[1].side_effect = partial(hidpp.request, responses)
mock_base[2].side_effect = partial(hidpp.ping, responses)
test_device = device.DeviceFactory.create_device(device_info)
test_device._codename = None
test_device._name = None
test_device._kind = None
assert test_device.codename == codename
assert test_device.name == name
assert test_device.kind == kind
@pytest.mark.parametrize(
"device_info, responses, handle, _name, _codename, number, protocol, registers",
zip( zip(
[di_CCCC, di_C318, di_B530, di_C068, di_C08A, di_DDDD], [di_CCCC, di_C318, di_B530, di_C068, di_C08A, di_DDDD],
[hidpp.r_empty, hidpp.r_keyboard_1, hidpp.r_keyboard_2, hidpp.r_mouse_1, hidpp.r_mouse_2, hidpp.r_mouse_3], [hidpp.r_empty, hidpp.r_keyboard_1, hidpp.r_keyboard_2, hidpp.r_mouse_1, hidpp.r_mouse_2, hidpp.r_mouse_3],
@ -81,9 +105,10 @@ def test_DeviceFactory(device_info, responses, success, mock_base):
[None, "Illuminated", "Craft", "G700", "MX Vertical", None], [None, "Illuminated", "Craft", "G700", "MX Vertical", None],
[0xFF, 0x0, 0xFF, 0x0, 0xFF, 0xFF], [0xFF, 0x0, 0xFF, 0x0, 0xFF, 0xFF],
[1.0, 1.0, 4.5, 1.0, 4.5, 4.5], [1.0, 1.0, 4.5, 1.0, 4.5, 4.5],
[None, [], [], (common.NamedInt(7, "battery status"), common.NamedInt(81, "three leds")), [], None],
), ),
) )
def test_Device_info(device_info, responses, handle, _name, _codename, number, protocol, mock_base): def test_Device_info(device_info, responses, handle, _name, _codename, number, protocol, registers, mock_base):
mock_base[0].side_effect = hidpp.open_path mock_base[0].side_effect = hidpp.open_path
mock_base[1].side_effect = partial(hidpp.request, responses) mock_base[1].side_effect = partial(hidpp.request, responses)
mock_base[2].side_effect = partial(hidpp.ping, responses) mock_base[2].side_effect = partial(hidpp.ping, responses)
@ -95,6 +120,7 @@ def test_Device_info(device_info, responses, handle, _name, _codename, number, p
assert test_device._codename == _codename assert test_device._codename == _codename
assert test_device.number == number assert test_device.number == number
assert test_device._protocol == protocol assert test_device._protocol == protocol
assert test_device.registers == registers
assert bool(test_device) assert bool(test_device)
test_device.__del__() test_device.__del__()
@ -174,7 +200,7 @@ def test_Device_receiver(number, pairing_info, responses, handle, _name, codenam
@pytest.mark.parametrize( @pytest.mark.parametrize(
"number, pairing_info, responses, handle, unitId, modelId, tid_map, kind, firmware, serial, id, psl, rate", "number, info, responses, handle, unitId, modelId, tid, kind, firmware, serial, id, psl, rate",
zip( zip(
range(1, 7), range(1, 7),
[pi_CCCC, pi_2011, pi_4066, pi_1007, pi_407B, pi_DDDD], [pi_CCCC, pi_2011, pi_4066, pi_1007, pi_407B, pi_DDDD],
@ -192,55 +218,77 @@ def test_Device_receiver(number, pairing_info, responses, handle, _name, codenam
), ),
) )
def test_Device_ids( def test_Device_ids(
number, number, info, responses, handle, unitId, modelId, tid, kind, firmware, serial, id, psl, rate, mock_base, mock_hid
pairing_info,
responses,
handle,
unitId,
modelId,
tid_map,
kind,
firmware,
serial,
id,
psl,
rate,
mock_base,
mock_hid,
): ):
mock_base[0].side_effect = hidpp.open_path mock_base[0].side_effect = hidpp.open_path
mock_base[1].side_effect = partial(hidpp.request, hidpp.replace_number(responses, number)) mock_base[1].side_effect = partial(hidpp.request, hidpp.replace_number(responses, number))
mock_base[2].side_effect = partial(hidpp.ping, hidpp.replace_number(responses, number)) mock_base[2].side_effect = partial(hidpp.ping, hidpp.replace_number(responses, number))
mock_hid.side_effect = lambda x, y, z: x mock_hid.side_effect = lambda x, y, z: x
test_device = device.Device(Receiver(), number, True, pairing_info, handle=handle) test_device = device.Device(Receiver(), number, True, info, handle=handle)
assert test_device.unitId == unitId assert test_device.unitId == unitId
assert test_device.modelId == modelId assert test_device.modelId == modelId
assert test_device.tid_map == tid_map assert test_device.tid_map == tid
assert test_device.kind == kind assert test_device.kind == kind
assert test_device.firmware == firmware or len(test_device.firmware) > 0 and firmware is True assert test_device.firmware == firmware or len(test_device.firmware) > 0 and firmware is True
assert test_device.id == id assert test_device.id == id
assert test_device.power_switch_location == psl assert test_device.power_switch_location == psl
assert test_device.polling_rate == rate assert test_device.polling_rate == rate
class TestDevice(device.Device): # a fully functional Device but its HID++ functions look at local data
def __init__(self, responses, *args, **kwargs):
self.responses = responses
super().__init__(*args, **kwargs)
request = hidpp.Device.request
ping = hidpp.Device.ping
@pytest.mark.parametrize(
"device_info, responses, protocol, led, keys, remap, gestures, backlight, profiles",
[
(di_CCCC, hidpp.r_empty, 1.0, type(None), None, None, None, None, None),
(di_C318, hidpp.r_empty, 1.0, type(None), None, None, None, None, None),
(di_B530, hidpp.r_keyboard_1, 2.0, type(None), 0, 0, 0, None, None),
(di_B530, hidpp.complex_responses_1, 4.5, hidpp20.LEDEffectsInfo, 0, 0, 0, None, None),
(di_B530, hidpp.complex_responses_2, 4.5, hidpp20.RGBEffectsInfo, 8, 3, 1, True, True),
],
)
def test_Device_complex(device_info, responses, protocol, led, keys, remap, gestures, backlight, profiles):
test_device = TestDevice(responses, None, None, online=True, device_info=device_info)
test_device._name = "TestDevice"
test_device._protocol = protocol
assert type(test_device.led_effects) == led
if keys is None:
assert test_device.keys == keys
else:
assert len(test_device.keys) == keys
if remap is None:
assert test_device.remap_keys == remap
else:
assert len(test_device.remap_keys) == remap
assert (test_device.gestures is None) == (gestures is None)
assert (test_device.backlight is None) == (backlight is None)
assert (test_device.profiles is None) == (profiles is None)
""" TODO """ TODO
302-305 profiles
309-314 registers settings
318-337 settings set configuration
340-341 set configuration reset
344 reset persister
348-352 persister battery
355-368 battery set_battery_info
372-390 set_battery_info read_battery
394-396 read_battery enable_connection_notifications
401-420 enable_connection_notifications changed
425-451 changed add_notification_handler
465 add_notification_handler remove_notification_handler
470-473 remove_notification_handler handle_notification
476-480 handle_notification
""" """
# IMPORTANT TODO - battery # IMPORTANT TODO - battery

View File

@ -418,20 +418,6 @@ def test_KeysArrayV4_key(key, expected_index, expected_mapped_to, expected_remap
assert list(remappable_to) == expected_remappable_to assert list(remappable_to) == expected_remappable_to
responses_remap = [
hidpp.Response("0041", 0x0400),
hidpp.Response("03", 0x0410),
hidpp.Response("0301", 0x0410, "00"),
hidpp.Response("0050", 0x0420, "00FF"),
hidpp.Response("0050000200010001", 0x0430, "0050FF"), # Left Button
hidpp.Response("0051", 0x0420, "01FF"),
hidpp.Response("0051000200010000", 0x0430, "0051FF"), # Left Button
hidpp.Response("0052", 0x0420, "02FF"),
hidpp.Response("0052000100510000", 0x0430, "0052FF"), # key DOWN
hidpp.Response("050002", 0x0000, "1B04"), # REPROGRAMMABLE_KEYS_V4
] + hidpp.responses_key
@pytest.mark.parametrize( @pytest.mark.parametrize(
"device, index", [(device_zerofeatures, -1), (device_zerofeatures, 5), (device_standard, -1), (device_standard, 6)] "device, index", [(device_zerofeatures, -1), (device_zerofeatures, 5), (device_standard, -1), (device_standard, 6)]
) )
@ -448,9 +434,9 @@ def test_KeysArrayPersistent_index_error(device, index):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"responses, key, index, mapped_to, capabilities", "responses, key, index, mapped_to, capabilities",
[ [
(responses_remap, special_keys.CONTROL.Left_Button, 0, common.NamedInt(0x01, "Mouse Button Left"), 0x41), (hidpp.responses_remap, special_keys.CONTROL.Left_Button, 0, common.NamedInt(0x01, "Mouse Button Left"), 0x41),
(responses_remap, special_keys.CONTROL.Right_Button, 1, common.NamedInt(0x01, "Mouse Button Left"), 0x41), (hidpp.responses_remap, special_keys.CONTROL.Right_Button, 1, common.NamedInt(0x01, "Mouse Button Left"), 0x41),
(responses_remap, special_keys.CONTROL.Middle_Button, 2, common.NamedInt(0x51, "DOWN"), 0x41), (hidpp.responses_remap, special_keys.CONTROL.Middle_Button, 2, common.NamedInt(0x51, "DOWN"), 0x41),
], ],
) )
def test_KeysArrayPersistent_key(responses, key, index, mapped_to, capabilities): def test_KeysArrayPersistent_key(responses, key, index, mapped_to, capabilities):
@ -672,27 +658,15 @@ def test_LEDEffectInfo(feature, function, response, ID, capabilities, period):
assert info.period == period assert info.period == period
zone_responses_1 = [
hidpp.Response("00000102", 0x0410, "00FF00"),
hidpp.Response("0000000300040005", 0x0420, "000000"),
hidpp.Response("0001000B00080009", 0x0420, "000100"),
]
zone_responses_2 = [
hidpp.Response("0000000102", 0x0400, "00FF00"),
hidpp.Response("0000000300040005", 0x0400, "000000"),
hidpp.Response("0001000200080009", 0x0400, "000100"),
]
@pytest.mark.parametrize( @pytest.mark.parametrize(
"feature, function, offset, effect_function, responses, index, location, count, id_1", "feature, function, offset, effect_function, responses, index, location, count, id_1",
[ [
[hidpp20_constants.FEATURE.COLOR_LED_EFFECTS, 0x10, 0, 0x20, zone_responses_1, 0, 1, 2, 0xB], [hidpp20_constants.FEATURE.COLOR_LED_EFFECTS, 0x10, 0, 0x20, hidpp.zone_responses_1, 0, 1, 2, 0xB],
[hidpp20_constants.FEATURE.RGB_EFFECTS, 0x00, 1, 0x00, zone_responses_2, 0, 1, 2, 2], [hidpp20_constants.FEATURE.RGB_EFFECTS, 0x00, 1, 0x00, hidpp.zone_responses_2, 0, 1, 2, 2],
], ],
) )
def test_LEDZoneInfo(feature, function, offset, effect_function, responses, index, location, count, id_1): def test_LEDZoneInfo(feature, function, offset, effect_function, responses, index, location, count, id_1):
device = hidpp.Device(feature=feature, responses=responses) device = hidpp.Device(feature=feature, responses=responses, offset=0x07)
zone = hidpp20.LEDZoneInfo(feature, function, offset, effect_function, device, index) zone = hidpp20.LEDZoneInfo(feature, function, offset, effect_function, device, index)
@ -706,13 +680,13 @@ def test_LEDZoneInfo(feature, function, offset, effect_function, responses, inde
@pytest.mark.parametrize( @pytest.mark.parametrize(
"responses, setting, expected_command", "responses, setting, expected_command",
[ [
[zone_responses_1, hidpp20.LEDEffectSetting(ID=0), None], [hidpp.zone_responses_1, hidpp20.LEDEffectSetting(ID=0), None],
[zone_responses_1, hidpp20.LEDEffectSetting(ID=3, period=0x20, intensity=0x50), "000000000000000020500000"], [hidpp.zone_responses_1, hidpp20.LEDEffectSetting(ID=3, period=0x20, intensity=0x50), "000000000000000020500000"],
[zone_responses_1, hidpp20.LEDEffectSetting(ID=0xB, color=0x808080, period=0x20), "000180808000002000000000"], [hidpp.zone_responses_1, hidpp20.LEDEffectSetting(ID=0xB, color=0x808080, period=0x20), "000180808000002000000000"],
], ],
) )
def test_LEDZoneInfo_to_command(responses, setting, expected_command): def test_LEDZoneInfo_to_command(responses, setting, expected_command):
device = hidpp.Device(feature=hidpp20_constants.FEATURE.COLOR_LED_EFFECTS, responses=responses) device = hidpp.Device(feature=hidpp20_constants.FEATURE.COLOR_LED_EFFECTS, responses=responses, offset=0x07)
zone = hidpp20.LEDZoneInfo(hidpp20_constants.FEATURE.COLOR_LED_EFFECTS, 0x10, 0, 0x20, device, 0) zone = hidpp20.LEDZoneInfo(hidpp20_constants.FEATURE.COLOR_LED_EFFECTS, 0x10, 0, 0x20, device, 0)
command = zone.to_command(setting) command = zone.to_command(setting)
@ -720,19 +694,15 @@ def test_LEDZoneInfo_to_command(responses, setting, expected_command):
assert command == (bytes.fromhex(expected_command) if expected_command is not None else None) assert command == (bytes.fromhex(expected_command) if expected_command is not None else None)
effects_responses_1 = [hidpp.Response("0100000001", 0x0400)] + zone_responses_1
effects_responses_2 = [hidpp.Response("FFFF0100000001", 0x0400, "FFFF00")] + zone_responses_2
@pytest.mark.parametrize( @pytest.mark.parametrize(
"feature, cls, responses, readable, count, count_0", "feature, cls, responses, readable, count, count_0",
[ [
[hidpp20_constants.FEATURE.COLOR_LED_EFFECTS, hidpp20.LEDEffectsInfo, effects_responses_1, 1, 1, 2], [hidpp20_constants.FEATURE.COLOR_LED_EFFECTS, hidpp20.LEDEffectsInfo, hidpp.effects_responses_1, 1, 1, 2],
[hidpp20_constants.FEATURE.RGB_EFFECTS, hidpp20.RGBEffectsInfo, effects_responses_2, 1, 1, 2], [hidpp20_constants.FEATURE.RGB_EFFECTS, hidpp20.RGBEffectsInfo, hidpp.effects_responses_2, 1, 1, 2],
], ],
) )
def test_LED_RGB_EffectsInfo(feature, cls, responses, readable, count, count_0): def test_LED_RGB_EffectsInfo(feature, cls, responses, readable, count, count_0):
device = hidpp.Device(feature=feature, responses=responses) device = hidpp.Device(feature=feature, responses=responses, offset=0x07)
effects = cls(device) effects = cls(device)
@ -827,60 +797,15 @@ def test_OnboardProfile_bytes(hex, name, sector, enabled, buttons, gbuttons, res
assert yaml.safe_load(yaml.dump(profile)).to_bytes(len(hex) // 2).hex().upper() == hex assert yaml.safe_load(yaml.dump(profile)).to_bytes(len(hex) // 2).hex().upper() == hex
responses_profiles = [
hidpp.Response("0104010101020100FE0200", 0x0400),
hidpp.Response("000101FF", 0x0450, "00000000"),
hidpp.Response("FFFFFFFF", 0x0450, "00000004"),
hidpp.Response("01010290018003000700140028FFFFFF", 0x0450, "00010000"),
hidpp.Response("FFFF0000000000000000000000000000", 0x0450, "00010010"),
hidpp.Response("8000FFFF900aFF00800204548000FFFF", 0x0450, "00010020"),
hidpp.Response("900aFF00800204548000FFFF900aFF00", 0x0450, "00010030"),
hidpp.Response("800204548000FFFF900aFF0080020454", 0x0450, "00010040"),
hidpp.Response("8000FFFF900aFF00800204548000FFFF", 0x0450, "00010050"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0450, "00010060"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0450, "00010070"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0450, "00010080"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0450, "00010090"),
hidpp.Response("54004500370000000000000000000000", 0x0450, "000100A0"),
hidpp.Response("00000000000000000000000000000000", 0x0450, "000100B0"),
hidpp.Response("00000000000000000000000000000000", 0x0450, "000100C0"),
hidpp.Response("0A01020300500407000000FFFFFFFFFF", 0x0450, "000100D0"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0450, "000100E0"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB", 0x0450, "000100EE"),
]
responses_profiles_rom = [
hidpp.Response("0104010101020100FE0200", 0x0400),
hidpp.Response("00000000", 0x0450, "00000000"),
hidpp.Response("010101FF", 0x0450, "01000000"),
hidpp.Response("FFFFFFFF", 0x0450, "01000004"),
hidpp.Response("01010290018003000700140028FFFFFF", 0x0450, "01010000"),
hidpp.Response("FFFF0000000000000000000000000000", 0x0450, "01010010"),
hidpp.Response("8000FFFF900aFF00800204548000FFFF", 0x0450, "01010020"),
hidpp.Response("900aFF00800204548000FFFF900aFF00", 0x0450, "01010030"),
hidpp.Response("800204548000FFFF900aFF0080020454", 0x0450, "01010040"),
hidpp.Response("8000FFFF900aFF00800204548000FFFF", 0x0450, "01010050"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0450, "01010060"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0450, "01010070"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0450, "01010080"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0450, "01010090"),
hidpp.Response("54004500370000000000000000000000", 0x0450, "010100A0"),
hidpp.Response("00000000000000000000000000000000", 0x0450, "010100B0"),
hidpp.Response("00000000000000000000000000000000", 0x0450, "010100C0"),
hidpp.Response("0A01020300500407000000FFFFFFFFFF", 0x0450, "010100D0"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0450, "010100E0"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB", 0x0450, "010100EE"),
]
@pytest.mark.parametrize( @pytest.mark.parametrize(
"responses, name, count, buttons, gbuttons, sectors, size", "responses, name, count, buttons, gbuttons, sectors, size",
[ [
(responses_profiles, "ONB", 1, 2, 2, 1, 254), (hidpp.responses_profiles, "ONB", 1, 2, 2, 1, 254),
(responses_profiles_rom, "ONB", 1, 2, 2, 1, 254), (hidpp.responses_profiles_rom, "ONB", 1, 2, 2, 1, 254),
], ],
) )
def test_OnboardProfiles_device(responses, name, count, buttons, gbuttons, sectors, size): def test_OnboardProfiles_device(responses, name, count, buttons, gbuttons, sectors, size):
device = hidpp.Device(name, True, 4.5, responses=responses, feature=hidpp20_constants.FEATURE.ONBOARD_PROFILES) device = hidpp.Device(name, True, 4.5, responses=responses, feature=hidpp20_constants.FEATURE.ONBOARD_PROFILES, offset=0x9)
device._profiles = None device._profiles = None
profiles = _hidpp20.get_profiles(device) profiles = _hidpp20.get_profiles(device)

View File

@ -348,6 +348,7 @@ simple_tests = [
Setup( Setup(
FeatureTest(settings_templates.OnboardProfiles, 0, 1, offset=0x0C), FeatureTest(settings_templates.OnboardProfiles, 0, 1, offset=0x0C),
common.NamedInts(**{"Disabled": 0, "Profile 1": 1, "Profile 2": 2}), common.NamedInts(**{"Disabled": 0, "Profile 1": 1, "Profile 2": 2}),
hidpp.Response("01030001010101000101", 0x0C00),
hidpp.Response("00010100000201FFFFFFFFFFFFFFFFFF", 0x0C50, "00000000"), hidpp.Response("00010100000201FFFFFFFFFFFFFFFFFF", 0x0C50, "00000000"),
hidpp.Response("000201FFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000004"), hidpp.Response("000201FFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000004"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000008"), hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000008"),
@ -358,6 +359,7 @@ simple_tests = [
Setup( Setup(
FeatureTest(settings_templates.OnboardProfiles, 1, 0, offset=0x0C), FeatureTest(settings_templates.OnboardProfiles, 1, 0, offset=0x0C),
common.NamedInts(**{"Disabled": 0, "Profile 1": 1, "Profile 2": 2}), common.NamedInts(**{"Disabled": 0, "Profile 1": 1, "Profile 2": 2}),
hidpp.Response("01030001010101000101", 0x0C00),
hidpp.Response("00010100000201FFFFFFFFFFFFFFFFFF", 0x0C50, "00000000"), hidpp.Response("00010100000201FFFFFFFFFFFFFFFFFF", 0x0C50, "00000000"),
hidpp.Response("000201FFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000004"), hidpp.Response("000201FFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000004"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000008"), hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000008"),