Files
erqiwang_youle/server/games/erqiwang/docs/compliance/02-测试计划.md
T
joywayerandClaude Opus 5 a4361a802d 二七王:补 9 处 design 规则的正/反/边界用例(均通过变异检验)
对 design §1~§12 重做「每条规则是否三类用例齐全」的审计。此前的覆盖矩阵按
「被测函数」组织,容易漏掉跨函数才体现的规则,本轮补齐 9 处:

- G1/G2 §4.2 叫分:下限5与非首家不叫接受,负数/缺call/步进外/同分拒;
  「不叫即退出本局叫分」——反悔再叫被 SEAT 拒、callproc 不变、仍轮到下一家
- G3 §4.5 埋牌:非庄家 SEAT、step2/step5 STEP、7张/9张/空数组 PARAM
- G4 §5.1 每轮由上一轮牌面最大的一方先出(闲1赢/闲2赢两种)
- G5 §6.2 闲家赢计入台面全部分牌(含庄家自己打出的)、庄家赢作废、
  两个闲家谁赢结果一致
- G6 §8 算奖快照:庄家埋后28(已埋不在内)、闲家28、投降36、打出后不缩水
- G7 §3 对子只认同花色同点数两副:跨花色副7/副2、正副7、大小王均不成对
- G8 §6.3 赢末轮的牌不全是主牌就不扣底(副牌拖拉机/混合出牌/顺序颠倒)
- G9 §11 无超时托管守卫:对局阶段 min_ontimeout 调用次数必须为 0,
  将来有人加超时代打就会转红

每条都在副本上注入违反该规则的改动确认转红(7 组变异全部被抓住)。

顺带修一个测试自身的问题:mkBury 桩缺 do_burycard,导致「埋牌张数校验被
改松」这类变异表现为整个文件崩溃而非某条断言转红,后续断言全不执行。桩已
补完整到能走完成功路径。

全套单测 462 → 511 项全绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 13:36:09 +08:00

24 KiB
Raw Blame History

二七王服务端 · 合规测试计划

目标:用 Node 单测/集成测系统覆盖 design.md 的全部服务端可验证规则,做到"规则 → 用例"可追溯,作为"代码是否符合手册"的自动化证据(与 01-design合规逐节核对.md 的人工审计互补)。

运行:node server/games/erqiwang/test/run.js。测试原理与双运行时见 test/README.md。测试纪律(正/反/边界、不软化断言、失败先裁根因)见 docs/server/development-guide/04 §10。


0. 分层与测试类型

层 含义 依赖 现状
L1 单元 纯函数直接调用(arith/config/paiju 静态计算) 仅 _shim 的平台工具 已有 test_arith/test_config/test_paiju(部分)
L2 局内集成 cls_youle_erqiwang_paiju.new(o_desk,firstseat) 造牌局,驱动 do_callgrade→do_choiceflower→do_burycard→do_playcard…→get_paiju_account 验证状态/结算 mock o_desk/o_room + shim;不经 mod.js 仅 get_paiju_account 造了极简对象,无完整一局驱动
L3 RPC/广播 mod.js 收包入口 → 校验 → 广播 mock check_player/SendPack/sendpack_toother,捕获下发包 完全未覆盖

发牌随机性处理:do_dealpai 用 min_random。L2 需要可控发牌——测试 _shim 提供可注入的 min_random(预置序列或指定发牌结果),使一局可复现。这是 L2 的前置基建。


1. 覆盖矩阵(按 design 章节)

状态:✅ 已覆盖 · 🟡 部分 · ❌ 待补。用例列标注 正/反/边界 三类(docs/server/development-guide/04 §10 要求三类齐全)。

§2 牌局构成

规则 被测 用例(正/反/边界) 层 状态
92 张、去两副 3/4 init_cards/do_dealpai 正:发完 3 家各 28 + 底 8 = 92;反:牌堆不含 number 3/4;边界:两副各花色计数 L2 ❌
分值 5→5、10→10、K→10、余 0 init_cards 正:各面值 score;边界:非分牌 score=0 L1/L2 🟡(扣底/结算间接)

