import { test } from 'node:test'; import assert from 'node:assert/strict'; import { join } from 'node:path'; import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { ROOT } from '../lib/paths.mjs'; import { loadSource, SourceError } from '../ui-migration/gameabc-source.mjs'; const REAL_SOURCE = join(ROOT, '..', 'projects', 'Game_Surface_3', 'output'); function fakeSource(overrides = {}) { const dir = mkdtempSync(join(tmpdir(), 'gameabc-src-')); const files = { 'gameabc_Object.json': { ObjectList: [ {}, { Property: { ObjectID: 1, ObjectType: 2, ObjectName: '背景', Left: 0, Top: 0, Width: 1280, Height: 720, BelongLayerID: 1, IndexOfLayer: 1, ImageFileID: 1, FrameStyle: 0, FrameIndex: 0, L9: 0, T9: 0, R9: 0, B9: 0, GroupID: 1, VoiceFileID: 0, TimerInterval: 0 }, Event: { mousedown: 1, mouseup: 1 } }, ], }, 'gameabc_Layer.json': { LayerList: [{}, { Property: { LayerID: 1, LayerName: 'Logo_Layer' }, ObjectList: [1] }] }, 'gameabc_GroupList.json': { GroupList: [{ GroupID: 1, ObjectList: [1] }] }, 'gameabc_Image.json': { ImageFileList: [{}, { id: 1, w_all: 1280, h_all: 720, w: 1, h: 1, frame_all: 1, bmp: '00001.png', w1: 1280, h1: 720 }] }, ...overrides, }; for (const [name, content] of Object.entries(files)) { writeFileSync(join(dir, name), JSON.stringify(content)); } return dir; } test('loadSource 解析对象、层、组、图,并附上 events', () => { const dir = fakeSource(); try { const s = loadSource(dir); assert.equal(s.objects.size, 1); assert.equal(s.objects.get(1).ObjectName, '背景'); assert.deepEqual(s.objects.get(1).events, ['mousedown', 'mouseup']); assert.deepEqual(s.layers, [{ layerId: 1, name: 'Logo_Layer', objectIds: [1] }]); assert.deepEqual(s.groups, [{ groupId: 1, objectIds: [1] }]); assert.equal(s.images.get(1).bmp, '00001.png'); } finally { rmSync(dir, { recursive: true, force: true }); } }); test('loadSource 跳过源数据里的空占位槽 {}', () => { const dir = fakeSource(); try { const s = loadSource(dir); assert.equal(s.objects.size, 1, '首个 {} 占位不应变成对象'); assert.equal(s.layers.length, 1); } finally { rmSync(dir, { recursive: true, force: true }); } }); test('loadSource 对网格与帧数不符的图显式抛错(不兜底)', () => { const dir = fakeSource({ 'gameabc_Image.json': { ImageFileList: [{}, { id: 1, w_all: 100, h_all: 100, w: 3, h: 4, frame_all: 11, bmp: 'bad.png', w1: 33, h1: 25 }] }, }); try { assert.throws(() => loadSource(dir), SourceError); assert.throws(() => loadSource(dir), /bad\.png/); } finally { rmSync(dir, { recursive: true, force: true }); } }); test('loadSource 对缺失文件显式抛错', () => { const dir = mkdtempSync(join(tmpdir(), 'gameabc-empty-')); try { assert.throws(() => loadSource(dir), /缺少源数据文件/); } finally { rmSync(dir, { recursive: true, force: true }); } }); test('loadSource 在真实源数据上得到已知规模(回归护栏)', () => { const s = loadSource(REAL_SOURCE); assert.equal(s.objects.size, 991, '对象总数'); assert.equal(s.layers.length, 55, '界面数'); assert.equal(s.groups.length, 80, '分组数'); assert.equal(s.images.size, 439, '图片数'); const multi = [...s.images.values()].filter((i) => i.frame_all > 1); assert.equal(multi.length, 139, '多帧图数'); });