|
@@ -45,7 +45,13 @@ func recommendCompare(c Case, lg, tg *SideResult) ([]Diff, []Assertion) {
|
|
|
|
|
|
|
|
// W4-A 的期望:每个用户、每张表、`balance` 与 `total_recommended_amount` 各 +m。
|
|
// W4-A 的期望:每个用户、每张表、`balance` 与 `total_recommended_amount` 各 +m。
|
|
|
want := c.AmountCents
|
|
want := c.AmountCents
|
|
|
|
|
+ // 推荐人声明 `Absent`(W4-B)时,八增量块里的**推荐人两组**不适用:
|
|
|
|
|
+ // 那一侧的行为是"建行 + 部分列 NULL",逐侧期望在下面 W4-B 那三条里各写一遍。
|
|
|
|
|
+ referrerAbsent := c.Recommend != nil && c.Recommend.Referrer.Absent
|
|
|
for _, g := range groups {
|
|
for _, g := range groups {
|
|
|
|
|
+ if referrerAbsent && (g.name == "推荐人·全局" || g.name == "推荐人·校区") {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
lgDBal := g.lgB.Balance - g.lgA.Balance
|
|
lgDBal := g.lgB.Balance - g.lgA.Balance
|
|
|
lgDRec := g.lgB.Recommended - g.lgA.Recommended
|
|
lgDRec := g.lgB.Recommended - g.lgA.Recommended
|
|
|
tgDBal := g.tgB.Balance - g.tgA.Balance
|
|
tgDBal := g.tgB.Balance - g.tgA.Balance
|
|
@@ -62,6 +68,66 @@ func recommendCompare(c Case, lg, tg *SideResult) ([]Diff, []Assertion) {
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // ---- W4-B:推荐人**两侧都没有账户行** ⇒ 走建行分支 ⇒ 逐侧分歧 ----
|
|
|
|
|
+ //
|
|
|
|
|
+ // 三句话,**各一条独立断言**(合成一条"整体不等"的话,将来放宽其中一句,
|
|
|
|
|
+ // 另外两句会跟着失效而无人知道):
|
|
|
|
|
+ // ① 全局 balance:legacy 有 `DEFAULT 0.000` ⇒ **确实 +m**;target 也 +m ⇒ 两侧一致;
|
|
|
|
|
+ // ② 校区 balance:legacy 建行只写 3 列、该列**无 DEFAULT** ⇒ **NULL**(没到账);target +m;
|
|
|
|
|
+ // ③ total_recommended_amount:**两张表都无 DEFAULT** ⇒ legacy 两处都是 **NULL**;target 两处 +m。
|
|
|
|
|
+ //
|
|
|
|
|
+ // 成因一句话:**两张表的默认值不对称**(`t_user_expense.balance` 有 0.000、`t_user_expense_school` 没有)。
|
|
|
|
|
+ // 定性 LEGACY-DEFECT(F2/C1-11 同族,但**方向相反**:这次是"全局到了、校区没到")。
|
|
|
|
|
+ if c.Recommend != nil && c.Recommend.Referrer.Absent {
|
|
|
|
|
+ lr, tr := lg.After.Recommender, tg.After.Recommender
|
|
|
|
|
+ lrc, trc := lg.After.RecommenderCampus, tg.After.RecommenderCampus
|
|
|
|
|
+ lb, tb := lg.Before.Recommender, tg.Before.Recommender
|
|
|
|
|
+ lbc, tbc := lg.Before.RecommenderCampus, tg.Before.RecommenderCampus
|
|
|
|
|
+
|
|
|
|
|
+ add("W4-B·推荐人 全局 Δbalance", fmt.Sprintf("%+d", lr.Balance-lb.Balance),
|
|
|
|
|
+ fmt.Sprintf("%+d", tr.Balance-tb.Balance), lr.Balance-lb.Balance == tr.Balance-tb.Balance,
|
|
|
|
|
+ "两侧都应 +m(全局列有 DEFAULT 0.000)")
|
|
|
|
|
+ asserts = append(asserts, Assertion{Kind: AssertionBusiness,
|
|
|
|
|
+ Name: "W4-B① 全局 `balance`:**两侧都 +m**(`t_user_expense.balance` 有 `DEFAULT 0.000`,建行后有值)",
|
|
|
|
|
+ Pass: lr.Balance-lb.Balance == want && tr.Balance-tb.Balance == want,
|
|
|
|
|
+ Detail: fmt.Sprintf("legacy %+d(期望 %+d)| target %+d(期望 %+d)| m=%d。"+
|
|
|
|
|
+ "这一条是**唯一两侧一致**的那句 —— 也是为什么只看全局会漏掉整个缺陷",
|
|
|
|
|
+ lr.Balance-lb.Balance, want, tr.Balance-tb.Balance, want, want),
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ add("W4-B·推荐人 校区 Δbalance", fmt.Sprintf("%+d(NULL=%v)", lrc.Balance-lbc.Balance, lrc.Nulls.Balance),
|
|
|
|
|
+ fmt.Sprintf("%+d(NULL=%v)", trc.Balance-tbc.Balance, trc.Nulls.Balance),
|
|
|
|
|
+ c.IntentionalStrict, "legacy 建行只写 3 列 ⇒ 该列无 DEFAULT ⇒ NULL")
|
|
|
|
|
+ asserts = append(asserts, Assertion{Kind: AssertionBusiness,
|
|
|
|
|
+ Name: "W4-B② 校区 `balance`:legacy **仍是 NULL(没到账)** / target **+m 且有值**",
|
|
|
|
|
+ Pass: lrc.Nulls.Balance && lrc.Balance-lbc.Balance == 0 && !trc.Nulls.Balance && trc.Balance-tbc.Balance == want,
|
|
|
|
|
+ Detail: fmt.Sprintf("legacy Δ=%+d NULL=%v | target Δ=%+d NULL=%v | m=%d。"+
|
|
|
|
|
+ "legacy 侧 `SET balance=balance+m` 在 NULL 上运算仍是 NULL ⇒ **校区一分没记**",
|
|
|
|
|
+ lrc.Balance-lbc.Balance, lrc.Nulls.Balance, trc.Balance-tbc.Balance, trc.Nulls.Balance, want),
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ add("W4-B·推荐人 Δrecommended(全局/校区)",
|
|
|
|
|
+ fmt.Sprintf("%+d/%+d (NULL %v/%v)", lr.Recommended-lb.Recommended, lrc.Recommended-lbc.Recommended,
|
|
|
|
|
+ lr.Nulls.Recommended, lrc.Nulls.Recommended),
|
|
|
|
|
+ fmt.Sprintf("%+d/%+d (NULL %v/%v)", tr.Recommended-tb.Recommended, trc.Recommended-trc.Recommended,
|
|
|
|
|
+ tr.Nulls.Recommended, trc.Nulls.Recommended),
|
|
|
|
|
+ c.IntentionalStrict, "两张表这一列都无 DEFAULT")
|
|
|
|
|
+ asserts = append(asserts, Assertion{Kind: AssertionBusiness,
|
|
|
|
|
+ Name: "W4-B③ `total_recommended_amount`:legacy **全局与校区都是 NULL(两边都没记)** / target 两处都 +m",
|
|
|
|
|
+ Pass: lr.Nulls.Recommended && lrc.Nulls.Recommended &&
|
|
|
|
|
+ lr.Recommended-lb.Recommended == 0 && lrc.Recommended-lbc.Recommended == 0 &&
|
|
|
|
|
+ !tr.Nulls.Recommended && !trc.Nulls.Recommended &&
|
|
|
|
|
+ tr.Recommended-tb.Recommended == want && trc.Recommended-trc.Recommended == want,
|
|
|
|
|
+ Detail: fmt.Sprintf("legacy 全局 %+d NULL=%v、校区 %+d NULL=%v | target 全局 %+d NULL=%v、校区 %+d NULL=%v。"+
|
|
|
|
|
+ "⚠ **NULL 不是 0**:它表示「累计推荐金额从未被写成功过」,与「推荐金额确实是 0」在账上完全不同;"+
|
|
|
|
|
+ "按 Q1 口径 target 应为 0.00 的地方这里是 +m —— 这就是缺陷本身",
|
|
|
|
|
+ lr.Recommended-lb.Recommended, lr.Nulls.Recommended,
|
|
|
|
|
+ lrc.Recommended-lbc.Recommended, lrc.Nulls.Recommended,
|
|
|
|
|
+ tr.Recommended-tb.Recommended, tr.Nulls.Recommended,
|
|
|
|
|
+ trc.Recommended-trc.Recommended, trc.Nulls.Recommended),
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 正向断言(F22 同族):**两个用户**的钱都真的动了。
|
|
// 正向断言(F22 同族):**两个用户**的钱都真的动了。
|
|
|
// 少了这条,"两侧都不动 ⇒ 全 0 相等"会全绿 —— 而那正是"游标没进循环"的形态。
|
|
// 少了这条,"两侧都不动 ⇒ 全 0 相等"会全绿 —— 而那正是"游标没进循环"的形态。
|
|
|
lgUser := lg.After.Global.Balance - lg.Before.Global.Balance
|
|
lgUser := lg.After.Global.Balance - lg.Before.Global.Balance
|