From ad7ced67601c761ec48316993e0d81a02359fb78 Mon Sep 17 00:00:00 2001 From: troytt <47798984@qq.com> Date: Mon, 14 Sep 2026 14:51:50 +0000 Subject: [PATCH] =?UTF-8?q?test:=20=E4=BF=AE=E5=A4=8D=E4=B8=89=E5=A4=84?= =?UTF-8?q?=E8=B7=B3=E8=BF=87=E5=AE=88=E5=8D=AB=EF=BC=8C=E5=AE=83=E4=BB=AC?= =?UTF-8?q?=E5=8F=AA=E5=9C=A8=E7=9C=9F=E5=AE=9E=E8=B5=84=E6=BA=90=E5=88=B0?= =?UTF-8?q?=E4=BD=8D=E6=97=B6=E6=89=8D=E6=9A=B4=E9=9C=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 这三个测试都犯了同一个错误:**守卫检查的资源,和实际读取的资源不是同 一个**。在 `samples/d2` 缺席时它们一律静默跳过,看起来是绿的;真实 MPQ 一旦放进来,守卫放行,然后立刻炸在一个完全无关的缺失文件上。 - `tests/dcc.test.ts` 守卫看 `samples/d2`,扫描目标却硬编码成 `samples/fixtures`——那里没有 `d2char.mpq`。于是这个套件**从来没有真正跑过**:没资源时跳过,有资源时 `TypeError: Cannot read properties of null (reading 'listFiles')`。 目标改为 `samples/d2`;打开归档失败时由"打日志后继续"改为 `throw` 并带上归档名,避免把"文件缺失"伪装成 100 行之外的空指针; `let characters: any` 收紧为 `MpqArchive | null`。 - `tests/widths.test.ts` 守卫看 `samples/d2`,真实输入却是一个空成员名和 `scripts/browser/checks/map-widths.txt`——后者在仓库里从未存在过。 改为按实际输入判断。顺带补 `: string` 标注,否则空字符串字面量会被 收窄成 `never`。 - `tests/formats-malformed.test.ts` 守卫看 `samples/d2` 目录是否存在,却去读其中一个散落的 `.cof`。但 `samples/d2/` 放的是 MPQ **归档**,不是解包后的目录树,目录存在完全 不能说明那个文件存在。改为直接判断该文件路径。 修复后,在真实 MPQ 就位的情况下: 21 passed | 1 skipped (22 files),421 passed | 2 skipped (423),tsc 0 error。 其中 `dcc.test.ts` 从"0 个测试"变成真正执行。 --- tests/dcc.test.ts | 14 ++++++++++---- tests/formats-malformed.test.ts | 11 ++++++++--- tests/widths.test.ts | 12 ++++++++++-- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/tests/dcc.test.ts b/tests/dcc.test.ts index a4a5bb3..1c83b66 100644 --- a/tests/dcc.test.ts +++ b/tests/dcc.test.ts @@ -136,7 +136,11 @@ interface DccResult { readonly dcc: DccFile } -const args = ['samples/fixtures'] +// This sweep needs the original character/object archives, so it must target +// the real drop — `samples/fixtures` has no `d2char.mpq`. Keep this in step +// with `isSkip` above: guarding on one directory while reading another is what +// previously made this suite silently unrunnable. +const args = ['samples/d2'] const dir = args.find((a) => !a.startsWith('--')) ?? 'samples/d2' const quick = args.includes('--quick') @@ -610,12 +614,14 @@ async function sweepSorceress(archive: MpqArchive, names: readonly string[]): Pr console.log(`== cof + dcc verification over ${dir}${quick ? ' (quick)' : ''} ==`) const characterPath = `${dir}/${CHARACTER_ARCHIVE}` -let characters: any = null; +let characters: MpqArchive | null = null; try { characters = await MpqArchive.open(await fileSource(characterPath)) } catch (err) { - console.log(`cannot open ${characterPath}: ${messageOf(err)}`) - // disabled exit: 2) + // Do not fall through: the old code logged here and then dereferenced + // `characters`, turning "archive missing" into an opaque TypeError 100 lines + // away from the cause. + throw new Error(`cannot open ${characterPath}: ${messageOf(err)}`) } const characterNames = (await characters.listFiles()).map(normalize) console.log(`${CHARACTER_ARCHIVE}: ${String(characterNames.length)} members listed`) diff --git a/tests/formats-malformed.test.ts b/tests/formats-malformed.test.ts index 844fce8..a2c99cd 100644 --- a/tests/formats-malformed.test.ts +++ b/tests/formats-malformed.test.ts @@ -132,9 +132,14 @@ describe('Malformed binary formats fail loudly', () => { }); describe('cof', () => { - const hasD2Drop = fs.existsSync(path.join(__dirname, '../samples/d2')); - test.skipIf(!hasD2Drop)('valid decodes successfully on real asset', () => { - const validCof = fs.readFileSync(path.join(__dirname, '../samples/d2/data/global/chars/so/co/sowaxlbh.cof')); + // `samples/d2/` holds the original MPQ *archives*, not an extracted tree, + // so the presence of that directory says nothing about whether this loose + // .cof exists. Guard on the file we actually open, otherwise dropping in + // real assets turns a silent skip into a hard ENOENT. + const realCofPath = path.join(__dirname, '../samples/d2/data/global/chars/so/co/sowaxlbh.cof'); + const hasRealCof = fs.existsSync(realCofPath); + test.skipIf(!hasRealCof)('valid decodes successfully on real asset', () => { + const validCof = fs.readFileSync(realCofPath); const out = decodeCof(validCof); expect(out.numberOfLayers).toBe(16); }); diff --git a/tests/widths.test.ts b/tests/widths.test.ts index 7a90426..438cf3f 100644 --- a/tests/widths.test.ts +++ b/tests/widths.test.ts @@ -16,7 +16,15 @@ import { readFile } from 'node:fs/promises' import { MpqArchive } from '../src/mpq/archive.ts' import { fileSource } from '../src/mpq/file-source.ts' import { decodeSpriteFile } from '../src/formats/cel.ts' -const isSkip = true && !fs.existsSync('samples/d2'); +const WIDTHS_ARCHIVE: string = 'samples/fixtures' +const WIDTHS_MEMBER: string = '' +const WIDTHS_PATH: string = 'scripts/browser/checks/map-widths.txt' +// This check needs a per-frame widths sidecar and a named member. Neither has +// ever been present in the repo, and neither is supplied by `samples/d2` — so +// guarding on that directory (as this file used to) meant the suite stayed +// silently skipped until real assets appeared, then failed on an unrelated +// missing file. Guard on the inputs actually opened below. +const isSkip = WIDTHS_MEMBER === '' || !fs.existsSync(WIDTHS_PATH); const _results: any[] = []; let suiteCompleted = false; let problems: string[] = []; @@ -31,7 +39,7 @@ function check(nameOrOk: any, okOrMessage: any, detail?: string) { } if (!isSkip) { -const [path, member, widthsPath] = ['samples/fixtures', '', 'scripts/browser/checks/map-widths.txt'] +const [path, member, widthsPath] = [WIDTHS_ARCHIVE, WIDTHS_MEMBER, WIDTHS_PATH] if (path === undefined || member === undefined || widthsPath === undefined) { console.error('usage: node scripts/verify-widths.ts ') // disabled exit: 2)