zbparse/flask_app/test_case/test_combine_and_update_results.py

417 lines
12 KiB
Python
Raw Normal View History

2024-12-03 17:37:02 +08:00
def combine_and_update_results(original_data, updates):
def normalize_key(key):
"""
规范化键名
- 替换全角点号为半角点号
- 删除所有空格包括半角和全角
"""
# 替换全角点号(.、。)为半角点号(.
key = key.replace('', '.').replace('', '.')
# 删除所有空格(半角空格和全角空格)
key = key.replace(' ', '').replace('\u3000', '')
return key
def normalize_original_data(d):
"""
递归规范化原始数据字典的键
"""
if not isinstance(d, dict):
return d
normalized = {}
for k, v in d.items():
nk = normalize_key(k)
normalized[nk] = normalize_original_data(v)
return normalized
def normalize_update_value(value):
"""
递归规范化更新字典中嵌套的字典的键
"""
if isinstance(value, dict):
return {normalize_key(k): normalize_update_value(v) for k, v in value.items()}
else:
return value
def recursive_update(data, key, value):
"""
递归更新嵌套字典
"""
keys = key.split('.')
for k in keys[:-1]:
data = data.setdefault(k, {})
if isinstance(value, dict) and isinstance(data.get(keys[-1], None), dict):
data[keys[-1]] = {**data.get(keys[-1], {}), **value}
else:
data[keys[-1]] = value
# 1. 规范化原始数据字典的键
original_data = normalize_original_data(original_data)
# 2. 规范化更新字典的键
normalized_updates = {}
for key, value in updates.items():
nk = normalize_key(key)
nv = normalize_update_value(value)
normalized_updates[nk] = nv
# 3. 执行递归更新
for key, value in normalized_updates.items():
recursive_update(original_data, key, value)
return original_data
# 测试用例1复杂情况
def test_complex_case():
original_data = {
'username': 'Alice',
'user。details': {
'age': 30,
'address line': '123 Main St', # 全角空格
'preferences': {
'color': 'blue',
'food': 'sushi'
}
},
'status': 'active',
'metrics': {
'score': 85,
'rank': 5
},
'list_field': [1, 2, 3]
}
updates = {
'user. name': 'Bob', # 更新user.name
'user.details.age': 31, # 更新嵌套字段
'user.details.addressline': '456 Elm St', # 更新地址,键中有空格被移除
'user.details.preferences.hobby': 'cycling', # 添加新的嵌套字段
'status': 'inactive', # 更新顶级字段
'metrics.score': {'current': 90, 'max': 100}, # 更新为字典
'metrics.new_metric': 50, # 添加新的顶级嵌套字段
'new_field': 'new_value', # 添加新的顶级字段
'list_field': [4, 5] # 更新列表字段
}
expected_result = {
'user': {
'name': 'Bob',
'details': {
'age': 31,
'addressline': '456 Elm St',
'preferences': {
'color': 'blue',
'food': 'sushi',
'hobby': 'cycling'
}
}
},
'status': 'inactive',
'metrics': {
'score': {'current': 90, 'max': 100},
'rank': 5,
'new_metric': 50
},
'list_field': [4, 5],
'new_field': 'new_value'
}
result = combine_and_update_results(original_data, updates)
assert result == expected_result, f"测试复杂情况失败。\n预期: {expected_result}\n实际: {result}"
print("测试复杂情况通过。")
# 测试用例2更新为空
def test_empty_updates():
original_data = {
'key1': 'value1',
'key2': {
'subkey': 'subvalue'
}
}
updates = {}
expected_result = {
'key1': 'value1',
'key2': {
'subkey': 'subvalue'
}
}
result = combine_and_update_results(original_data, updates)
assert result == expected_result, f"测试更新为空失败。\n预期: {expected_result}\n实际: {result}"
print("测试更新为空通过。")
# 测试用例3原始数据为空
def test_empty_original():
original_data = {}
updates = {
'newkey': 'new value',
'nested。key.sub key': 123
}
expected_result = {
'new.key': 'newvalue',
'nested.key': {
'subkey': 123
}
}
result = combine_and_update_results(original_data, updates)
assert result == expected_result, f"测试原始数据为空失败。\n预期: {expected_result}\n实际: {result}"
print("测试原始数据为空通过。")
# 测试用例4更新中包含非字典类型的值
def test_non_dict_values():
original_data = {
'ab': {
'cd': 1
},
'listfield': [1, 2, 3]
}
updates = {
'a.b.c.d': {'new': 2},
'list.field': 'not a list anymore'
}
expected_result = {
'a': {
'b': {
'c': {
'd': {'new': 2}
}
}
},
'list.field': 'not a list anymore'
}
result = combine_and_update_results(original_data, updates)
assert result == expected_result, f"测试更新中包含非字典类型的值失败。\n预期: {expected_result}\n实际: {result}"
print("测试更新中包含非字典类型的值通过。")
# 测试用例5键中包含全角空格
def test_full_width_spaces():
original_data = {
'key with fullwidth spaces': 'value1',
'nestedkey withspaces': {
'sub key': 'subvalue'
}
}
updates = {
'key with fullwidth spaces': 'updated_value',
'nested.key with spaces.new subkey': 'new_subvalue'
}
expected_result = {
'keywithfullwidthspaces': 'updated_value',
'nested': {
'keywithspaces': {
'subkey': 'new_subvalue'
}
}
}
result = combine_and_update_results(original_data, updates)
assert result == expected_result, f"测试键中包含全角空格失败。\n预期: {expected_result}\n实际: {result}"
print("测试键中包含全角空格通过。")
# 测试用例6复杂嵌套和不同数据类型
def test_nested_and_various_types():
original_data = {
'configsettings': {
'resolution': '1080p',
'volume': 75,
'controls': {
'jump': 'space',
'crouch': 'ctrl'
}
},
'userpreferences': {
'theme': 'dark',
'notifications': True
}
}
updates = {
'config.settings.resolution': '4K',
'config.settings.controls.run': 'shift', # 添加新控制
'config.settings.volume': 80, # 更新音量
'user.preferences.theme': 'light', # 更新主题
'user.preferences.language': 'en-US', # 添加新偏好
'newsection.setting': 'enabled' # 添加新部分
}
expected_result = {
'config': {
'settings': {
'resolution': '4K',
'volume': 80,
'controls': {
'jump': 'space',
'crouch': 'ctrl',
'run': 'shift'
}
}
},
'user': {
'preferences': {
'theme': 'light',
'notifications': True,
'language': 'en-US'
}
},
'new.section': {
'setting': 'enabled'
}
}
result = combine_and_update_results(original_data, updates)
assert result == expected_result, f"测试复杂嵌套和不同数据类型失败。\n预期: {expected_result}\n实际: {result}"
print("测试复杂嵌套和不同数据类型通过。")
# 测试用例7键仅包含空格和点号
def test_keys_only_spaces_and_dots():
original_data = {
' .': 'value1',
'  ': 'value2', # 仅全角空格
'nestedkey': {
'subkey': 'subvalue'
}
}
updates = {
'.': 'updated_value1',
'nested.key.subkey': 'updated_subvalue'
}
expected_result = {
'..': 'updated_value1',
'': 'value2', # 全角空格被删除后键为空字符串
'nested': {
'key': {
'subkey': 'updated_subvalue'
}
}
}
result = combine_and_update_results(original_data, updates)
assert result == expected_result, f"测试键仅包含空格和点号失败。\n预期: {expected_result}\n实际: {result}"
print("测试键仅包含空格和点号通过。")
# 测试用例8更新覆盖整个嵌套结构
def test_overwrite_nested_structure():
original_data = {
'settings': {
'display': {
'brightness': 70,
'contrast': 50
},
'sound': {
'volume': 80
}
}
}
updates = {
'settings.display': 'default', # 覆盖整个display字典
'settings.sound.volume': 90 # 更新音量
}
expected_result = {
'settings': {
'display': 'default',
'sound': {
'volume': 90
}
}
}
result = combine_and_update_results(original_data, updates)
assert result == expected_result, f"测试覆盖整个嵌套结构失败。\n预期: {expected_result}\n实际: {result}"
print("测试覆盖整个嵌套结构通过。")
# 测试用例9更新包含列表中的字典
def test_update_with_list_of_dicts():
original_data = {
'users': [
{'name': 'Alice', 'age': 30},
{'name': 'Bob', 'age': 25}
],
'settings': {
'theme': 'dark'
}
}
updates = {
'users': [
{'name': 'Alice', 'age': 31}, # 更新第一个用户的年龄
{'name': 'Bob', 'age': 26}, # 更新第二个用户的年龄
{'name': 'Charlie', 'age': 22} # 添加新用户
],
'settings.theme': 'light' # 更新主题
}
expected_result = {
'users': [
{'name': 'Alice', 'age': 31},
{'name': 'Bob', 'age': 26},
{'name': 'Charlie', 'age': 22}
],
'settings': {
'theme': 'light'
}
}
result = combine_and_update_results(original_data, updates)
assert result == expected_result, f"测试更新包含列表中的字典失败。\n预期: {expected_result}\n实际: {result}"
print("测试更新包含列表中的字典通过。")
# 测试用例10键重复但规范化后不同
def test_duplicate_keys_after_normalization():
original_data = {
'key': {
'one':'value1',
'two':'value2'
}
}
updates = {
'key.one': 'updated_value',
'keytwo': 'updated_value3'
}
expected_result = {
'keyone': 'updated_value', # 'keyone' 和 'key.one ' 规范化后合并为 'keyone'
'keytwo': 'updated_value3' # 'key two' 规范化后为 'keytwo'
}
result = combine_and_update_results(original_data, updates)
assert result == expected_result, f"测试键重复但规范化后不同失败。\n预期: {expected_result}\n实际: {result}"
print("测试键重复但规范化后不同通过。")
# 主函数,运行所有测试用例
def run_all_tests():
test_functions = [
# test_complex_case,
# test_empty_updates,
# test_empty_original,
# test_non_dict_values,
# test_full_width_spaces,
# test_nested_and_various_types,
# test_keys_only_spaces_and_dots,
# test_overwrite_nested_structure,
# test_update_with_list_of_dicts,
test_duplicate_keys_after_normalization
]
for test_func in test_functions:
try:
test_func()
except AssertionError as e:
print(e)
except Exception as ex:
print(f"{test_func.__name__} 运行时发生错误: {ex}")
print("所有测试用例已执行完毕。")
if __name__ == '__main__':
run_all_tests()