二七王:LayoutSolver grid 补显式失败校验,attach 四角补精确坐标测试
审查发现 _solveGrid 在 count > cols*rows 时静默截断多出的项,违反显式失败 红线;补校验直接抛错并报出 count 与容量。fillOrder 字段之前从未被读取、 形同虚设,改为显式拒绝除 'row' 外的值(不实现列优先,YAGNI)。 测试补 grid 超载/恰好满格/fillOrder 三态,以及 attach 四角(topLeft/ bottomLeft/bottomRight)的精确坐标核对(此前只有 topRight 有精确值)。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -137,7 +137,17 @@ var EQW_LayoutSolver = EQW_LayoutSolver || {
|
||||
|
||||
//grid:固定行列的按钮阵,逐行调 distributeHorizontally(清单 §6.1)
|
||||
_solveGrid: function (n, ctx) {
|
||||
var count = (typeof ctx.count === 'number') ? ctx.count : (n.cols * n.rows);
|
||||
//fillOrder 目前只实现行优先;不写等同 row,写了别的值一律显式拒绝(YAGNI,不做无人用的列优先)
|
||||
if (n.fillOrder && n.fillOrder !== 'row') {
|
||||
throw new Error('[EQW_LayoutSolver] grid 仅支持 fillOrder=row,暂不支持: ' + n.fillOrder);
|
||||
}
|
||||
|
||||
var capacity = n.cols * n.rows;
|
||||
var count = (typeof ctx.count === 'number') ? ctx.count : capacity;
|
||||
//配置与运行时项数不一致时必须显式报错,不能静默截断多出的项(工程总则 §7 显式失败)
|
||||
if (count > capacity) {
|
||||
throw new Error('[EQW_LayoutSolver] grid 项数超出容量: count=' + count + ' > cols(' + n.cols + ')*rows(' + n.rows + ')=' + capacity);
|
||||
}
|
||||
if (count <= 0) { return []; }
|
||||
|
||||
var out = [];
|
||||
|
||||
@@ -87,6 +87,21 @@ t.eq('grid 第8项 y', g[7].y, 160 + 56 + 24);
|
||||
// count 少于满格时只出 count 个
|
||||
t.eq('grid 不足一行', EQW_LayoutSolver.solve(grid, { count: 3 }).length, 3);
|
||||
|
||||
// 边界:count 恰好等于容量(cols*rows=14)时正常返回,不抛错
|
||||
t.eq('grid 恰好满格不抛错', EQW_LayoutSolver.solve(grid, { count: 14 }).length, 14);
|
||||
|
||||
// count 超出容量:显式抛错,不静默截断多出的项
|
||||
t.eq('grid 超载抛错', throws(() => EQW_LayoutSolver.solve(grid, { count: 15 })), true);
|
||||
|
||||
// fillOrder 校验:目前只支持行优先(YAGNI,未实现列优先),不写等同 row
|
||||
const gridNoFillOrder = { kind: 'grid', anchorX: 640, anchorY: 160, cols: 7, rows: 2,
|
||||
itemWidth: 74, itemHeight: 56, spacingX: 7, spacingY: 24, anchor: 'center' };
|
||||
t.eq('grid 不写 fillOrder 正常', EQW_LayoutSolver.solve(gridNoFillOrder, { count: 14 }).length, 14);
|
||||
t.eq('grid fillOrder=row 正常', EQW_LayoutSolver.solve(grid, { count: 14 }).length, 14);
|
||||
const gridColumnOrder = { kind: 'grid', anchorX: 640, anchorY: 160, cols: 7, rows: 2,
|
||||
itemWidth: 74, itemHeight: 56, spacingX: 7, spacingY: 24, anchor: 'center', fillOrder: 'column' };
|
||||
t.eq('grid fillOrder=column 抛错', throws(() => EQW_LayoutSolver.solve(gridColumnOrder, { count: 14 })), true);
|
||||
|
||||
// ============ attach 内部对齐(corner 为空)============
|
||||
const rects = { TARGET: { x: 100, y: 200, width: 80, height: 40 } };
|
||||
const attachIn = { kind: 'attach', target: 'TARGET', hAlign: 'right', vAlign: 'top',
|
||||
@@ -107,12 +122,29 @@ const attachCorner = { kind: 'attach', target: 'TARGET', corner: 'topRight',
|
||||
const a2 = EQW_LayoutSolver.solve(attachCorner, { rects: rects });
|
||||
t.eq('attach 外侧右上角', a2, [{ x: 100 + 80 - 20 + 4, y: 200 + 6, width: 20, height: 10 }]);
|
||||
|
||||
// 四个角都要能解
|
||||
// 四个角都要能解(通用检查:长度与类型)
|
||||
['topLeft', 'topRight', 'bottomLeft', 'bottomRight'].forEach(c => {
|
||||
const r = EQW_LayoutSolver.solve({ kind: 'attach', target: 'TARGET', corner: c, w: 20, h: 10 }, { rects: rects });
|
||||
t.eq('attach 角 ' + c + ' 可解', r.length === 1 && typeof r[0].x === 'number', true);
|
||||
});
|
||||
|
||||
// 四角精确坐标核对:target={x:100,y:200,width:80,height:40},sprite={w:20,h:10},offset 缺省=0
|
||||
// topLeft(AlignmentUtils.js:266-272):x=target.x=100,y=target.y=200
|
||||
const cTopLeft = EQW_LayoutSolver.solve({ kind: 'attach', target: 'TARGET', corner: 'topLeft', w: 20, h: 10 }, { rects: rects });
|
||||
t.eq('attach 角 topLeft 精确坐标', cTopLeft, [{ x: 100, y: 200, width: 20, height: 10 }]);
|
||||
|
||||
// topRight(AlignmentUtils.js:292-298):x=target.x+target.width-sprite.width=100+80-20=160,y=target.y=200
|
||||
const cTopRight = EQW_LayoutSolver.solve({ kind: 'attach', target: 'TARGET', corner: 'topRight', w: 20, h: 10 }, { rects: rects });
|
||||
t.eq('attach 角 topRight 精确坐标', cTopRight, [{ x: 160, y: 200, width: 20, height: 10 }]);
|
||||
|
||||
// bottomLeft(AlignmentUtils.js:318-324):x=target.x=100,y=target.y+target.height-sprite.height=200+40-10=230
|
||||
const cBottomLeft = EQW_LayoutSolver.solve({ kind: 'attach', target: 'TARGET', corner: 'bottomLeft', w: 20, h: 10 }, { rects: rects });
|
||||
t.eq('attach 角 bottomLeft 精确坐标', cBottomLeft, [{ x: 100, y: 230, width: 20, height: 10 }]);
|
||||
|
||||
// bottomRight(AlignmentUtils.js:344-350):x=target.x+target.width-sprite.width=100+80-20=160,y=同 bottomLeft=230
|
||||
const cBottomRight = EQW_LayoutSolver.solve({ kind: 'attach', target: 'TARGET', corner: 'bottomRight', w: 20, h: 10 }, { rects: rects });
|
||||
t.eq('attach 角 bottomRight 精确坐标', cBottomRight, [{ x: 160, y: 230, width: 20, height: 10 }]);
|
||||
|
||||
// ============ bySeat 合并:列出的覆盖、未列出的继承 ============
|
||||
const bySeat = {
|
||||
kind: 'fan', direction: 'horizontal', itemWidth: 90, itemHeight: 155,
|
||||
|
||||
Reference in New Issue
Block a user