二七王:重新生成真包夹具、补捕 StartWar、修复一致性测试用例间污染
服务端 8452535 改了下发面(chupai1/2/3 新增 playproc、deskinfo step2/3 新增
curmultiple、maipai 新增 seatlist、bottomcards/burycards 顺序统一),前端真包
夹具 packets.json 已过期,重新导出并逐项核对新字段存在与三处/两处顺序一致。
夹具新增顶层 startwar[](每座位一份,结构=deskwar=deskinfo,取自 do_new_paiju
之后、jiaofen 之前的同一时刻),独立存放、不混入 seats[],避免 packetIndex 对
齐锚点错位;test_fixture.js 补相应断言。
修复 test_consistency.js 的用例间污染:EQW_GameState.reset() 按设计不清
room.playerScores(跨局累积量),旧版增量路径从不写它,实际靠"沿用同进程里
上一次全量路径写入的残留"凑出假绿,换座位顺序或调整执行顺序就会转红。改为
每个对齐点独立起步(buildIncremental/buildFull 各自 reset),且增量路径先喂
StartWar 再喂增量包,与真实客户端时序一致,不再依赖任何隐式残留。已验证正
序/倒序跑出的 PASS/FAIL 集合逐条相同。
修完后 23 checks:15 绿、8 红。红项均已归因:3 处为任务已知的前端未接线缺口
(table.playproc 映射、table.pushlist 累积、maipai.seatlist 消费),另发现两
类同类缺口(ResyncHandler 未映射 deskinfo 新增的 curmultiple 字段、BuryHandler
埋牌后未清空 my.bottomCards),均未改动 client/js 正式代码,留给下一个前端任务。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,26 +43,43 @@ function pick(snap, exclude) {
|
||||
return out;
|
||||
}
|
||||
|
||||
// 每个对齐点独立起步,不共用进程内任何残留(下面两个 build 函数各自从
|
||||
// EQW_GameState.reset() + 显式赋值房间级字段开始,互不依赖调用顺序/次数):
|
||||
//
|
||||
// 【曾经的假绿】EQW_GameState.reset() 按设计不清 room.playerScores(它是"跨局不清"的
|
||||
// 房间级累积量,见 GameState.js 注释)。旧版路径 A 从不写 playerScores(fapai 包不带),
|
||||
// 于是它的值全靠"上一次由谁最后写过"——如果上一次恰好是路径 B(deskinfo 带 PlayerInfo)
|
||||
// 跑过,路径 A 就会【继承】那份残留,凑巧与路径 B 的期望值相等,测试假绿;换一个座位
|
||||
// 顺序、或把它放到第一个跑,残留没了就立刻转红。
|
||||
// 真实客户端不存在这个残留——它在 fapai 之前先收到 StartWar(deskwar,见夹具补捕),
|
||||
// 由它给出 room.playerScores 的开局初值。所以路径 A 的真实起点也改成先喂 StartWar,
|
||||
// 每次都显式重新赋值,不再依赖任何"恰好还没被冲掉的旧值"。
|
||||
function buildIncremental(seat, packetIndex) {
|
||||
EQW_GameState.reset();
|
||||
EQW_GameState.room.mySeat = seat;
|
||||
EQW_GameState.room.options = EQW_RoomOptions_Parse.parse(fx.roomtype);
|
||||
EQW_ResyncHandler.handleStartWar({ data: fx.startwar[seat] });
|
||||
fx.seats[seat].slice(0, packetIndex).forEach(p => {
|
||||
EQW_Dispatcher.dispatch({ rpc: p.rpc, data: p.data });
|
||||
});
|
||||
return EQW_GameState.snapshot();
|
||||
}
|
||||
|
||||
function buildFull(seat, info) {
|
||||
EQW_GameState.reset();
|
||||
EQW_GameState.room.mySeat = seat;
|
||||
EQW_GameState.room.options = EQW_RoomOptions_Parse.parse(fx.roomtype);
|
||||
EQW_ResyncHandler.handleDeskinfo(info);
|
||||
return EQW_GameState.snapshot();
|
||||
}
|
||||
|
||||
// 对每个座位、每个 deskinfo 快照点做比对
|
||||
let compared = 0;
|
||||
fx.deskinfo.forEach(snapPoint => {
|
||||
const seat = snapPoint.seat;
|
||||
|
||||
// —— 路径 A:增量累积 ——
|
||||
EQW_GameState.reset();
|
||||
EQW_GameState.room.mySeat = seat;
|
||||
EQW_GameState.room.options = EQW_RoomOptions_Parse.parse(fx.roomtype);
|
||||
fx.seats[seat].slice(0, snapPoint.packetIndex).forEach(p => {
|
||||
EQW_Dispatcher.dispatch({ rpc: p.rpc, data: p.data });
|
||||
});
|
||||
const incremental = EQW_GameState.snapshot();
|
||||
|
||||
// —— 路径 B:deskinfo 全量重建 ——
|
||||
EQW_GameState.reset();
|
||||
EQW_GameState.room.mySeat = seat;
|
||||
EQW_GameState.room.options = EQW_RoomOptions_Parse.parse(fx.roomtype);
|
||||
EQW_ResyncHandler.handleDeskinfo(snapPoint.info);
|
||||
const full = EQW_GameState.snapshot();
|
||||
const incremental = buildIncremental(seat, snapPoint.packetIndex);
|
||||
const full = buildFull(seat, snapPoint.info);
|
||||
|
||||
t.eq('座位' + seat + ' step' + snapPoint.step + ' 增量 == 全量',
|
||||
pick(incremental, EXCLUDE), pick(full, EXCLUDE));
|
||||
|
||||
Reference in New Issue
Block a user