§3 主牌顺序 / 编码

规则 被测 用例 层 状态
主牌 code 降序=设计顺序(大王>小王>正7>副7>正2>副2>主A…主5>副牌) id_to_code/order_cards 正:排序结果逐位;边界:正/副 7、正/副 2 的相对大小;主A vs 副2 L1 ❌(间接用到,无专测)
相邻链 + 6/8 可连、7 不与 6/8 连 is_continuous 正:全相邻段逐对;反:7-6/8-7/9-7 不连;边界:8-6 连、大王-小王连 L1 🟡(甩牌/算奖间接)
副7/副2 跨花色比大小归一 trump_rank/can_followcard 正:副7 vs 副7 不可压;反:正7 压副7 L1 🟡(甩牌间接)

§4 开局与坐庄

规则 被测 用例 层 状态
叫分 5~70、步进5、暂定庄必叫、后叫更低/不叫 mod.jiaofen 校验 + do_callgrade 正:合法叫分推进;反:>70/非5倍/首家0/叫≥当前;边界:叫70、叫5 L3(校验)+L1(do_callgrade) ❌
叫5立即上庄、两家不叫上庄 do_callgrade 正:叫5→banker;正:一家叫另两家不叫→banker;边界:三家叫分序列 L1 ❌
坐庄轮换:庄赢连庄、庄输/投降下家、首局庄=0号 desk.do_prepare/makewar 正:result=0 连庄;正:result=1/2 顺延;边界:首局 firstseat=0 L2/L3 ❌
阶段机 1→2→3→5→6,无 step4 do_up_banker/do_choiceflower/do_burycard 正:各 handler 后 step 值;反:错误 step 调用被拒 L2/L3 ❌
投降仅70分/step2/庄家/不埋牌 mod.touxiang 正:70分 step2 投降→结算;反:≠70/step≠2/非庄;边界:投降后 step=6 L3 ❌
70分暗牌向所有玩家亮3秒(+ancard3s)、非70只发庄 mod.jiaofen(shangzhuang) 正:70→闲家有 bottomcards+ancard3s;反:非70 闲家无 bottomcards L3 ❌
选主后先选主后埋牌 do_choiceflower/do_burycard 正:flower 记录、step 推进;边界:埋牌须8张且在手 L2 🟡(check_cards_inhand 未测)

§5 出牌规则

规则 被测 用例 层 状态
§5.1/5.2 跟牌/毙牌/垫牌/混合出牌/拖拉机覆盖度 get_followcard/can_followcard 正:同花色跟、有对必出对、有拖必出拖、两对不连必出、尽量长拖优先;反:缺牌型被拒、放长拖只出散对被拒;毙牌(须完全缺门):副单→主单、副对→主对、副N连→主N连;垫牌/混合出牌:cardvalue=0 不争权 L1 ✅(test_follow 50 例,含 else 欠约束修复回归)
§5.3 拖拉机相邻 is_continuous/get_tuolaji_list 见 §3 L1 🟡
§5.4 甩牌:副禁甩/最大性/甩错 can_playcard/opp_can_beat_flush/decompose_trump 已覆盖(合法/甩错含smallest/副禁甩/单张/对子/拖拉机) L1 ✅
§5.4.4 跟甩牌强制分量拆解 flush_follow_ok 已覆盖(有对必打对/有拖必打拖/退化/主牌最大化/无主全垫) L1 ✅

§6 捡分与扣底

规则 被测 用例 层 状态
§6.1 分值 init_cards 见 §2 L1 🟡
§6.2 闲家赢归闲、庄赢作废、两闲谁赢都算闲 do_playcard/get_jian_grade 正:闲赢累计分;反:庄赢不计;边界:两闲各赢 L2 🟡(1 集成例)
§6.3 扣底倍数 单1/对2/N连2N、全主牌守卫、取最高规格 get_bottom_multiple 已覆盖 L1 ✅
§6.3 触发:闲家用主牌赢末轮才扣底 get_bottom_account 正:闲家主牌赢末轮翻倍;反:非主牌赢不扣、庄家赢不扣 L2 ❌

