From 503ad4b3742a1ddaeb2c224f19a5f7cef2023eae Mon Sep 17 00:00:00 2001 From: Joywayer Date: Wed, 26 Aug 2026 22:27:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=8C=E4=B8=83=E7=8E=8B=EF=BC=9ASeatMap=20?= =?UTF-8?q?=E5=BA=A7=E4=BD=8D=E5=8F=B7=E6=98=BE=E5=BC=8F=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=EF=BC=8C=E5=8E=BB=E6=8E=89=E6=81=92=E7=9C=9F=E6=96=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - toDisplay 此前不校验入参:toDisplay(seat, undefined) 会算出 NaN,NaN 既不等于 0 也不等于 1,最后落到 return 'LEFT'——一个看起来很合理的错误答案。现与兄弟方法 toSeat 一样对非 0/1/2 显式抛错;toSeat 的 mySeat 同样校验(否则算出 NaN 座位号)。 补 8 条反面用例 + 1 条「合法组合不被误伤」的正面用例。 - test_cardcodec.js 删掉 t.eq('deck1/deck2 全部同帧', true, true) 这条恒真断言, 改为收集不匹配项后断言为空——恒真断言在上面的循环被删掉后仍会 PASS。 Co-Authored-By: Claude Opus 5 (1M context) --- client/js/01_SubGame/codes/core/SeatMap.js | 15 +++++++++++++-- client/tests/test_cardcodec.js | 6 ++++-- client/tests/test_seatmap.js | 21 +++++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/client/js/01_SubGame/codes/core/SeatMap.js b/client/js/01_SubGame/codes/core/SeatMap.js index 7b7c559..700b9f6 100644 --- a/client/js/01_SubGame/codes/core/SeatMap.js +++ b/client/js/01_SubGame/codes/core/SeatMap.js @@ -13,16 +13,27 @@ var EQW_SeatMap = EQW_SeatMap || { LEFT: 'LEFT', RIGHT: 'RIGHT', - //服务端座位 → 显示位键 + //服务端座位 → 显示位键。 + //入参必须是 0/1/2:非法值(undefined / 3 / 小数)会算出 NaN,NaN 既不等于 0 也不等于 1, + //最后落到 return 'LEFT'——一个看起来很合理的错误答案。故与 toSeat 一样显式抛错 toDisplay: function (seat, mySeat) { + this._requireSeat(seat, 'seat'); + this._requireSeat(mySeat, 'mySeat'); var d = ((seat - mySeat) % 3 + 3) % 3; if (d === 0) { return 'SELF'; } if (d === 1) { return 'RIGHT'; } return 'LEFT'; }, - //显示位键 → 服务端座位 + _requireSeat: function (v, name) { + if (v !== 0 && v !== 1 && v !== 2) { + throw new Error('[EQW_SeatMap] ' + name + ' 必须是 0/1/2,收到: ' + v); + } + }, + + //显示位键 → 服务端座位。mySeat 同样必须是 0/1/2(否则算出 NaN 座位号) toSeat: function (displayKey, mySeat) { + this._requireSeat(mySeat, 'mySeat'); if (displayKey === 'SELF') { return mySeat; } if (displayKey === 'RIGHT') { return (mySeat + 1) % 3; } if (displayKey === 'LEFT') { return (mySeat + 2) % 3; } diff --git a/client/tests/test_cardcodec.js b/client/tests/test_cardcodec.js index a6447b7..5d418ef 100644 --- a/client/tests/test_cardcodec.js +++ b/client/tests/test_cardcodec.js @@ -20,12 +20,14 @@ const cases = [ cases.forEach(c => t.eq('帧号 ' + c[2] + ' id=' + c[0], EQW_CardCodec.cardIdToFrame(c[0]), c[1])); // ---- 两副牌同一张牌共用同一帧 ---- +// 逐张比对;不再补一条 t.eq(true, true) 的恒真断言——那种检查在循环被删掉后仍然 PASS +const deckMismatch = []; for (let id = 0; id < 54; id++) { if (EQW_CardCodec.cardIdToFrame(id) !== EQW_CardCodec.cardIdToFrame(id + 54)) { - t.eq('deck1/deck2 同帧 id=' + id, false, true); + deckMismatch.push(id); } } -t.eq('deck1/deck2 全部同帧', true, true); +t.eq('deck1/deck2 逐张同帧', deckMismatch, []); // ---- 帧号值域:54 张牌只落在 1–54 ---- let inRange = true; diff --git a/client/tests/test_seatmap.js b/client/tests/test_seatmap.js index a1396b1..b1fa385 100644 --- a/client/tests/test_seatmap.js +++ b/client/tests/test_seatmap.js @@ -41,4 +41,25 @@ t.eq('下家(seat+1)%3 恒在右上', nextOk, true); // ---- 反面:非法显示位显式抛错,不静默返回 ---- t.eq('非法显示位抛错', throws(() => EQW_SeatMap.toSeat('TOP', 0)), true); +// ---- 反面:非法座位号显式抛错 ---- +// toDisplay 曾不做校验:((NaN)%3+3)%3 = NaN,既不等于 0 也不等于 1,最后落到 return 'LEFT' +// ——一个看起来很合理的错误答案,比抛错难查得多 +t.eq('toDisplay mySeat=undefined 抛错', throws(() => EQW_SeatMap.toDisplay(0, undefined)), true); +t.eq('toDisplay seat=undefined 抛错', throws(() => EQW_SeatMap.toDisplay(undefined, 0)), true); +t.eq('toDisplay seat=3 抛错', throws(() => EQW_SeatMap.toDisplay(3, 0)), true); +t.eq('toDisplay seat=-1 抛错', throws(() => EQW_SeatMap.toDisplay(-1, 0)), true); +t.eq('toDisplay seat=1.5 抛错', throws(() => EQW_SeatMap.toDisplay(1.5, 0)), true); +t.eq('toDisplay seat 是字符串 抛错', throws(() => EQW_SeatMap.toDisplay('1', 0)), true); +t.eq('toDisplay seat=null 抛错', throws(() => EQW_SeatMap.toDisplay(null, 0)), true); +t.eq('toSeat mySeat=undefined 抛错', throws(() => EQW_SeatMap.toSeat('SELF', undefined)), true); +t.eq('toSeat mySeat=3 抛错', throws(() => EQW_SeatMap.toSeat('LEFT', 3)), true); +// 正面:合法的 9 种组合都不抛错(上面已逐条断言过返回值,这里确认校验没误伤) +let legalOk = true; +for (let my = 0; my < 3; my++) { + for (let s = 0; s < 3; s++) { + if (throws(() => EQW_SeatMap.toDisplay(s, my))) { legalOk = false; } + } +} +t.eq('合法座位号不被误伤', legalOk, true); + process.exit(t.done('seatmap') ? 0 : 1);