test: 修复三处跳过守卫,它们只在真实资源到位时才暴露

这三个测试都犯了同一个错误:**守卫检查的资源,和实际读取的资源不是同
一个**。在 `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 个测试"变成真正执行。
This commit is contained in:
troytt 2026-09-14 14:51:50 +00:00
parent 68c7890eee
commit ad7ced6760
3 changed files with 28 additions and 9 deletions

View File

@ -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`)

View File

@ -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);
});

View File

@ -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 <archive> <member> <widths-file>')
// disabled exit: 2)