From 6a9a40b856ab3a824eeffe376d6ede7046d25541 Mon Sep 17 00:00:00 2001 From: Rob Berwick Date: Sun, 17 Nov 2024 16:47:22 +0000 Subject: [PATCH 1/3] refactor: move _data_to_message and rename make `_data_to_message` a standalone function, move it to a `utilities` package, and rename --- src/blinkstick/blinkstick.py | 28 +++++++--------------------- src/blinkstick/utilities.py | 18 ++++++++++++++++++ tests/utilities/__init__.py | 0 3 files changed, 25 insertions(+), 21 deletions(-) create mode 100644 src/blinkstick/utilities.py create mode 100644 tests/utilities/__init__.py diff --git a/src/blinkstick/blinkstick.py b/src/blinkstick/blinkstick.py index 1ccbb78..76b036f 100644 --- a/src/blinkstick/blinkstick.py +++ b/src/blinkstick/blinkstick.py @@ -16,6 +16,7 @@ ) from blinkstick.constants import VENDOR_ID, PRODUCT_ID, BlinkStickVariant from blinkstick.exceptions import BlinkStickException +from blinkstick.utilities import string_to_info_block_data if sys.platform == "win32": from blinkstick.backends.win32 import Win32Backend as USBBackend @@ -454,25 +455,6 @@ def get_info_block2(self) -> str: result += chr(i) return result - def _data_to_message(self, data: str) -> bytes: - """ - Helper method to convert a string to byte array of 32 bytes. - - @type data: str - @param data: The data to convert to byte array - - @rtype: byte[32] - @return: It fills the rest of bytes with zeros. - """ - byte_array = bytearray([1]) - for c in data: - byte_array.append(ord(c)) - - for i in range(32 - len(data)): - byte_array.append(0) - - return bytes(byte_array) - def set_info_block1(self, data: str) -> None: """ Sets the infoblock1 with specified string. @@ -482,7 +464,9 @@ def set_info_block1(self, data: str) -> None: @type data: str @param data: InfoBlock1 for the backend to set """ - self.backend.control_transfer(0x20, 0x9, 0x0002, 0, self._data_to_message(data)) + self.backend.control_transfer( + 0x20, 0x9, 0x0002, 0, string_to_info_block_data(data) + ) def set_info_block2(self, data: str) -> None: """ @@ -493,7 +477,9 @@ def set_info_block2(self, data: str) -> None: @type data: str @param data: InfoBlock2 for the backend to set """ - self.backend.control_transfer(0x20, 0x9, 0x0003, 0, self._data_to_message(data)) + self.backend.control_transfer( + 0x20, 0x9, 0x0003, 0, string_to_info_block_data(data) + ) def set_random_color(self) -> None: """ diff --git a/src/blinkstick/utilities.py b/src/blinkstick/utilities.py new file mode 100644 index 0000000..095c3c0 --- /dev/null +++ b/src/blinkstick/utilities.py @@ -0,0 +1,18 @@ +def string_to_info_block_data(data: str) -> bytes: + """ + Helper method to convert a string to byte array of 32 bytes. + + @type data: str + @param data: The data to convert to byte array + + @rtype: byte[32] + @return: It fills the rest of bytes with zeros. + """ + byte_array = bytearray([1]) + for c in data: + byte_array.append(ord(c)) + + for i in range(32 - len(data)): + byte_array.append(0) + + return bytes(byte_array) diff --git a/tests/utilities/__init__.py b/tests/utilities/__init__.py new file mode 100644 index 0000000..e69de29 From 350b45617ed000c305e8dfe374bf21f1b9cb78a7 Mon Sep 17 00:00:00 2001 From: Rob Berwick Date: Sun, 17 Nov 2024 16:51:07 +0000 Subject: [PATCH 2/3] test: Add tests for `string_to_info_block_data` --- tests/utilities/test_string_to_info_block.py | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/utilities/test_string_to_info_block.py diff --git a/tests/utilities/test_string_to_info_block.py b/tests/utilities/test_string_to_info_block.py new file mode 100644 index 0000000..bb0d709 --- /dev/null +++ b/tests/utilities/test_string_to_info_block.py @@ -0,0 +1,29 @@ +from blinkstick.utilities import string_to_info_block_data + + +def test_string_to_info_block_data_converts_string_to_byte_array(): + block_string = "hello" + expected_padding_length = 31 - len(block_string) + result = string_to_info_block_data("hello") + expected = b"\x01hello" + b"\x00" * expected_padding_length + assert result == expected + + +def test_string_to_info_block_data_handles_empty_string(): + result = string_to_info_block_data("") + expected = b"\x01" + b"\x00" * 31 + assert result == expected + + +def test_string_to_info_block_data_truncates_long_string(): + long_string = "a" * 40 + result = string_to_info_block_data(long_string) + expected = b"\x01" + b"a" * 31 + assert result == expected + + +def test_string_to_info_block_data_handles_exact_31_characters(): + exact_string = "a" * 31 + result = string_to_info_block_data(exact_string) + expected = b"\x01" + b"a" * 31 + assert result == expected From ab1d58d49af5889de27f42c20d14281cb518eb13 Mon Sep 17 00:00:00 2001 From: Rob Berwick Date: Sun, 17 Nov 2024 17:06:02 +0000 Subject: [PATCH 3/3] fix: Fix infoblock setting bugs * restrict info block data string to 31 bytes * correctly handle empty string --- src/blinkstick/utilities.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/blinkstick/utilities.py b/src/blinkstick/utilities.py index 095c3c0..a828fc1 100644 --- a/src/blinkstick/utilities.py +++ b/src/blinkstick/utilities.py @@ -8,11 +8,10 @@ def string_to_info_block_data(data: str) -> bytes: @rtype: byte[32] @return: It fills the rest of bytes with zeros. """ - byte_array = bytearray([1]) - for c in data: - byte_array.append(ord(c)) + info_block_data = data[:31] + byte_array = bytearray([1] + [0] * 31) - for i in range(32 - len(data)): - byte_array.append(0) + for i, c in enumerate(info_block_data): + byte_array[i + 1] = ord(c) return bytes(byte_array)