Files
opendance-web/web-server/test/vrm-inspector.spec.ts
T

77 lines
2.8 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 { mkdtempSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { describe, expect, it } from 'vitest';
import { inspectVrm } from '../src/models/vrm-inspector';
const dir = mkdtempSync(join(tmpdir(), 'opendance-vrm-'));
/** 构造合法 GLB:magic + version + length + JSON chunk */
function buildGlb(json: unknown): Buffer {
const jsonBuf = Buffer.from(JSON.stringify(json), 'utf8');
const pad = (4 - (jsonBuf.length % 4)) % 4;
const padded = Buffer.concat([jsonBuf, Buffer.alloc(pad, 0x20)]);
const header = Buffer.alloc(12);
header.write('glTF', 0, 'ascii');
header.writeUInt32LE(2, 4);
header.writeUInt32LE(12 + 8 + padded.length, 8);
const chunkHeader = Buffer.alloc(8);
chunkHeader.writeUInt32LE(padded.length, 0);
chunkHeader.writeUInt32LE(0x4e4f534a, 4);
return Buffer.concat([header, chunkHeader, padded]);
}
function write(name: string, content: Buffer): string {
const path = join(dir, name);
writeFileSync(path, content);
return path;
}
describe('VRM 版本识别', () => {
it('识别 VRM 1.0(VRMC_vrm 扩展)', async () => {
const path = write('v1.vrm', buildGlb({ extensions: { VRMC_vrm: { specVersion: '1.0' } } }));
const result = await inspectVrm(path);
expect(result.isGlb).toBe(true);
expect(result.vrmVersion).toBe('1.0');
});
it('识别 VRM 0.x(VRM 扩展)', async () => {
const path = write('v0.vrm', buildGlb({ extensions: { VRM: { specVersion: '0.0', exporterVersion: '0.79' } } }));
const result = await inspectVrm(path);
expect(result.vrmVersion).toBe('0.0');
});
it('VRM 扩展缺失时版本为 null(普通 GLB)', async () => {
const path = write('plain.glb', buildGlb({ asset: { version: '2.0' }, meshes: [] }));
const result = await inspectVrm(path);
expect(result.isGlb).toBe(true);
expect(result.vrmVersion).toBeNull();
expect(result.generator).toBeNull();
});
it('文本 glTF 不按 GLB 处理', async () => {
const path = write('scene.gltf', Buffer.from('{"asset":{"version":"2.0"}}', 'utf8'));
const result = await inspectVrm(path);
expect(result.isGlb).toBe(false);
expect(result.vrmVersion).toBeNull();
});
it('文件过小时报错', async () => {
const path = write('tiny.glb', Buffer.from('glTF', 'ascii'));
await expect(inspectVrm(path)).rejects.toThrow(/过小/);
});
it('首 chunk 非 JSON 时报错', async () => {
const header = Buffer.alloc(12);
header.write('glTF', 0, 'ascii');
header.writeUInt32LE(2, 4);
header.writeUInt32LE(32, 8);
const chunk = Buffer.alloc(8);
chunk.writeUInt32LE(4, 0);
chunk.writeUInt32LE(0x004e4942, 4); // 'BIN\0'
await expect(inspectVrm(write('bin-first.glb', Buffer.concat([header, chunk, Buffer.alloc(4)])))).rejects.toThrow(
/JSON/,
);
});
});