- 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) <noreply@anthropic.com>
66 lines
3.1 KiB
JavaScript
66 lines
3.1 KiB
JavaScript
// 服务端座位 ↔ 显示位(清单 §0.1)
|
||
const { load, throws } = require('./_load');
|
||
const t = require('./_assert')();
|
||
|
||
load('client/js/01_SubGame/codes/core/SeatMap.js');
|
||
|
||
// ---- 3×3 全组合 ----
|
||
// mySeat=0: 自己0、下家1在右上、上家2在左上
|
||
t.eq('my0 seat0', EQW_SeatMap.toDisplay(0, 0), 'SELF');
|
||
t.eq('my0 seat1', EQW_SeatMap.toDisplay(1, 0), 'RIGHT');
|
||
t.eq('my0 seat2', EQW_SeatMap.toDisplay(2, 0), 'LEFT');
|
||
t.eq('my1 seat1', EQW_SeatMap.toDisplay(1, 1), 'SELF');
|
||
t.eq('my1 seat2', EQW_SeatMap.toDisplay(2, 1), 'RIGHT');
|
||
t.eq('my1 seat0', EQW_SeatMap.toDisplay(0, 1), 'LEFT');
|
||
t.eq('my2 seat2', EQW_SeatMap.toDisplay(2, 2), 'SELF');
|
||
t.eq('my2 seat0', EQW_SeatMap.toDisplay(0, 2), 'RIGHT');
|
||
t.eq('my2 seat1', EQW_SeatMap.toDisplay(1, 2), 'LEFT');
|
||
|
||
// ---- 反向 ----
|
||
t.eq('my1 -> RIGHT 是座位2', EQW_SeatMap.toSeat('RIGHT', 1), 2);
|
||
t.eq('my2 -> RIGHT 是座位0', EQW_SeatMap.toSeat('RIGHT', 2), 0);
|
||
t.eq('my2 -> LEFT 是座位1', EQW_SeatMap.toSeat('LEFT', 2), 1);
|
||
t.eq('my0 -> SELF 是座位0', EQW_SeatMap.toSeat('SELF', 0), 0);
|
||
|
||
// ---- 互逆:任意 mySeat/seat 组合 toSeat(toDisplay(s)) == s ----
|
||
let ok = true;
|
||
for (let my = 0; my < 3; my++) {
|
||
for (let s = 0; s < 3; s++) {
|
||
if (EQW_SeatMap.toSeat(EQW_SeatMap.toDisplay(s, my), my) !== s) { ok = false; }
|
||
}
|
||
}
|
||
t.eq('toDisplay/toSeat 互逆', ok, true);
|
||
|
||
// ---- 与服务端 get_nextseat 一致:下家恒在 RIGHT ----
|
||
let nextOk = true;
|
||
for (let my = 0; my < 3; my++) {
|
||
if (EQW_SeatMap.toDisplay((my + 1) % 3, my) !== 'RIGHT') { nextOk = false; }
|
||
}
|
||
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);
|