§7 结算:子数与升级

规则 被测 用例 层 状态
常规算子 基础子数 + 大光×3/小光×2/过庄×1/升N级、Q=40 get_base_bycall/get_qvalue/get_upgrade 已覆盖各档代表值 L1 ✅(可补每档过庄/小光分界与升3级)
爬坡 基础子数梯度 + 分段Q 同上(climb=true) 已覆盖各档 L1 ✅
X=基础×倍率、庄赢/闲赢符号、按房间爬坡切换 get_paiju_account 正:大光/过庄/升级/爬坡局 seatlist;边界:banker=-1 L2 🟡(仅65小光+投降)

§8 算奖

规则 被测 用例 层 状态
§8.1 常规算奖只庄家、三/四王+连对链、6-8个7/2、无≥10老主/无作废 get_chongguan 已覆盖 L1 ✅
§8.2 亮牌阈值/统计、只亮结构 get_liangpai 已覆盖 4 例 L1 🟡(补 王≥3/7≥6 组合、边界9/10)
§8.3 傍王按位开关、庄闲每王1奖 get_paiju_account(bangwang) 正:傍王局 grade_aw 含王奖;反:未勾选不计 L2 ❌
§8.4 算奖并入 X×(2Ni−Nj−Nk)、含闲-闲、投降X=1 get_paiju_account 正:庄1奖/闲傍王2奖的三家净额;边界:三家同时有奖 L2 ❌(公式单测有,集成未测)
§8 快照:庄埋后28/闲发后28;投降庄36无主 get_seat_cards_award 正:庄排除已埋;正:投降含底36;边界:无主花色无连对链 L2 🟡(投降 count 间接)

§9 查牌 / 明牌

规则 被测 用例 层 状态
报无主统计 info/baozhu 门控 mod.chupai 正:可查牌下发 info/baozhu;反:不查牌 info 缺失、baozhu=0 L3 ❌
亮牌/PushCards.seatlist 门控 mod.maipai/get_deskinfo 正:可查牌闲家有 liangpai;反:不查牌无 L3 ❌
明牌 mingpai:可查牌+已报无主+出牌阶段 mod.mingpai 正:条件满足返回他家主牌;反:不查牌/未报无主/非出牌阶段被拒 L3 ❌

§10 房间设置

规则 被测 用例 层 状态
位串解析、局数6/12、扣卡房主2·4/AA1·2 config.parse/export.get_asetcount/get_needroomcard 已覆盖(config 复刻映射) L1 ✅(可改为直接调 export 函数)
傍王/爬坡/查牌三开关生效 get_paiju_account/mod.* 傍王/爬坡见 §7/§8;查牌见 §9 L2/L3 🟡

§12 完整流程

规则 被测 用例 层 状态
一局端到端:发牌→叫分坐庄→选主→埋牌→逐轮出牌→末轮扣底→结算→轮庄 全链路 正:一局可控发牌打到结算,各家总分正确;含连庄/下家轮转 L2 ❌

§11 牌局交互提示中,选主对子数/亮底牌等随对应阶段包下发;闲家三提示(踩/没分/有分)为服务端转发项(mod.tishi,见 P1)。


2. 待补用例清单(按优先级)

