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.
This commit is contained in:
@@ -43,6 +43,26 @@ def _build_no_device_index_fixture() -> bytes:
|
|||||||
return make_fit(records)
|
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("<HH", 255, 999) + original_file_name)
|
||||||
|
|
||||||
|
# device_info: device_index(0/u8), manufacturer(2/u16), product(4/u16), product_name(27/string, size 20)
|
||||||
|
device_def = definition(
|
||||||
|
1, DEVICE_INFO_MESG_NUM, [(0, 1, 0x02), (2, 2, 0x84), (4, 2, 0x84), (27, 20, 0x07)]
|
||||||
|
)
|
||||||
|
original_device_name = b"MyWhoosh App\x00".ljust(20, b"\x00")
|
||||||
|
creator = data(1, struct.pack("<BHH", 0, 255, 999) + original_device_name)
|
||||||
|
|
||||||
|
records = file_def + file_data + device_def + creator
|
||||||
|
return make_fit(records)
|
||||||
|
|
||||||
|
|
||||||
def _read_device_info_records(path: Path) -> list[dict[int, int]]:
|
def _read_device_info_records(path: Path) -> list[dict[int, int]]:
|
||||||
"""Parse raw bytes and return one dict of {field_num: value} per device_info record,
|
"""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."""
|
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
|
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:
|
def test_convert_fit_device_defaults_to_edge_1030_plus() -> None:
|
||||||
device = GarminDevice()
|
device = GarminDevice()
|
||||||
assert device.manufacturer_id == 1
|
assert device.manufacturer_id == 1
|
||||||
|
|||||||
Reference in New Issue
Block a user