"""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"