P0 · 规则/金额关键 —— ✅ 已完成

  1. ✅ §5.1/5.2 正常跟牌/毙牌/垫牌/混合出牌/拖拉机覆盖度(can_followcard,test_follow.js 50 例)——单张/对子/拖拉机的必出、毙牌数量对应(副单→主单/副对→主对/副N连→主N连、且毙牌须完全缺门)、垫牌与"混合出牌"(有该花色不够+补主牌→cardvalue=0 不争权)、缺门/同花色不足/对子不够各分支、多候选拖拉机(D1 崩溃回归)、降级递归 else 欠约束回归(三组等长 2 连对时出孤立对→拒),正反边界齐全。
  2. ✅ §7/§8 结算集成扩充(get_paiju_account,test_paiju.js)——大光/过庄/升2级、爬坡局、傍王局(庄3王,N=4)、不傍王对照、投降,逐档验证 seatlist 各家 grade。
  3. ✅ §4.2 叫分坐庄(do_callgrade,test_callgrade.js 6 例)——叫5立即上庄、两家不叫上庄、后叫更低→最低者上庄、不同首家。
  4. ✅ §6.3 扣底触发(get_bottom_account,test_paiju.js)——闲家主对/两连对赢末轮才扣底(×2/×4);副牌赢、庄家赢均不扣。

注:§4.2 中 mod.jiaofen 的入参校验(>70/非5倍/首家必叫/后叫更低)属 L3,随投降/暗牌/查牌门控一起在 P1 补。

P1 · 规则关键、需 RPC 脚手架 —— ✅ 已完成(_rpc.js + test_rpc.js / test_desk.js)

  1. ✅ §9 查牌门控 + mingpai——chupai 的 info/baozhu 按 nocheck 门控(可查有/不查无);mingpai 合法下发他家主牌,不查牌/未报无主/非出牌阶段均拒。
  2. ✅ §4 投降 + 暗牌亮牌——touxiang 仅 70分/step2/庄家;真实 jiaofen 驱动到 70分上庄,验证 shangzhuang 闲家有 bottomcards+ancard3s、叫5上庄闲家无。
  3. ✅ §4.2 mod.jiaofen 入参校验——>70/非5倍/首家必叫/后叫更低 全部拒,合法接受。
  4. ✅ §4.6 坐庄轮换 do_prepare——庄赢连庄、闲赢/投降下家。

P2 · 补强既有 —— ✅ 已完成

  1. ✅ §2 牌局构成专测(test_deal)、§3 编码/排序专测(test_arith:order_cards + is_continuous 链)。
  2. ✅ §9 mod.maipai 亮牌门控 / get_deskinfo PushCards 门控(test_rpc 端到端驱动后验证)。
  3. ✅ §8.2 亮牌更多阈值(6个7/固定主9-10边界)、§7 算子每档分界+升3级(test_arith)。
  4. ✅ §12 端到端(test_rpc 真实驱动到出牌就绪)。
  5. ✅ §10 直接调 export.get_asetcount/get_needroomcard/get_needroomcard_joinroom(test_config)。
  6. ✅ §11 闲家三提示 mod.tishi——正:闲家 step5 发 踩/没分/有分,只转发给对家(3-banker-seat,验证 fromid/seat/tip);反:庄家发/非出牌阶段/非法 tip/缺 tip 均拒(test_rpc 11 例)。

3. 集成脚手架需求(实现 L2/L3 的前置)

  • L2 局内驱动器 test/_harness.js:
    • 可注入发牌的 min_random(或直接构造 o_paiju.cards 指定各家手牌),使牌局可复现。
    • mock o_desk(seatlist 累积、get_desk_account、o_room.roomtype/asetcount)与 o_room。
    • 提供"驱动一局到某阶段"的辅助:叫分序列 → 选主 → 埋牌 → 出牌序列。
  • L3 RPC 捕获器:mock youle_erqiwang.import.check_player(返回构造的 o_room)、o_room.method.sendpack_toother/youle_erqiwang.app.SendPack(把下发包收集进数组),断言包字段(含 §9 门控、暗牌、投降、chupai1/2/3、jiesuan)。

4. 完成定义(DoD)—— ✅ 已达成

  • ✅ 覆盖矩阵中所有 ❌/🟡 项补到 ✅(详见 §5 现状),每条规则至少含正/反/边界;
  • node test/run.js 全绿、退出码 0;
  • 新增用例遵守测试纪律:不改正式代码去迁就测试、不软化断言、失败先用证据裁根因;
  • 本计划与 01-design合规逐节核对.md 的结论一致(自动化测试成为人工审计的可回归证据)。

