template/script/__test__/build-resource.test.ts

218 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
mkdtemp,
mkdir,
readFile,
rm,
stat,
writeFile
} from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { dirname, join } from 'node:path';
import { afterEach, describe, expect, it } from 'vitest';
import { buildContent } from '../build-resource';
const tempDirs: string[] = [];
/** 创建独立的临时 fixture 根目录,并登记以便用例结束后统一清理 */
async function createRoot() {
const root = await mkdtemp(join(tmpdir(), 'mota-content-filter-'));
tempDirs.push(root);
return root;
}
/** 在 fixture 的源目录下写入文件,必要时创建父目录 */
async function writeSource(
root: string,
name: string,
content: string | Buffer
) {
const file = join(root, 'src', name);
await mkdir(dirname(file), { recursive: true });
await writeFile(file, content);
return file;
}
/** 以空字符集执行一次 content 构建 */
function buildFixture(root: string) {
return buildContent({
sourceDir: join(root, 'src'),
outputDir: join(root, 'out'),
chars: ''
});
}
/** 读取输出目录中的文本文件 */
function readOutput(root: string, name: string) {
return readFile(join(root, 'out', name), 'utf-8');
}
/** 判断输出目录中是否存在指定文件 */
async function outputExists(root: string, name: string) {
try {
await stat(join(root, 'out', name));
return true;
} catch {
return false;
}
}
afterEach(async () => {
const dirs = tempDirs.splice(0);
await Promise.all(
dirs.map(dir => rm(dir, { recursive: true, force: true }))
);
});
describe('buildContent', () => {
// 根目录的 jsonc 必须去掉整行注释并压成纯 JSON,后缀保持不变
it('minifies a root jsonc file', async () => {
const root = await createRoot();
await writeSource(
root,
'core.jsonc',
'// Type: IGameCore\n// --- SYSTEM PREFIX END --- //\n{ "floorId": "MT0" }\n'
);
const stats = await buildFixture(root);
const output = await readOutput(root, 'core.jsonc');
expect(JSON.parse(output)).toEqual({ floorId: 'MT0' });
expect(output).not.toContain('//');
expect(stats.jsonc).toBe(1);
});
// 根目录即使出现 .list.jsonc 也必须全量输出,根调用显式跳过清单过滤
it('keeps every root file even when a root list exists', async () => {
const root = await createRoot();
await writeSource(root, '.list.jsonc', '["core"]\n');
await writeSource(root, 'core.jsonc', '{ "value": 1 }\n');
await writeSource(root, 'other.jsonc', '{ "value": 2 }\n');
await buildFixture(root);
expect(await outputExists(root, 'core.jsonc')).toBe(true);
expect(await outputExists(root, 'other.jsonc')).toBe(true);
expect(await outputExists(root, '.list.jsonc')).toBe(true);
});
// defaults 目录即使存在 .list.jsonc 也必须全量输出并压缩
it('keeps every defaults file even when a defaults list exists', async () => {
const root = await createRoot();
await writeSource(root, 'defaults/.list.jsonc', '["env"]\n');
await writeSource(
root,
'defaults/env.jsonc',
'// Type: env\n{ "value": 1 }\n'
);
await writeSource(root, 'defaults/other.jsonc', '{ "value": 2 }\n');
await buildFixture(root);
expect(await outputExists(root, 'defaults/env.jsonc')).toBe(true);
expect(await outputExists(root, 'defaults/other.jsonc')).toBe(true);
expect(await outputExists(root, 'defaults/.list.jsonc')).toBe(true);
expect(await readOutput(root, 'defaults/other.jsonc')).not.toContain(
'//'
);
expect(
JSON.parse(await readOutput(root, 'defaults/.list.jsonc'))
).toEqual(['env']);
});
// maps 清单带注释时先剥离注释,再按清单保留文件并剔除未引用文件
it('filters a maps directory by its list', async () => {
const root = await createRoot();
await writeSource(
root,
'maps/.list.jsonc',
'// Type: string[], without .jsonc suffix\n// --- SYSTEM PREFIX END --- //\n["keep"]\n'
);
await writeSource(root, 'maps/keep.jsonc', '{ "value": "keep" }\n');
await writeSource(root, 'maps/drop.jsonc', '{ "value": "drop" }\n');
await buildFixture(root);
expect(await outputExists(root, 'maps/keep.jsonc')).toBe(true);
expect(await outputExists(root, 'maps/drop.jsonc')).toBe(false);
expect(await outputExists(root, 'maps/.list.jsonc')).toBe(true);
const list = await readOutput(root, 'maps/.list.jsonc');
expect(list).not.toContain('//');
expect(JSON.parse(list)).toEqual(['keep']);
});
// texture 清单是对象形态且使用完整文件名,命中文件按字节原样拷贝
it('filters a texture directory by object list and full file name', async () => {
const root = await createRoot();
await writeSource(
root,
'texture/.list.jsonc',
'{"textures":[{"type":"grid","source":"a.png"}]}\n'
);
const bytes = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x01, 0x02]);
await writeSource(root, 'texture/a.png', bytes);
await writeSource(root, 'texture/b.png', Buffer.from([0x03]));
await buildFixture(root);
expect(await outputExists(root, 'texture/a.png')).toBe(true);
expect(await outputExists(root, 'texture/b.png')).toBe(false);
const output = await readFile(join(root, 'out', 'texture', 'a.png'));
expect(Buffer.compare(output, bytes)).toBe(0);
});
// font 清单按完整文件名保留,未引用文件被剔除
it('filters a font directory by its list', async () => {
const root = await createRoot();
await writeSource(root, 'font/.list.jsonc', '["ok.fake"]\n');
await writeSource(root, 'font/ok.fake', 'ok');
await writeSource(root, 'font/skip.fake', 'skip');
await buildFixture(root);
expect(await outputExists(root, 'font/ok.fake')).toBe(true);
expect(await outputExists(root, 'font/skip.fake')).toBe(false);
});
// 没有清单的非 defaults 子文件夹必须全量输出
it('keeps every file in a sub directory without a list', async () => {
const root = await createRoot();
await writeSource(
root,
'extra/free.jsonc',
'// Type: free\n{ "value": 1 }\n'
);
await writeSource(root, 'extra/free.txt', 'free');
await buildFixture(root);
expect(await outputExists(root, 'extra/free.txt')).toBe(true);
expect(await readOutput(root, 'extra/free.jsonc')).not.toContain('//');
});
// 根目录的非 jsonc 文件按原样拷贝
it('copies a root non-jsonc file verbatim', async () => {
const root = await createRoot();
const source = 'export const item = 1;\n';
await writeSource(root, 'item.ts', source);
await buildFixture(root);
expect(await readOutput(root, 'item.ts')).toBe(source);
});
// 统计结果必须与实际输出文件数一致
it('reports stats matching the emitted files', async () => {
const root = await createRoot();
await writeSource(root, 'core.jsonc', '{ "value": 1 }\n');
await writeSource(root, 'maps/.list.jsonc', '["keep"]\n');
await writeSource(root, 'maps/keep.jsonc', '{ "value": 2 }\n');
await writeSource(root, 'maps/drop.jsonc', '{ "value": 3 }\n');
const stats = await buildFixture(root);
expect(stats.files).toBe(3);
expect(stats.jsonc).toBe(3);
expect(stats.fonts).toBe(0);
});
});