test:导出脚本增加零漏拷/零多拷硬保证

质疑"某个目录有没有被打进 zip"时, 原先只能人工逐目录核对。现在把这个检查做进
脚本, 每次导出都跑:

copyDir 记录每个被复制文件在 zip 中应有的条目名, verifyZipFile 把它与实际 zip
条目做**逐个双向比对** —— 少一个报"漏拷"并列出文件名, 多一个报"多拷"。这样
漏拷会当场失败, 而不是等在别的电脑上解压缩时才发现。

自检输出新增一行, 例如:
  自检: 零漏拷 ✅(1381/1381) / CRC 逐条 ✅ / 偏移一致 ✅ / ...

同时把 copyDir 的条目名拼接由"从 nameOfParent 反推"改为显式传 relBase, 去掉
原先那段绕的 split/map 逻辑。

新增 3 条测试(漏拷拒绝 / 多拷拒绝 / 清单吻合时放行且 README.txt 豁免), 本
测试文件 19/19 通过, npm test 全量 17 个测试文件通过。
This commit is contained in:
2026-10-17 16:13:09 +08:00
parent 336b4d21da
commit 7909cf2b22
3 changed files with 121 additions and 7 deletions

View File

@@ -355,6 +355,71 @@ test('verifyZipFile: --no-certs 时出现 cert-profile 应被拒绝', async (t)
/* ============================ 导出骨架 ============================ */
test('verifyZipFile: 漏拷应被拒绝 (expectFiles 与 zip 内容不符)', async (t) => {
const root = tmpDir(t);
const fixture = makeFixture(path.join(root, 'mp-harmony'));
const zipPath = path.join(root, 'out.zip');
await zipDirectory(fixture, zipPath);
// 假装 EntryCard/entry/base/snapshot/widget-2x2.png 被复制了, 但 zip 里其实没有
const expectFiles = [
'mp-harmony/AppScope/app.json5',
'mp-harmony/a/b/c/deep.txt',
'mp-harmony/a/repeatable.txt',
'mp-harmony/a/random.bin',
'mp-harmony/a/中文名.txt',
'mp-harmony/a/zero.txt',
'mp-harmony/EntryCard/entry/base/snapshot/widget-2x2.png',
];
await assert.rejects(
() => verifyZipFile(zipPath, { withCerts: false, skipRequired: true, expectFiles }),
/漏拷/,
'expectFiles 里多出的文件必须被报为漏拷',
);
});
test('verifyZipFile: 多拷应被拒绝 (zip 内出现复制清单外的文件)', async (t) => {
const root = tmpDir(t);
const fixture = makeFixture(path.join(root, 'mp-harmony'));
const zipPath = path.join(root, 'out.zip');
await zipDirectory(fixture, zipPath);
// 清单里故意少写一个, zip 里却存在 -> 应报多拷
const expectFiles = [
'mp-harmony/AppScope/app.json5',
'mp-harmony/a/b/c/deep.txt',
'mp-harmony/a/repeatable.txt',
'mp-harmony/a/random.bin',
'mp-harmony/a/中文名.txt',
// 漏掉 a/zero.txt
];
await assert.rejects(
() => verifyZipFile(zipPath, { withCerts: false, skipRequired: true, expectFiles }),
/多拷/,
'清单外的 zip 文件必须被报为多拷',
);
});
test('verifyZipFile: 清单完全吻合时应通过 (含 README.txt 豁免)', async (t) => {
const root = tmpDir(t);
const fixture = makeFixture(path.join(root, 'mp-harmony'));
fs.writeFileSync(path.join(fixture, 'README.txt'), '# 说明');
const zipPath = path.join(root, 'out.zip');
await zipDirectory(fixture, zipPath);
const expectFiles = [
'mp-harmony/AppScope/app.json5',
'mp-harmony/a/b/c/deep.txt',
'mp-harmony/a/repeatable.txt',
'mp-harmony/a/random.bin',
'mp-harmony/a/中文名.txt',
'mp-harmony/a/zero.txt',
'mp-harmony/README.txt',
];
const res = await verifyZipFile(zipPath, { withCerts: false, skipRequired: true, expectFiles });
assert.equal(res.files, 7);
});
test('copyDir: 排除规则在真实复制中生效', async (t) => {
const root = tmpDir(t);
const src = path.join(root, 'src');