package dwbg import ( "encoding/json" "strings" "testing" "tyapi-server/internal/domains/api/dto" "go.uber.org/zap" ) func TestEmptySinanReportMarshal(t *testing.T) { params := dto.DWBG6A2CReq{ Name: "张三", IDCard: "320321199102011152", MobileNo: "13812345678", } report := emptySinanReport(params) data, err := json.Marshal(report) if err != nil { t.Fatalf("序列化失败: %v", err) } var parsed map[string]interface{} if err := json.Unmarshal(data, &parsed); err != nil { t.Fatalf("反序列化失败: %v", err) } requiredModules := []string{ "baseInfo", "standLiveInfo", "riskPoint", "securityInfo", "antiFraudInfo", "riskList", "applicationStatistics", "lendingStatistics", "performanceStatistics", "overdueRecord", "creditDetail", "rentalBehavior", "riskSupervision", "judicialLeaseReport", } for _, module := range requiredModules { if _, ok := parsed[module]; !ok { t.Errorf("缺少顶层模块: %s", module) } } antiFraud, ok := parsed["antiFraudInfo"].(map[string]interface{}) if !ok { t.Fatal("antiFraudInfo 类型错误") } for _, key := range []string{"moneyLaundering", "deceiver", "gamblerPlayer", "gamblerBanker"} { if _, exists := antiFraud[key]; !exists { t.Errorf("antiFraudInfo 缺少键: %s", key) } } rental, ok := parsed["rentalBehavior"].(map[string]interface{}) if !ok { t.Fatal("rentalBehavior 类型错误") } if len(rental) != len(rentalBehaviorFieldNames) { t.Errorf("rentalBehavior 字段数 = %d, want %d", len(rental), len(rentalBehaviorFieldNames)) } } func TestTransformToSinanReportAllNil(t *testing.T) { params := dto.DWBG6A2CReq{ Name: "张三", IDCard: "320321199102011152", MobileNo: "13812345678", } apiData := map[string]interface{}{ "YYSY35TA": nil, "YYSYE7V5": nil, "YYSYH6F3": nil, "YYSYP0T4": nil, "FLXGDEA9": nil, "FLXG8B4D": nil, "FLXG7E8F": nil, "JRZQ5E9F": nil, "JRZQ1D09": nil, } report := transformToSinanReport(apiData, params, zap.NewNop()) if _, err := json.Marshal(report); err != nil { t.Fatalf("全 nil 数据源仍应可序列化: %v", err) } } func TestTransformToSinanReportWithMockData(t *testing.T) { params := dto.DWBG6A2CReq{ Name: "黄春丽", IDCard: "452621197903185522", MobileNo: "13907764404", } apiData := map[string]interface{}{ "YYSYH6F3": map[string]interface{}{ "result": "0", "sex": "女", "address": "广西壮族自治区百色地区百色市", "channel": "cmcc", }, "YYSYE7V5": map[string]interface{}{ "status": 0, "channel": "cmcc", }, "YYSY35TA": map[string]interface{}{ "prov": "广西壮族自治区", "city": "南宁", "name": "中国移动", }, "YYSYP0T4": map[string]interface{}{ "time": "[24,-1)", }, "FLXG8B4D": map[string]interface{}{ "gamblerBanker": "A", }, "FLXGDEA9": map[string]interface{}{ "level": "A1,C3", }, "JRZQ5E9F": map[string]interface{}{ "xyp_cpl0001": "2", "xyp_cpl0007": "2", "xyp_cpl0008": "1", "xyp_cpl0011": "2", "xyp_cpl0012": "2", "xyp_cpl0013": "3", "xyp_cpl0044": "1", "xyp_cpl0074": "0.56", "xyp_model_score_mid": "500", }, "JRZQ1D09": map[string]interface{}{ "m12": map[string]interface{}{ "id": map[string]interface{}{"allnum": "7", "orgnum": "1", "tot_mons": "16"}, "cell": map[string]interface{}{"allnum": "7", "orgnum": "1", "tot_mons": "16"}, }, "idcard_relation_phone": 1, "phone_relation_idard": 0, }, } report := transformToSinanReport(apiData, params, zap.NewNop()) standLive := report["standLiveInfo"].(map[string]interface{}) if standLive["finalAuthResult"] != "0" || standLive["verification"] != "0" { t.Errorf("standLiveInfo 三要素映射错误: %+v", standLive) } if standLive["inTime"] != "24" { t.Errorf("inTime = %v, want 24", standLive["inTime"]) } security := report["securityInfo"].(map[string]interface{}) if security["front"] != 1 || security["escape"] != 0 || security["drug"] != 1 { t.Errorf("securityInfo 解析错误: %+v", security) } antiFraud := report["antiFraudInfo"].(map[string]interface{}) if antiFraud["gamblerBanker"] != "A" { t.Errorf("antiFraudInfo.gamblerBanker = %v", antiFraud["gamblerBanker"]) } riskList := report["riskList"].(map[string]interface{}) if riskList["creditLeaseRisk"] != 1 { t.Errorf("creditLeaseRisk = %v, want 1", riskList["creditLeaseRisk"]) } if riskList["vehicleLeaseViolation"] != 1 { t.Errorf("vehicleLeaseViolation = %v, want 1", riskList["vehicleLeaseViolation"]) } if riskList["highRiskArea"] != 0 { t.Errorf("highRiskArea = %v, want 0", riskList["highRiskArea"]) } riskPoint := report["riskPoint"].(map[string]interface{}) if riskPoint["antiFraudRisk"] != 1 { t.Errorf("antiFraudRisk = %v, want 1", riskPoint["antiFraudRisk"]) } if riskPoint["judicialCase"] != 0 { t.Errorf("judicialCase = %v, want 0", riskPoint["judicialCase"]) } perf := report["performanceStatistics"].(map[string]interface{}) if perf["serialVersionUID"] != 1 { t.Errorf("serialVersionUID = %v, want 1", perf["serialVersionUID"]) } } func TestMapYYSYH6F3StandLive(t *testing.T) { cases := []struct { result, wantFinal, wantVerify string }{ {"0", "0", "0"}, {"1", "1", "1"}, {"2", "1", "-1"}, {"", "1", "-1"}, } for _, tc := range cases { final, verify := mapYYSYH6F3StandLive(tc.result) if final != tc.wantFinal || verify != tc.wantVerify { t.Errorf("result=%q got (%s,%s) want (%s,%s)", tc.result, final, verify, tc.wantFinal, tc.wantVerify) } } } func TestParseSecurityInfoLevel(t *testing.T) { info := parseSecurityInfoLevel("A,C3") if info["escape"] != 1 || info["front"] != 0 || info["drug"] != 1 { t.Fatalf("A,C3 => %+v", info) } info = parseSecurityInfoLevel("A1") if info["front"] != 1 || info["escape"] != 0 { t.Fatalf("A1 => %+v", info) } } func TestIndustryBlacklistHit(t *testing.T) { if !industryBlacklistHit("D1,B") { t.Fatal("D1 should hit industry blacklist") } if industryBlacklistHit("A1,C3") { t.Fatal("A1,C3 should not hit industry blacklist") } } func TestReportNoNullValues(t *testing.T) { params := dto.DWBG6A2CReq{ Name: "张三", IDCard: "320321199102011152", MobileNo: "13812345678", } apiData := map[string]interface{}{ "FLXG7E8F": map[string]interface{}{ "judicial_data": map[string]interface{}{ "breachCaseList": []interface{}{}, "consumptionRestrictionList": []interface{}{}, "lawsuitStat": map[string]interface{}{ "count": map[string]interface{}{ "count_beigao": 0, "larq_stat": "", }, "civil": map[string]interface{}{ "cases": []interface{}{}, "count": map[string]interface{}{"count_total": 0}, }, }, }, }, } report := transformToSinanReport(apiData, params, zap.NewNop()) cleaned, ok := stripNullValues(report).(map[string]interface{}) if !ok { t.Fatal("stripNullValues failed") } if reportContainsNull(cleaned) { t.Fatal("report still contains null after strip") } data, err := json.Marshal(cleaned) if err != nil { t.Fatalf("marshal failed: %v", err) } if strings.Contains(string(data), "null") { t.Fatalf("JSON contains null: %s", string(data)) } } func TestBuildJudicialLeaseReportWithCases(t *testing.T) { apiData := map[string]interface{}{ "FLXG7E8F": map[string]interface{}{ "judicial_data": map[string]interface{}{ "breachCaseList": []interface{}{}, "consumptionRestrictionList": []interface{}{}, "lawsuitStat": map[string]interface{}{ "count": map[string]interface{}{ "count_total": 1, "count_beigao": 1, "larq_stat": "2026(1)", "ay_stat": "民事(1)", }, "civil": map[string]interface{}{ "cases": []interface{}{ map[string]interface{}{ "c_ah": "(2019)桂0103民初5129号", "n_ssdw": "原告", "n_ajjzjd": "已结案", "n_ajlx": "民事一审", "c_dsrxx": []interface{}{ map[string]interface{}{ "c_mc": "黄春丽", "n_ssdw": "原告", "n_dsrlx": "自然人", }, }, }, }, "count": map[string]interface{}{ "count_total": 1, "count_beigao": 1, }, }, "preservation": map[string]interface{}{ "cases": []interface{}{}, "count": map[string]interface{}{"count_total": 1}, }, "implement": map[string]interface{}{ "cases": []interface{}{}, "count": map[string]interface{}{"count_total": 0}, }, }, }, }, } jlr := buildJudicialLeaseReport(apiData) courtInfo := jlr["courtInfo"].(map[string]interface{}) if courtInfo["civilCasesCount"] != 1 { t.Fatalf("civilCasesCount = %v", courtInfo["civilCasesCount"]) } if courtInfo["preservationCasesCount"] != 1 { t.Fatalf("preservationCasesCount = %v", courtInfo["preservationCasesCount"]) } newMult := courtInfo["newMultCourtInfo"].(map[string]interface{}) civilCases, ok := newMult["civilCases"].([]interface{}) if !ok || len(civilCases) != 1 { t.Fatalf("civilCases missing or empty: %+v", newMult["civilCases"]) } if _, has := newMult["preservationCases"]; has { t.Fatal("preservationCases list should be omitted when empty") } overview := jlr["caseOverviewInfo"].(map[string]interface{}) if overview["beigaoTotalCasesCounts"] != 1 { t.Fatalf("beigaoTotalCasesCounts = %v", overview["beigaoTotalCasesCounts"]) } } func TestM1PlusCountCaps(t *testing.T) { apiData := map[string]interface{}{ "JRZQ5E9F": map[string]interface{}{ "xyp_cpl0029": "1", "xyp_cpl0030": "1", "xyp_cpl0031": "1", }, } record := buildOverdueRecord(apiData) if record["m1PlusCountLast6Months"] != 3 { t.Fatalf("6m cap = %v", record["m1PlusCountLast6Months"]) } if record["m1PlusCountLast12Months"] != 3 { t.Fatalf("12m cap = %v", record["m1PlusCountLast12Months"]) } }