diff --git a/cocoscreator_projects/scripts/lib/skin.mjs b/cocoscreator_projects/scripts/lib/skin.mjs index b1698a6..7cb56a6 100644 --- a/cocoscreator_projects/scripts/lib/skin.mjs +++ b/cocoscreator_projects/scripts/lib/skin.mjs @@ -69,7 +69,18 @@ export function validateOverrides(frameworkUiDir, overrideDir) { if (needSizeCheck) { const a = readPngSize(join(frameworkUiDir, ...rel.split(posix.sep))); const b = readPngSize(join(overrideDir, ...rel.split(posix.sep))); - if (a && b && (a.width !== b.width || a.height !== b.height)) { + if (!a || !b) { + const side = !a ? '框架' : 'override'; + errors.push({ + path: rel, + code: 'size-unreadable', + message: + `框架 UI 图片必须是 PNG(无法读取尺寸:${side})。` + + `请改用 PNG,或连 .meta 一起提供(例外通道)`, + }); + continue; + } + if (a.width !== b.width || a.height !== b.height) { errors.push({ path: rel, code: 'size-mismatch', diff --git a/cocoscreator_projects/scripts/test/skin.test.mjs b/cocoscreator_projects/scripts/test/skin.test.mjs index e413bae..4022e3a 100644 --- a/cocoscreator_projects/scripts/test/skin.test.mjs +++ b/cocoscreator_projects/scripts/test/skin.test.mjs @@ -147,13 +147,41 @@ test('图片尺寸不同但自带 meta(例外通道)→ 通过', () => { test('非图片资源(音效)不做尺寸校验', () => { const d = makeDirs(); try { - writeFile(d.fw, 'audio/click.wav', 'aaaa'); - writeFile(d.ov, 'audio/click.wav', 'bbbbbbbbbbbb'); + // 用真实的、有效的、尺寸不同的 PNG 字节,但扩展名是 .wav + // 如果 isImage() 门控被删掉,因为尺寸不同会报 size-mismatch,用例失败 + writeFile(d.fw, 'audio/click.wav', makePng(64, 64)); + writeFile(d.ov, 'audio/click.wav', makePng(256, 256)); const r = validateOverrides(d.fw, d.ov); assert.deepEqual(r.errors, []); } finally { cleanup(d.root); } }); +// ---- validateOverrides:尺寸不可读 ---- +test('图片尺寸无法读取(非 PNG)→ size-unreadable', () => { + const d = makeDirs(); + try { + png(d.fw, 'atlas-hall/btn.png', 64, 64); + writeFile(d.ov, 'atlas-hall/btn.png', 'this is not a png but it is long enough to pass the 24-byte length check'); + const r = validateOverrides(d.fw, d.ov); + assert.equal(r.errors.length, 1); + assert.equal(r.errors[0].code, 'size-unreadable'); + assert.match(r.errors[0].message, /无法读取尺寸/); + assert.match(r.errors[0].message, /PNG/); + assert.equal(r.matched.length, 0); + } finally { cleanup(d.root); } +}); + +test('readPngSize 长度足够但签名不对 → 返回 null', () => { + const d = makeDirs(); + try { + // 构造一个 24 字节以上、但 PNG 签名不对的数据 + const buf = Buffer.alloc(30, 0x00); + buf.write('NOTPNG', 1, 'ascii'); + const p = writeFile(d.fw, 'test.png', buf); + assert.equal(readPngSize(p), null); + } finally { cleanup(d.root); } +}); + // ---- validateOverrides:Spine ---- test('Spine 整套覆盖 → 通过,且贴图豁免尺寸校验', () => { const d = makeDirs();