zbparse/flask_app/test_case/test_combine_and_update_results.py
2024-12-03 17:37:02 +08:00

417 lines
12 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()