import { test } from 'node:test'; import assert from 'node:assert/strict'; import { PNG } from 'pngjs'; import { splitSheet, reassemble, pixelsEqual, verifySheet } from '../ui-migration/frame-io.mjs'; /** 造一张 w×h 网格的测试图,每格填不同颜色,便于验证切分位置 */ function makeSheet(cols, rows, cellW, cellH) { const png = new PNG({ width: cols * cellW, height: rows * cellH }); for (let r = 0; r < rows; r++) { for (let c = 0; c < cols; c++) { const idx = r * cols + c; // 行优先编号 for (let y = 0; y < cellH; y++) { for (let x = 0; x < cellW; x++) { const o = ((r * cellH + y) * png.width + (c * cellW + x)) << 2; png.data[o] = (idx * 20) & 0xff; // R 编码帧号,便于断言 png.data[o + 1] = 0x40; png.data[o + 2] = 0x80; png.data[o + 3] = 0xff; } } } } return PNG.sync.write(png); } const IMG = { id: 1, w_all: 60, h_all: 40, w: 3, h: 2, frame_all: 6, bmp: 'test.png', w1: 20, h1: 20 }; test('splitSheet 切出 frame_all 张,尺寸为单帧尺寸', () => { const frames = splitSheet(makeSheet(3, 2, 20, 20), IMG); assert.equal(frames.length, 6); const first = PNG.sync.read(frames[0]); assert.equal(first.width, 20); assert.equal(first.height, 20); }); test('splitSheet 按行优先取帧:下标 0..5 的 R 通道依次为 0,20,40,60,80,100', () => { const frames = splitSheet(makeSheet(3, 2, 20, 20), IMG); const reds = frames.map((b) => PNG.sync.read(b).data[0]); assert.deepEqual(reds, [0, 20, 40, 60, 80, 100], '若切成列优先,顺序会变为 0,60,20,80,40,100'); }); test('reassemble(splitSheet(x)) 的像素与 x 完全一致(完全验证的核心不变量)', () => { const sheet = makeSheet(3, 2, 20, 20); const back = reassemble(splitSheet(sheet, IMG), IMG); assert.equal(pixelsEqual(sheet, back), true); }); test('pixelsEqual 对像素不同的图返回 false', () => { const a = makeSheet(3, 2, 20, 20); const bPng = PNG.sync.read(a); bPng.data[0] = (bPng.data[0] + 1) & 0xff; // 改一个字节 assert.equal(pixelsEqual(a, PNG.sync.write(bPng)), false); }); test('pixelsEqual 忽略编码差异:同像素不同压缩等级仍为 true', () => { const src = PNG.sync.read(makeSheet(3, 2, 20, 20)); const enc0 = PNG.sync.write(src, { deflateLevel: 0 }); const enc9 = PNG.sync.write(src, { deflateLevel: 9 }); assert.notEqual(Buffer.compare(enc0, enc9), 0, '前提:两种编码的文件字节确实不同'); assert.equal(pixelsEqual(enc0, enc9), true, '但像素数据必须判为相同'); }); test('verifySheet 对正常图返回 ok', () => { assert.deepEqual(verifySheet(makeSheet(3, 2, 20, 20), IMG), { ok: true }); }); test('verifySheet 对尺寸与网格声明不符的图返回失败原因', () => { const wrong = makeSheet(2, 2, 20, 20); // 实际 40x40,但 IMG 声明 60x40 const r = verifySheet(wrong, IMG); assert.equal(r.ok, false); assert.match(r.reason, /尺寸/); });