5. 当前状态小结 —— ✅ DoD 达成,P0/P1/P2 全部完成

共 511 项断言全绿(test_arith 122 / test_calc 49 / test_callgrade 6 / test_config 19 / test_deal 12 / test_desk 6 / test_endgame 25 / test_follow 58 / test_followdiff 12 / test_input 34 / test_paiju 50 / test_rpc 89 / test_success 29)。其中 test_calc/test_followdiff 见 §7、G1~G9 见 §8。

design 全部服务端可验证章节均有正/反/边界单测:

  • §2 构成:test_deal 92张/去3-4/三家28+底8/分值。
  • §3 编码/排序:test_arith order_cards 降序=设计顺序、is_continuous 相邻链逐段+反例。
  • §4:叫分坐庄 do_callgrade、mod.jiaofen 入参校验、投降 touxiang 条件、70分上庄暗牌亮牌下发、坐庄轮换 do_prepare。
  • §5:正常跟牌全面覆盖(§5.1/5.2)——按跟牌方手牌各分支穷举:主牌首出与副牌首出、单张/对子/拖拉机各牌型、有同花必出对应牌型、同花不足则出仅有的+补、缺门毙牌(数量对应)与垫牌(不压)、拖拉机的对子不够/同花无对/多候选拖拉机(D1崩溃回归)/3连对/富余对子必出拖、手牌数==首出张数全部必出;甩牌全面覆盖(§5.4)——合法(纯单/纯对/单+拖/单+对+拖三混)、甩错(单张/主对/拖拉机分量各自被压、双对之一被压)、副牌禁甩(对手缺门与非缺门)、甩错惩罚实际执行(do_playcard 只打最小一张、其余留手);跟甩牌全面覆盖(§5.4.4)——对子必出、拖拉机必出/退化对子/退化到单张、多组拖拉机、混合demand逐分量对位、主牌最大化、无主全垫,以及"首出甩牌→跟牌违规→do_playcard 拒"的集成。
  • §6:捡分(结算集成间接)、扣底倍数+触发。
  • §7:算子常规+爬坡逐档、每档分界+升3级、结算集成(大光/过庄/升级/爬坡/傍王/投降)。
  • §8:算奖 get_chongguan、亮牌 get_liangpai(含 6个7/固定主9-10边界)、算奖并入 X×N(傍王对照)。
  • §9:查牌门控(chupai info/baozhu、maipai liangpai、deskinfo PushCards seatlist)、明牌 mingpai。
  • §10:位串解析、局数/扣卡(直接调 export 接口)。
  • §12:端到端(叫分→上庄→选主→埋牌→出牌ready,真实 RPC 驱动)。

说明:§12 覆盖到"出牌准备就绪"(各阶段串接正确);完整 28 墩逐墩对打需一个合法出牌选择器,属后续增强,非规则合规缺口(逐墩规则已由 §5/§6 单测覆盖)。


6. 第三轮补充:design 之外的可验证维度

前两轮的覆盖矩阵完全按 design 章节组织,因此平台接入、客户端入参、下发面一致性、协议红线这几类根本不在矩阵里——270 项全绿却漏掉了 1 项阻断级与 3 项严重缺陷(见 01-design合规逐节核对.md「第三轮核对」)。本节把这些维度补进测试计划,后续复核必须一并跑。

