二七王:第六轮核对(多局大局 + 整局带牌型模糊),未发现不一致
前五轮的端到端都只跑单局、且只出单张。本轮补两个从未被驱动过的维度: 一、多局大局(design §12.1 步骤10 / §12.2 / §4.6) 真实驱动 6 局与 12 局:跨局轮庄与「上局 banker+result」严格对应,另单独造出 result=0 的庄赢局验证连庄端到端(此前只有 do_prepare 的桩单测);每局零和、 累计分与逐局累加一致;account 只在末局出现,打满后再准备被拒;房卡只扣一次; 战绩载荷完整;中途解散按当前累计分结算、result=3。全部相符。 二、整局带牌型模糊(新增 test/test_fuzz.js) test_endgame 的驱动器只会出单张,对子/拖拉机/甩牌/甩错在整局链路里从未跑过。 新测试用带牌型的对局补上,并对每一墩用独立参考实现重算「谁最大」与服务端 比对(不是抽查),另独立重算捡分、扣底倍数、算奖与捡分子数分配。探针阶段 跑了 160 局约 3800 墩(4 个种子)0 异常,入库版固定为 20 局约 480 墩、0.3s。 变异检验:牌的归属写给非胜者、单张毙牌不再压过副牌、算奖分配去掉 ×X、 跟牌牌面值改回未排序入参 —— 四条全部转红。 过程中修正了测试自身的三个问题(已写进 test/README 与 compliance): - 参考实现的 rank 取了负数,而 0 是「不参与本墩」的哨兵,哨兵反而数值最大; - 闲家捡分按 playowner 累加再与 aset.grade 比,是拿被测字段自证,playowner 写错时两边一起错照样通过 —— 改成按独立算出的墩胜者累计; - 扣底倍数再调 get_bottom_multiple 去比,同样是自证,倍数表改成恒返回 2 也 通过 —— 改成按 design §6.3 独立重算。 另:该文件的覆盖下限是发牌相关的,随机发牌下扣底可能一次都不出现(实测 60 次里有 1 次),故把发牌也接到固定种子上;随机发牌的整局覆盖由 test_endgame 承担。 全套单测 511 → 519 项全绿,总耗时 < 1.7s。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -44,13 +44,15 @@ node server/games/erqiwang/test/test_arith.js # 单独跑某一组
|
||||
|
||||
- `test_calc.js`:**§7 算子全量对拍**。参考实现逐字转写自 §7.1/§7.2/§7.3 的判定表,与 `get_base_bycall` / `get_qvalue` / `get_upgrade` 比对 **2 种算子模式 × 14 个叫分档 × grade 0~260 = 7308 格**(每格比 base/Q/判定倍率/最终子数四项),另按 design 的 17 张表逐格抽查 141 个"写死的最终子数"。断言按(模式,叫分档)与表名分组,失败能直接定位到档位。
|
||||
- `test_followdiff.js`:**§5.2 跟牌强制层级穷举差分**。参考裁定按 §5.2 原文写(缺门/不足/够牌 × 单张/对子/N 连对 + 最长拖拉机优先的档案比较),对每手牌**枚举全部 C 张出牌组合**逐个比对"参考允许 vs `can_followcard` 允许",任何一侧多放行或多拒绝都会被抓到(约 11 万组)。
|
||||
- `test_fuzz.js`:**整局模糊 + 每墩胜者差分**。`test_endgame.js` 的驱动器只会出单张,所以对子/拖拉机/甩牌/甩错在「整局链路」里从未跑过——单测逐个覆盖了 `can_playcard`/`can_followcard`,但它们与 `do_playcard`/`mod.chupai`/结算的**集成**是空白。本文件用带牌型的对局补上(20 局约 480 墩,四种房间选项组合轮换),并对**每一墩**用独立参考实现重算"谁最大"与服务端比对(不是抽查,每墩都比),另独立重算闲家捡分、扣底倍数、算奖与捡分子数的分配。提交时还会把牌按**最坏顺序**摆(`[K,K,Q,Q]→[K,Q,K,Q]`,把每个对子拆开),压服务端判定的入参顺序无关性。
|
||||
|
||||
这两组都做过**变异检验**(在副本上注入缺陷确认会转红):关掉 `follow_tractor_cover_ok` → `test_followdiff` 三种拖拉机首出全红;把大光倍率改 3→4、常规 55 档 base 改 4→5、爬坡 40/35 档 Q 改 20→40 → `test_calc` 精确指出档位与 grade。
|
||||
三组都做过**变异检验**(在副本上注入缺陷确认会转红):关掉 `follow_tractor_cover_ok` → `test_followdiff` 三种拖拉机首出全红;大光倍率改 3→4 / 常规 55 档 base 改 4→5 / 爬坡 40·35 档 Q 改 20→40 → `test_calc` 精确指出档位与 grade;牌的归属写给非胜者、单张毙牌不再压过副牌、算奖分配去掉 `×X`、跟牌牌面值改回未排序入参 → `test_fuzz` 全部转红。
|
||||
|
||||
两点写法约定,改这两个文件时别破坏:
|
||||
改这三个文件时别破坏的写法约定:
|
||||
|
||||
- **随机源必须是固定种子的 PRNG**(`test_followdiff.js` 里的 xorshift32),不用 `Math.random`——同一份代码每次跑的用例集完全相同,不抖动。
|
||||
- **随机源必须是固定种子的 PRNG**,不用 `Math.random`——同一份代码每次跑的用例集完全相同。`test_fuzz.js` 连**发牌**也接到同一个种子上:它末尾的覆盖下限(甩牌/毙牌/扣底各出现多少次)是发牌相关的,用随机发牌时稀有事件会在某些运行里一次都不出现而让断言随机转红(实测 60 次里有 1 次 0 次扣底)。随机发牌的整局覆盖由 `test_endgame.js` 承担,两者互补。
|
||||
- **关键结构要用确定性手牌钉死**,不能指望随机造牌覆盖到。例如「同花色三组互不相邻的两连对」(12 张)是唯一能区分"只出零散对子"与"先凑最长拖拉机"的形状(少于 3 组时任取 3 对必含相邻对,测不出差别);纯随机造牌造不出它,关掉覆盖度校验也全绿,差分就形同虚设。`structHands()` 就是为此存在的,另注意别让掺入的其他花色把手牌撑过枚举上限而被静默跳过。
|
||||
- **不变量不能拿被测字段自证**。`test_fuzz` 里踩过两次:① 闲家捡分若按 `playowner` 累加再与 `aset.grade` 比,`playowner` 写错时两边一起错、断言照样通过——改成按**独立算出的墩胜者**累计;② 扣底倍数若再调 `get_bottom_multiple` 去比,倍数表被改成恒返回 2 也通过——改成按 design §6.3 独立重算。
|
||||
|
||||
## 约定(dev-guide §10 测试纪律)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user