From e1e57d9b6b2fb8df674a98f3ed89dfab7ede600e Mon Sep 17 00:00:00 2001 From: Bastian Wagner Date: Sat, 15 Aug 2026 10:41:20 +0200 Subject: [PATCH] test: cover product_name string field write path in FIT patcher Addresses review finding: no test previously exercised file_id field 8 or device_info field 27 (product_name), the only string-typed fields this task patches, leaving _write_field_value's string branch (buffer sizing, null-terminator handling) unregression-tested. --- tests/fit/test_rewriter_patching.py | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/fit/test_rewriter_patching.py b/tests/fit/test_rewriter_patching.py index 40dc403..a17f6ba 100644 --- a/tests/fit/test_rewriter_patching.py +++ b/tests/fit/test_rewriter_patching.py @@ -43,6 +43,26 @@ def _build_no_device_index_fixture() -> bytes: return make_fit(records) +def _build_product_name_fixture() -> bytes: + """file_id field 8 and device_info field 27 are both product_name (string) fields — + the only string field type this task patches. No sensor record here, so the single + device_info record present is unambiguously the creator.""" + # file_id: manufacturer(1/u16), product(2/u16), product_name(8/string, size 20) + file_def = definition(0, FILE_ID_MESG_NUM, [(1, 2, 0x84), (2, 2, 0x84), (8, 20, 0x07)]) + original_file_name = b"MyWhoosh\x00".ljust(20, b"\x00") + file_data = data(0, struct.pack(" list[dict[int, int]]: """Parse raw bytes and return one dict of {field_num: value} per device_info record, in file order, so creator and sensor records can be distinguished positionally.""" @@ -124,6 +144,23 @@ def test_convert_fit_device_leaves_device_info_without_device_index_untouched( assert values[4] == 1234 +def test_convert_fit_device_patches_product_name_string_fields(tmp_path: Path) -> None: + """file_id field 8 and device_info field 27 (creator) are both string fields, written via + _write_field_value's string branch (buffer sizing + null-terminator handling). Neither is + exercised by the numeric-only base fixture used elsewhere in this module.""" + source = tmp_path / "source.fit" + source.write_bytes(_build_product_name_fixture()) + output = tmp_path / "output.fit" + + convert_fit_device(source, output) + + values = read_device_field_values(output) + values_by_key = {(v.global_message_num, v.field_num): v.value for v in values} + + assert values_by_key[(FILE_ID_MESG_NUM, 8)] == "Edge 1030 Plus" + assert values_by_key[(DEVICE_INFO_MESG_NUM, 27)] == "Edge 1030 Plus" + + def test_convert_fit_device_defaults_to_edge_1030_plus() -> None: device = GarminDevice() assert device.manufacturer_id == 1