维度 被测 用例(正/反/边界) 文件 状态
客户端入参合法性 check_cards_valid / check_cards_inhand 正:单张/多张/边界 id 0 与 107;反:非数组(undefined/null/字符串/伪数组)、空数组、重复 id、越界、负数、小数、数字字符串;反:不在手上/已出/已埋 test_input ✅ 21
重复 id 不得伪造牌型 mod.maipai / mod.chupai 反:8 个重复 id 埋牌被拒且一张未埋;反:重复 id 出牌被拒;正:8 张不同牌埋牌成功且实埋 8 张;反:越界/非数组入参不抛异常且不产生出牌 test_input ✅ 7
§9 报无主即时刷新 do_playcard 正:打空瞬间三家统计与主花色标志同时刷新;边界:报无主前三家均为 [-1,-1] test_input ✅ 6
红线 data.success(成功包) class.desk/mod.js/get_paiju_account 正:fapai/zhunbei/jiaofen/shangzhuang/xuanzhu/maipai/chupai1/mingpai/tishi 均带 success:true;正:jiesuan 的正常/投降/解散三种 type 都带 test_success ✅ 12
红线 data.success(失败回包) 各 handler 失败分支 反:每个 handler 取代表性失败路径,断言"恰好回 1 包 + success:false + errcode 正确 + 回到请求者 fromid",覆盖 STEP/SEAT/PARAM/RULE/PLAYER 五类 test_success ✅ 17
§7.3 下发面 multiple 与结算同源 mod.jiaofen / get_deskinfo / get_paiju_account 正:叫 45 分在常规房/爬坡房分别得 6/7;正:上庄包与重连 ChooseMain 一致;边界:与结算包 aset.multiple 逐一对齐 test_rpc ✅ 7
§5.4 甩牌下发面 chupai1 正:合法甩牌带 shuai 分量;反:非甩牌不带;反:甩错只打最小一张且不带 shuai test_rpc ✅ 8
重连 pushlist 结构 get_deskinfo 正:轮数正确、内层恒 3 个座位、无 undefined;正:按本局主牌花色排序(主5 排在副A 前) test_rpc ✅ 4
§9 出牌历史按查牌模式门控 get_deskinfo 反:不查牌房无 pushlist;正:可查牌房有 pushlist;边界:两种模式下当前轮桌面牌 playproc.cards 都必须恢复 test_rpc ✅ 4
§3 相邻链花色 is_continuous 正:同花色 8-6 连;反:三组跨花色 8-6 不连;反:差 2 但非 8/6 不连 test_arith ✅ 5

关于超时:countdown 只作展示、服务端不做任何超时动作,这是 design §11 确认的规则(并非缺口),因此没有也不需要「超时自动操作」的用例;反过来,若将来有人给服务端加了超时代打,那才是违反 design §11——现已由 test_rpc 的守卫用例拦下(见 §8 G9)。


7. 第五轮:按 design 原文另写参考实现的差分测试

前六节的用例都是手写的场景枚举——覆盖的是"我想到的情况"。第五轮补两组差分测试:把 design 的规则整条转写成参考实现,与代码大面积对拍,覆盖手写用例想不到的组合。

文件 覆盖 规模
test_calc.js §7 算子全量对拍:参考实现逐字转写自 §7.1/§7.2/§7.3 判定表,比 base / Q / 判定倍率 / 最终子数 2 模式 × 14 档 × grade 0~260 = 7308 格,另按 design 的 17 张表逐格抽查 141 个写死的最终子数
test_followdiff.js §5.2 跟牌强制层级穷举差分:参考裁定按原文写,对每手牌枚举全部 C 张出牌组合逐个对拍 约 11 万组

差分测试的强度取决于造牌器,不取决于对拍逻辑。 第一版 test_followdiff 用纯随机抽牌跑 7.8 万组全绿,但把 follow_tractor_cover_ok 整个关掉依然全绿——因为唯一能区分"只出零散对子"与"先凑最长拖拉机"的形状是「同花色三组互不相邻的两连对」(12 张),随机抽根本抽不出来。故:

  • 随机源必须是固定种子 PRNG(不用 Math.random),保证用例集可复现;
  • 关键结构必须用确定性手牌钉死(structHands()),不能指望随机覆盖到;
  • 注意别让掺入的其他花色把手牌撑过枚举上限而被静默跳过(踩过一次)。

8. 第五轮:逐规则的正/反/边界补全

