change pairing error values to intenums

* refactoring(logitech_receiver/notifications): change to enums PairingError and BoltPairingError

* refactoring(logitech_receiver/notifications): change to enums PairingError and BoltPairingError (Fix pre-commit checks)

* refactor(logitech_receiver/base.py): create unit tests for ping function before replacing ERRORNamedInts by IntEnum

* refactor(logitech_receiver/base.py): create unit tests for request function before replacing ERROR NamedInts by IntEnum

* refactor(logitech_receiver/base.py): create unit tests for ping function before replacing ERRORNamedInts by IntEnum (add exclusion for macOS)

* refactor(logitech_receiver/base.py): create unit tests for ping function before replacing ERRORNamedInts by IntEnum (fix for python < 3.10)
This commit is contained in:
Romain Loutrel 2024-10-23 22:22:22 +02:00 committed by GitHub
parent 2185a8390c
commit 79ffbda903
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 99 additions and 9 deletions

View File

@ -102,8 +102,17 @@ ERROR = NamedInts(
wrong_pin_code=0x0C,
)
PAIRING_ERRORS = NamedInts(device_timeout=0x01, device_not_supported=0x02, too_many_devices=0x03, sequence_timeout=0x06)
BOLT_PAIRING_ERRORS = NamedInts(device_timeout=0x01, failed=0x02)
class PairingError(IntEnum):
DEVICE_TIMEOUT = 0x01
DEVICE_NOT_SUPPORTED = 0x02
TOO_MANY_DEVICES = 0x03
SEQUENCE_TIMEOUT = 0x06
class BoltPairingError(IntEnum):
DEVICE_TIMEOUT = 0x01
FAILED = 0x02
class Registers(IntEnum):

View File

