fix(skin): 修复最终评审发现的 6 处缺陷(junction 排除失效/meta 静默丢失等)
跨任务视角发现的问题:Critical1 materialize.mjs 的 junction 排除比较在 Windows 上因长路径前缀恒假、从未生效,且测试夹具的 junction 指向真源自身, 掩盖了此问题;Critical2 composeSkin 例外通道在 uuid 缺失/框架侧无 meta 时 静默失败,违反第二准则;Important3 可覆盖范围误把 theme/ 下的框架 TS 代码 也纳入;Important5 cli-entry 测试漏注册 check-skin/build-game;Important6 composeSkin 与 check-skin 各自拼路径,未共用 paths.mjs 权威推导;Important7 --platform 缺值时静默落到默认平台。逐条修复并补测试,Critical1 用诱饵框架 目录验证过能真正杀掉该 bug(变异推演见 fix report)。 spec §5 step5 的 dist/<name>/ 拷贝按要求标注为本期未实现,不实现。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import { join } from 'node:path';
|
||||
import { mkdirSync, writeFileSync, rmSync, mkdtempSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { deflateSync } from 'node:zlib';
|
||||
import { listAssets, readPngSize, validateOverrides } from '../lib/skin.mjs';
|
||||
import { listAssets, listCoverableAssets, readPngSize, validateOverrides } from '../lib/skin.mjs';
|
||||
|
||||
// ---- 测试辅助:零依赖生成指定尺寸的 PNG ----
|
||||
function crc32(buf) {
|
||||
@@ -59,6 +59,36 @@ test('listAssets 对不存在的目录返回空数组', () => {
|
||||
assert.deepEqual(listAssets('/no/such/dir'), []);
|
||||
});
|
||||
|
||||
// ---- listCoverableAssets:Important 3——可覆盖范围须限定为 spec §2 规则 3 的 8 个目录 ----
|
||||
test('listCoverableAssets 排除 theme/ 与 README.md,只保留 8 个白名单目录下的资源', () => {
|
||||
const d = makeDirs();
|
||||
try {
|
||||
png(d.fw, 'atlas-hall/btn.png');
|
||||
writeFile(d.fw, 'README.md', '# framework ui');
|
||||
writeFile(d.fw, 'theme/default-theme.ts', 'export const DEFAULT_THEME = {};');
|
||||
writeFile(d.fw, 'theme/types.ts', 'export interface ThemeConfig {}');
|
||||
const covered = listCoverableAssets(d.fw).sort();
|
||||
assert.deepEqual(covered, ['atlas-hall/btn.png']);
|
||||
assert.ok(!covered.some((f) => f.startsWith('theme/')), 'theme/ 下的框架代码不属于可覆盖资源');
|
||||
assert.ok(!covered.includes('README.md'), 'README.md 不是可覆盖资源');
|
||||
} finally { cleanup(d.root); }
|
||||
});
|
||||
|
||||
test('validateOverrides:override 放一个 .ts 到 theme/ 会被判为 orphan(不在可覆盖范围内)', () => {
|
||||
const d = makeDirs();
|
||||
try {
|
||||
png(d.fw, 'atlas-hall/btn.png');
|
||||
writeFile(d.fw, 'theme/resolve-theme.ts', 'export function resolveTheme() {}');
|
||||
// 子游戏企图覆盖框架代码
|
||||
writeFile(d.ov, 'theme/resolve-theme.ts', 'export function resolveTheme() { /* hijacked */ }');
|
||||
const r = validateOverrides(d.fw, d.ov);
|
||||
assert.equal(r.errors.length, 1);
|
||||
assert.equal(r.errors[0].code, 'orphan');
|
||||
assert.equal(r.errors[0].path, 'theme/resolve-theme.ts');
|
||||
assert.equal(r.matched.length, 0, 'theme 覆盖不应被当作合法命中');
|
||||
} finally { cleanup(d.root); }
|
||||
});
|
||||
|
||||
// ---- readPngSize ----
|
||||
test('readPngSize 读出宽高;非 PNG 返回 null', () => {
|
||||
const d = makeDirs();
|
||||
|
||||
Reference in New Issue
Block a user