From 778a7c82acc83586034304260cc33b6664bceb48 Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Thu, 4 Dec 2025 19:54:26 -0800 Subject: [PATCH 1/2] chore: Add tests that reproduce key parsing bugs --- .../__snapshots__/test_file_cache.ambr | 6 ++-- tests/devices/test_file_cache.py | 14 ++++++++- tests/test_containers.py | 29 +++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/tests/devices/__snapshots__/test_file_cache.ambr b/tests/devices/__snapshots__/test_file_cache.ambr index f093c4f2..5fe0a978 100644 --- a/tests/devices/__snapshots__/test_file_cache.ambr +++ b/tests/devices/__snapshots__/test_file_cache.ambr @@ -3,7 +3,7 @@ CacheData(home_data=None, device_info={}, network_info={}, home_map_info={}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) # --- # name: test_set_and_flush_and_get[default-multiple_fields_cache] - CacheData(home_data=HomeData(id=123456, name='My Home', products=[HomeDataProduct(id='product-id-123', name='Roborock S7 MaxV', model='roborock.vacuum.a27', category=, code='a27', icon_url=None, attribute=None, capability=0, schema=[HomeDataProductSchema(id='101', name='rpc_request', code='rpc_request_code', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='102', name='rpc_response', code='rpc_response', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='120', name='错误代码', code='error_code', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='121', name='设备状态', code='state', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='122', name='设备电量', code='battery', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='123', name='清扫模式', code='fan_power', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='124', name='拖地模式', code='water_box_mode', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='125', name='主刷寿命', code='main_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='126', name='边刷寿命', code='side_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='127', name='滤网寿命', code='filter_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='128', name='额外状态', code='additional_props', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='130', name='完成事件', code='task_complete', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='131', name='电量不足任务取消', code='task_cancel_low_power', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='132', name='运动中任务取消', code='task_cancel_in_motion', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='133', name='充电状态', code='charge_status', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='134', name='烘干状态', code='drying_status', mode='ro', type='RAW', product_property=None, property=None, desc=None)])], devices=[HomeDataDevice(duid='abc123', name='Roborock S7 MaxV', local_key='key123key123key1', fv='02.56.02', product_id='product-id-123', attribute=None, active_time=1672364449, runtime_env=None, time_zone_id='America/Los_Angeles', icon_url='no_url', lon=None, lat=None, share=False, share_time=None, online=True, pv='1.0', room_id=2362003, tuya_uuid=None, tuya_migrated=False, extra='{"RRPhotoPrivacyVersion": "1"}', sn='abc123', feature_set='2234201184108543', new_feature_set='0000000000002041', device_status={'121': 8, '122': 100, '123': 102, '124': 203, '125': 94, '126': 90, '127': 87, '128': 0, '133': 1, '120': 0}, silent_ota_switch=True, setting=None, f=None)], received_devices=[], lon=None, lat=None, geo_name=None, rooms=[HomeDataRoom(id=2362048, name='Example room 1'), HomeDataRoom(id=2362044, name='Example room 2'), HomeDataRoom(id=2362041, name='Example room 3')]), device_info={}, network_info={'abc123': NetworkInfo(ip='1.1.1.1', ssid='test_wifi', mac='aa:bb:cc:dd:ee:ff', bssid='aa:bb:cc:dd:ee:ff', rssi=-50)}, home_map_info={}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) + CacheData(home_data=HomeData(id=123456, name='My Home', products=[HomeDataProduct(id='product-id-123', name='Roborock S7 MaxV', model='roborock.vacuum.a27', category=, code='a27', icon_url=None, attribute=None, capability=0, schema=[HomeDataProductSchema(id='101', name='rpc_request', code='rpc_request_code', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='102', name='rpc_response', code='rpc_response', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='120', name='错误代码', code='error_code', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='121', name='设备状态', code='state', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='122', name='设备电量', code='battery', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='123', name='清扫模式', code='fan_power', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='124', name='拖地模式', code='water_box_mode', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='125', name='主刷寿命', code='main_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='126', name='边刷寿命', code='side_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='127', name='滤网寿命', code='filter_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='128', name='额外状态', code='additional_props', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='130', name='完成事件', code='task_complete', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='131', name='电量不足任务取消', code='task_cancel_low_power', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='132', name='运动中任务取消', code='task_cancel_in_motion', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='133', name='充电状态', code='charge_status', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='134', name='烘干状态', code='drying_status', mode='ro', type='RAW', product_property=None, property=None, desc=None)])], devices=[HomeDataDevice(duid='abc123', name='Roborock S7 MaxV', local_key='key123key123key1', fv='02.56.02', product_id='product-id-123', attribute=None, active_time=1672364449, runtime_env=None, time_zone_id='America/Los_Angeles', icon_url='no_url', lon=None, lat=None, share=False, share_time=None, online=True, pv='1.0', room_id=2362003, tuya_uuid=None, tuya_migrated=False, extra='{"RRPhotoPrivacyVersion": "1"}', sn='abc123', feature_set='2234201184108543', new_feature_set='0000000000002041', device_status={'121': 8, '122': 100, '123': 102, '124': 203, '125': 94, '126': 90, '127': 87, '128': 0, '133': 1, '120': 0}, silent_ota_switch=True, setting=None, f=None)], received_devices=[], lon=None, lat=None, geo_name=None, rooms=[HomeDataRoom(id=2362048, name='Example room 1'), HomeDataRoom(id=2362044, name='Example room 2'), HomeDataRoom(id=2362041, name='Example room 3')]), device_info={}, network_info={'abc123': NetworkInfo(ip='1.1.1.1', ssid='test_wifi', mac='aa:bb:cc:dd:ee:ff', bssid='aa:bb:cc:dd:ee:ff', rssi=-50)}, home_map_info={1: CombinedMapInfo(map_flag=1, name='Test Map', rooms=[NamedRoomMapping(segment_id=1023, iot_id='4321', name='Living Room')])}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) # --- # name: test_set_and_flush_and_get[default-populated_cache] CacheData(home_data=HomeData(id=123456, name='My Home', products=[HomeDataProduct(id='product-id-123', name='Roborock S7 MaxV', model='roborock.vacuum.a27', category=, code='a27', icon_url=None, attribute=None, capability=0, schema=[HomeDataProductSchema(id='101', name='rpc_request', code='rpc_request_code', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='102', name='rpc_response', code='rpc_response', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='120', name='错误代码', code='error_code', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='121', name='设备状态', code='state', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='122', name='设备电量', code='battery', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='123', name='清扫模式', code='fan_power', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='124', name='拖地模式', code='water_box_mode', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='125', name='主刷寿命', code='main_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='126', name='边刷寿命', code='side_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='127', name='滤网寿命', code='filter_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='128', name='额外状态', code='additional_props', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='130', name='完成事件', code='task_complete', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='131', name='电量不足任务取消', code='task_cancel_low_power', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='132', name='运动中任务取消', code='task_cancel_in_motion', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='133', name='充电状态', code='charge_status', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='134', name='烘干状态', code='drying_status', mode='ro', type='RAW', product_property=None, property=None, desc=None)])], devices=[HomeDataDevice(duid='abc123', name='Roborock S7 MaxV', local_key='key123key123key1', fv='02.56.02', product_id='product-id-123', attribute=None, active_time=1672364449, runtime_env=None, time_zone_id='America/Los_Angeles', icon_url='no_url', lon=None, lat=None, share=False, share_time=None, online=True, pv='1.0', room_id=2362003, tuya_uuid=None, tuya_migrated=False, extra='{"RRPhotoPrivacyVersion": "1"}', sn='abc123', feature_set='2234201184108543', new_feature_set='0000000000002041', device_status={'121': 8, '122': 100, '123': 102, '124': 203, '125': 94, '126': 90, '127': 87, '128': 0, '133': 1, '120': 0}, silent_ota_switch=True, setting=None, f=None)], received_devices=[], lon=None, lat=None, geo_name=None, rooms=[HomeDataRoom(id=2362048, name='Example room 1'), HomeDataRoom(id=2362044, name='Example room 2'), HomeDataRoom(id=2362041, name='Example room 3')]), device_info={}, network_info={}, home_map_info={}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) @@ -12,7 +12,7 @@ CacheData(home_data=None, device_info={}, network_info={}, home_map_info={}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) # --- # name: test_set_and_flush_and_get[json-multiple_fields_cache] - CacheData(home_data=HomeData(id=123456, name='My Home', products=[HomeDataProduct(id='product-id-123', name='Roborock S7 MaxV', model='roborock.vacuum.a27', category=, code='a27', icon_url=None, attribute=None, capability=0, schema=[HomeDataProductSchema(id='101', name='rpc_request', code='rpc_request_code', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='102', name='rpc_response', code='rpc_response', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='120', name='错误代码', code='error_code', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='121', name='设备状态', code='state', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='122', name='设备电量', code='battery', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='123', name='清扫模式', code='fan_power', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='124', name='拖地模式', code='water_box_mode', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='125', name='主刷寿命', code='main_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='126', name='边刷寿命', code='side_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='127', name='滤网寿命', code='filter_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='128', name='额外状态', code='additional_props', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='130', name='完成事件', code='task_complete', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='131', name='电量不足任务取消', code='task_cancel_low_power', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='132', name='运动中任务取消', code='task_cancel_in_motion', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='133', name='充电状态', code='charge_status', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='134', name='烘干状态', code='drying_status', mode='ro', type='RAW', product_property=None, property=None, desc=None)])], devices=[HomeDataDevice(duid='abc123', name='Roborock S7 MaxV', local_key='key123key123key1', fv='02.56.02', product_id='product-id-123', attribute=None, active_time=1672364449, runtime_env=None, time_zone_id='America/Los_Angeles', icon_url='no_url', lon=None, lat=None, share=False, share_time=None, online=True, pv='1.0', room_id=2362003, tuya_uuid=None, tuya_migrated=False, extra='{"RRPhotoPrivacyVersion": "1"}', sn='abc123', feature_set='2234201184108543', new_feature_set='0000000000002041', device_status={'121': 8, '122': 100, '123': 102, '124': 203, '125': 94, '126': 90, '127': 87, '128': 0, '133': 1, '120': 0}, silent_ota_switch=True, setting=None, f=None)], received_devices=[], lon=None, lat=None, geo_name=None, rooms=[HomeDataRoom(id=2362048, name='Example room 1'), HomeDataRoom(id=2362044, name='Example room 2'), HomeDataRoom(id=2362041, name='Example room 3')]), device_info={}, network_info={'abc123': NetworkInfo(ip='1.1.1.1', ssid='test_wifi', mac='aa:bb:cc:dd:ee:ff', bssid='aa:bb:cc:dd:ee:ff', rssi=-50)}, home_map_info={}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) + CacheData(home_data=HomeData(id=123456, name='My Home', products=[HomeDataProduct(id='product-id-123', name='Roborock S7 MaxV', model='roborock.vacuum.a27', category=, code='a27', icon_url=None, attribute=None, capability=0, schema=[HomeDataProductSchema(id='101', name='rpc_request', code='rpc_request_code', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='102', name='rpc_response', code='rpc_response', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='120', name='错误代码', code='error_code', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='121', name='设备状态', code='state', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='122', name='设备电量', code='battery', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='123', name='清扫模式', code='fan_power', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='124', name='拖地模式', code='water_box_mode', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='125', name='主刷寿命', code='main_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='126', name='边刷寿命', code='side_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='127', name='滤网寿命', code='filter_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='128', name='额外状态', code='additional_props', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='130', name='完成事件', code='task_complete', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='131', name='电量不足任务取消', code='task_cancel_low_power', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='132', name='运动中任务取消', code='task_cancel_in_motion', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='133', name='充电状态', code='charge_status', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='134', name='烘干状态', code='drying_status', mode='ro', type='RAW', product_property=None, property=None, desc=None)])], devices=[HomeDataDevice(duid='abc123', name='Roborock S7 MaxV', local_key='key123key123key1', fv='02.56.02', product_id='product-id-123', attribute=None, active_time=1672364449, runtime_env=None, time_zone_id='America/Los_Angeles', icon_url='no_url', lon=None, lat=None, share=False, share_time=None, online=True, pv='1.0', room_id=2362003, tuya_uuid=None, tuya_migrated=False, extra='{"RRPhotoPrivacyVersion": "1"}', sn='abc123', feature_set='2234201184108543', new_feature_set='0000000000002041', device_status={'121': 8, '122': 100, '123': 102, '124': 203, '125': 94, '126': 90, '127': 87, '128': 0, '133': 1, '120': 0}, silent_ota_switch=True, setting=None, f=None)], received_devices=[], lon=None, lat=None, geo_name=None, rooms=[HomeDataRoom(id=2362048, name='Example room 1'), HomeDataRoom(id=2362044, name='Example room 2'), HomeDataRoom(id=2362041, name='Example room 3')]), device_info={}, network_info={'abc123': NetworkInfo(ip='1.1.1.1', ssid='test_wifi', mac='aa:bb:cc:dd:ee:ff', bssid='aa:bb:cc:dd:ee:ff', rssi=-50)}, home_map_info={1: CombinedMapInfo(map_flag=1, name='Test Map', rooms=[NamedRoomMapping(segment_id=1023, iot_id='4321', name='Living Room')])}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) # --- # name: test_set_and_flush_and_get[json-populated_cache] CacheData(home_data=HomeData(id=123456, name='My Home', products=[HomeDataProduct(id='product-id-123', name='Roborock S7 MaxV', model='roborock.vacuum.a27', category=, code='a27', icon_url=None, attribute=None, capability=0, schema=[HomeDataProductSchema(id='101', name='rpc_request', code='rpc_request_code', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='102', name='rpc_response', code='rpc_response', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='120', name='错误代码', code='error_code', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='121', name='设备状态', code='state', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='122', name='设备电量', code='battery', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='123', name='清扫模式', code='fan_power', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='124', name='拖地模式', code='water_box_mode', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='125', name='主刷寿命', code='main_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='126', name='边刷寿命', code='side_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='127', name='滤网寿命', code='filter_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='128', name='额外状态', code='additional_props', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='130', name='完成事件', code='task_complete', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='131', name='电量不足任务取消', code='task_cancel_low_power', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='132', name='运动中任务取消', code='task_cancel_in_motion', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='133', name='充电状态', code='charge_status', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='134', name='烘干状态', code='drying_status', mode='ro', type='RAW', product_property=None, property=None, desc=None)])], devices=[HomeDataDevice(duid='abc123', name='Roborock S7 MaxV', local_key='key123key123key1', fv='02.56.02', product_id='product-id-123', attribute=None, active_time=1672364449, runtime_env=None, time_zone_id='America/Los_Angeles', icon_url='no_url', lon=None, lat=None, share=False, share_time=None, online=True, pv='1.0', room_id=2362003, tuya_uuid=None, tuya_migrated=False, extra='{"RRPhotoPrivacyVersion": "1"}', sn='abc123', feature_set='2234201184108543', new_feature_set='0000000000002041', device_status={'121': 8, '122': 100, '123': 102, '124': 203, '125': 94, '126': 90, '127': 87, '128': 0, '133': 1, '120': 0}, silent_ota_switch=True, setting=None, f=None)], received_devices=[], lon=None, lat=None, geo_name=None, rooms=[HomeDataRoom(id=2362048, name='Example room 1'), HomeDataRoom(id=2362044, name='Example room 2'), HomeDataRoom(id=2362041, name='Example room 3')]), device_info={}, network_info={}, home_map_info={}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) @@ -21,7 +21,7 @@ CacheData(home_data=None, device_info={}, network_info={}, home_map_info={}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) # --- # name: test_set_and_flush_and_get[pickle-multiple_fields_cache] - CacheData(home_data=HomeData(id=123456, name='My Home', products=[HomeDataProduct(id='product-id-123', name='Roborock S7 MaxV', model='roborock.vacuum.a27', category=, code='a27', icon_url=None, attribute=None, capability=0, schema=[HomeDataProductSchema(id='101', name='rpc_request', code='rpc_request_code', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='102', name='rpc_response', code='rpc_response', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='120', name='错误代码', code='error_code', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='121', name='设备状态', code='state', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='122', name='设备电量', code='battery', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='123', name='清扫模式', code='fan_power', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='124', name='拖地模式', code='water_box_mode', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='125', name='主刷寿命', code='main_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='126', name='边刷寿命', code='side_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='127', name='滤网寿命', code='filter_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='128', name='额外状态', code='additional_props', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='130', name='完成事件', code='task_complete', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='131', name='电量不足任务取消', code='task_cancel_low_power', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='132', name='运动中任务取消', code='task_cancel_in_motion', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='133', name='充电状态', code='charge_status', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='134', name='烘干状态', code='drying_status', mode='ro', type='RAW', product_property=None, property=None, desc=None)])], devices=[HomeDataDevice(duid='abc123', name='Roborock S7 MaxV', local_key='key123key123key1', fv='02.56.02', product_id='product-id-123', attribute=None, active_time=1672364449, runtime_env=None, time_zone_id='America/Los_Angeles', icon_url='no_url', lon=None, lat=None, share=False, share_time=None, online=True, pv='1.0', room_id=2362003, tuya_uuid=None, tuya_migrated=False, extra='{"RRPhotoPrivacyVersion": "1"}', sn='abc123', feature_set='2234201184108543', new_feature_set='0000000000002041', device_status={'121': 8, '122': 100, '123': 102, '124': 203, '125': 94, '126': 90, '127': 87, '128': 0, '133': 1, '120': 0}, silent_ota_switch=True, setting=None, f=None)], received_devices=[], lon=None, lat=None, geo_name=None, rooms=[HomeDataRoom(id=2362048, name='Example room 1'), HomeDataRoom(id=2362044, name='Example room 2'), HomeDataRoom(id=2362041, name='Example room 3')]), device_info={}, network_info={'abc123': NetworkInfo(ip='1.1.1.1', ssid='test_wifi', mac='aa:bb:cc:dd:ee:ff', bssid='aa:bb:cc:dd:ee:ff', rssi=-50)}, home_map_info={}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) + CacheData(home_data=HomeData(id=123456, name='My Home', products=[HomeDataProduct(id='product-id-123', name='Roborock S7 MaxV', model='roborock.vacuum.a27', category=, code='a27', icon_url=None, attribute=None, capability=0, schema=[HomeDataProductSchema(id='101', name='rpc_request', code='rpc_request_code', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='102', name='rpc_response', code='rpc_response', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='120', name='错误代码', code='error_code', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='121', name='设备状态', code='state', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='122', name='设备电量', code='battery', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='123', name='清扫模式', code='fan_power', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='124', name='拖地模式', code='water_box_mode', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='125', name='主刷寿命', code='main_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='126', name='边刷寿命', code='side_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='127', name='滤网寿命', code='filter_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='128', name='额外状态', code='additional_props', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='130', name='完成事件', code='task_complete', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='131', name='电量不足任务取消', code='task_cancel_low_power', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='132', name='运动中任务取消', code='task_cancel_in_motion', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='133', name='充电状态', code='charge_status', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='134', name='烘干状态', code='drying_status', mode='ro', type='RAW', product_property=None, property=None, desc=None)])], devices=[HomeDataDevice(duid='abc123', name='Roborock S7 MaxV', local_key='key123key123key1', fv='02.56.02', product_id='product-id-123', attribute=None, active_time=1672364449, runtime_env=None, time_zone_id='America/Los_Angeles', icon_url='no_url', lon=None, lat=None, share=False, share_time=None, online=True, pv='1.0', room_id=2362003, tuya_uuid=None, tuya_migrated=False, extra='{"RRPhotoPrivacyVersion": "1"}', sn='abc123', feature_set='2234201184108543', new_feature_set='0000000000002041', device_status={'121': 8, '122': 100, '123': 102, '124': 203, '125': 94, '126': 90, '127': 87, '128': 0, '133': 1, '120': 0}, silent_ota_switch=True, setting=None, f=None)], received_devices=[], lon=None, lat=None, geo_name=None, rooms=[HomeDataRoom(id=2362048, name='Example room 1'), HomeDataRoom(id=2362044, name='Example room 2'), HomeDataRoom(id=2362041, name='Example room 3')]), device_info={}, network_info={'abc123': NetworkInfo(ip='1.1.1.1', ssid='test_wifi', mac='aa:bb:cc:dd:ee:ff', bssid='aa:bb:cc:dd:ee:ff', rssi=-50)}, home_map_info={1: CombinedMapInfo(map_flag=1, name='Test Map', rooms=[NamedRoomMapping(segment_id=1023, iot_id='4321', name='Living Room')])}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) # --- # name: test_set_and_flush_and_get[pickle-populated_cache] CacheData(home_data=HomeData(id=123456, name='My Home', products=[HomeDataProduct(id='product-id-123', name='Roborock S7 MaxV', model='roborock.vacuum.a27', category=, code='a27', icon_url=None, attribute=None, capability=0, schema=[HomeDataProductSchema(id='101', name='rpc_request', code='rpc_request_code', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='102', name='rpc_response', code='rpc_response', mode='rw', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='120', name='错误代码', code='error_code', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='121', name='设备状态', code='state', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='122', name='设备电量', code='battery', mode='ro', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='123', name='清扫模式', code='fan_power', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='124', name='拖地模式', code='water_box_mode', mode='rw', type='ENUM', product_property=None, property='{"range": []}', desc=None), HomeDataProductSchema(id='125', name='主刷寿命', code='main_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='126', name='边刷寿命', code='side_brush_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='127', name='滤网寿命', code='filter_life', mode='rw', type='VALUE', product_property=None, property='{"max": 100, "min": 0, "step": 1, "unit": null, "scale": 1}', desc=None), HomeDataProductSchema(id='128', name='额外状态', code='additional_props', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='130', name='完成事件', code='task_complete', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='131', name='电量不足任务取消', code='task_cancel_low_power', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='132', name='运动中任务取消', code='task_cancel_in_motion', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='133', name='充电状态', code='charge_status', mode='ro', type='RAW', product_property=None, property=None, desc=None), HomeDataProductSchema(id='134', name='烘干状态', code='drying_status', mode='ro', type='RAW', product_property=None, property=None, desc=None)])], devices=[HomeDataDevice(duid='abc123', name='Roborock S7 MaxV', local_key='key123key123key1', fv='02.56.02', product_id='product-id-123', attribute=None, active_time=1672364449, runtime_env=None, time_zone_id='America/Los_Angeles', icon_url='no_url', lon=None, lat=None, share=False, share_time=None, online=True, pv='1.0', room_id=2362003, tuya_uuid=None, tuya_migrated=False, extra='{"RRPhotoPrivacyVersion": "1"}', sn='abc123', feature_set='2234201184108543', new_feature_set='0000000000002041', device_status={'121': 8, '122': 100, '123': 102, '124': 203, '125': 94, '126': 90, '127': 87, '128': 0, '133': 1, '120': 0}, silent_ota_switch=True, setting=None, f=None)], received_devices=[], lon=None, lat=None, geo_name=None, rooms=[HomeDataRoom(id=2362048, name='Example room 1'), HomeDataRoom(id=2362044, name='Example room 2'), HomeDataRoom(id=2362041, name='Example room 3')]), device_info={}, network_info={}, home_map_info={}, home_map_content={}, home_map_content_base64={}, device_features=None, trait_data=None) diff --git a/tests/devices/test_file_cache.py b/tests/devices/test_file_cache.py index c4d95cde..4ffeaa74 100644 --- a/tests/devices/test_file_cache.py +++ b/tests/devices/test_file_cache.py @@ -9,6 +9,7 @@ from syrupy import SnapshotAssertion from roborock.data import HomeData +from roborock.data.containers import CombinedMapInfo, NamedRoomMapping from roborock.data.v1.v1_containers import NetworkInfo from roborock.devices.cache import CacheData from roborock.devices.file_cache import FileCache @@ -38,7 +39,18 @@ async def test_get_from_non_existent_cache(cache_file: pathlib.Path) -> None: [ CacheData(), CacheData(home_data=HOME_DATA), - CacheData(home_data=HOME_DATA, network_info={"abc123": NETWORK_INFO}), + CacheData( + home_data=HOME_DATA, + network_info={"abc123": NETWORK_INFO}, + home_map_info={ + # Ensure that int keys are serialized and parsed correctly + 1: CombinedMapInfo( + map_flag=1, + name="Test Map", + rooms=[NamedRoomMapping(segment_id=1023, iot_id="4321", name="Living Room")], + ) + }, + ), ], ids=["empty_cache", "populated_cache", "multiple_fields_cache"], ) diff --git a/tests/test_containers.py b/tests/test_containers.py index 3b5e7902..089219d4 100644 --- a/tests/test_containers.py +++ b/tests/test_containers.py @@ -59,6 +59,7 @@ class ComplexObject(RoborockBase): nested_dict: dict[str, SimpleObject] | None = None nested_list: list[SimpleObject] | None = None any: Any | None = None + nested_int_dict: dict[int, SimpleObject] | None = None @dataclass @@ -92,6 +93,9 @@ def test_complex_object() -> None: "nested1": SimpleObject(name="Nested1", value=1), "nested2": SimpleObject(name="Nested2", value=2), }, + nested_int_dict={ + 10: SimpleObject(name="IntKey1", value=10), + }, nested_list=[SimpleObject(name="Nested3", value=3), SimpleObject(name="Nested4", value=4)], any="This can be anything", ) @@ -104,6 +108,9 @@ def test_complex_object() -> None: "nested1": {"name": "Nested1", "value": 1}, "nested2": {"name": "Nested2", "value": 2}, }, + "nestedIntDict": { + 10: {"name": "IntKey1", "value": 10}, + }, "nestedList": [ {"name": "Nested3", "value": 3}, {"name": "Nested4", "value": 4}, @@ -119,6 +126,9 @@ def test_complex_object() -> None: "nested1": SimpleObject(name="Nested1", value=1), "nested2": SimpleObject(name="Nested2", value=2), } + assert deserialized.nested_int_dict == { + 10: SimpleObject(name="IntKey1", value=10), + } assert deserialized.nested_list == [ SimpleObject(name="Nested3", value=3), SimpleObject(name="Nested4", value=4), @@ -126,6 +136,25 @@ def test_complex_object() -> None: assert deserialized.any == "This can be anything" +@pytest.mark.parametrize( + ("data"), + [ + { + "nested_int_dict": {10: {"name": "IntKey1", "value": 10}}, + }, + { + "nested_int_dict": {"10": {"name": "IntKey1", "value": 10}}, + } + ] +) +def test_from_dict_key_types(data: dict) -> None: + """Test serialization and deserialization of a complex object.""" + obj = ComplexObject.from_dict(data) + assert obj.nested_int_dict == { + 10: SimpleObject(name="IntKey1", value=10), + } + + def test_ignore_unknown_keys() -> None: """Test that we don't fail on unknown keys.""" data = { From 383a2440158d448b23824e5de3da7541e7d3dd69 Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Thu, 4 Dec 2025 21:55:07 -0800 Subject: [PATCH 2/2] chore: fix lint errors --- tests/test_containers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_containers.py b/tests/test_containers.py index 089219d4..034ba717 100644 --- a/tests/test_containers.py +++ b/tests/test_containers.py @@ -144,8 +144,8 @@ def test_complex_object() -> None: }, { "nested_int_dict": {"10": {"name": "IntKey1", "value": 10}}, - } - ] + }, + ], ) def test_from_dict_key_types(data: dict) -> None: """Test serialization and deserialization of a complex object."""