@ -91,7 +91,7 @@ def _process_receiver_notification(receiver: Receiver, hidpp_notification: HIDPP
receiver.pairing.new_device = None
pair_error = ord(hidpp_notification.data[:1])
if pair_error:
receiver.pairing.error = error_string = hidpp10_constants.PAIRING_ERRORS[pair_error]
receiver.pairing.error = error_string = hidpp10_constants.PairingError(pair_error)
receiver.pairing.new_device = None
logger.warning("pairing error %d: %s", pair_error, error_string)
receiver.changed(reason=reason)
@ -110,7 +110,7 @@ def _process_receiver_notification(receiver: Receiver, hidpp_notification: HIDPP
receiver.pairing.device_passkey = None
discover_error = ord(hidpp_notification.data[:1])
if discover_error:
receiver.pairing.error = discover_string = hidpp10_constants.BOLT_PAIRING_ERRORS[discover_error]
receiver.pairing.error = discover_string = hidpp10_constants.BoltPairingError(discover_error)
logger.warning("bolt discovering error %d: %s", discover_error, discover_string)
receiver.changed(reason=reason)
return True
@ -150,7 +150,7 @@ def _process_receiver_notification(receiver: Receiver, hidpp_notification: HIDPP
elif hidpp_notification.address == 0x02 and not pair_error:
receiver.pairing.new_device = receiver.register_new_device(hidpp_notification.data[7])
if pair_error:
receiver.pairing.error = error_string = hidpp10_constants.BOLT_PAIRING_ERRORS[pair_error]
receiver.pairing.error = error_string = hidpp10_constants.BoltPairingError(pair_error)
receiver.pairing.new_device = None
logger.warning("pairing error %d: %s", pair_error, error_string)
receiver.changed(reason=reason)

View File

@ -1,6 +1,15 @@
import struct
import sys
from unittest import mock
import pytest
from logitech_receiver import base
from logitech_receiver import exceptions
from logitech_receiver.base import HIDPP_SHORT_MESSAGE_ID
from logitech_receiver.base import request
from logitech_receiver.hidpp10_constants import ERROR
@pytest.mark.parametrize(
@ -111,3 +120,69 @@ def test_get_next_sw_id():
assert res1 == 2
assert res2 == 3
@pytest.mark.parametrize(
"prefix, error_code, return_error, raise_exception",
[
(b"\x8f", ERROR.invalid_SubID__command, False, False),
(b"\x8f", ERROR.invalid_SubID__command, True, False),
(b"\xff", ERROR.invalid_SubID__command, False, True),
],
)
def test_request_errors(prefix: bytes, error_code: ERROR, return_error: bool, raise_exception: bool):
handle = 0
device_number = 66
next_sw_id = 0x02
reply_data_sw_id = struct.pack("!H", 0x0000 | next_sw_id)
with mock.patch(
"logitech_receiver.base._read",
return_value=(HIDPP_SHORT_MESSAGE_ID, device_number, prefix + reply_data_sw_id + struct.pack("B", error_code)),
), mock.patch("logitech_receiver.base._skip_incoming", return_value=None), mock.patch(
"logitech_receiver.base.write", return_value=None
), mock.patch("logitech_receiver.base._get_next_sw_id", return_value=next_sw_id):
if raise_exception:
with pytest.raises(exceptions.FeatureCallError) as context:
request(handle, device_number, next_sw_id, return_error=return_error)
assert context.value.number == device_number
assert context.value.request == next_sw_id
assert context.value.error == error_code
assert context.value.params == b""
else:
result = request(handle, device_number, next_sw_id, return_error=return_error)
assert result == (error_code if return_error else None)
@pytest.mark.skipif(sys.platform == "darwin", reason="Test only runs on Linux")
@pytest.mark.parametrize(
"simulated_error, expected_result",
[
(ERROR.invalid_SubID__command, 1.0),
(ERROR.resource_error, None),
(ERROR.connection_request_failed, None),
(ERROR.unknown_device, exceptions.NoSuchDevice),
],
)
def test_ping_errors(simulated_error: ERROR, expected_result):
handle = 1
device_number = 1
next_sw_id = 0x05
reply_data_sw_id = struct.pack("!H", 0x0010 | next_sw_id)
with mock.patch(
"logitech_receiver.base._read",
return_value=(HIDPP_SHORT_MESSAGE_ID, device_number, b"\x8f" + reply_data_sw_id + bytes([simulated_error])),
), mock.patch("logitech_receiver.base._get_next_sw_id", return_value=next_sw_id):
if isinstance(expected_result, type) and issubclass(expected_result, Exception):
with pytest.raises(expected_result) as context:
base.ping(handle=handle, devnumber=device_number)
assert context.value.number == device_number
assert context.value.request == struct.unpack("!H", reply_data_sw_id)[0]
else:
result = base.ping(handle=handle, devnumber=device_number)
assert result == expected_result

View File

@ -1,8 +1,10 @@
import pytest
from logitech_receiver import hidpp10_constants
from logitech_receiver import notifications
from logitech_receiver.base import HIDPPNotification
from logitech_receiver.common import Notification
from logitech_receiver.hidpp10_constants import BoltPairingError
from logitech_receiver.hidpp10_constants import PairingError
from logitech_receiver.hidpp10_constants import Registers
from logitech_receiver.receiver import Receiver
@ -24,8 +26,12 @@ class MockLowLevelInterface:
@pytest.mark.parametrize(
"sub_id, notification_data, expected_error, expected_new_device",
[
(Registers.DISCOVERY_STATUS_NOTIFICATION, b"\x01", "device_timeout", None),
(Registers.PAIRING_STATUS_NOTIFICATION, b"\x02", "failed", None),
(Registers.DISCOVERY_STATUS_NOTIFICATION, b"\x01", BoltPairingError.DEVICE_TIMEOUT, None),
(Registers.PAIRING_STATUS_NOTIFICATION, b"\x02", BoltPairingError.FAILED, None),
(Notification.PAIRING_LOCK, b"\x01", PairingError.DEVICE_TIMEOUT, None),
(Notification.PAIRING_LOCK, b"\x02", PairingError.DEVICE_NOT_SUPPORTED, None),
(Notification.PAIRING_LOCK, b"\x03", PairingError.TOO_MANY_DEVICES, None),
(Notification.PAIRING_LOCK, b"\x06", PairingError.SEQUENCE_TIMEOUT, None),
],
)
def test_process_receiver_notification(sub_id, notification_data, expected_error, expected_new_device):
@ -35,5 +41,5 @@ def test_process_receiver_notification(sub_id, notification_data, expected_error
result = notifications._process_receiver_notification(receiver, notification)
assert result
assert receiver.pairing.error == hidpp10_constants.BOLT_PAIRING_ERRORS[expected_error]
assert receiver.pairing.error == expected_error
assert receiver.pairing.new_device is expected_new_device