对 design §1~§12 重新做了一次"每条规则是否三类用例齐全"的审计。覆盖面本来就广,但仍有 9 处 design 明文规则缺用例(多是规则本身而非入参校验,前几轮的矩阵按"被测函数"组织,容易漏掉这类"跨函数才体现"的规则)。

# design 规则 补的用例(正/反/边界) 文件
G1 §4.2 暂定庄家必须叫、其后才可"更低或不叫" 边界:下限 5 接受;正:非首家 call=0 接受;反:负数 / 缺 call(NaN) / 步进外小值 1 / 与当前叫分相同 均拒 test_rpc
G2 §4.2 "不叫"即退出本局叫分,轮次跳过他 正:首家叫 65 后轮到 seat1;正:seat1 不叫后跳到 seat2;反:seat1 反悔再叫 → SEAT 拒、callproc 不变、仍轮到 seat2、未产生庄家 test_rpc
G3 §4.5 埋牌仅庄家、仅埋牌阶段、恰 8 张 反:非庄家 → SEAT;反:step2/step5 埋 → STEP;边界:7 张 / 9 张 / 空数组 → PARAM test_rpc
G4 §5.1 每轮由上一轮牌面最大的一方先出 正:闲 1 赢 → 下一轮 start/currseat 都是 1;边界:闲 2 赢 → 改由闲 2 先出 test_paiju
G5 §6.2 闲家赢 → 台面全部分牌计入;庄家赢 → 分牌作废 反:庄赢 → 下发面无 grade、闲家捡分 0;正:闲 1 赢 → 15 分(含庄家自己打出的 ♥5);边界:闲 2 赢结果与闲 1 赢一致("两个闲家谁大不影响") test_paiju
G6 §8 算奖快照的时间点与静态性 正:庄家 = 埋牌后 28 张、已埋 8 张不在内;正:闲家 = 发牌后 28 张;边界:投降局庄家 = 发牌+暗牌 36 张;边界:之后打出 10 张,快照仍是同样的 28 张 test_paiju
G7 §3 对子只认同花色同点数的两副 正:同花色两副 ♥7/♥2/大王成对;反:♥7+♣7、♥2+♣2、正7+副7、正2+副2、大王+小王 均不成对;边界:四张跨花色 7/2 组不出拖拉机,而正7对+副7对可以 test_arith
G8 §6.3 赢末轮的牌不全是主牌就不扣底 反:副牌两连对赢 → 0;反:混合出牌(主K+副K)→ 0;边界:主副提交顺序颠倒仍判 0 test_arith
G9 §11 无超时托管(守卫) 守卫:叫分→选主→埋牌→出牌全程 min_ontimeout 调用次数为 0。将来若有人加"超时自动出牌/代打",必然要注册定时器,这条即转红 test_rpc

每条都做了变异检验(在副本上注入违反该规则的改动,确认对应断言转红):

注入的缺陷 转红的断言
去掉 mod.jiaofen 的"非当前叫分位"校验 G2 三条
埋牌张数 != 8 放宽为 < 1 G3 两条边界
§6.2 改成庄家赢也累计闲家捡分 G5 一条
下一轮改为固定庄家先出 G4 两条
算奖快照不排除已埋的牌 G6 两条 + 亮牌快照一条
get_pairlist 放宽为"只看点数" G7 五条
在 mod.chupai 里注册一个定时器 G9 一条

过程中的一个教训:M2(埋牌张数)第一次跑出来是整个文件崩溃而不是干净的 FAIL——因为 mkBury 桩缺 do_burycard,校验一被改松就走到成功路径抛异常,后面的断言全不执行。桩要完整到能走完成功路径,否则"校验被改松"这类变异只会表现为崩溃,定位与信号都变差。已修。

原列在此处的两项「待外部输入」均已由规则设计者拍板:「不查牌模式是否屏蔽出牌历史」确认屏蔽,已改 design §9 + 代码 + 用例(见上表);「超时托管默认动作」确认维持现状、不做超时动作,已写入 design §11。至此测试计划无待外部输入项。