Files
group_xinghuo_jinrong/tests/test_wave1_data_masker.py
T

180 lines
5.6 KiB
Python
Raw Normal View History

"""Wave 1:信息脱敏模块单元测试(CS-C-12,纯函数无需 DB)。"""
from app.utils.data_masker import (
mask_bank_card,
mask_dict_fields,
mask_id_card,
mask_name,
mask_phone,
mask_text,
)
# ---------------------------------------------------------------------------
# 手机号
# ---------------------------------------------------------------------------
def test_mask_phone_standard():
assert mask_phone("13812345678") == "138****5678"
def test_mask_phone_already_masked_passthrough():
assert mask_phone("139****1001") == "139****1001"
def test_mask_phone_none_and_empty():
assert mask_phone(None) is None
assert mask_phone("") == ""
def test_mask_phone_invalid_format_untouched():
assert mask_phone("12345") == "12345" # 非 11 位手机号不强行处理
# ---------------------------------------------------------------------------
# 身份证
# ---------------------------------------------------------------------------
def test_mask_id_card_18_digits():
assert mask_id_card("110101199003071234") == "110***********1234"
def test_mask_id_card_18_with_tail_x():
assert mask_id_card("11010119900307123X") == "110***********123X"
assert mask_id_card("11010119900307123x") == "110***********123X" # 小写 x 归一
def test_mask_id_card_15_digits_legacy():
# 15 位老证:前 3 + 8 个 * + 后 4
assert mask_id_card("110101900307123") == "110********7123"
def test_mask_id_card_already_masked_passthrough():
assert mask_id_card("310101199903XXXXXX") == "310101199903XXXXXX"
# ---------------------------------------------------------------------------
# 姓名(只保留姓)
# ---------------------------------------------------------------------------
def test_mask_name_two_chars():
assert mask_name("张三") == "张*"
assert mask_name("李四") == "李*"
def test_mask_name_three_chars():
assert mask_name("张明明") == "张**"
def test_mask_name_four_or_more():
assert mask_name("欧阳修先生") == "欧****"
def test_mask_name_already_masked_passthrough():
assert mask_name("客户·王**") == "客户·王**"
assert mask_name("陈**兰") == "陈**兰"
def test_mask_name_none_and_single():
assert mask_name(None) is None
assert mask_name("张") == "张"
# ---------------------------------------------------------------------------
# 银行卡
# ---------------------------------------------------------------------------
def test_mask_bank_card_continuous():
assert mask_bank_card("6222021234567890") == "************7890"
def test_mask_bank_card_with_spaces():
assert mask_bank_card("6222 0212 3456 7890") == "**** **** **** 7890"
def test_mask_bank_card_with_hyphens():
assert mask_bank_card("6222-0212-3456-7890") == "****-****-****-7890"
def test_mask_bank_card_too_short_untouched():
assert mask_bank_card("12345") == "12345"
# ---------------------------------------------------------------------------
# 自由文本兜底扫描
# ---------------------------------------------------------------------------
def test_mask_text_mixed_pii():
text = "我的手机13812345678,身份证110101199003071234,卡号6222021234567890"
out = mask_text(text)
assert "138****5678" in out
assert "110***********1234" in out
assert "************7890" in out
def test_mask_text_spaced_bank_card():
out = mask_text("收款卡号 6222 0212 3456 7890 请查收")
assert "**** **** **** 7890" in out
def test_mask_text_legacy_id_card():
out = mask_text("老证号 110101900307123 已登记")
assert "110********7123" in out
def test_mask_text_no_pii_untouched():
text = "今天想了解一下货币基金的赎回规则"
assert mask_text(text) == text
def test_mask_text_amount_and_date_not_falsely_masked():
# 金额(小数点分隔)与日期不应被当作卡号/身份证
assert mask_text("金额520000.00元") == "金额520000.00元"
assert mask_text("到期日2026-09-08") == "到期日2026-09-08"
def test_mask_text_phone_not_cut_from_card():
# 16 位卡号中即便包含 1[3-9] 开头的片段,也不应被手机号规则误切
out = mask_text("6222138123456789")
assert out == "************6789"
# ---------------------------------------------------------------------------
# 结构化数据批量脱敏
# ---------------------------------------------------------------------------
def test_mask_dict_fields_single_row():
row = {
"customer_id": "CUST-1001",
"display_name": "李四",
"phone_mask": "139****1001", # 库中已脱敏 → 放行
"payer_name": "王五",
"amount": 5000.00, # 非字符串原样保留
}
out = mask_dict_fields(row)
assert out["display_name"] == "李*"
assert out["phone_mask"] == "139****1001"
assert out["payer_name"] == "王*"
assert out["amount"] == 5000.00
assert out["customer_id"] == "CUST-1001"
# 不入参修改
assert row["display_name"] == "李四"
def test_mask_dict_fields_list_of_rows():
rows = [
{"product_name": "现金宝货币", "counterparty_name": "张三"},
{"product_name": "稳健债基", "counterparty_name": "李四"},
]
out = mask_dict_fields(rows)
assert out[0]["counterparty_name"] == "张*"
assert out[1]["counterparty_name"] == "李*"
assert out[0]["product_name"] == "现金宝货币"
def test_mask_dict_fields_custom_mapping():
row = {"contact_mobile": "13812345678", "remark": "ok"}
out = mask_dict_fields(row, {"contact_mobile": "phone"})
assert out["contact_mobile"] == "138****5678"
assert out["remark"] == "ok"